ib-trailing-stop — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited ib-trailing-stop (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Places IB native TRAIL orders against stocks and naked LEAPS in the portfolio. IB auto-adjusts the stop trigger as the price climbs and locks it as price falls.
PMCC positions are intentionally excluded — use ib-stop-loss for those (a standalone trailing stop on the PMCC long leg would break the hedge at trigger).
Default mode is dry-run — no orders are placed unless --execute is in the request.
TWS or IB Gateway must be running locally with API enabled:
Port fallback: If the configured port fails, automatically retry on the other port. If the retry succeeds, save to memory which account type worked (live/paper) and reuse it for all IB skill calls in this and future sessions — until the user explicitly asks for the other account. If both ports fail, ask the user to verify that TWS or IB Gateway is running with API access enabled.
Dry-run (default — no orders placed):
uv run python .claude/skills/ib-trailing-stop/scripts/trailing_stop.py --symbols JOBY --trail-pct 20Execute (cancel orphan TS_ orders + place new TS_ TRAIL orders):
uv run python .claude/skills/ib-trailing-stop/scripts/trailing_stop.py --symbols JOBY --trail-pct 20 --executeExecute forced (cancel + replace existing TS_ orders with current parameters):
uv run python .claude/skills/ib-trailing-stop/scripts/trailing_stop.py --execute --forcedFormat JSON output as a markdown report with three sections:
#### Section 1: Existing TRAIL Orders Show all_trail_orders.module (TS_ orders) and all_trail_orders.manual (manually placed). If orphan_orders is non-empty, warn that these were cancelled (execute mode) or need manual cancellation (dry-run).
#### Section 2: Positions For each entry in positions, show a table:
| Field | Value |
|---|---|
| Symbol | JOBY — stock (1000 shares) |
| Spot | $7.50 |
| Reference | $7.50 (max of current $7.50, avg cost $5.00) |
| Trail params | 20% (initial stop $6.00) → action: place_new |
| Existing trail | none |
For LEAPS rows, also show the option leg (strike/expiry) and current option mark.
action values:
place_new — no existing TS_ order; one will be created in execute modepreserve_existing — TS_ already in place; left alone (IB has been tracking the high)overwrite — --forced is on; existing TS_ will be cancelled and replaced#### Section 3: Order Results (execute mode only) Per-position result with order_id and order_ref.
action: place_new (these are about to get a new TRAIL).preserve_existing separately so user knows nothing changed.trail_stop_price) so user knows where IB has trailed to.| Flag | Default | Description |
|---|---|---|
--port | 7497 | IB Gateway/TWS port |
--account | all | Specific account ID |
--symbols | all | Analyze only these symbols |
--trail-pct | 20 | Trail amount as percentage of reference |
--trail-amt | — | Trail amount in dollars (mutually exclusive with --trail-pct) |
--price-mode | mid | Option pricing: mid or last (LEAPS only) |
--execute | off | Cancel orphans + place TS_ TRAIL orders |
--forced | off | Cancel and replace existing TS_ orders (requires --execute) |
{
"generated_at": "2026-05-29 10:00 ET",
"data_delay": "real-time",
"dry_run": true,
"forced": false,
"trail_pct": 20.0,
"trail_amt": null,
"accounts": ["U1234567"],
"symbols_filter": ["JOBY"],
"all_trail_orders": {"module": [], "manual": []},
"orphan_orders": [],
"positions": [
{
"symbol": "JOBY",
"type": "stock",
"account": "U1234567",
"qty": 1000,
"underlying_price": 7.50,
"stock": {
"avg_cost": 5.00,
"current_price": 7.50
},
"trail_stop": {
"trail_pct": 20.0,
"trail_amt": null,
"reference": 7.50,
"initial_stop_price": 6.00,
"action": "place_new",
"existing_trail": null
}
}
]
}max(current_price, avg_cost) — locks in profit when above cost, never starts below entry.current_price as the reference (can place an initial stop below entry, useful when re-arming after a drawdown).--forced to deliberately reset.ib-stop-loss for those.TS_{SYM}_{STRIKE}_{EXPIRY}_{RIGHT} — naked LEAPS TRAIL orders (right is C or P so calls and puts on the same strike/expiry don't collide)TS_{SYM}_STK — stock TRAIL ordersAll analytics live in src/trading_skills/broker/trailing_stop.py:
Analytics (no IBKR — testable in isolation):
calc_trail_reference — max(current_price, avg_cost) normally; current_price if forcedcalc_initial_trail_stop_price — reference × (1 − trail_pct/100) or reference − trail_amtidentify_trailable_positions — stocks + naked LEAPS; PMCC excludedbuild_trail_analysis — full per-position output dictdetect_orphan_trail_orders — TS_ TRAIL orders for gone positionssummarize_all_trail_orders — splits IB TRAIL orders into module vs manualData layer (IBKR):
get_trailing_stop_data — main entry point_cancel_orphan_orders — cancel stale TS_ orders_place_simple_trail_order — native TRAIL order on stock or option_execute_position_trail — dispatch per position type~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.