Fortress Script Reference
Usage guide for all 12 Python tools. Each section shows common command patterns, key flags, and a live preview of real output. All scripts run from ~/fortress/scripts/ using python3.
Flags auto-updated weekly — last refresh: 08 Jul 2026
Fortress Optimizer
fortress_v26.py
LEAPS Builder
leap_builder.py
CC Scanner
cc_scanner.py
CC Manager
cc_manager.py
Fortress Rebuild
fortress_rebuild.py
FIGHT Recovery
fortress_fight.py
Fortress Repair
fortress_repair.py
Repair Trades
repair_trades.py
Stock Researcher
stock_researcher.py
LEAPS vs Fortress
leaps_vs_fort.py
GS Put Seller
gs_put_seller.py
Fortress Optimizer
fortress_v26.py β ~5100 lines
Three-archetype optimizer (PIONEER / DIAMOND / VAULT). Selects LC+SP+HP+SC strikes for minimum capital, max leverage.
Common Usage
Live IBKR β single ticker
python3 fortress_v26.py --live --tickers NVDA --contracts 10
Live β multiple tickers
python3 fortress_v26.py --live --tickers MSTR COIN BMNR --contracts MSTR:5 COIN:10 BMNR:20
From CSV (no IBKR needed)
python3 fortress_v26.py ~/fortress/runs/CSVs/NVDA_20260401.csv --contracts 10
Short-term mode + risk cap
python3 fortress_v26.py --live --tickers XLE --short-term --risk XLE:50k
Sigma analysis + parallel
python3 fortress_v26.py --live --tickers QQQ SPY --sigma --parallel 4
Key Flags
| Flag | Description | Default |
|---|---|---|
| csv_files | One or more fortress export CSVs. Required unless --live is used. If a ticker appears in multiple files, first occurrence is used. | |
| --contracts | Contracts per ticker. Single number (e.g. --contracts 5) or per-ticker pairs (e.g. --contracts XLP:10 XLU:5 MSTR:10). Mix: --contracts 5 XLP:10 (5 default, override XLP to 10). | |
| --risk | Max loss budget per ticker in dollars. Per-ticker pairs (e.g. --risk MSTR:80000 COIN:50000). Supports k/K suffix (e.g. MSTR:80k = 80000) and m/M (1m = 1000000). Without --risk, ML ceiling defaults to notional (stock Γ shares). Removes two-pass RM bootstrapping. Single-pass ML-capped search. | |
| --fight-otm | FIGHT mode CC OTM% from stressed stock (default: 0.01 = 1%). Range 0.00 (ATM) to 0.15 (15% OTM). Lower = more premium, more management. Higher = less premium, less management. | |
| --run-label | Custom label for output folder. Routes outputs to runs/{label}/ and generates a combined portfolio survival+FIGHT dashboard. Example: --run-label RESTRUCTURE | |
| --dd-level | Max drawdown level for survival curve (default: 40, max: 90). 5% steps to 40%, then 10% steps beyond. E.g. --dd-level 60 produces [5,10,15,20,25,30,35,40,50,60]. Use 60 for high-beta, 90 for crypto. Resilience thresholds (ARMORED=25%, RESILIENT=15%) unchanged. | 40 |
| --drawdown-pct | Drawdown % for stress testing (default: IV-scaled) | |
| --min-income-dte | Minimum DTE for income calls (default: 7) | 7 |
| --delta | SC delta cap for income calls (e.g. --delta 0.20). Without this flag, default is 0.35. | |
| --sigma | Show CC sigma analysis in dashboard (e.g. --sigma 1.0). Displays alternative CC at the given sigma floor. Does not affect CC selection, only dashboard display. | |
| --tickers | Filter to specific tickers (e.g. --tickers TSLA NVDA) | |
| --no-dashboard | Skip HTML dashboard generation | |
| --no-browser | Do not open the dashboard in the browser after completion | |
| --no-json | Skip JSON results file | |
| --all | When --contracts has per-ticker overrides, include ALL tickers from CSV (not just the mentioned ones). Unmentioned tickers get the default contract count. | |
| --landscape | Run landscape correlation analysis per ticker (verifies metric independence assumptions) | |
| --short-term | Short-term income mode: uses all LEAPS chains (not just far), defaults delta to 0.50 and min-income-dte to 28. Adds friction model (assignment probability, rebuild cost, net-after-friction) and exit profit to output and dashboard. Designed for aggressive income strategies that accept assignment. | |
| --live | Live mode: connect to IBKR TWS, fetch chains in real-time, run optimizer on live data. Requires ib_insync and running TWS. Use --contracts TICKER:N to specify tickers. Saves fetched data to CSV for reuse. | |
| --host | IBKR TWS host (default: 127.0.0.1) | 127.0.0.1 |
| --port | IBKR port (default: auto-detect. Tries 4001 Gateway Live, 4002 Gateway Paper, 7496 TWS Live, 7497 TWS Paper) | 0 |
| --client-id | IBKR client ID (default: 99) | 99 |
| --account | IBKR account for the --margin whatIf (TIMS maintenance margin varies by account). Default: first managed account. | |
| --parallel | Number of parallel IBKR connections for live mode (v27 default: 1 = mega-batch, one connection, one cascade across all tickers so tier sleeps amortize; CEILING: 4). Values > 4 silently deadlock IBKR Gateway on default-tier accounts (see PARALLEL_FETCH_SPEC.md Lessons Learned #1). Each worker gets its own connection at clientId=base+i. | 1 |
| --income-dte | DTE range for income calls in live mode (default: 5 46). Example: --income-dte 7 46 | |
| --leaps-dte | DTE range for LEAPS in live mode (default: 180 9999, short-term default: 180 450). Limits which LEAPS chains are fetched. Example: --leaps-dte 180 450 | |
| --publish | Publish dashboard to Cloudflare Pages via wrangler. Copies dashboard as index.html and deploys via wrangler. Example: --publish ~/Downloads/fortress-dashboard | |
| --notify | Send push notification via ntfy.sh when dashboard is ready. Install ntfy app on phone, subscribe to your topic. Example: --notify fortress-abhi | |
| --telemetry | v20.10: Always on (kept for backward compat). Scan telemetry exported in every JSON output. | True |
| --no-audit | Skip auto-generating audit HTML after scan. | False |
| --margin | Compute REAL IBKR portfolio (TIMS) maintenance margin per archetype via a whatIf simulation (never a live order) and add a Maint. Margin row to the dashboard. Needs a write-enabled TWS/Gateway during US RTH. When it cannot price (off-RTH, no API write access, qualify fail) the row shows NA rather than disappearing. Works in --live and CSV modes (port auto-detects). | False |
Output Location
runs/fortress/{TICKER}/latest.html
runs/fortress/{TICKER}/{TIMESTAMP}.html
runs/fortress/{TICKER}/audit_{TIMESTAMP}.html
runs/CSVs/{TICKER}_{TIMESTAMP}.csv β live mode only
LEAPS Builder
leap_builder.py β ~2120 lines
Builds optimal LC+SP+HP fortress structures for new tickers. Bucket A (deep ITM) vs Bucket B (OTM leverage), configurable split.
Common Usage
Single ticker, default split (50/50 ITM/OTM)
python3 leap_builder.py --tickers NVDA:250k
Multiple tickers, explicit mode
python3 leap_builder.py --tickers MSTR:100k:itm COIN:80k:otm
Custom budget split (70% ITM, 30% OTM)
python3 leap_builder.py --tickers GOOG:200k:both --budget-split 70/30
From CSV (skip IBKR)
python3 leap_builder.py --tickers XLE:150k --csv ~/fortress/runs/CSVs/XLE_chain.csv
Ticker Format
--tickers TICKER:BUDGET[:MODE]
MODE options:
itm β Bucket A only (deep ITM, income-focused)
otm β Bucket B only (OTM leverage play)
both β Split between A and B (default)
Key Flags
| Flag | Description | Default |
|---|---|---|
| --tickers | One or more positions. SIZE = 30k/100k/1m (budget) or 20c (contracts). MODE (optional, NORMAL only) = itm or otm to narrow; omit for both. BREAKOUT mode forces ITM internally (no MODE needed). See epilog. | |
| --csv | Use a saved chain CSV (offline mode, skip IBKR). CSV must include the requested tickers. | |
| --cc-overlay | Scan CC overlay (short-dated calls above safe strike) for the Bucket A winner. Off by default. | |
| --parallel | Parallel workers (live mode only, hard cap 4; default 4). Each worker uses its own IBKR connection. --parallel 1 forces serial mode. Above 4 silently deadlocks IBKR Gateway, do not raise. | 4 |
| --min-dte | Minimum DTE for LEAPS chain discovery (default: 270) | 270 |
| --max-chains | Number of furthest-out chains to scan (default: 3) | 3 |
| --html | Override HTML output path (default: routed via OutputManager) | |
| --audit | Override audit JSON output path (default: routed via OutputManager) | |
| --host | IBKR host (default: 127.0.0.1) | 127.0.0.1 |
| --port | IBKR port (default: 0 = auto-detect TWS Live 7496 / Gateway Live 4001 / Gateway Paper 4002 / TWS Paper 7497) | 0 |
| --client-id | IBKR client ID (default: 95) | 95 |
| --account | IBKR account for the --margin whatIf (TIMS maintenance margin varies by account). Default: first managed account. | |
| --breakout | Breakout mode: score by weighted P&L across sigma-multiples of the stock's expected move over HORIZON months (default: 6). Targets auto-scale by stock IV (UAMY high-vol -> bigger % targets, MU low-vol -> smaller % targets). Forces Bucket A (deep ITM), lowers --min-dte to 60 and scans EVERY chain >= 60 DTE (no max-chains cap). Skips CC overlay. E.g. --breakout (6mo), --breakout 3 (aggressive). | |
| --breakout-target | Override sigma-scaled scoring with a SINGLE fixed-pct target (e.g. --breakout-target 0.50 = +50%). Use when you want a specific scenario, not the IV-adaptive default. Only meaningful with --breakout. | |
| --stop-loss-pct | Score by reward / MTM-loss-at-stop instead of reward / structural-ML. E.g. --stop-loss-pct 0.15 evaluates each structure as if you cut losses when stock drops 15% from entry. Adds a Stop Profile card and re-ranks. Currently only meaningful with --breakout; accepted with --yolo but not yet wired (silent no-op there). | |
| --yolo | YOLO mode: widened OTM ranges (LC 95-300% of stock, SP 30-130%) and tail-weighted scoring (peak at +200% / +300% = 3-4x stock). Bucket A still runs as a context comparison; Bucket B renders FIRST. Use only on high-conviction directional bets (e.g. MARA in a crypto bull cycle). Mutually exclusive with --breakout. | |
| --yolo-cap | Override LC max strike multiplier in YOLO mode (default: 3.0 = 300% of stock). Lower it for low-vol megacaps (e.g. --yolo-cap 1.5 for NVDA so LC max = 150% stock); raise it for hypervol microcaps (e.g. --yolo-cap 4.0). Only meaningful with --yolo. | 3.00 |
| --anchor | Anchor all comparisons to a specific chain. Without LABEL: use the FURTHEST chain available (max DTE, gives the thesis most runway). With LABEL: match by DTE ('625d') or expiration prefix ('2028-01'). Restricts the Best Fortress and Best Pure picks to that chain so the Verdict / P&L / Stop Profile tables compare apples-to-apples within one expiry. Adds an 'Anchor Cost Analysis' card showing what anchoring costs (or saves) vs the free-choice score-best winners. | |
| --all | Run NORMAL + BREAKOUT + YOLO in one go and generate a single combined dashboard with a Master Verdict summary at the top + collapsible per-mode sections below. One IBKR fetch shared across all three scans. Use this when evaluating a name and you want all three lenses on one page. Composes with --anchor for cross-mode chain consistency. | |
| --margin | MARGIN MODE: per-chain Fortress comparison normalized to a single contract count (the max across chains) so every chain is apples-to-apples. Two use cases only: Stock replacement (Bucket A) + Moderate-bull (Bucket B). Columns: Delta, Sh Eqv (share-equivalent delta), IC, ML, Margin (Reg-T put-spread, NA outside RTH), BE, and a clickable PnL panel (-50% to +300%). Best pick per bucket = highest weighted P&L. Ignores --all and --anchor. |
Output Location
runs/leaps/{TICKER}/latest.html
runs/leaps/{TICKER}/{TIMESTAMP}.html
runs/leaps/{TICKER}/audit_{TIMESTAMP}.json
LEAPS vs Fortress
leaps_vs_fort.py β ~1350 lines
Head-to-head comparison of fortress_v26 (4-leg income Fortress) vs leap_builder (3-leg leveraged long) for ONE ticker at ONE max-loss budget. Equal-DTE tables, normalized breakeven-strike CC income for both structures, P&L curve from -50% to +300%, scored recommendation. Read-only.
Common Usage
Live head-to-head (needs RTH for true TIMS margin, Reg-T fallback otherwise)
python3 leaps_vs_fort.py MU:100k
Size to a TIMS maintenance-margin budget instead of max loss
python3 leaps_vs_fort.py DELL:150k --margin-budget 80k
Offline: one fortress-format CSV feeds both tools
python3 leaps_vs_fort.py MU:100k --csv ~/fortress/runs/CSVs/MU_20260620.csv
With AI narrative on the recommended pick
python3 leaps_vs_fort.py TSLA:200k --ai
Key Flags
| Flag | Description | Default |
|---|---|---|
| position | Ticker and max-loss budget, e.g. MU:100k (consistent with --tickers / --contracts elsewhere). | |
| --margin-budget | Optional maintenance-margin budget, e.g. 100k. When set, structures are sized to fit this TIMS budget instead of max loss. | |
| --csv | Chain CSV (fortress-export format) used for BOTH tools instead of live IBKR. A single fortress CSV works for both. | |
| --csv-fort | Override the Fortress CSV (must be fortress-export format). Falls back to --csv. | |
| --csv-leaps | Override the LEAPS CSV (its own native chains CSV, for max fidelity). Falls back to --csv. | |
| --fort-contracts | Contract count for the raw Fortress dashboards. Default: estimated from the LEAPS run so the raw dashboards are budget-relevant. | |
| --account | IBKR account for the TIMS margin whatIf in BOTH tools. Maintenance margin varies by account; default is the first managed account. | |
| --no-margin-curve | Skip the real-TIMS margin curve (whatIf at each displayed count +/- 2). Faster, but the inline editor then shows linear margin estimates only. | |
| --ai | Add an Anthropic-generated narrative (needs ANTHROPIC_API_KEY). |
Output Location
runs/leaps_vs_fort/{TICKER}/latest.html
deploy/leaps_vs_fort/{TICKER}.html β CF staged
Covered Call Scanner
cc_scanner.py β ~3070 lines
Sigma-band scoring for CC strikes above safe strike. IER (Income Efficiency Ratio) ranking. Single ticker or batch portfolio scan.
Common Usage
Single ticker with safe strike
python3 cc_scanner.py NVDA 480 --contracts 10
Batch portfolio scan from CSV (v3.0 mega-batch, one IBKR connection)
python3 cc_scanner.py --csv positions.csv
Reload previous scan (no IBKR)
python3 cc_scanner.py --from-scan ~/fortress/runs/CSVs/cc_scan_data.csv
Drawdown mode (tighter delta cap 0.25)
python3 cc_scanner.py GLD 165 --contracts 20 --drawdown-mode
Key Flags
| Flag | Description | Default |
|---|---|---|
| ticker | Stock ticker symbol (single-ticker mode) | |
| safe_strike | Safe Strike of the fortress (single-ticker mode) | |
| --csv | Path to CSV position file for batch/portfolio scan (requires IBKR) | |
| --from-scan | Path to previously exported scan CSV (no IBKR needed, dashboards only) | |
| --output-dir | Output directory for all files (default: ./outputs) | ./outputs |
| --contracts | Number of contracts (single-ticker mode, default: 10) | 10 |
| --max-delta | Maximum delta filter (default: 0.40) | 0.40 |
| --max-dte | Maximum DTE to scan (default: from CSV per-ticker, or 45 in single-ticker mode) | |
| --min-dte | Minimum DTE to scan (default: from CSV per-ticker, or 2 in single-ticker mode) | |
| --host | IBKR TWS host (default: 127.0.0.1) | 127.0.0.1 |
| --port | IBKR port (default: auto-detect. Tries 4001, 4002, 7496, 7497) | 0 |
| --client-id | IBKR client ID (default: 30) | 30 |
| --drawdown-mode | Enable drawdown mode (tighter DTE preference) | |
| --no-browser | Do not auto-open dashboards in browser | |
| --output | Output HTML filepath (single-ticker mode only) | |
| --parallel | Number of parallel IBKR connections for batch mode (default: 4). Each worker gets its own connection at clientId=base+i. Do NOT raise above 4: parallel=6 was tested and caused silent Gateway deadlock (IBKR stops responding without emitting 354/420). 4 workers x 50 batch size = 200 peak concurrent subscriptions, which this account tolerates reliably. | 4 |
| --tickers | Filter --csv to only these tickers (e.g. --tickers MSFT NVDA TSLA) | |
| --score-ledger | Fix 5: resolve matured picks in the calibration ledger via yfinance and print predicted-vs-realized calibration by sigma band. No IBKR needed. | |
| --skip-cc-timing | Skip the automatic cc_timing.py refresh at start of run. By default cc_scanner runs cc_timing first (uses yfinance, no IBKR conflict, ~15-30s) so the per-ticker weekly gate panel reflects today\'s close. Use this flag for fast re-renders when you trust the existing telemetry. |
Output Location
runs/cc_scanner/{TICKER}/latest.html β per ticker
runs/cc_scanner/cc_scan_PORTFOLIO.html β master view
runs/CSVs/cc_scan_data.csv β reusable scan data
CC Manager
cc_manager.py β ~2550 lines
Covered-call income HEALTH CHECK and goal tracker, not an order/strike tool. Reuses fortress_rebuild's cached chains plus the trade-log sheet: 3-month sold-CC behaviour, goal tracking (floor vs ideal), open-CC buyback book, forward candidates and regime overlay. Read-only, no live option scan.
Common Usage
Standard run (fortress_rebuild must have run first)
python3 cc_manager.py
Pure offline: skip the small live fetch of open-CC marks
python3 cc_manager.py --no-live-marks
Custom goal band + longer lookback
python3 cc_manager.py --floor 30000 --ideal 50000 --months 6
Run and push the dashboard to Cloudflare
python3 cc_manager.py --deploy
Key Flags
| Flag | Description | Default |
|---|---|---|
| --rebuild-cache | fortress_rebuild last_scan.json to reuse for chains (default: runs/rebuild/last_scan.json) | |
| --no-live-marks | skip the small live IBKR fetch of open-CC marks for Insight 1 (use the cached marks even if the gateway is up) | |
| --csv | active fortresses CSV (default: active_fortresses.csv) | |
| --host | IBKR host for the Insight 1 live mark fetch | 127.0.0.1 |
| --account | IBKR account filter (default: all) | |
| --floor | monthly income floor in dollars for the goal tracker (default 30,000) | 30000.0 |
| --ideal | ideal monthly income in dollars for the goal tracker (default 50,000) | 50000.0 |
| --months | lookback window in months for sold-CC history (default 3) | 3 |
| --spread | per-ticker cap (0-1) for the Mix variation; lower = more diversified (default 0.67) | 0.67 |
| --bullish | comma-separated longer-term bullish holds to exclude from sell recommendations (default: GLXY,RIOT) | GLXY,RIOT |
| --max-target | legacy/no-op: Max now sells every available contract, so this no longer bounds it | 75000.0 |
| --no-html | console only | |
| --deploy | push the staged dashboard to Cloudflare (runs deploy_cf.sh) after the run | |
| --score | grade past projections vs realised income from the ledger (no IBKR); advisory calibration read |
Output Location
runs/cc_manager/PORTFOLIO/latest.html
deploy/cc_manager/PORTFOLIO.html β CF staged
CC Check
cc_check.py β ~390 lines
Reads active_fortresses.csv, scans all IBKR accounts, and reports missing or partial covered call coverage.
Common Usage
Default scan (all accounts, active_fortresses.csv)
python3 cc_check.py
Custom CSV
python3 cc_check.py --csv my_list.csv
Specific account only
python3 cc_check.py --account U1234567
Specific port
python3 cc_check.py --port 4001
Key Flags
| Flag | Description | Default |
|---|---|---|
| --csv | CSV file with Ticker, Contracts columns (default: active_fortresses.csv) | |
| --port | IBKR port (0 = auto-detect) | 0 |
| --account | IBKR account ID (omit to scan all accounts) | |
| --max-dte | Max DTE for short calls to count as coverage (default: 180) | 180 |
| --no-survival | Skip the stock-price + CC-survival fetch (faster, no market data) |
Output Location
runs/cc_check/PORTFOLIO/latest.html
deploy/cc_check/PORTFOLIO.html β CF staged
Fortress Rebuild (Lifecycle Manager)
fortress_rebuild.py β ~3100 lines
Read-only lifecycle analyzer. Scans every fortress position across all IBKR accounts and recommends one action per fortress: SKIP, WAIT, ROLL, UNCAP, or REBUILD. Surfaces ride-to-expiry math (stock flat vs stock at CC strike), proactive roll candidates, and stranded-WAIT escalations. Routes all IBKR fetches through module_ibkr_fetch for identical reliability and logging (FROZENβDELAYEDβSNAP cascade, OI backfill, deep-ITM historical fallback).
Common Usage
Scan every fortress across every account
python3 fortress_rebuild.py
Bind to active_fortresses.csv (authoritative Entry / Safe Strike / Net Debit)
python3 fortress_rebuild.py --csv
Filter to specific tickers
python3 fortress_rebuild.py --tickers COIN,MSTR,IREN
Horizon cutoff β only fortresses with HP expiring by date; CC scan window tightens to match
python3 fortress_rebuild.py --expiry 2026-09-30
Single account
python3 fortress_rebuild.py --account U18827291
Fast mode β skip proactive roll fetches (useful for triage on slow IBKR)
python3 fortress_rebuild.py --no-rolls
Re-render from cached scan (no IBKR) β iterate on decision logic offline
python3 fortress_rebuild.py --cached
Decisions Produced
SKIP — structurally safe, no action needed.
WAIT — margin OK but borderline; monitor. Borderline variants show theta/trip-wire narrative.
WAIT (MARGINAL) — sigma is thin; roll candidates fetched proactively to find an escape.
ROLL CC — concrete roll candidate identified with credit, new sigma, and survival.
UNCAP — close the short call (strike capped, no forward roll viable).
REBUILD — structural damage; suggests going to leap_builder or fortress_repair.
WAIT — margin OK but borderline; monitor. Borderline variants show theta/trip-wire narrative.
WAIT (MARGINAL) — sigma is thin; roll candidates fetched proactively to find an escape.
ROLL CC — concrete roll candidate identified with credit, new sigma, and survival.
UNCAP — close the short call (strike capped, no forward roll viable).
REBUILD — structural damage; suggests going to leap_builder or fortress_repair.
Ride-to-Expiry Math
Every decision shows the "do nothing" baseline as explicit P/L:
CLOSE P/L — close fortress now at market mids.
STOCK FLAT — hold through CC expiry, stock unchanged. CC extrinsic decays to zero.
STOCK @ $strike — hold through CC expiry, stock rallies to cap. Adds fortress gain using full synthetic delta (LC long + SP short − HP long).
CLOSE P/L — close fortress now at market mids.
STOCK FLAT — hold through CC expiry, stock unchanged. CC extrinsic decays to zero.
STOCK @ $strike — hold through CC expiry, stock rallies to cap. Adds fortress gain using full synthetic delta (LC long + SP short − HP long).
Key Flags
| Flag | Description | Default |
|---|---|---|
| --host | TWS host | 127.0.0.1 |
| --port | TWS port (default 7496) | 7496 |
| --client-id | IBKR clientId | 25 |
| --account | Single account to scan (default: all managed) | |
| --tickers | Ticker filter. Space-separated or comma-separated (e.g. --tickers COIN MSTR IREN or --tickers COIN,MSTR). | |
| --exclude | Tickers to EXCLUDE from the run. Same syntax as --tickers (space or comma separated). Applied after --tickers, so you can include a set then drop a few (e.g. --exclude META or --exclude META,NEM). | |
| --expiry | Horizon cutoff date. (1) Hedge-put (HP): only show fortresses whose HP expires by this date. (2) Short-call (CC): scan CCs whose DTE is within (cutoff - today). Without --expiry, HP is unfiltered and CC horizon defaults to 90d. Accepts 2026-09-18, 20260918, 17122027 (DDMMYYYY), 18-sep-2026, 2026-Sep-18, 18/09/2026, YYYY-MM, etc. | |
| --csv | Use active_fortresses.csv as structural authority (ticker β LC/SP/HP strikes + Entry/Safe Strike/Net Debit/Contracts). Binds CSV rows to live IBKR legs. Without a PATH, defaults to ~/fortress/scripts/active_fortresses.csv. Without --csv, the script falls back to fuzzy-matching legs in IBKR positions. | |
| --cached | Reuse cached scan data (skip IBKR) | |
| --no-rolls | Skip roll-chain fetches (faster) | |
| --get-cc-timing | Run cc_timing.py first to refresh the weekly-gate telemetry JSON (BB ladder + BB ZONE source). Use when running ad-hoc mid-day so the gate matches current weekly bars. Skip on nightly cron runs β cc_timing is already a separate job there. | |
| --cc-suggest | Append a section at the bottom of the dashboard with short-call candidates for both UNCAPPED fortresses (fresh CC to sell) and SKIP+CC fortresses (roll options). Natural-ladder view with up to three algorithmic picks highlighted: BEST EV, SAFEST VIABLE, and (drawdown rolldowns only) RISKY HARVEST β a below-SS pick that explicitly trades a locked-loss-on-assignment for premium credit. | |
| --cc-suggest-max-dte | Max DTE for CC suggestions (default 20, matches the 'rarely sell beyond 20d' convention). | 20 |
| --cc-suggest-scope | Which fortresses to include: BOTH (default), UNCAPPED (gear-mode only), or CAPPED (SKIP+CC only). | BOTH |
| --cc-suggest-max-rows | Optional explicit cap on candidate rows per expiry. Default: no cap (every strike that survives the 0.05-0.40 delta band is shown and considered for marker selection). Pass an integer to truncate by delta descending. | |
| --json | Also write raw JSON to this path | |
| --html | Also write HTML to this explicit path (OutputManager always runs) |
Output Location
runs/rebuild/{TICKER_LIST}/latest.html
deploy/rebuild/{TICKER_LIST}.html β CF staged
FIGHT Income Recovery
fortress_fight.py β ~2320 lines
Aggressive drawdown recovery via near-ATM short-dated calls. P&L curves at 8 price points, gap-up scenarios, income target tracking.
Common Usage
From fortress_results.json (most common)
python3 fortress_fight.py --from-results ~/fortress/runs/fortress/NVDA/fortress_results.json
Manual ticker + position detail
python3 fortress_fight.py --ticker NVDA:10:480:20260620 --fight-dte 7 --fight-otm 0.01
Multiple tickers from results
python3 fortress_fight.py --from-results fortress_results.json --tickers NVDA GLD COIN
Custom gap-up + income targets
python3 fortress_fight.py --ticker MSTR:5:350:20270117 --gap-pct 0.15 --targets 0.25 0.50 0.75 1.00
Key Flags
| Flag | Description | Default |
|---|---|---|
| csv_file | Chain data CSV (skips live chain fetch, still reads IBKR portfolio) | |
| --tickers | Ticker symbols. Space-separated or comma-separated (e.g. --tickers NOW COPX or --tickers NOW,COPX). Contracts, Safe Strike, and ND are read from the --csv file. | |
| --csv | Path to active_fortresses.csv (ticker β contracts, Safe Strike, legs, ND). Defaults to active_fortresses.csv in the scripts directory. | |
| --legs | Optional leg detail (e.g. GLD:HP:410:20260630:7.214). Repeatable. | |
| --from-results | Read positions from fortress_results.json | |
| --all | Portfolio FIGHT mode: scan every ticker in the --csv roster, keep only UNCAPPED fortresses (no active short calls in IBKR, i.e. cc_check NONE), analyze the UNDERWATER ones, and write a PORTFOLIO master dashboard with per-ticker click-throughs. | |
| --host | IBKR TWS host (default: 127.0.0.1) | 127.0.0.1 |
| --port | IBKR port (default: auto-detect. Tries 4001, 4002, 7496, 7497) | 0 |
| --client-id | IBKR API client ID (default: 99). Parallel workers use client_id+100+N to avoid collisions. | 99 |
| --account | IBKR account ID (e.g. U1234567). If omitted, uses the first managed account. | |
| --legacy-fetch | Use the old per-ticker worker fetch (one connection per worker, per-group tier sleeps) instead of the single-connection mega-batch. For parity comparison; the mega-batch is the default. | |
| --parallel | Parallel IBKR connections (default: 4) | 4 |
| --eager-escape | Fetch escape-path chains for EVERY flagged call (incl. capped-only WATCH names like GLD/META). Complete but slow: those chains are otherwise deferred to on-demand --tickers T runs to keep the portfolio run fast. | |
| --expiry | HP (hedge put) expiry date. Accepts: 20260630, 30-Jun-2026, 30-jun-26, Jun-2026. Selects which fortress structure to analyze. If omitted, uses the nearest active HP per ticker. | |
| --min-dte | FIGHT CC DTE floor (range 1-45). Default auto-anchors the nearest gamma-safe upcoming Friday (>= 2 DTE): the floor drops from 4 to include it (Tue Fri = 3d, Wed Fri = 2d), else stays 4. Pass a value to override: BELOW 4 catches a near weekly (pin/gamma, warned); ABOVE 4 opens fetch + pick to the full band above the floor (e.g. --min-dte 30 = 30-45d, longer-tenor fewer-rolls). | |
| --html | HTML output path (default: fight_TICKER_TIMESTAMP.html) | |
| --no-html | Suppress HTML output entirely | |
| --json | JSON output path | |
| --force | Show roll decisions for ALL current CCs regardless of sigma | |
| --roi | Override annual ROI on ML for normal income ref (e.g. 0.80 for 80%). Default: IV-based (LOW 45%, MED 75%, HIGH 95%) | |
| --nd | Original entry ND per share (immutable, from trade creation). Overrides IBKR-computed ND after HP rolls. Bare number form applies to all --tickers (e.g. --nd 107.37). Per-ticker form: --nd MSFT:107.37 --nd GLD:137.34 |
Output Location
runs/fight/{TICKER}/latest.html
runs/fight/{TICKER}/{TIMESTAMP}.html
Fortress Repair Analyzer
fortress_repair.py β ~2800 lines
Analyzes SP roll-down paths to lower the safe strike. Recommends HP repairs with payback analysis. Post-repair CC sustainability included.
Common Usage
Analyze specific tickers
python3 fortress_repair.py NVDA MSTR COIN
All fortress positions in portfolio
python3 fortress_repair.py --all
Filter by HP expiry, limit payback period
python3 fortress_repair.py --all --expiry 2026-06 --max-payback 0.5
With CC income override
python3 fortress_repair.py XLE --cc-income 0.45 --hp-min-dte 45 --hp-max-dte 90
Key Flags
| Flag | Description | Default |
|---|---|---|
| tickers | Ticker(s) to analyze (e.g. IREN IWM TSLA) | |
| --all | Analyze all fortress positions in portfolio | |
| --expiry | Filter to positions with HP expiring by this date (YYYY-MM or YYYYMMDD). Repair targets use --hp-max-dte independently. | |
| --hp-min-dte | Min DTE for HP candidates (default: 60). --min-target-dte is an alias (repair_trades.py parity). | 60 |
| --hp-max-dte | Max DTE for HP candidates (default: 120) | 120 |
| --gap-mult | Max ratio of new_gap vs current gap (default: 2.0). HP candidates whose roll-down would widen the SP-HP gap beyond this multiplier are rejected. Use 1.5 for tight RM discipline, 3.0 for aggressive roll-down freedom. | 2.0 |
| --price-multiplier | Add pick_score ROI component at Nx current stock price. For parabolic movers (crypto miners, high-beta names) where default 4x/5x grid underweights tail outcomes. Must be > 1. Float values accepted (e.g. 7.5, 10). | 0 |
| --max-payback | Max payback period in years for repair candidates (default: 1.0). Candidates with payback above this are flagged but still shown. | 1.0 |
| --cc-income | Monthly CC income per share override (e.g., 4.00). If not set, auto-estimates from the active SC leg. | 0 |
| --maint-roll-dte | DTE threshold for healthy-fortress HP maintenance roll (default: 45). Healthy positions whose HP DTE drops below this trigger MAINTAIN analysis (roll-out to similar/smaller-ML strike) instead of REPAIR (roll-down). | 45 |
| --maint-cost-cap | Max ratio of new HP annual cost vs CC annual income for a maintenance roll candidate to qualify (default: 0.25). Keeps the rolled hedge easily covered by income. | 0.25 |
| --no-maint | Skip the maintenance-roll pass on healthy fortresses. | |
| --max-analyze-dte | Skip fortresses whose HP DTE exceeds this (default: 120). A hedge with months of runway isn't an actionable roll today; they show as OK. | 120 |
| --account | Limit scan to this account ID. Default scans ALL managed accounts and concatenates positions. | |
| --positions | CSV with actual position data (overrides IBKR avg_cost). Required col: ticker. Optional: nd_per_share, lc_strike, sp_strike, hp_strike, sc_strike, contracts, ic, safe_strike | |
| --json | Export to JSON file | |
| --html | Export HTML dashboard | |
| --csv | CSV with safe strikes / ND / contracts / leg strikes per ticker (cols accepted: TICKER, SS, ND, CONTRACTS, LC, SP, HP, SC). Compatible with active_fortresses.csv. Defaults to ~/fortress/scripts/active_fortresses.csv. Pass --csv '' to disable. Values here take precedence over IBKR-derived metrics, AND restrict --all scope to the tickers listed. | DEFAULT |
| --nd | Net Debit per share override (e.g., 16.0). Single-ticker runs only. Overrides --csv ND and IBKR avg_cost. | 0 |
Output Location
runs/repair/{TICKER}/latest.html
runs/repair/{TICKER}_{TICKER2}/latest.html β multi-ticker
Repair Trades Finder
repair_trades.py β ~3990 lines
Finds concrete 6-leg BAG repair trades (close 3 + open 3) with real IBKR prices. Exhaustive 1k-2k combo search, TIMS margin enrichment, P&L curves.
Common Usage
Basic repair analysis
python3 repair_trades.py MSTR
Specify expiry + contracts
python3 repair_trades.py COIN --expiry 20270117 --contracts 5
With IBKR margin check + CC overlay
python3 repair_trades.py BMNR --margin --cc --gap-mult 3.0
Crypto miner: 3x price projection + FIGHT panel
python3 repair_trades.py MARA --price-multiplier 3 --fight --cc
Custom DTE range for target LEAPS
python3 repair_trades.py NVDA --min-target-dte 400 --max-target-dte 800
Key Flags
| Flag | Description | Default |
|---|---|---|
| ticker | Ticker to analyze (e.g. MARA) | |
| --expiry | Current position expiry to match (YYYYMMDD or 18-sep-2026). If omitted, auto-detects from portfolio. | |
| --contracts | Override contract count (e.g. 200 for 200 contracts = 20000 shares) | 0 |
| --lc | Select fortress structure by LC strike (e.g. --lc 60). Required when multiple structures exist on the same expiry. | 0 |
| --html | HTML output path (default: repair_<TICKER>_<timestamp>.html) | |
| --audit | Audit log JSON path (default: audit_<TICKER>_<timestamp>.json) | |
| --gap-mult | Max gap multiplier vs current gap (default: 2.0x) | 2.0 |
| --margin | Run IBKR whatIf margin checks on top candidates (requires write access) | |
| --min-target-dte | Minimum DTE for target LEAPS expiries (default: 365) | 365 |
| --max-target-dte | Maximum DTE for target LEAPS expiries (default: 1100) | 1100 |
| --price-multiplier | Add P&L projection at Nx current price (e.g., 10 for 10x). For parabolic movers like crypto miners. | 0 |
| --cc | Add CC income overlay to lens picks (scans DTE 5-50 call chains) | |
| --fight | Add FIGHT income panel: near-ATM short-dated CCs for income while waiting on repair. Shows gap risk tiers at 5/10/20% of ML. | |
| --nd | Override net debit per share (all-in cost basis). IBKR avg cost is wrong after repairs/rolls. Use your real all-in ND. e.g. --nd 2.21 | 0 |
| --no-roll | Skip roll candidates entirely. Only restructure within current expiry. | |
| --max-candidates | Cap total candidates after merge (default 250000). Trims lowest-score candidates to bound memory and audit JSON size on dense-strike chains. Set 0 to disable. | 250000 |
| --pnl | P&L curve only. Connects to IBKR, reads position, prints P&L at expiry to console. No repair analysis. Use with --expiry, --lc, --nd as needed. | |
| --pnl-max | Max stock price for P&L curve (default: 5x current price) | 0 |
| --roll-short-put | Roll-down-short-put mode: keep LC/HP, find the optimal lower-strike short put to cut early-assignment risk on a deep-ITM SP. Runs this analysis only and exits. | |
| --rsp-expiry | Expiry for the new short put (default: current SP expiry). Roll the strike down on the same date by default. | |
| --rsp-min-strike | Floor for candidate new SP strikes (default: stock x0.5; always kept above the HP strike). | 0 |
| --rsp-max-strike | Ceiling for candidate new SP strikes (default: current SP strike, exclusive). | 0 |
| --rsp-cushion | Target extrinsic/carry cushion for assignment-safe (default 1.0; >=1 means the put holder has no early-exercise incentive). | 1.0 |
| --rsp-rate | Risk-free rate for the carry / early-exercise boundary (default 0.04). | 0.04 |
Output Location
runs/repair_trades/{TICKER}/latest.html
runs/repair_trades/{TICKER}/audit_{TIMESTAMP}.json
Stock Researcher
stock_researcher.py β ~3040 lines
4-pillar quantitative scoring: Fundamentals (40%) + Technicals (15%) + Fortress Fit (30%) + Valuation (15%). AI narrative via Claude API. Hard gates apply.
Common Usage
Research single ticker
python3 stock_researcher.py NVDA
Batch research (multiple tickers)
python3 stock_researcher.py MSTR COIN BMNR RKLB HOOD AMD SOFI NVDA PLTR MU
Custom investment horizon
python3 stock_researcher.py GOOG --horizon "2-3 years"
No IBKR (yfinance IV only)
python3 stock_researcher.py MU AMD PLTR --no-ibkr
Scoring Pillars
| Pillar | Weight | Key Metrics |
|---|---|---|
| Fundamentals | 40% | Revenue growth, margins, FCF, debt |
| Fortress Fit | 30% | IV, liquidity, options chain depth, trend alignment |
| Valuation | 15% | P/E, P/S, EV/EBITDA vs peers |
| Technicals | 15% | Momentum, moving averages, RSI |
Key Flags
| Flag | Description | Default |
|---|---|---|
| tickers | Stock tickers | |
| --horizon | Investment horizon (default: '1-2 years') | 1-2 years |
| --output | Output HTML path | |
| --api-key | Anthropic API key (or ANTHROPIC_API_KEY env) | |
| --no-ibkr | Skip IBKR, yfinance IV only | |
| --json | Also dump raw data as JSON alongside HTML |
Output Location
runs/research/{TICKER}/latest.html
runs/research/{TICKER1}_{TICKER2}/latest.html β multi
GS Put Seller
gs_put_seller.py β ~1200 lines
Goldman Sachs "Art of Put Selling" screener. Finds optimal puts by FCF yield targets (1x / 2x / 3x monthly FCF). Specific tickers or SPX/QQQ/IWM discovery mode.
Common Usage
Specific tickers
python3 gs_put_seller.py --tickers MSFT AAPL NVDA GOOG
Discovery mode (screen index constituents)
python3 gs_put_seller.py --scan --top 10
No IBKR, specific expiry
python3 gs_put_seller.py --tickers QQQ SPY --no-ibkr --expiry 20260515
Capital sizing + force rescan
python3 gs_put_seller.py --scan --capital 500000 --collateral-pct 25 --rescan
Key Flags
| Flag | Description | Default |
|---|---|---|
| --tickers | Space-separated ticker symbols | |
| --scan | Discovery mode: screen SPX, QQQ, IWM constituents | False |
| --top | Top N stocks per index in discovery mode (default: 10) | 10 |
| --expiry | Target expiration (YYYYMMDD). Auto-selects nearest monthly 20-45 DTE if omitted | |
| --capital | Total portfolio capital for position sizing | |
| --collateral-pct | Collateral % per put (100=fully collateralized, default: 100) | 100 |
| --port | TWS port (default: 0 = auto-detect TWS/Gateway) | 0 |
| --no-ibkr | Use yfinance instead of IBKR for options data | False |
| --min-oi | Minimum open interest filter (default: 100) | 100 |
| --max-spread-pct | Maximum bid-ask spread as % of bid (default: 15.0) | 15.0 |
| --output | Output directory for HTML report | |
| --rescan | Force fresh discovery scan, ignore cache | False |
Output Location
deploy/gs_putseller/{TICKER1}_{TICKER2}.html
(also staged to deploy/ for CF Pages)