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 β€” ~5100 lines
Three-archetype optimizer (PIONEER / DIAMOND / VAULT). Selects LC+SP+HP+SC strikes for minimum capital, max leverage.
HTML + JSON IBKR or CSV
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
FlagDescriptionDefault
csv_filesOne or more fortress export CSVs. Required unless --live is used. If a ticker appears in multiple files, first occurrence is used.
--contractsContracts 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).
--riskMax 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-otmFIGHT 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-labelCustom label for output folder. Routes outputs to runs/{label}/ and generates a combined portfolio survival+FIGHT dashboard. Example: --run-label RESTRUCTURE
--dd-levelMax 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-pctDrawdown % for stress testing (default: IV-scaled)
--min-income-dteMinimum DTE for income calls (default: 7)7
--deltaSC delta cap for income calls (e.g. --delta 0.20). Without this flag, default is 0.35.
--sigmaShow 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.
--tickersFilter to specific tickers (e.g. --tickers TSLA NVDA)
--no-dashboardSkip HTML dashboard generation
--no-browserDo not open the dashboard in the browser after completion
--no-jsonSkip JSON results file
--allWhen --contracts has per-ticker overrides, include ALL tickers from CSV (not just the mentioned ones). Unmentioned tickers get the default contract count.
--landscapeRun landscape correlation analysis per ticker (verifies metric independence assumptions)
--short-termShort-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.
--liveLive 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.
--hostIBKR TWS host (default: 127.0.0.1)127.0.0.1
--portIBKR port (default: auto-detect. Tries 4001 Gateway Live, 4002 Gateway Paper, 7496 TWS Live, 7497 TWS Paper)0
--client-idIBKR client ID (default: 99)99
--accountIBKR account for the --margin whatIf (TIMS maintenance margin varies by account). Default: first managed account.
--parallelNumber 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-dteDTE range for income calls in live mode (default: 5 46). Example: --income-dte 7 46
--leaps-dteDTE 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
--publishPublish dashboard to Cloudflare Pages via wrangler. Copies dashboard as index.html and deploys via wrangler. Example: --publish ~/Downloads/fortress-dashboard
--notifySend push notification via ntfy.sh when dashboard is ready. Install ntfy app on phone, subscribe to your topic. Example: --notify fortress-abhi
--telemetryv20.10: Always on (kept for backward compat). Scan telemetry exported in every JSON output.True
--no-auditSkip auto-generating audit HTML after scan.False
--marginCompute 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
runs/fortress/{TICKER}/latest.html runs/fortress/{TICKER}/{TIMESTAMP}.html runs/fortress/{TICKER}/audit_{TIMESTAMP}.html runs/CSVs/{TICKER}_{TIMESTAMP}.csv ← live mode only
deploy/fortress/MSFT.html
β†— open full
πŸ—
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.
HTML + JSON Audit IBKR
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
--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)
FlagDescriptionDefault
--tickersOne 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.
--csvUse a saved chain CSV (offline mode, skip IBKR). CSV must include the requested tickers.
--cc-overlayScan CC overlay (short-dated calls above safe strike) for the Bucket A winner. Off by default.
--parallelParallel 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-dteMinimum DTE for LEAPS chain discovery (default: 270)270
--max-chainsNumber of furthest-out chains to scan (default: 3)3
--htmlOverride HTML output path (default: routed via OutputManager)
--auditOverride audit JSON output path (default: routed via OutputManager)
--hostIBKR host (default: 127.0.0.1)127.0.0.1
--portIBKR port (default: 0 = auto-detect TWS Live 7496 / Gateway Live 4001 / Gateway Paper 4002 / TWS Paper 7497)0
--client-idIBKR client ID (default: 95)95
--accountIBKR account for the --margin whatIf (TIMS maintenance margin varies by account). Default: first managed account.
--breakoutBreakout 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-targetOverride 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-pctScore 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).
--yoloYOLO 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-capOverride 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
--anchorAnchor 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.
--allRun 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.
--marginMARGIN 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.
runs/leaps/{TICKER}/latest.html runs/leaps/{TICKER}/{TIMESTAMP}.html runs/leaps/{TICKER}/audit_{TIMESTAMP}.json
deploy/leaps/MSFT.html
β†— open full
βš–οΈ
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.
HTML dashboard IBKR or CSV
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
FlagDescriptionDefault
positionTicker and max-loss budget, e.g. MU:100k (consistent with --tickers / --contracts elsewhere).
--margin-budgetOptional maintenance-margin budget, e.g. 100k. When set, structures are sized to fit this TIMS budget instead of max loss.
--csvChain CSV (fortress-export format) used for BOTH tools instead of live IBKR. A single fortress CSV works for both.
--csv-fortOverride the Fortress CSV (must be fortress-export format). Falls back to --csv.
--csv-leapsOverride the LEAPS CSV (its own native chains CSV, for max fidelity). Falls back to --csv.
--fort-contractsContract count for the raw Fortress dashboards. Default: estimated from the LEAPS run so the raw dashboards are budget-relevant.
--accountIBKR account for the TIMS margin whatIf in BOTH tools. Maintenance margin varies by account; default is the first managed account.
--no-margin-curveSkip the real-TIMS margin curve (whatIf at each displayed count +/- 2). Faster, but the inline editor then shows linear margin estimates only.
--aiAdd an Anthropic-generated narrative (needs ANTHROPIC_API_KEY).
runs/leaps_vs_fort/{TICKER}/latest.html deploy/leaps_vs_fort/{TICKER}.html ← CF staged
deploy/leaps_vs_fort/MU.html
β†— open full
πŸ”
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.
HTML per ticker + portfolio IBKR
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
FlagDescriptionDefault
tickerStock ticker symbol (single-ticker mode)
safe_strikeSafe Strike of the fortress (single-ticker mode)
--csvPath to CSV position file for batch/portfolio scan (requires IBKR)
--from-scanPath to previously exported scan CSV (no IBKR needed, dashboards only)
--output-dirOutput directory for all files (default: ./outputs)./outputs
--contractsNumber of contracts (single-ticker mode, default: 10)10
--max-deltaMaximum delta filter (default: 0.40)0.40
--max-dteMaximum DTE to scan (default: from CSV per-ticker, or 45 in single-ticker mode)
--min-dteMinimum DTE to scan (default: from CSV per-ticker, or 2 in single-ticker mode)
--hostIBKR TWS host (default: 127.0.0.1)127.0.0.1
--portIBKR port (default: auto-detect. Tries 4001, 4002, 7496, 7497)0
--client-idIBKR client ID (default: 30)30
--drawdown-modeEnable drawdown mode (tighter DTE preference)
--no-browserDo not auto-open dashboards in browser
--outputOutput HTML filepath (single-ticker mode only)
--parallelNumber 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
--tickersFilter --csv to only these tickers (e.g. --tickers MSFT NVDA TSLA)
--score-ledgerFix 5: resolve matured picks in the calibration ledger via yfinance and print predicted-vs-realized calibration by sigma band. No IBKR needed.
--skip-cc-timingSkip 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.
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
deploy/cc_scanner/PORTFOLIO.html
β†— open full
🎯
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.
HTML dashboard Cached chains + light IBKR
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
FlagDescriptionDefault
--rebuild-cachefortress_rebuild last_scan.json to reuse for chains (default: runs/rebuild/last_scan.json)
--no-live-marksskip the small live IBKR fetch of open-CC marks for Insight 1 (use the cached marks even if the gateway is up)
--csvactive fortresses CSV (default: active_fortresses.csv)
--hostIBKR host for the Insight 1 live mark fetch127.0.0.1
--accountIBKR account filter (default: all)
--floormonthly income floor in dollars for the goal tracker (default 30,000)30000.0
--idealideal monthly income in dollars for the goal tracker (default 50,000)50000.0
--monthslookback window in months for sold-CC history (default 3)3
--spreadper-ticker cap (0-1) for the Mix variation; lower = more diversified (default 0.67)0.67
--bullishcomma-separated longer-term bullish holds to exclude from sell recommendations (default: GLXY,RIOT)GLXY,RIOT
--max-targetlegacy/no-op: Max now sells every available contract, so this no longer bounds it75000.0
--no-htmlconsole only
--deploypush the staged dashboard to Cloudflare (runs deploy_cf.sh) after the run
--scoregrade past projections vs realised income from the ledger (no IBKR); advisory calibration read
runs/cc_manager/PORTFOLIO/latest.html deploy/cc_manager/PORTFOLIO.html ← CF staged
deploy/cc_manager/PORTFOLIO.html
β†— open full
βœ…
CC Check
cc_check.py β€” ~390 lines
Reads active_fortresses.csv, scans all IBKR accounts, and reports missing or partial covered call coverage.
HTML dashboard IBKR
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
FlagDescriptionDefault
--csvCSV file with Ticker, Contracts columns (default: active_fortresses.csv)
--portIBKR port (0 = auto-detect)0
--accountIBKR account ID (omit to scan all accounts)
--max-dteMax DTE for short calls to count as coverage (default: 180)180
--no-survivalSkip the stock-price + CC-survival fetch (faster, no market data)
runs/cc_check/PORTFOLIO/latest.html deploy/cc_check/PORTFOLIO.html ← CF staged
deploy/cc_check/PORTFOLIO.html
β†— open full
🧭
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).
HTML dashboard IBKR
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
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.
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).
FlagDescriptionDefault
--hostTWS host127.0.0.1
--portTWS port (default 7496)7496
--client-idIBKR clientId25
--accountSingle account to scan (default: all managed)
--tickersTicker filter. Space-separated or comma-separated (e.g. --tickers COIN MSTR IREN or --tickers COIN,MSTR).
--excludeTickers 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).
--expiryHorizon 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.
--csvUse 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.
--cachedReuse cached scan data (skip IBKR)
--no-rollsSkip roll-chain fetches (faster)
--get-cc-timingRun 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-suggestAppend 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-dteMax DTE for CC suggestions (default 20, matches the 'rarely sell beyond 20d' convention).20
--cc-suggest-scopeWhich fortresses to include: BOTH (default), UNCAPPED (gear-mode only), or CAPPED (SKIP+CC only).BOTH
--cc-suggest-max-rowsOptional 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.
--jsonAlso write raw JSON to this path
--htmlAlso write HTML to this explicit path (OutputManager always runs)
runs/rebuild/{TICKER_LIST}/latest.html deploy/rebuild/{TICKER_LIST}.html ← CF staged
deploy/rebuild/PORTFOLIO.html
β†— open full
⚑
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.
HTML + JSON IBKR
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
FlagDescriptionDefault
csv_fileChain data CSV (skips live chain fetch, still reads IBKR portfolio)
--tickersTicker 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.
--csvPath to active_fortresses.csv (ticker β†’ contracts, Safe Strike, legs, ND). Defaults to active_fortresses.csv in the scripts directory.
--legsOptional leg detail (e.g. GLD:HP:410:20260630:7.214). Repeatable.
--from-resultsRead positions from fortress_results.json
--allPortfolio 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.
--hostIBKR TWS host (default: 127.0.0.1)127.0.0.1
--portIBKR port (default: auto-detect. Tries 4001, 4002, 7496, 7497)0
--client-idIBKR API client ID (default: 99). Parallel workers use client_id+100+N to avoid collisions.99
--accountIBKR account ID (e.g. U1234567). If omitted, uses the first managed account.
--legacy-fetchUse 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.
--parallelParallel IBKR connections (default: 4)4
--eager-escapeFetch 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.
--expiryHP (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-dteFIGHT 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).
--htmlHTML output path (default: fight_TICKER_TIMESTAMP.html)
--no-htmlSuppress HTML output entirely
--jsonJSON output path
--forceShow roll decisions for ALL current CCs regardless of sigma
--roiOverride annual ROI on ML for normal income ref (e.g. 0.80 for 80%). Default: IV-based (LOW 45%, MED 75%, HIGH 95%)
--ndOriginal 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
runs/fight/{TICKER}/latest.html runs/fight/{TICKER}/{TIMESTAMP}.html
deploy/fight/PORTFOLIO.html
β†— open full
πŸ”§
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.
HTML dashboard IBKR
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
FlagDescriptionDefault
tickersTicker(s) to analyze (e.g. IREN IWM TSLA)
--allAnalyze all fortress positions in portfolio
--expiryFilter to positions with HP expiring by this date (YYYY-MM or YYYYMMDD). Repair targets use --hp-max-dte independently.
--hp-min-dteMin DTE for HP candidates (default: 60). --min-target-dte is an alias (repair_trades.py parity).60
--hp-max-dteMax DTE for HP candidates (default: 120)120
--gap-multMax 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-multiplierAdd 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-paybackMax payback period in years for repair candidates (default: 1.0). Candidates with payback above this are flagged but still shown.1.0
--cc-incomeMonthly CC income per share override (e.g., 4.00). If not set, auto-estimates from the active SC leg.0
--maint-roll-dteDTE 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-capMax 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-maintSkip the maintenance-roll pass on healthy fortresses.
--max-analyze-dteSkip 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
--accountLimit scan to this account ID. Default scans ALL managed accounts and concatenates positions.
--positionsCSV 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
--jsonExport to JSON file
--htmlExport HTML dashboard
--csvCSV 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
--ndNet Debit per share override (e.g., 16.0). Single-ticker runs only. Overrides --csv ND and IBKR avg_cost.0
runs/repair/{TICKER}/latest.html runs/repair/{TICKER}_{TICKER2}/latest.html ← multi-ticker
deploy/fortress_repair/ALL.html
β†— open full
βš™οΈ
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.
HTML + JSON Audit IBKR
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
FlagDescriptionDefault
tickerTicker to analyze (e.g. MARA)
--expiryCurrent position expiry to match (YYYYMMDD or 18-sep-2026). If omitted, auto-detects from portfolio.
--contractsOverride contract count (e.g. 200 for 200 contracts = 20000 shares)0
--lcSelect fortress structure by LC strike (e.g. --lc 60). Required when multiple structures exist on the same expiry.0
--htmlHTML output path (default: repair_<TICKER>_<timestamp>.html)
--auditAudit log JSON path (default: audit_<TICKER>_<timestamp>.json)
--gap-multMax gap multiplier vs current gap (default: 2.0x)2.0
--marginRun IBKR whatIf margin checks on top candidates (requires write access)
--min-target-dteMinimum DTE for target LEAPS expiries (default: 365)365
--max-target-dteMaximum DTE for target LEAPS expiries (default: 1100)1100
--price-multiplierAdd P&L projection at Nx current price (e.g., 10 for 10x). For parabolic movers like crypto miners.0
--ccAdd CC income overlay to lens picks (scans DTE 5-50 call chains)
--fightAdd FIGHT income panel: near-ATM short-dated CCs for income while waiting on repair. Shows gap risk tiers at 5/10/20% of ML.
--ndOverride 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.210
--no-rollSkip roll candidates entirely. Only restructure within current expiry.
--max-candidatesCap 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
--pnlP&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-maxMax stock price for P&L curve (default: 5x current price)0
--roll-short-putRoll-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-expiryExpiry for the new short put (default: current SP expiry). Roll the strike down on the same date by default.
--rsp-min-strikeFloor for candidate new SP strikes (default: stock x0.5; always kept above the HP strike).0
--rsp-max-strikeCeiling for candidate new SP strikes (default: current SP strike, exclusive).0
--rsp-cushionTarget extrinsic/carry cushion for assignment-safe (default 1.0; >=1 means the put holder has no early-exercise incentive).1.0
--rsp-rateRisk-free rate for the carry / early-exercise boundary (default 0.04).0.04
runs/repair_trades/{TICKER}/latest.html runs/repair_trades/{TICKER}/audit_{TIMESTAMP}.json
deploy/repair_trades/COIN.html
β†— open full
🧠
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.
HTML report
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
PillarWeightKey Metrics
Fundamentals40%Revenue growth, margins, FCF, debt
Fortress Fit30%IV, liquidity, options chain depth, trend alignment
Valuation15%P/E, P/S, EV/EBITDA vs peers
Technicals15%Momentum, moving averages, RSI
FlagDescriptionDefault
tickersStock tickers
--horizonInvestment horizon (default: '1-2 years')1-2 years
--outputOutput HTML path
--api-keyAnthropic API key (or ANTHROPIC_API_KEY env)
--no-ibkrSkip IBKR, yfinance IV only
--jsonAlso dump raw data as JSON alongside HTML
runs/research/{TICKER}/latest.html runs/research/{TICKER1}_{TICKER2}/latest.html ← multi
deploy/research/SNOW.html
β†— open full
πŸ’°
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.
HTML dashboard IBKR or yfinance
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
FlagDescriptionDefault
--tickersSpace-separated ticker symbols
--scanDiscovery mode: screen SPX, QQQ, IWM constituentsFalse
--topTop N stocks per index in discovery mode (default: 10)10
--expiryTarget expiration (YYYYMMDD). Auto-selects nearest monthly 20-45 DTE if omitted
--capitalTotal portfolio capital for position sizing
--collateral-pctCollateral % per put (100=fully collateralized, default: 100)100
--portTWS port (default: 0 = auto-detect TWS/Gateway)0
--no-ibkrUse yfinance instead of IBKR for options dataFalse
--min-oiMinimum open interest filter (default: 100)100
--max-spread-pctMaximum bid-ask spread as % of bid (default: 15.0)15.0
--outputOutput directory for HTML report
--rescanForce fresh discovery scan, ignore cacheFalse
deploy/gs_putseller/{TICKER1}_{TICKER2}.html (also staged to deploy/ for CF Pages)
(no recent output)
β†— open full