{"id":"a30010a0-19e7-4446-af16-929cf5c94092","entityType":"agent","slug":"clawhub-alexliu0130-ibkr-options-assistant","name":"Ibkr Options Assistant","canonicalUrl":"https://www.xpersona.co/agent/clawhub-alexliu0130-ibkr-options-assistant","canonicalPath":"/agent/clawhub-alexliu0130-ibkr-options-assistant","generatedAt":"2026-10-11T07:41:44.774Z","source":"CLAWHUB","claimStatus":"UNCLAIMED","verificationTier":"NONE","summary":{"evidence":{"source":"editorial-content","verified":true,"confidence":"high","updatedAt":"2026-10-11T03:43:05.882Z","emptyReason":null},"description":"Interactive Brokers options & stock trading assistant. Provides real-time portfolio Greeks, option chain analysis, McMillan/Overby strategy recommendations,... Skill: Ibkr Options Assistant Owner: alexliu0130 Summary: Interactive Brokers options & stock trading assistant. Provides real-time portfolio Greeks, option chain analysis, McMillan/Overby strategy recommendations,... Tags: claude-code:0.2.4, greeks:0.2.4, ibkr:0.2.4, interactive-brokers:0.2.4, latest:0.2.6, options:0.2.4, portfolio:0.2.4, quantitative-finance:0.2.4, trading:0.2.4, trading-assistant:0.2.4, wheel-stra","descriptionLabel":"Technical summary","evidenceSummary":"Capability contract not published. No trust telemetry is available yet. 1.2K downloads reported by the source. Last updated 10/11/2026.","installCommand":"clawhub skill install s1795h15v46ekgqsyhrf8r6wcn83z8mk:ibkr-options-assistant","sourceUrl":"https://clawhub.ai/alexliu0130/ibkr-options-assistant","homepage":"https://clawhub.ai/alexliu0130/skills/ibkr-options-assistant","primaryLinks":[{"label":"View on ClawHub","url":"https://clawhub.ai/alexliu0130/ibkr-options-assistant","kind":"source"},{"label":"Homepage","url":"https://clawhub.ai/alexliu0130/skills/ibkr-options-assistant","kind":"homepage"}],"safetyScore":84,"overallRank":62,"popularityScore":61,"trustScore":null,"claimedByName":null,"isOwner":false,"seoDescription":"Interactive Brokers options & stock trading assistant. Provides real-time portfolio Greeks, option chain analysis, McMillan/Overby strategy recommendations,... "},"coverage":{"evidence":{"source":"public-profile","verified":false,"confidence":"medium","updatedAt":"2026-10-11T03:43:05.882Z","emptyReason":null},"protocols":[{"protocol":"OPENCLEW","label":"OpenClaw","status":"self-declared","notes":"Declared in the public agent profile."}],"capabilities":[],"verifiedCount":0,"selfDeclaredCount":1,"capabilityMatrix":{"rows":[{"key":"OPENCLEW","type":"protocol","support":"unknown","confidenceSource":"profile","notes":"Listed on profile"}],"flattenedTokens":"protocol:OPENCLEW|unknown|profile"}},"adoption":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-11T03:43:05.882Z","emptyReason":null},"stars":null,"forks":null,"downloads":1170,"packageName":null,"latestVersion":"0.2.6","tractionLabel":"1.2K downloads"},"release":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-11T03:43:05.868Z","emptyReason":null},"lastUpdatedAt":"2026-10-11T03:43:05.882Z","lastCrawledAt":"2026-10-11T03:43:05.868Z","lastIndexedAt":null,"nextCrawlAt":"2026-10-12T03:43:05.868Z","lastVerifiedAt":null,"highlights":[{"version":"0.2.6","createdAt":"2026-05-15T08:35:52.261Z","changelog":"New status_dashboard.py — one IBKR snapshot, three output formats (ANSI for terminal / Telegram-friendly Markdown / JSON for agents). Same builder feeds all three renderers. Default mode covers portfolio + positions with ITM flags + this-week expiries + Wheel stages in ~5s. --full adds IV env + recent P&L. Reviewed by independent reviewer before release; 3 critical interface-mismatch bugs caught and fixed in the same commit. ClientId offset 20.","fileCount":32,"zipByteSize":145182},{"version":"0.2.5","createdAt":"2026-05-14T15:22:05.689Z","changelog":"Critical bug fixes. ITM/OTM judgement was wrong for any agent reading the JSON because the underlying spot price was buried inside greeks.und_price while the option's own price sat at the top level next to strike. OPT entries now expose option_price, und_price, itm, moneyness at the top level. Also: short-put max_loss formula corrected (-(strike-premium)*100 was previously -strike*100), options_chain data_type reflects real ticker.marketDataType, session+Flex fills are deduplicated with per-tuple occurrence index, and 6 smaller fixes (falsy checks, type='credit' lie, wheel called_away→closed, etc). Reviewed by an independent reviewer agent before release.","fileCount":30,"zipByteSize":135906},{"version":"0.2.4","createdAt":"2026-05-14T12:52:27.077Z","changelog":"Renamed from ibkr-trader-toolkit. Clarifies positioning as an options-analysis assistant driven by Claude/AI, not a trading bot. No behavior changes — same 17 scripts, same dual-gate trading safety, same JSON output.","fileCount":30,"zipByteSize":131980}]},"execution":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No published capability contract is available yet."},"installCommand":"clawhub skill install s1795h15v46ekgqsyhrf8r6wcn83z8mk:ibkr-options-assistant","setupComplexity":"low","setupSteps":["Setup complexity is LOW. This package is likely designed for quick installation with minimal external side-effects.","Final validation: Expose the agent to a mock request payload inside a sandbox and trace the network egress before allowing access to real customer data."],"contract":{"contractStatus":"missing","authModes":[],"requires":[],"forbidden":[],"supportsMcp":false,"supportsA2a":false,"supportsStreaming":false,"inputSchemaRef":null,"outputSchemaRef":null,"dataRegion":null,"contractUpdatedAt":null,"sourceUpdatedAt":null,"freshnessSeconds":null},"invocationGuide":{"preferredApi":{"snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-alexliu0130-ibkr-options-assistant/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-alexliu0130-ibkr-options-assistant/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-alexliu0130-ibkr-options-assistant/trust"},"curlExamples":["curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-alexliu0130-ibkr-options-assistant/snapshot\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-alexliu0130-ibkr-options-assistant/contract\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-alexliu0130-ibkr-options-assistant/trust\""],"jsonRequestTemplate":{"query":"summarize this repo","constraints":{"maxLatencyMs":2000,"protocolPreference":["OPENCLEW"]}},"jsonResponseTemplate":{"ok":true,"result":{"summary":"...","confidence":0.9},"meta":{"source":"CLAWHUB","generatedAt":"2026-10-11T07:41:44.771Z"}},"retryPolicy":{"maxAttempts":3,"backoffMs":[500,1500,3500],"retryableConditions":["HTTP_429","HTTP_503","NETWORK_TIMEOUT"]}},"endpoints":{"dossierUrl":"https://www.xpersona.co/api/v1/agents/clawhub-alexliu0130-ibkr-options-assistant/dossier","snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-alexliu0130-ibkr-options-assistant/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-alexliu0130-ibkr-options-assistant/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-alexliu0130-ibkr-options-assistant/trust"}},"reliability":{"evidence":{"source":"runtime-metrics","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No trust, reliability, or runtime telemetry is available."},"trust":{"status":"unavailable","handshakeStatus":"UNKNOWN","verificationFreshnessHours":null,"reputationScore":null,"p95LatencyMs":null,"successRate30d":null,"fallbackRate":null,"attempts30d":null,"trustUpdatedAt":null,"trustConfidence":"unknown","sourceUpdatedAt":null,"freshnessSeconds":null},"decisionGuardrails":{"doNotUseIf":["Contract metadata is missing or unavailable for deterministic execution."],"safeUseWhen":[],"riskFlags":["missing_or_unavailable_contract","trust_data_unavailable","schema_references_missing"],"operationalConfidence":"low"},"executionMetrics":{"observedLatencyMsP50":null,"observedLatencyMsP95":null,"estimatedCostUsd":null,"uptime30d":null,"rateLimitRpm":null,"rateLimitBurst":null,"lastVerifiedAt":null,"verificationSource":null},"runtimeMetrics":{"successRate":null,"avgLatencyMs":null,"avgCostUsd":null,"hallucinationRate":null,"retryRate":null,"disputeRate":null,"p50Latency":null,"p95Latency":null,"lastUpdated":null}},"benchmarks":{"evidence":{"source":"no-benchmark-data","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No benchmark suites or observed failure patterns are available."},"suites":[],"failurePatterns":[]},"artifacts":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"high","updatedAt":"2026-10-11T03:43:05.882Z","emptyReason":null},"readme":"Skill: Ibkr Options Assistant\n\nOwner: alexliu0130\n\nSummary: Interactive Brokers options & stock trading assistant. Provides real-time portfolio Greeks, option chain analysis, McMillan/Overby strategy recommendations,...\n\nTags: claude-code:0.2.4, greeks:0.2.4, ibkr:0.2.4, interactive-brokers:0.2.4, latest:0.2.6, options:0.2.4, portfolio:0.2.4, quantitative-finance:0.2.4, trading:0.2.4, trading-assistant:0.2.4, wheel-strategy:0.2.4\n\nVersion history:\n\nv0.2.6 | 2026-05-15T08:35:52.261Z | user\n\nNew status_dashboard.py — one IBKR snapshot, three output formats (ANSI for terminal / Telegram-friendly Markdown / JSON for agents). Same builder feeds all three renderers. Default mode covers portfolio + positions with ITM flags + this-week expiries + Wheel stages in ~5s. --full adds IV env + recent P&L. Reviewed by independent reviewer before release; 3 critical interface-mismatch bugs caught and fixed in the same commit. ClientId offset 20.\n\nv0.2.5 | 2026-05-14T15:22:05.689Z | user\n\nCritical bug fixes. ITM/OTM judgement was wrong for any agent reading the JSON because the underlying spot price was buried inside greeks.und_price while the option's own price sat at the top level next to strike. OPT entries now expose option_price, und_price, itm, moneyness at the top level. Also: short-put max_loss formula corrected (-(strike-premium)*100 was previously -strike*100), options_chain data_type reflects real ticker.marketDataType, session+Flex fills are deduplicated with per-tuple occurrence index, and 6 smaller fixes (falsy checks, type='credit' lie, wheel called_away→closed, etc). Reviewed by an independent reviewer agent before release.\n\nv0.2.4 | 2026-05-14T12:52:27.077Z | user\n\nRenamed from ibkr-trader-toolkit. Clarifies positioning as an options-analysis assistant driven by Claude/AI, not a trading bot. No behavior changes — same 17 scripts, same dual-gate trading safety, same JSON output.\n\nArchive index:\n\nArchive v0.2.6: 32 files, 145182 bytes\n\nFiles: CHANGELOG.md (14759b), LICENSE (1068b), README.md (29604b), README.zh-CN.md (25567b), references/greeks_primer.md (6944b), references/options_book_summary.md (34351b), references/strategies.md (12384b), references/trading.md (13720b), references/troubleshooting.md (9693b), references/wheel_strategy.md (10838b), requirements.txt (104b), scripts/alerts_monitor.py (10503b), scripts/concentration.py (8904b), scripts/contracts.py (13074b), scripts/cost_basis.py (12893b), scripts/earnings_calendar.py (7536b), scripts/flex_import.py (11588b), scripts/ib_client.py (4129b), scripts/market_quote.py (3503b), scripts/options_analyzer.py (29555b), scripts/options_chain.py (9735b), scripts/options_daily.py (13481b), scripts/pnl_analytics.py (11150b), scripts/portfolio_positions.py (6601b), scripts/risk_simulator.py (7813b), scripts/status_dashboard.py (19556b), scripts/technical_indicators.py (6054b), scripts/trade.py (35987b), scripts/wheel_tracker.py (7071b), skill-card.md (2361b), SKILL.md (7914b), _meta.json (141b)\n\nFile v0.2.6:SKILL.md\n\n---\nname: ibkr-options-assistant\ndescription: Interactive Brokers options & stock trading assistant. Provides real-time portfolio Greeks, option chain analysis, McMillan/Overby strategy recommendations, P&L statistics, Wheel strategy tracking, earnings warnings, risk simulation, and a complete toolkit for options traders. Use this skill whenever the user asks about specific options trades, position risk, buy/sell recommendations, IV environment, P&L, wheel strategy, earnings impact on options, or any IBKR account data — even if they don't explicitly mention \"IBKR\". For stock price queries, always use market_quote.py instead of web search.\n---\n\n# IBKR Trader Toolkit\n\nReal-time data, options analysis, and portfolio risk for Interactive Brokers — all via JSON-emitting CLI scripts.\n\n**Core rule:** Scripts produce data. You (the model) produce the analysis.\n\n---\n\n## When to trigger this skill\n\n| User asks about... | Example phrasing |\n|---|---|\n| Stock / ETF prices | \"What's SPY at?\" \"Current AAPL price\" |\n| Option chains, Greeks, IV | \"Show me AAPL puts for next month\" |\n| Strategy ideas | \"Should I sell a put on MU?\" |\n| Position risk | \"Am I too long delta?\" |\n| P&L, win rate, history | \"How are my wheel trades doing?\" |\n| Earnings risk | \"Does ARM report before my call expires?\" |\n| Alerts / monitoring | \"Warn me if SPY IV > 80%ile\" |\n\nFire **even if the user doesn't mention IBKR** — if they're asking about *their* positions or P&L, this skill is the source of truth.\n\n**Critical:** For stock prices, always use `market_quote.py`. **Never** web-search a stock price — the web is minutes-to-hours stale.\n\n---\n\n## Workflows\n\n### \"What's my account state right now?\" / \"Status update\"\n\nFor a one-glance snapshot (positions, Greeks, ITM, this-week expiries, wheel\nstages):\n\n```bash\nstatus_dashboard.py --output telegram   # in chat-style channels\nstatus_dashboard.py --output json       # parse and recompose freely\nstatus_dashboard.py                     # rich ANSI for terminals\n```\n\nAdd `--full` to also include IV environment per held symbol and recent P&L\n(slower — extra IBKR calls). Use `--output json` when you (the agent) want\nto organize the reply yourself instead of inheriting the script's layout.\n\n### \"Should I sell a put on $SYM?\"\n\nRun these in order, then synthesize:\n\n| Step | Command | Why |\n|------|---------|-----|\n| 1 | `portfolio_positions.py` | Know existing exposure first |\n| 2 | `earnings_calendar.py SYM --days 60` | Avoid earnings inside DTE |\n| 3 | `options_analyzer.py SYM --outlook bullish --risk-profile conservative --iv-context` | Get IV environment + candidate strikes |\n| 4 | `options_chain.py SYM --dte-min 25 --dte-max 45` | Live mid prices for chosen strikes |\n\n**Your recommendation must include:** strike • delta • premium • breakeven • annualized yield • earnings/IV warnings.\n\n---\n\n### \"What's my portfolio looking like?\"\n\n| Step | Command |\n|------|---------|\n| 1 | `portfolio_positions.py` → positions + Greeks |\n| 2 | `options_daily.py` → expiry warnings + IV summary |\n| 3 | `pnl_analytics.py --days 7` → recent realized P&L |\n\n---\n\n### \"I'm thinking of adding trade X — is it safe?\"\n\n```bash\nrisk_simulator.py --add \"SYM STRIKE EXPIRY R ACTION QTY\"\n```\n\nFlag any of:\n- **Vega magnitude doubles** → much more IV-exposed\n- **Net delta flips sign** → directional bet now opposite\n- **One symbol > 30% of capital** → concentration risk\n\n---\n\n### \"How's my wheel doing?\"\n\n```bash\nwheel_tracker.py summary\n```\n\nReturns per-symbol: stage (`short_put` / `assigned` / `covered_call` / `closed`), cumulative premium, days in cycle, annualized return.\n\n---\n\n### \"Should I roll position X?\"\n\n| Step | Command | Why |\n|------|---------|-----|\n| 1 | `portfolio_positions.py` | Confirm the leg's current strike, expiry, P&L, delta |\n| 2 | `options_chain.py SYM --dte-min 25 --dte-max 60` | Survey roll candidates further out |\n| 3 | Consult [`references/wheel_strategy.md`](references/wheel_strategy.md) | \"Roll vs accept assignment\" decision tree |\n\n**Your recommendation must include:** new strike • new DTE • net credit (new premium − close cost) • effective basis change vs current leg • roll count so far (cap at 2).\n\n---\n\n## Script reference\n\n| Script | When to use |\n|--------|-------------|\n| `status_dashboard.py [--full] [--output ansi/telegram/json]` | \"What's the state of my account right now?\" — one-glance snapshot for terminal, Telegram, or agent consumption |\n| `market_quote.py SYM [SYM2 ...]` | Any stock/ETF price question |\n| `portfolio_positions.py` | What do I own? Portfolio Greeks |\n| `options_chain.py SYM` | Strikes survey + IV by expiry |\n| `options_analyzer.py SYM --outlook X --risk-profile Y --iv-context` | Strategy ideas given outlook |\n| `options_daily.py` | Morning/EOD options report (start here) |\n| `pnl_analytics.py [--days N]` | Realized P&L, win rate, best/worst |\n| `risk_simulator.py --add \"...\"` | Pre-trade Greeks impact |\n| `earnings_calendar.py SYM ...` | Earnings within N days |\n| `technical_indicators.py SYM` | RSI / MA / BB / ATR |\n| `wheel_tracker.py summary` | Wheel cycle status & yield |\n| `alerts_monitor.py` | Threshold rules (cron-friendly) |\n| `cost_basis.py SYM [...]` | Premium-adjusted effective cost basis (wheel) |\n| `concentration.py` | HHI, sector mix, top-N portfolio concentration |\n| `flex_import.py [--flex-dir ...]` | Parse IBKR Flex CSV/XML history into JSON |\n| `trade.py <stock\\|option\\|combo\\|...>` | **Place orders** (opt-in, dual-gate). See `references/trading.md` |\n\nAll read-only scripts:\n- Output JSON to stdout (or to `--output FILE`)\n- Read IBKR config from env vars (`IBKR_HOST`, `IBKR_PORT`, `IBKR_CLIENT_ID_BASE`, `IBKR_MARKET_DATA_TYPE`)\n- Cannot place orders — only `trade.py` can, and only when both `IBKR_TRADING_ENABLED=1` and `--confirm-trade` are present\n\n---\n\n## Pre-trade checklist (every options recommendation)\n\nBefore suggesting any options trade, verify all three:\n\n1. **IV environment** — from `options_analyzer.py --iv-context`. Don't sell premium in low-IV; don't buy premium in high-IV.\n2. **Earnings inside DTE** — from `earnings_calendar.py`. IV crush after earnings flips the math.\n3. **Existing position Greeks** — from `portfolio_positions.py`. If already +5000 delta, adding more is wrong direction-of-thesis or not.\n\nState each check explicitly:\n> \"IV environment: low (ratio 0.7); earnings: none in next 45 days; current net delta: +1,200.\"\n\nThis lets the user audit the reasoning.\n\n---\n\n## Operating constraints\n\n| Constraint | What it means |\n|------------|---------------|\n| **JSON in, judgement out** | The script's `recommendations` list is candidate data, not a final answer. Re-rank against the user's situation. |\n| **Smart data type** | `IBKR_MARKET_DATA_TYPE=3` by default — IBKR auto-upgrades to realtime when user is subscribed, falls back to delayed otherwise. If quotes look stale, check market hours + subscriptions. |\n| **One clientId per script** | If you see `clientId already in use`, wait a few seconds or bump `IBKR_CLIENT_ID_BASE`. |\n| **Cache chains across calls** | `options_chain.py --output /tmp/chain.json` then `options_analyzer.py --chain-file /tmp/chain.json` saves IBKR roundtrips. |\n\n---\n\n## Deeper references\n\nRead on demand when the user's question warrants it:\n\n- [`references/strategies.md`](references/strategies.md) — full McMillan/Overby strategy library + selection matrix\n- [`references/greeks_primer.md`](references/greeks_primer.md) — practical Delta/Gamma/Vega/Theta interpretation\n- [`references/wheel_strategy.md`](references/wheel_strategy.md) — strike/DTE selection, roll-vs-assign decision tree\n- [`references/options_book_summary.md`](references/options_book_summary.md) — McMillan/Overby/Natenberg/Sinclair operational rules\n- [`references/troubleshooting.md`](references/troubleshooting.md) — connection errors, subscription issues\n\nFile v0.2.6:README.md\n\n# IBKR Options Assistant\n\n> A complete options & stock trading assistant for Interactive Brokers — real-time Greeks, McMillan/Overby strategy library, P&L analytics, Wheel tracking, earnings warnings, and risk simulation. Designed to plug straight into Claude Code as a skill.\n\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n[![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)\n[![IBKR](https://img.shields.io/badge/broker-Interactive%20Brokers-red.svg)](https://www.interactivebrokers.com/)\n\n> [中文版 README](README.zh-CN.md)\n\n<!-- screenshot: hero -->\n\n---\n\n## Table of Contents\n\n- [Features](#-features)\n- [At a glance — status_dashboard.py](#-at-a-glance--status_dashboardpy)\n- [Requirements](#-requirements)\n- [IBKR Market Data Subscriptions](#-ibkr-market-data-subscriptions)\n- [Quick Start](#-quick-start)\n- [Operations Guide (Second User, Auto-Restart)](#-operations-guide)\n- [Trading Mode (Optional)](#-trading-mode-optional)\n- [Security Model](#-security-model)\n- [Claude Code Integration](#-claude-code-integration)\n- [Command Reference](#-command-reference)\n- [Configuration](#-configuration)\n- [Troubleshooting](#-troubleshooting)\n- [Advanced](#-advanced)\n- [Contributing](#-contributing)\n- [License](#-license)\n- [Disclaimer](#-disclaimer)\n\n---\n\n## ✨ Features\n\n17 focused Python scripts. Read-only scripts output JSON so Claude (or any other agent) can reason about the data. Only `trade.py` can place orders, and only when both safety gates are explicitly opened.\n\n**Data & quotes**\n- `market_quote.py` — Real-time bid/ask/last/IV/volume for stocks, ETFs, options.\n- `contracts.py` — Universal contract resolver (`SPY`, `AAPL 2026-06-19 200 C`, etc.).\n- `technical_indicators.py` — RSI, MA(20/50/200), Bollinger, ATR with text summary.\n\n**Options analysis**\n- `options_chain.py` — Full option chain with Greeks, OI, volume, IV per expiry.\n- `options_analyzer.py` — McMillan/Overby strategy recommender (20+ strategies across 4 tiers, IV-aware).\n- `options_daily.py` — End-of-day options report: warnings, IV environment, position-specific suggestions.\n\n**Portfolio & P&L**\n- `portfolio_positions.py` — Live positions with per-leg and portfolio-level Greeks.\n- `pnl_analytics.py` — Realized P&L, win rate, best/worst trades (from `ib.executions` + optional Flex CSV).\n- `flex_import.py` — Parse IBKR Flex Statement CSV/XML history into normalized JSON.\n- `cost_basis.py` — **Premium-adjusted** effective cost basis (the wheel-trader number IBKR doesn't compute).\n- `concentration.py` — HHI, sector mix, top-N concentration risk metrics.\n- `risk_simulator.py` — \"What if I add this trade?\" Greeks delta preview before execution.\n\n**Strategy automation**\n- `wheel_tracker.py` — Track wheel cycles (short put → assignment → covered call → called away) with cumulative premium and annualized yield.\n- `earnings_calendar.py` — Next earnings date for portfolio symbols, flags options positions expiring across earnings.\n- `alerts_monitor.py` — YAML-driven threshold alerts (delta, IV percentile, DTE, P&L) for cron use.\n\n**Trade execution (opt-in)**\n- `trade.py` — Stocks, single-leg options, multi-leg combos, futures, FX. Dual-gate safety (`IBKR_TRADING_ENABLED=1` + `--confirm-trade`). See [Trading Mode](#-trading-mode-optional).\n\n**Connection layer**\n- `ib_client.py` — Shared IB Gateway connection with readonly safety, per-script clientId offsets, and historical-data pacing.\n\n---\n\n## 📺 At a glance — `status_dashboard.py`\n\nOne command, three renderings, same data. Use it as a quick health check,\ndrop it into a Telegram bot, or feed JSON to an agent.\n\n```bash\nstatus_dashboard.py                     # rich ANSI for terminals\nstatus_dashboard.py --output telegram   # Telegram-friendly markdown\nstatus_dashboard.py --output json       # structured for agents\nstatus_dashboard.py --full              # also fetch IV env + recent P&L\n```\n\nThe Telegram rendering is intentionally emoji-driven so it survives\nnon-monospace fonts:\n\n```\n🤖 IBKR Options Assistant\n🟢 2026-05-15 09:32 ET (RTH)\n\n组合 Greeks\nΔ +1240 · Γ -45 · Vega -380 · Θ +210\n🟢 未实现 $+2,340.50\n\n持仓 (1 stk + 2 opt)\n📊 SPY +100 STK 🟢 $+1,240\n🟢 MU -1P 110 05/23 Δ-32 🟢 $+220\n🔴 AAPL -2P 200 06/19 Δ-65 🔴 $-380\n\n本周到期 (≤7d)\n⏰ MU -P 110 DTE 5 🟢\n\nWheel 状态\n🟡 AAPL short_put · 累计 $1,450 · 年化 18.3%\n🔵 SPY covered_call · 累计 $820 · 年化 12.7%\n```\n\nANSI/JSON outputs show the same data with terminal colors or structured fields.\n\n---\n\n## 📋 Requirements\n\n| Requirement | Notes |\n|---|---|\n| **Python** | 3.10 or newer |\n| **IBKR account** | Live or paper. Paper account is fine for learning. |\n| **IB Gateway** | Free download from [IBKR](https://www.interactivebrokers.com/en/trading/ibgateway-stable.php). TWS also works (different port). |\n| **Market data subscriptions** | See [next section](#-ibkr-market-data-subscriptions) — needed for realtime quotes & Greeks. Delayed data is free. |\n| **OS** | macOS / Linux / Windows. All scripts are pure Python. |\n\n> **Why IB Gateway, not TWS?** Gateway is headless, uses less memory, and is the standard choice for programmatic access. TWS works too — set `IBKR_PORT=7497` (paper) or `7496` (live).\n\n---\n\n## 💳 IBKR Market Data Subscriptions\n\nThis toolkit's value depends heavily on **what data IBKR will send you**. Subscriptions are configured per account at Client Portal → Settings → User Settings → Market Data Subscriptions.\n\n### What each feature needs\n\n| Feature | Subscriptions needed | Works on delayed? |\n|---------|---------------------|-------------------|\n| Stock/ETF price (`market_quote.py`) | None — Snapshot bundle for realtime, otherwise delayed | ✅ Yes |\n| Portfolio positions & P&L (`portfolio_positions.py`, `pnl_analytics.py`) | None — account data is always available | ✅ Yes |\n| Option chain bid/ask (`options_chain.py`) | **OPRA Top of Book** | ⚠️ Partial — bid/ask only, no Greeks |\n| **Option Greeks** (IV, delta, gamma, vega, theta) | **OPRA + the underlying's stock exchange** | ❌ **No** — Greeks require realtime |\n| Earnings calendar (`earnings_calendar.py`) | None — uses Nasdaq public API | ✅ Yes |\n| Technical indicators (`technical_indicators.py`) | None — uses historical bars (free) | ✅ Yes |\n\n**Key insight from IBKR API docs:**\n> *\"To receive live Greek values it is necessary to have market data subscriptions for both the option and the underlying contract.\"*\n\nTranslation: if you only subscribe to OPRA but not (say) NYSE ARCA, you get SPY option **prices** but not SPY option **Greeks** — because IBKR can't compute delta/gamma without realtime underlying.\n\n### Recommended bundles for this toolkit\n\n| Bundle | Monthly cost | Waived if | What you get |\n|--------|--------------|-----------|--------------|\n| **Free (delayed)** | $0 | always | Stock prices, bid/ask, portfolio data, historical bars. **No Greeks**, no live IV environment. |\n| **OPRA only** | $1.50 | $20+ commissions/mo | Realtime option bid/ask. Greeks only for symbols whose underlying you also subscribe to. |\n| **US Securities Bundle + OPRA** ⭐ recommended | $11.50 | $30+ commissions/mo | Realtime stock + option data + Greeks for all US-listed symbols. The toolkit's full feature set. |\n\n**Bundle contents (US Securities Snapshot and Futures Value Bundle):**\n- Consolidated realtime NBBO for US stocks/ETFs\n- Top-of-book for major futures (CME, CBOT, COMEX, NYMEX)\n- OTC Markets quotes\n\n> **Commission waiver math:** If you trade 1 lot of options per week (~4 contracts × $0.65 commission ≈ $2.60/wk = ~$10/mo), you're partway there. Two roundtrip options trades per month usually clears the $30 threshold.\n\n### How to subscribe\n\n1. Log into [IBKR Client Portal](https://www.interactivebrokers.com/sso/Login)\n2. Settings (top right) → User Settings → Market Data Subscriptions\n3. Click \"Configure\"\n4. Search and add:\n   - **\"US Securities Snapshot and Futures Value Bundle\"** (NL)\n   - **\"OPRA Top of Book\"** (NL)\n5. Confirm and accept\n6. Subscriptions usually activate within 10 minutes; restart IB Gateway\n\n### How the toolkit handles missing subscriptions\n\nThe default `IBKR_MARKET_DATA_TYPE=3` (delayed-smart) tells IBKR:\n> *\"Give me realtime if I'm subscribed; fall back to delayed if I'm not.\"*\n\nThis means **the toolkit works on day one with $0 subscriptions** — you just won't have Greeks until you upgrade. No Error 10089 crashes.\n\nIf you ever want to force a specific mode:\n- `IBKR_MARKET_DATA_TYPE=1` — strict realtime (errors on unsubscribed)\n- `IBKR_MARKET_DATA_TYPE=3` — smart delayed (default; auto-upgrades)\n- `IBKR_MARKET_DATA_TYPE=4` — delayed-frozen (last cached value, useful after-hours)\n\n**Sources:**\n- [IBKR Market Data Pricing](https://www.interactivebrokers.com/en/pricing/market-data-pricing.php)\n- [TWS API: Option Greeks docs](https://interactivebrokers.github.io/tws-api/option_computations.html)\n\n---\n\n## 🚀 Quick Start\n\n### 1. Install IB Gateway\n\nDownload from [interactivebrokers.com/en/trading/ibgateway-stable.php](https://www.interactivebrokers.com/en/trading/ibgateway-stable.php) and install. Launch it and log in with your IBKR credentials (use **paper** mode for testing).\n\n<!-- screenshot: gateway-login -->\n\n### 2. Enable the API\n\nInside IB Gateway:\n\n1. `Configure → Settings → API → Settings`\n2. Check **Enable ActiveX and Socket Clients**\n3. Check **Read-Only API** (recommended — this toolkit is read-only by design)\n4. **Socket port**: `4001` (live) or `4002` (paper). Match this to `IBKR_PORT` in your `.env`.\n5. **Trusted IPs**: add `127.0.0.1`\n6. Leave **Allow connections from localhost only** checked — it's safer and the toolkit doesn't need it disabled.\n7. Click **OK** and restart Gateway.\n\n<!-- screenshot: gateway-api-settings -->\n\n### 3. Clone & install\n\n```bash\ngit clone https://github.com/AlexLiu0130/ibkr-options-assistant.git\ncd ibkr-options-assistant\n\npython -m venv .venv\nsource .venv/bin/activate            # Windows: .venv\\Scripts\\activate\n\npip install -r requirements.txt\n```\n\n### 4. Configure environment\n\n```bash\ncp .env.example .env\n$EDITOR .env\n```\n\nMinimum fields to review (defaults usually work):\n\n```ini\nIBKR_HOST=127.0.0.1\nIBKR_PORT=4001                  # 4002 if paper, 7497 if TWS paper\nIBKR_CLIENT_ID_BASE=11\nIBKR_MARKET_DATA_TYPE=3         # default 3; auto-upgrades to realtime when subscribed\n```\n\n### 5. First call\n\nWith Gateway logged in:\n\n```bash\npython scripts/market_quote.py SPY\n```\n\nExpected output (JSON):\n\n```json\n{\n  \"symbol\": \"SPY\",\n  \"last\": 612.34,\n  \"bid\": 612.31,\n  \"ask\": 612.35,\n  \"volume\": 28931402,\n  \"timestamp\": \"2026-05-12 10:14:22\"\n}\n```\n\nIf you see this — you're done. Try `python scripts/portfolio_positions.py` next.\n\n---\n\n## 🛠️ Operations Guide\n\nRunning this toolkit 24/7 reliably hits two operational problems IBKR doesn't talk about loudly. Solve them once, never think about them again.\n\n### Problem 1: Mobile app kills your Gateway session\n\n**IBKR allows only one active session per username.** If your script runs IB Gateway on the Mac and then you open IBKR Mobile to check your portfolio, **the mobile login kicks the Gateway out** — all your scripts fail until you log Gateway back in.\n\n**Solution: Create a second user (free)**\n\nUse one username for the API (Gateway) and another for the mobile/TWS. They share the same account and see the same positions, but each has its own login session.\n\n**Steps:**\n\n1. Log into [IBKR Client Portal](https://www.interactivebrokers.com/sso/Login) with your primary username\n2. Profile icon (top right) → **Settings**\n3. Under **Account Settings**, find **Users & Access Rights**\n4. Click **+** to add a user\n5. Select **\"Yes\"** for *\"Is this a secondary user for the primary account holder?\"*\n6. Complete the form (the second user can be view-only or have trading rights — your choice)\n7. Submit. IBKR usually approves within 1 business day\n8. Logout, log in with the new secondary username once to set the password\n9. **Use the secondary username in IB Gateway**; keep the primary for the mobile app\n\nThis is **free** and the second user has full read access to the same account.\n\n**Source:** [Adding a Second User on IBKR](https://help.piranhaprofits.com/knowledge/how-to-create-a-second-user-why-do-i-need-it)\n\n---\n\n### Problem 2: Gateway dies overnight, scripts fail at 9am\n\nIB Gateway auto-logs-out daily (IBKR forces it for security) and sometimes crashes after weeks of uptime. If you rely on cron jobs or a morning routine, you want it always-on.\n\n**Solution: Auto-restart with launchd (macOS) or systemd (Linux)**\n\n#### macOS — launchd\n\nCreate `~/Library/LaunchAgents/com.user.ibgateway.plist`:\n\n```xml\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTD/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n    <key>Label</key>\n    <string>com.user.ibgateway</string>\n    <key>ProgramArguments</key>\n    <array>\n        <string>/Applications/IB Gateway 10.30/ibgateway.app/Contents/MacOS/JavaApplicationStub</string>\n    </array>\n    <key>RunAtLoad</key>\n    <true/>\n    <key>KeepAlive</key>\n    <true/>\n    <key>StandardOutPath</key>\n    <string>/tmp/ibgateway.out.log</string>\n    <key>StandardErrorPath</key>\n    <string>/tmp/ibgateway.err.log</string>\n</dict>\n</plist>\n```\n\nLoad it:\n\n```bash\nlaunchctl load ~/Library/LaunchAgents/com.user.ibgateway.plist\n```\n\nIt will auto-restart Gateway whenever it dies. To stop: `launchctl unload ~/Library/LaunchAgents/com.user.ibgateway.plist`.\n\n> **Note:** Gateway still requires daily 2FA via IBKR Mobile. Auto-restart handles crashes but not the once-a-day login prompt — set [auto-restart inside Gateway](#enable-auto-restart-inside-gateway) (see below) to skip 2FA for 7 days.\n\n#### Enable auto-restart inside Gateway\n\nIn IB Gateway: **Configure → Lock and Exit → Auto Restart**. Pick a daily restart time (e.g. 03:00 ET). This keeps Gateway running for up to a week without re-entering 2FA. After 7 days you have to log in manually once.\n\n#### Linux — systemd\n\nCreate `~/.config/systemd/user/ibgateway.service`:\n\n```ini\n[Unit]\nDescription=IB Gateway\nAfter=network.target\n\n[Service]\nExecStart=/opt/ibgateway/ibgateway\nRestart=always\nRestartSec=30\n\n[Install]\nWantedBy=default.target\n```\n\n```bash\nsystemctl --user enable --now ibgateway\n```\n\n---\n\n### Problem 3: `Warning 2105: ushmds connection broken`\n\nIf `market_quote.py` or `technical_indicators.py` hangs and you see this in Gateway logs, **IBKR's US historical-data farm is down**. It's a server-side outage; usually self-heals in 5–30 minutes.\n\n**What you'll see:**\n\n```\nreqHistoricalData: Timeout for Stock(...)\nRuntimeError: Historical data returned empty\n```\n\n**Diagnose by enabling logs:**\n\n```python\nfrom ib_async import util\nutil.logToConsole()\n# look for: Warning 2105, reqId -1: 历史市场数据场连接中断:ushmds\n```\n\n**What still works during a `ushmds` outage:**\n- `options_chain.py`, `portfolio_positions.py`, `options_daily.py` — they use realtime market data (`hfarm`), not historical\n- `market_quote.py`, `technical_indicators.py` — these need `ushmds`, will time out\n\n**Workarounds:**\n- Wait it out (5–30 min, IBKR usually recovers automatically)\n- Restart IB Gateway to force-reconnect to a different farm endpoint\n- For automation, scripts should treat historical-data errors as soft failures — the toolkit already raises a clear `RuntimeError` you can catch upstream\n\n---\n\n## 💱 Trading Mode (Optional)\n\nThe 13 core scripts in this toolkit are **read-only by design** — they query\ndata and compute Greeks, but never call `ib.placeOrder()`. If you want to\nactually place orders, opt in by using `scripts/trade.py`, the **one** script\nin the repo that sends orders.\n\n`trade.py` supports stocks, single-leg options, multi-leg option combos,\nfutures, and FX. Every order command requires **two safety gates**:\n\n1. `IBKR_TRADING_ENABLED=1` env var (set per shell)\n2. `--confirm-trade` CLI flag (set per invocation)\n\nWithout both, the script runs in dry-run mode — it qualifies the contract,\nruns pre-flight checks (Gateway readonly toggle, buying power, notional &\nquantity guardrails, blocklist), and prints exactly what it *would* have sent,\nwithout calling `placeOrder()`.\n\n**Quick example (dry-run):**\n\n```bash\npython scripts/trade.py option MU 2026-06-12 720 P 2 \\\n    --action SELL --order-type LMT --limit-price 14.50\n# → mode: \"dry_run\", result: \"DRY_RUN_NO_ORDER_PLACED\"\n```\n\n**Quick example (live, paper account first!):**\n\n```bash\nexport IBKR_PORT=4002          # paper\nexport IBKR_TRADING_ENABLED=1  # Gate 1\npython scripts/trade.py option MU 2026-06-12 720 P 2 \\\n    --action SELL --order-type LMT --limit-price 14.50 \\\n    --confirm-trade             # Gate 2\n```\n\nBuilt-in guardrails reject notionals > $100k, stock qty > 10,000, option qty\n> 1,000, and any symbol in `IBKR_TRADING_BLOCKLIST` — override with\n`--allow-large`.\n\n⚠️ **Test on paper (`IBKR_PORT=4002`) before pointing at live.** Full docs,\nall subcommands, cancel/list-orders workflow, and bilingual reference in\n[`references/trading.md`](references/trading.md).\n\n---\n\n## 🔐 Security Model\n\nThis toolkit talks to a live broker session, so the security posture is worth\nstating explicitly. Most of it is by design — what matters is knowing where\nthe trust boundaries are.\n\n### What the toolkit can do\n\n| Capability | Which scripts | Default state |\n|------------|---------------|---------------|\n| Read your IBKR account (positions, balances, P&L, market data) | All scripts | **On** — required for any analysis |\n| Place / cancel / list orders against your IBKR account | `trade.py` only | **Off** — needs `IBKR_TRADING_ENABLED=1` **and** `--confirm-trade` |\n| Call `api.nasdaq.com` (and `finnhub.io` if `FINNHUB_API_KEY` set) | `earnings_calendar.py` | On — public HTTPS, no IBKR credentials transmitted |\n| Read / write `~/.ibkr_wheel_journal.json`, `~/.ibkr_alerts.yaml`, `~/.ibkr_flex/*.csv` | Wheel / alerts / Flex scripts | On — user-owned files in `$HOME` |\n| Evaluate arbitrary code from config files | **None** | `alerts_monitor.py` parses conditions via `ast.parse` with a strict whitelist (no `eval`, no `__import__`, no attribute access) |\n\nThe 16 non-trading scripts open the IBKR connection with `readonly=True`. Only\n`trade.py` uses `readonly=False`, and only after both gates are open.\n\n### Trust boundaries\n\nThe toolkit's authority is bounded by **two layers you control**, not by the toolkit itself:\n\n1. **The IB Gateway login** — your gateway session decides which account is reachable. Use a paper trading account (`IBKR_PORT=4002`) or a dedicated read-only IBKR sub-user if you want to cap blast radius further. Leaving Gateway's \"Read-Only API\" toggle enabled prevents `trade.py` from working at all, even with both software gates opened.\n2. **The two software gates inside `trade.py`** — `IBKR_TRADING_ENABLED` (env) and `--confirm-trade` (CLI flag). Missing either one and the script prints a dry-run payload and exits without contacting the broker. Additional guardrails refuse oversized orders (`--allow-large` required for notional > $100k, options qty > 1000, stock qty > 10000) and honor `IBKR_TRADING_BLOCKLIST` for tickers you never want touched.\n\n### Data the toolkit emits\n\nRead-only scripts emit JSON to stdout (or to `--output FILE`) containing your\npositions, P&L history, Greeks, Flex statement contents, and similar\nbroker-derived data. This is the toolkit's purpose — Claude (or any other\nagent) reads that JSON to reason about your portfolio. Treat the output the\nsame way you'd treat a brokerage statement:\n\n- Don't paste it into untrusted chats or share `--output` files publicly.\n- The agent context window will contain the same data while you're working — keep that conversation private.\n- Nothing is uploaded by the toolkit itself; it only talks to the IBKR Gateway and (optionally) Nasdaq / Finnhub public endpoints.\n\n### Recommended setup\n\n- Run on a personal machine, not shared infrastructure.\n- Keep IB Gateway's \"Allow connections from localhost only\" checked.\n- Default `IBKR_HOST=127.0.0.1` is correct unless you specifically need a remote Gateway.\n- Use a paper account during initial testing.\n- Leave `trade.py`'s safety gates closed unless you explicitly want order execution.\n\n---\n\n## 🤖 Claude Code Integration\n\nThis repo ships a `SKILL.md` so Claude Code can use it directly. Two ways to install:\n\n### Option A — Symlink (recommended for development)\n\n```bash\nmkdir -p ~/.claude/skills\nln -s \"$(pwd)\" ~/.claude/skills/ibkr-options-assistant\n```\n\nRestart Claude Code. Ask: *\"What's SPY trading at right now?\"* — Claude will trigger `market_quote.py` instead of doing a web search.\n\n### Option B — Plugin\n\nIf you use the Claude Code plugin system, point the marketplace at this repo and install `ibkr-options-assistant` from your plugin manager.\n\n### Trigger phrases\n\nThe skill description (see `SKILL.md`) is tuned to fire whenever you mention any of: options strategy, position risk, Greeks, IV, wheel, earnings impact on options, P&L analysis, or stock price. You usually don't need to say \"use IBKR\".\n\n---\n\n## 📖 Command Reference\n\nAll scripts read `.env` automatically and accept `--help`. Every script prints JSON to stdout and logs to stderr — pipe stdout into `jq` or `--output file.json`.\n\n| Script | One-liner | Example |\n|---|---|---|\n| `market_quote.py` | Real-time quote for one symbol | `python scripts/market_quote.py SPY` |\n| `options_chain.py` | Option chain with Greeks | `python scripts/options_chain.py AAPL --dte-min 7 --dte-max 45` |\n| `portfolio_positions.py` | Live positions + Greeks | `python scripts/portfolio_positions.py` |\n| `options_analyzer.py` | Strategy recommender | `python scripts/options_analyzer.py SPY --outlook bullish --iv-context` |\n| `options_daily.py` | End-of-day options report | `python scripts/options_daily.py --output ~/daily.json` |\n| `pnl_analytics.py` | Realized P&L summary | `python scripts/pnl_analytics.py --days 30 --by symbol` |\n| `earnings_calendar.py` | Next earnings + DTE | `python scripts/earnings_calendar.py AAPL ARM MU --days 30` |\n| `risk_simulator.py` | Pre-trade Greeks preview | `python scripts/risk_simulator.py --add \"AAPL 200 2026-06-26 P SELL 2\"` |\n| `technical_indicators.py` | RSI / MA / BB / ATR | `python scripts/technical_indicators.py NVDA --indicators rsi,ma,bb` |\n| `wheel_tracker.py` | Wheel cycle journal | `python scripts/wheel_tracker.py summary` |\n| `alerts_monitor.py` | Threshold alerts | `python scripts/alerts_monitor.py --config ~/.ibkr_alerts.yaml` |\n| `cost_basis.py` | Premium-adjusted cost basis (wheel) | `python scripts/cost_basis.py MU --portfolio-file /tmp/portfolio.json` |\n| `concentration.py` | HHI / sector / top-N concentration | `python scripts/concentration.py` |\n| `flex_import.py` | Parse IBKR Flex CSV/XML history | `python scripts/flex_import.py --flex-dir ~/.ibkr_flex --since 2026-01-01` |\n| `trade.py` | **Place orders (opt-in)** — see [Trading Mode](#-trading-mode-optional) | `python scripts/trade.py stock AAPL 1` (dry-run by default) |\n| `contracts.py` | (library) contract resolver | imported by other scripts |\n| `ib_client.py` | (library) shared connection | imported by other scripts |\n\n### Common patterns\n\n**Save a chain then analyze offline** (avoids hammering IBKR):\n\n```bash\npython scripts/options_chain.py AAPL --output /tmp/aapl_chain.json\npython scripts/options_analyzer.py AAPL --outlook neutral \\\n       --chain-file /tmp/aapl_chain.json --iv-context\n```\n\n**Cron a daily alerts check** (every weekday at 9:33am):\n\n```cron\n33 9 * * 1-5 cd /path/to/ibkr-options-assistant && \\\n    .venv/bin/python scripts/alerts_monitor.py >> ~/.ibkr_alerts.log 2>&1\n```\n\n**Risk-check before a trade**:\n\n```bash\npython scripts/risk_simulator.py \\\n    --add \"SPY 600 2026-06-19 P SELL 1\" \\\n    --add \"SPY 580 2026-06-19 P BUY 1\"\n```\n\n---\n\n## 🔧 Configuration\n\nAll configuration lives in `.env` (copied from `.env.example`).\n\n| Variable | Default | Purpose |\n|---|---|---|\n| `IBKR_HOST` | `127.0.0.1` | Gateway host. Almost always localhost. |\n| `IBKR_PORT` | `4001` | `4001` Gateway live · `4002` Gateway paper · `7496` TWS live · `7497` TWS paper |\n| `IBKR_CLIENT_ID_BASE` | `11` | Scripts add an offset (7–16); the resulting clientId must be unique across all your apps. |\n| `IBKR_MARKET_DATA_TYPE` | `3` | `1` realtime · `2` frozen · `3` delayed (default — auto-upgrades to realtime when subscribed) · `4` delayed-frozen |\n| `FINNHUB_API_KEY` | *(unset)* | Optional. Falls back when `yahoo-earnings-calendar` is unavailable. Free at <https://finnhub.io>. |\n| `IBKR_FLEX_TOKEN` | *(unset)* | Optional. IBKR Flex Web Service token for full historical P&L (beyond the ~2-day execution window). |\n| `IBKR_FLEX_QUERY_ID` | *(unset)* | Optional. Flex Query ID. |\n\n### ClientId offsets\n\nEach script reserves a unique offset so they can coexist:\n\n```\nmarket_quote.py        offset 7   → clientId = base + 7\noptions_chain.py       offset 8\nportfolio_positions.py offset 9\noptions_analyzer.py    offset 10\noptions_daily.py       offset 11\npnl_analytics.py       offset 12\nrisk_simulator.py      offset 13\ntechnical_indicators   offset 14\nwheel_tracker.py       offset 15\nalerts_monitor.py      offset 16\n```\n\nWith `IBKR_CLIENT_ID_BASE=11` (default), `market_quote.py` uses clientId `18`. If you run TWS/Gateway with **another** app on clientId `18`, raise the base.\n\n### User data (outside the repo)\n\nThese files live in your home dir and are not committed:\n\n- `~/.ibkr_wheel_journal.json` — wheel cycle entries\n- `~/.ibkr_alerts.yaml` — alert rules\n- `~/.ibkr_flex/*.csv` — Flex Statement exports\n\n---\n\n## ❓ Troubleshooting\n\nFull guide: [`references/troubleshooting.md`](references/troubleshooting.md). The five issues that cover 90% of first-run problems:\n\n### 1. `clientId X already in use`\n\nTwo scripts (or two copies of one script) hit IB Gateway with the same clientId. Either:\n- Wait for the previous script to disconnect (usually a couple of seconds), **or**\n- Raise `IBKR_CLIENT_ID_BASE` to a value no other app uses, **or**\n- Confirm you don't have TWS *and* Gateway running at the same time on overlapping clientIds.\n\n### 2. `Error 200: No security definition has been found`\n\nThe contract didn't resolve. Causes:\n- Typo in the symbol (`SPYY` → `SPY`).\n- Expired option date.\n- Strike doesn't exist (e.g. `599.5` when only `599` and `600` are listed).\n- Exchange routing — for some tickers you need to pass `--exchange ARCA` instead of `SMART`.\n\n### 3. `Error 10091: subscription required`\n\nYou don't have a real-time market-data subscription for that exchange. Two fixes:\n- Switch to delayed: `IBKR_MARKET_DATA_TYPE=3` in `.env`.\n- Subscribe (Account Management → Settings → Market Data Subscriptions).\n\n### 4. Connection refused / `TimeoutError`\n\nGateway isn't reachable. Checklist:\n- Is Gateway running and **logged in**? (A logged-out Gateway doesn't accept connections.)\n- Is the port in `.env` the same as Gateway's `API → Settings → Socket port`?\n- Is `127.0.0.1` in **Trusted IPs**?\n- Restart Gateway after changing API settings — they don't take effect live.\n\n### 5. `modelGreeks is None`\n\nThe market is closed and there's no cached delayed-Greeks snapshot. Either wait for the next open, or set `IBKR_MARKET_DATA_TYPE=4` (delayed-frozen) and retry — delayed-frozen serves the last delayed snapshot from previous session.\n\n---\n\n## 📚 Advanced\n\n| Topic | Doc |\n|---|---|\n| Full strategy library (20+ McMillan/Overby strategies with construction, IV preference, P&L profile) | [`references/strategies.md`](references/strategies.md) |\n| Greeks primer (Delta, Gamma, Vega, Theta, Rho — practical interpretation) | [`references/greeks_primer.md`](references/greeks_primer.md) |\n| Wheel strategy in depth (strike/DTE selection, roll-vs-assign decision tree) | [`references/wheel_strategy.md`](references/wheel_strategy.md) |\n| All known errors and fixes | [`references/troubleshooting.md`](references/troubleshooting.md) |\n\n---\n\n## 🤝 Contributing\n\nPRs and issues welcome. Keep it minimal:\n\n- One concern per PR.\n- New scripts should output JSON to stdout, log to stderr, and reserve a unique `CLIENT_ID_OFFSET`.\n- No hard-coded paths — read configuration from `os.getenv()`.\n- No buy/sell recommendations baked into the scripts; the toolkit produces *data*, the user (or Claude) makes decisions.\n\n---\n\n## 📜 License\n\n[MIT](LICENSE). Use it, fork it, ship it.\n\n---\n\n## ⚠️ Disclaimer\n\n**This software is for educational and personal use only. It is not financial advice.**\n\n- The toolkit is **read-only by design**: it queries data and does Greeks math; it does not place orders. The repo never calls `placeOrder()`.\n- All trading decisions are yours. Options trading involves substantial risk of loss and is not appropriate for every investor.\n- The `options_analyzer.py` recommendations are educational mappings from outlook + risk profile → strategy templates. They do not consider your personal situation, capital, or tax position.\n- Past performance shown by `pnl_analytics.py` does not predict future results.\n- IBKR connectivity, market data quality, and third-party APIs (Yahoo, Finnhub) can fail. Verify critical numbers against your broker's UI before acting.\n\nBy using this software you agree that the authors and contributors are not liable for any trading losses, missed trades, or data errors.\n\nFile v0.2.6:_meta.json\n\n{\n  \"ownerId\": \"kn7d98bzsjt5mkh9hb3rj3arm983z82x\",\n  \"slug\": \"ibkr-options-assistant\",\n  \"version\": \"0.2.6\",\n  \"publishedAt\": 1778834152261\n}\n\nFile v0.2.6:references/greeks_primer.md\n\n# Greeks Primer — Practical Interpretation\n\nThe \"Greeks\" measure how an option's price moves when something else moves. The toolkit reports them per-position and aggregates them across the portfolio in `portfolio_positions.py`. This is a working interpretation, not a textbook derivation.\n\n## The five Greeks at a glance\n\n| Greek | Measures | Per-unit move | Sign for long call | Sign for long put |\n|---|---|---|---|---|\n| **Delta** | Price sensitivity to underlying | $1 move in underlying | + (0 → +1) | − (0 → −1) |\n| **Gamma** | How fast delta changes | $1 move in underlying | + | + |\n| **Vega** | Price sensitivity to implied vol | 1 vol-point (1% IV) | + | + |\n| **Theta** | Time decay | 1 calendar day | − | − |\n| **Rho** | Sensitivity to interest rates | 1 percentage point | + | − |\n\nShort positions flip the sign of all Greeks (short call: negative delta, negative gamma, negative vega, positive theta).\n\n---\n\n## Delta — the directional one\n\n**What it tells you:** *\"If the stock moves $1, my option moves $delta.\"* For a 0.30-delta call: stock +$1 → call +$0.30 (× 100 shares = $30 per contract).\n\n**Common rules of thumb:**\n\n- Delta is also a rough probability of finishing ITM at expiry. A 0.30-delta put has ≈30% probability of expiring ITM — this is what wheel sellers use to pick strikes.\n- ATM options sit near ±0.50 delta. Deep ITM approach ±1.00. Deep OTM approach 0.\n- Stock has delta 1.00 per share (100 per round lot).\n\n**Portfolio level (`portfolio_positions.py`'s `net_delta`):**\n\n> *\"Net delta = +1,200\" means your account moves like +1,200 shares of the underlying basket.* If SPY drops $1, you lose ≈$1,200. Always reconcile this with your sizing.\n\n**When delta matters most:**\n\n- Directional trades — it's literally your directional exposure.\n- Wheel selection — pick the strike whose delta matches your acceptable assignment probability (typical wheel: 0.20–0.30 delta short put).\n\n---\n\n## Gamma — delta's accelerator\n\n**What it tells you:** *\"Delta itself isn't constant. Gamma is how much delta changes per $1 move.\"*\n\nLong options have **positive gamma**: a good thing — your delta increases when the move goes your way and decreases when it goes against you. Short options have **negative gamma**: brutal in fast moves.\n\n**Where it bites:**\n\n- **Gamma scalping** is the upside of long options.\n- **Gamma risk** on short options near expiry is the downside: a 0.20-delta short put can turn into a 0.70-delta short put overnight on an earnings gap.\n\n**Rule:** gamma is highest for **ATM options close to expiry**. If you're short premium with under a week to expiry, the gamma is screaming and a single bad day can blow through weeks of theta.\n\n---\n\n## Vega — the IV gauge\n\n**What it tells you:** *\"For every 1 percentage point increase in implied vol, the option price changes by $vega.\"* Long options are long vega; short options are short vega.\n\n**Worked example:**\n\n> If your portfolio shows `net_vega = +500`, then a 1% IV drop costs you $500. A 1% IV rise gains you $500. Across earnings, IV often drops 20–40% — a long-vega position can lose $10,000+ in seconds even if the stock goes the right way (\"IV crush\").\n\n**When vega matters most:**\n\n- **Holding through earnings:** check vega before, not after.\n- **Buying premium when IV is high:** you're paying up — even if you're right on direction you can lose to IV mean-reversion.\n- **Selling premium when IV is low:** you're getting nothing — and a vol spike will hurt.\n\n`options_analyzer.py --iv-context` reports the IV-to-HV ratio so you can avoid this trap.\n\n---\n\n## Theta — time decay\n\n**What it tells you:** *\"My option loses $theta in value each calendar day, holding everything else constant.\"* Theta is the **rent** the long pays the short for keeping the optionality alive.\n\n**Signs:**\n\n- Long options: theta < 0 (you pay).\n- Short options: theta > 0 (you collect).\n\n**Worked example:**\n\n> A short put with theta = +18 collects ≈$18/day. Over 30 days = $540 — assuming nothing else moves (which is the catch).\n\n**When theta matters most:**\n\n- **Premium-selling strategies** (CSP, covered call, iron condor, wheel): theta is your income; everything else is a risk against it.\n- **Long-premium directional bets**: you're fighting theta every day. Stocks need to move enough, in the right direction, fast enough.\n- **Theta accelerates as expiry approaches** — most theta decay happens in the last 30 days, and the very last week is dramatic.\n\n**Practical:** for a wheel, picking 30–45 DTE balances \"enough theta per day\" against \"still room to roll if it goes against me.\"\n\n---\n\n## Rho — the one you mostly ignore\n\n**What it tells you:** *\"For every 1% change in interest rates, my option changes by $rho.\"*\n\nFor typical 30–60 DTE retail options on US equities, rho is small enough to ignore — usually under $5 per contract per 1% rate move. It starts to matter for:\n\n- **LEAPS** (long-dated options, 1+ years). \n- **Cash-settled index options** in a rate-cut/hike cycle.\n- **Synthetic stock positions** (long call + short put at same strike) — rho is the carry cost.\n\nMost retail wheel and short-premium traders can treat rho as decoration.\n\n---\n\n## Portfolio-level Greeks\n\n`portfolio_positions.py` sums Greeks across all positions, normalized to share-equivalents:\n\n```json\n{\n  \"portfolio_greeks\": {\n    \"net_delta\": +1240.5,\n    \"net_gamma\": -18.2,\n    \"net_vega\": +452.0,\n    \"net_theta\": -84.1\n  }\n}\n```\n\n**How to read this:**\n\n| Greek | Interpretation |\n|---|---|\n| `net_delta = +1240` | Account moves like +1,240 shares of the underlying mix. SPY −$1 ≈ −$1,240. |\n| `net_gamma = −18` | For every $1 the underlying moves, my delta moves against me by 18. Risk concentrates near short strikes close to expiry. |\n| `net_vega = +452` | Long vega: +1% IV = +$452. -1% IV = −$452. |\n| `net_theta = −84` | Net long premium overall — I'm paying ≈$84/day in time decay. |\n\n**A net-vega-positive portfolio that you didn't intend to build is a common mistake** — easy to drift into by buying too many long calls. Run `portfolio_positions.py` weekly.\n\n---\n\n## When each Greek matters most\n\n| Scenario | Watch |\n|---|---|\n| Picking a wheel strike | **Delta** (0.20–0.30 target) |\n| Holding short premium through earnings | **Vega** (and don't) |\n| 0–7 DTE positions | **Gamma** (high — re-check intra-day) |\n| Premium-selling P&L attribution | **Theta** (income) + **Vega** (risk) |\n| LEAPS | **Rho** + Theta + Vega |\n| Stock + protective put | **Delta** of put (target around −0.20 to −0.30) |\n\n---\n\n## One last warning\n\nGreeks are model outputs (Black-Scholes-ish). They are accurate in normal markets and wrong in fast/illiquid markets. They depend on an IV input that itself moves. Treat them as **direction and rough magnitude**, not as a guarantee — especially for short-dated and far-OTM options where modelGreeks can return `None` or stale values.\n\nFile v0.2.6:references/options_book_summary.md\n\n# Options Book Summary — Operational Rules\n\nA lookup of operational rules distilled from four canonical options books, written as decision-ready heuristics rather than theory. Use this when reasoning about strategy selection, position sizing, adjustment, or risk.\n\n**Sources cited per rule:**\n- **(McMillan)** — Lawrence McMillan, *Options as a Strategic Investment*, 5th ed.\n- **(Overby)** — Brian Overby, *The Options Playbook* (TastyTrade lineage).\n- **(Natenberg)** — Sheldon Natenberg, *Option Volatility & Pricing*, 2nd ed.\n- **(Sinclair)** — Euan Sinclair, *Volatility Trading*, 2nd ed.\n\nThis is a **rule book**, not a textbook. For mechanics of Greeks see [`greeks_primer.md`](greeks_primer.md); for the strategy catalog see [`strategies.md`](strategies.md).\n\n---\n\n## Table of Contents\n\n1. [IV Environment Playbook](#1-iv-environment-playbook)\n2. [Strike Selection Rules](#2-strike-selection-rules)\n3. [DTE Selection Rules](#3-dte-selection-rules)\n4. [Adjustment Decision Tree](#4-adjustment-decision-tree)\n5. [Position Sizing](#5-position-sizing)\n6. [Skew Interpretation](#6-skew-interpretation)\n7. [Earnings IV Crush](#7-earnings-iv-crush)\n8. [Volatility Estimation](#8-volatility-estimation)\n9. [Greeks-vs-Greeks Relationships](#9-greeks-vs-greeks-relationships)\n10. [Common Mistakes (each book's \"don't\")](#10-common-mistakes)\n\n---\n\n## 1. IV Environment Playbook\n\nThe single most important question before opening an options trade: **is implied volatility rich or cheap?** Get this wrong and a directionally correct view still loses money.\n\n### Core rule\n\n> **Rule (McMillan):** When current IV is in the bottom 20% of its trailing-1-year range, **buy** premium (long straddle, long calendar, long single leg). When in the top 20%, **sell** premium (short strangle, iron condor, credit spread). Middle 60%: use **spreads** — debit spreads when you have directional conviction at low IV, credit spreads when you have directional conviction at high IV. (McMillan)\n\n### IV percentile vs IV rank — use both\n\n| Metric | Definition | When it helps |\n|---|---|---|\n| **IV rank** | (current IV − 52w low) / (52w high − 52w low) | Quick sense of where IV sits in its full year range |\n| **IV percentile** | % of trading days in the past year where IV was below today's | More robust to single-day spikes (e.g. earnings) |\n\n> **Rule (Sinclair):** Prefer IV percentile to IV rank in symbols with episodic volatility spikes (earnings, biotech catalysts). A single-day Vol spike inflates IV rank but barely moves IV percentile. (Sinclair)\n\n### Strategy → IV environment matrix\n\n| IV environment | Bullish | Bearish | Neutral | Volatile (expect a move) |\n|---|---|---|---|---|\n| **Low IV** (≤20%ile) | Long call, call debit spread, call ratio backspread | Long put, put debit spread | Long calendar, long butterfly | Long straddle, long strangle |\n| **Mid IV** (20–80%ile) | Bull call spread | Bear put spread | Iron condor (mild), short strangle (wide) | Long strangle |\n| **High IV** (≥80%ile) | Cash-secured put, bull put spread, jade lizard | Bear call spread | Short strangle, iron condor, iron butterfly | Avoid — wait for IV mean-reversion |\n\n> **Rule (Overby):** Don't sell premium for the sake of \"income\" when IV percentile is below 30. The premium you collect doesn't compensate for the gamma risk near expiry. Wait for IV to expand or switch to a defined-risk spread. (Overby)\n\n### Term structure\n\nImplied volatility varies by expiry. The shape tells you what the market is pricing.\n\n| Term structure | What it means | Trade idea |\n|---|---|---|\n| **Contango** (front IV < back IV) | Calm now, uncertainty later. The normal state in low-vol regimes. | Long calendars, short front / long back |\n| **Backwardation** (front IV > back IV) | Imminent event priced into front-month (earnings, FOMC, war). | Short front / long back (\"event vol harvest\"); never long front-month in this regime |\n| **Flat** | No view; spreads will be near fair value | Spreads, no edge for calendars |\n\n> **Rule (Natenberg):** A 10% drop in IV reduces a 30-DTE ATM option's price by roughly vega × 10. For typical equity ATM options that's ~30% of premium. This is why selling front-month into earnings backwardation is the **highest-Sharpe** vol trade — IV crush is mechanical, not random. (Natenberg)\n\n---\n\n## 2. Strike Selection Rules\n\nChoose strikes by **delta**, not by absolute price. Delta is comparable across symbols, expiries, and IV regimes; absolute strikes are not.\n\n### Delta targets by strategy\n\n| Strategy | Short-leg target delta | Notes |\n|---|---|---|\n| Cash-secured put | 0.20 – 0.30 | 0.30 = ~30% chance of assignment. Lower delta = lower premium but lower assignment risk. |\n| Covered call | 0.20 – 0.30 | 0.30 means ~30% chance the stock gets called away. |\n| Short strangle | 0.16 – 0.20 each side | 0.16 ≈ 1-σ OTM; standard TastyTrade default. |\n| Iron condor (short legs) | 0.16 – 0.30 each side | Tighten when IV is mid-range. |\n| Bull put / bear call (short leg) | 0.25 – 0.35 | Higher delta = higher premium but more touches. |\n| Long debit spread (long leg) | 0.50 – 0.70 | ITM legs hold more intrinsic value; less theta decay. |\n| Long debit spread (short leg) | 0.20 – 0.30 | Sells the OTM wing to cheapen the long. |\n| Protective put | 0.20 – 0.30 (5–10% OTM) | Insurance. Don't over-protect. |\n\n> **Rule (Overby):** A 0.30-delta short option roughly equals a 30% probability of being ITM at expiration. Use this as your \"win-rate envelope\" — never trade a strategy whose long-run win-rate doesn't beat the assignment cost. (Overby)\n\n### When to bend the rule\n\n> **Rule (McMillan):** In a stock you'd happily own at the strike, you can use a higher-delta short put (up to 0.40) — the \"loss\" of assignment is acquiring stock at a discount. In a stock you'd hate to own (poor balance sheet, secular decline), drop to 0.10–0.15 delta and accept lower premium. (McMillan)\n\n### Strike spacing rule\n\n> **Rule (Natenberg):** In a put credit spread, the optimal width is **1 to 1.5 standard deviations** of the underlying's expected move over the DTE. Wider spreads collect more premium but have worse risk/reward; tighter spreads have better R:R but are too narrow for normal noise. (Natenberg)\n\n---\n\n## 3. DTE Selection Rules\n\nTheta decay is not linear. Knowing the curve picks the sweet spot.\n\n### The theta-decay curve\n\n| DTE | Theta behavior | Trade implication |\n|---|---|---|\n| > 90 | Slow, linear theta. Vega dominates. | LEAPS for synthetic stock; calendars; long verticals when IV is low. |\n| 45–90 | Theta accelerating. Vega still meaningful. | The classic \"premium-selling\" window. Best risk/reward for short strangles, iron condors, cash-secured puts. |\n| 21–45 | Theta near maximum, gamma rising. | Most active management window — adjust here. |\n| 7–21 | Theta still high but **gamma is dangerous**. | Roll, close, or convert to a defined-risk spread. Don't open new naked short premium in this window. |\n| < 7 | Gamma extreme. A 1% underlying move = huge P&L swing. | Close. Period. Unless you're explicitly running 0-DTE on intraday timeframes. |\n\n> **Rule (Overby):** **45 DTE is the canonical short-premium entry point.** You collect 50–70% of the maximum premium before gamma turns on you. Close at 21 DTE (or 50% of max profit, whichever comes first). (Overby — TastyTrade convention)\n\n> **Rule (McMillan):** Calendars want **30–60 DTE on the long leg and 15–30 on the short leg.** The short leg decays faster (good); the long leg holds vega exposure to benefit from IV rise. Avoid calendars in front of expected IV drops (earnings IV crush will hurt the long leg). (McMillan)\n\n### Weekly vs monthly\n\n| Type | When to use |\n|---|---|\n| **Weeklies** | Only for: (a) 0–7 DTE income strategies you actively manage intraday, (b) hedging known events, (c) low-cost lottery tickets on news catalysts. Never sell weekly premium \"to collect theta\" — gamma will eat you. |\n| **Monthlies** | The default for credit spreads, iron condors, calendar spreads. More liquid, tighter bid/ask. |\n| **Quarterlies / LEAPS (60+ DTE)** | Synthetic stock, poor man's covered calls, long-vol bets ahead of high-IV regimes. |\n\n---\n\n## 4. Adjustment Decision Tree\n\nThe single hardest skill in options trading. Get this wrong and small losses become catastrophic; get it right and short-premium becomes durable.\n\n### Roll vs cut vs add: the three-question filter\n\nAsk in order:\n\n1. **Has the original thesis changed?** If yes → **CUT.** A roll on a broken thesis is throwing good money after bad.\n2. **Is there enough premium in the next expiry to re-establish the position at improved strikes?** If no → **CUT.** Rolling for a tiny credit just defers the problem.\n3. **Are you under 21 DTE and >50% of strike threatened?** If yes → **ROLL.** This is the canonical roll window.\n\n### Rolling a short put\n\n> **Rule (McMillan):** Roll **out and down** (further DTE, lower strike) only if you can do so for a **net credit**. If the roll requires a debit, you're better off closing and re-deploying capital. Track total credits across rolls — if cumulative credit drops below 0, you've extended the position too far. Cap at 2 rolls maximum. (McMillan)\n\n### Rolling a short call (when called-away risk is rising)\n\n> **Rule (Overby):** Roll **out and up** (further DTE, higher strike). If the underlying has rallied past your strike by more than 5%, ask: would I keep selling calls at this new strike if I weren't already in the trade? If no, let it be called away. The wheel's whole point is participating in upside that escapes your strike. (Overby)\n\n### Iron condor adjustments\n\n| Threat | Action |\n|---|---|\n| One side breached (e.g. underlying through put-side short strike) | Roll the **untested** side closer to current price for additional credit. Don't move the breached side — wait for mean-reversion or close. |\n| Both sides threatened (volatility expansion) | Close. The iron condor's edge depends on price staying inside the range; if it's gone, no roll fixes it. |\n| Underlying pinned at a short strike near expiry | Close 1 day before expiry; gamma assignment risk is too high. |\n\n### When to **add** (rarely)\n\n> **Rule (McMillan):** Add to a winning position only at structurally better prices, never to \"average down.\" If a short strangle is profitable and IV has expanded since entry, you can layer a second strangle at wider strikes for compounded premium. Never add to a losing strangle — that's catching a falling vol knife. (McMillan)\n\n### The \"Texas Hedge\" warning\n\n> **Rule (McMillan):** A \"Texas Hedge\" is a position that **adds risk in the same direction as the existing exposure** while pretending to hedge. Example: long stock + long call (both delta-positive). If your portfolio is already long-delta, buying more calls is not a hedge — it's leverage. Real hedges reduce net Greeks; Texas Hedges concentrate them. (McMillan)\n\n---\n\n## 5. Position Sizing\n\nMost options blowups are sizing problems, not strategy problems.\n\n### Max loss per trade\n\n> **Rule (Overby):** **No single defined-risk trade should risk more than 1–2% of account capital.** For an iron condor with $400 max loss and a $40,000 account, that's exactly one contract. (Overby)\n\n> **Rule (McMillan):** For undefined-risk trades (naked short strangle, short straddle), use a **margin-based 5% rule**: the maintenance margin requirement should not exceed 5% of account equity per position, with total undefined-risk margin capped at 25% of account. (McMillan)\n\n### Kelly-fraction caveats\n\n> **Rule (Sinclair):** Kelly suggests sizing positions by edge/variance. In options, **edge is hard to measure** and **variance is fat-tailed**. Use a **fractional Kelly** of 0.25–0.5 of the full Kelly bet. Going full-Kelly assumes you've correctly estimated both edge and variance; one bad estimate and you're ruined. (Sinclair)\n\n### Concentration\n\n> **Rule (Overby):** No single underlying should account for more than **20% of total portfolio delta**. Even if you have high conviction, a single-stock blow-up event (fraud, surprise miss, regulatory action) at 20%+ concentration is account-threatening. (Overby)\n\n### Defined vs undefined risk allocation\n\n| Account size | Max % in undefined-risk options |\n|---|---|\n| < $25k | 0% — use only defined-risk spreads |\n| $25k – $100k | ≤ 10% of net liq |\n| $100k – $500k | ≤ 20% of net liq |\n| > $500k | ≤ 30%, with diversification across uncorrelated underlyings |\n\n> **Rule (Natenberg):** The professional trader's mental sizing question is not \"how much will I make?\" but \"what's the worst-case Greeks exposure if vol expands 50% overnight?\" If you can't answer in dollars, your position is too large. (Natenberg)\n\n---\n\n## 6. Skew Interpretation\n\nPut skew = the market's price of crash insurance. Reading it tells you what professional dealers think.\n\n### What skew measures\n\n| Skew shape | Reading |\n|---|---|\n| **Steep put skew** (OTM puts much more expensive than OTM calls) | Crash risk priced in. Common in equities, especially after a recent selloff. Buying OTM puts here is **expensive insurance** — consider put spreads instead. |\n| **Flat skew** | Market sees symmetric risk. Rare in single stocks; common in FX and some commodities. |\n| **Call skew** (OTM calls more expensive than OTM puts) | Squeeze risk / takeover speculation / commodity scarcity. Common in GME-style situations and in some commodities (natural gas summer). |\n| **Smile** (both wings expensive) | Big move expected but direction unclear. Pre-event positioning. |\n\n> **Rule (Natenberg):** In equity index options, **put skew is the norm, not the anomaly**. A flat skew in SPX is itself a signal — usually that complacency has reached a top. The 1987 crash was preceded by historically flat skew. (Natenberg)\n\n### Trading the skew\n\n> **Rule (Sinclair):** When equity put skew steepens past its 1-year 90th percentile, **sell put spreads** (sell the high-IV near-money put, buy the lower-IV further-OTM put). The skew premium is your edge. When skew flattens to the 10th percentile, **buy puts outright** — the protection is cheap relative to history. (Sinclair)\n\n### Risk reversal as a skew gauge\n\nA 25-delta risk reversal (= 25Δ call IV − 25Δ put IV) is the cleanest single number for equity skew.\n\n| 25Δ RR | Interpretation |\n|---|---|\n| Strongly negative | Heavy put skew; put-buyers dominant; crash priced |\n| Near zero | Symmetric pricing |\n| Strongly positive | Call premium; squeeze/takeover priced |\n\n---\n\n## 7. Earnings IV Crush\n\nEarnings is the single most predictable IV event in equity options. Use it.\n\n### The mechanic\n\nBefore an earnings release, IV in the front-month expands to price the expected move (usually 5–15% for individual stocks). Within minutes after the release, IV collapses (\"crush\") back toward the longer-dated term-structure baseline. Whether the stock moves or not, **the option premium gets cut roughly in half**.\n\n### The trade-offs\n\n> **Rule (McMillan):** Long premium into earnings is a **−EV trade** unless your move estimate exceeds the option-implied move by a meaningful margin. The implied move is priced *exactly* to make long premium fair — and after crush, even a directionally correct move can lose money. (McMillan)\n\n> **Rule (Natenberg):** Selling premium into earnings is a **positive-vega-decay bet that the move will be smaller than implied**. Historical analysis: in liquid US equity options, the realized move beats the implied move only ~40% of the time, meaning sellers win ~60% of the time. **But the loser-tail can be very large** (gap moves >2σ happen 5–10% of the time). Size accordingly. (Natenberg)\n\n### Strategies by earnings stance\n\n| View | Strategy | Why |\n|---|---|---|\n| \"Stock moves less than implied\" | Iron condor or short strangle straddling the expected move, expire after the report | Captures full IV crush |\n| \"Stock moves more than implied\" | Long straddle/strangle, **close before earnings** | Long premium peaks the day before earnings; sell into the IV expansion |\n| \"Stock moves a specific amount in a specific direction\" | Calendar spread or directional debit spread | Pure direction bet, less vega risk |\n| \"I have no view, but I want IV crush exposure with limited risk\" | Short iron condor 1σ wide | Defined risk; profit if stock stays in range |\n\n> **Rule (Overby):** Never hold long options through earnings unless you're prepared to lose 50–70% of premium even if you're directionally right. The implied move is calibrated to your detriment. (Overby)\n\n### Pre-earnings IV ramp\n\n> **Rule (Sinclair):** Front-month IV typically rises ~30–60% in the 5 trading days before earnings (relative to non-earnings baseline IV). Selling 7-DTE puts 5 days before earnings → closing the day before earnings can harvest a portion of that ramp **without** taking event risk. (Sinclair)\n\n### Implied move vs straddle price (quick estimate)\n\nThe market's implied move for an event is approximated by the **ATM straddle price ÷ stock price**, multiplied by ~85% (a small correction because the straddle slightly over-prices the breakeven distance).\n\n> **Rule (Sinclair):** Implied move ≈ 0.85 × (ATM call price + ATM put price) / underlying price. Example: AAPL at $200 with ATM straddle worth $12 → implied move ≈ 0.85 × $12 / $200 = 5.1%. Compare against historical post-earnings moves: if AAPL's 8-quarter median post-earnings move is 3.5%, the market is overpricing the event by ~46% — that's a vol-selling setup. (Sinclair)\n\n---\n\n## 8. Volatility Estimation\n\nWhich estimator should you use?\n\n### The four ways volatility shows up\n\n> **Rule (Natenberg):** Four distinct measurements of volatility, all important:\n> 1. **Historical (realized) volatility** — what the underlying actually did. Backwards-looking.\n> 2. **Implied volatility** — what options are priced for. Forward-looking.\n> 3. **Implied skew** — how IV varies by strike. Tells you who's hedging what.\n> 4. **Term structure** — how IV varies by expiry. Tells you the timing of expected risk.\n>\n> A trader who reads only one of these is trading blind. (Natenberg)\n\n### Choosing a historical-vol estimator\n\n| Estimator | Pros | Cons | Use when |\n|---|---|---|---|\n| **Close-to-close** | Simplest; matches statistical theory | Ignores intraday range; high variance estimate | You need a quick baseline; have only daily closes |\n| **Parkinson** | Uses high-low range; ~5x more efficient than close-to-close | Assumes no drift, no overnight gaps | Pure intraday-vol estimation |\n| **Garman-Klass** | Uses OHLC; more efficient than Parkinson | Still no overnight gap handling | Liquid markets without significant overnight moves |\n| **Rogers-Satchell** | Handles drift | More complex; still no jump handling | Trending markets |\n| **Yang-Zhang** | Handles drift AND overnight gaps; ~14x more efficient than close-to-close | More complex calculation | The default for modern equity-vol research |\n| **GARCH(1,1)** | Models vol clustering and mean reversion | Parameters drift; needs refitting | Forecasting next-period vol, not just measurement |\n\n> **Rule (Sinclair):** Use **Yang-Zhang** as the default historical-vol estimator for daily equity data — it dominates simpler estimators for any series with overnight risk. Use **GARCH(1,1)** when you need a forecast, not just a measurement, but accept that GARCH systematically under-predicts large moves. (Sinclair)\n\n### Vol-of-vol\n\nThe volatility of volatility itself. High vol-of-vol → vol mean-reverts faster; low vol-of-vol → vol persists.\n\n> **Rule (Sinclair):** When vol-of-vol is high (VVIX rising), short-vol strategies become more dangerous: even small underlying moves trigger big IV swings, which means defined-risk spreads should be preferred over naked short premium. Conversely, low vol-of-vol regimes (calm-market, summer 2017-style) favor short premium because IV won't whip you. (Sinclair)\n\n### Variance swap intuition\n\nA variance swap pays the difference between **realized** variance and **strike** variance over a period. The variance-swap strike is computed from an option-strip portfolio.\n\n> **Rule (Sinclair):** The 30-day variance-swap strike is roughly **VIX squared**, scaled to daily. When VIX is 16, the market is pricing about 16% annualized realized vol over the next 30 days. If your forecast (from GARCH, recent history, or a view on macro) says realized vol will be ≤14, sell variance (short VIX/short strangle); if ≥18, buy variance. (Sinclair)\n\n---\n\n## 9. Greeks-vs-Greeks Relationships\n\nThe non-obvious interactions that catch new traders.\n\n### Gamma scalping math\n\nA delta-hedged long-gamma position profits when realized volatility exceeds implied volatility.\n\n> **Rule (Natenberg):** The expected daily P&L of a delta-hedged long-gamma position is:\n>\n>     P&L ≈ 0.5 × Γ × S² × (σ_realized² − σ_implied²) / 252\n>\n> where Γ is dollar gamma, S is stock price. Positive only when realized vol exceeds implied. This is **the entire reason** delta-hedged long-straddle positions exist as a trade — you're betting realized > implied over the holding period. (Natenberg)\n\n### Delta-Vega coupling\n\n> **Rule (Natenberg):** ATM options have the **highest vega**. OTM options have **lower vega but higher percentage IV sensitivity**. A 1-point IV move on an ATM call moves the price more in dollars, but a 1-point move on a 20-delta call moves the price more in % terms — important when sizing tail-vol trades. (Natenberg)\n\n### Theta vs Gamma trade-off\n\n> **Rule (Overby):** Every options trade is a bet on the relationship: **realized vol vs implied vol** is **theta vs gamma**. If you're collecting theta (short premium), you're paying gamma — meaning you lose if realized vol > implied. If you're paying theta (long premium), you're collecting gamma — meaning you win if realized vol > implied. There's no free lunch. (Overby)\n\n### Vega and DTE\n\n> **Rule (Natenberg):** Vega scales roughly with **√DTE**. A 90-DTE option has ~√3 ≈ 1.73x the vega of a 30-DTE option at the same strike. So when you want vega exposure (long volatility view), use longer DTE; when you want to avoid vega risk (short premium views), use shorter DTE — but trade off against gamma risk. (Natenberg)\n\n### Position-level vs single-leg Greeks\n\n> **Rule (McMillan):** Never think of an iron condor as \"selling premium.\" Think of it as a position with **net negative vega, net negative gamma, net positive theta, and bounded delta**. The decision to enter is not \"do I want to sell premium\" — it's \"do I want all four of those exposures right now?\" (McMillan)\n\n### Charm and color (the second-order Greeks)\n\n- **Charm** = dδ/dt = rate at which delta decays toward 0 (OTM) or ±1 (ITM) as time passes.\n- **Color** = dγ/dt = rate at which gamma changes over time.\n\n> **Rule (Natenberg):** Near expiry, charm and color **dominate** P&L for short-premium positions. A 1-DTE short straddle's gamma can triple intraday from a single 0.5% move. Manage 0–7 DTE positions in **delta terms hourly**, not daily. (Natenberg)\n\n### Delta-equivalent share thinking\n\nConvert option deltas to \"equivalent shares\" for portfolio-level risk:\n- A short put with 0.30 delta and quantity 1 contract = `+0.30 × 100 = +30 delta-equivalent shares`.\n- A long call with 0.70 delta and quantity 2 contracts = `+0.70 × 100 × 2 = +140 delta-equivalent shares`.\n\n> **Rule (McMillan):** Compute portfolio-level **net delta** as a single number. If it's +5000 on a $100k account, you have leverage of 50× the underlying — a 2% move costs $10k. Most retail blowups happen when net delta drifts past 1× capital without the trader noticing. (McMillan)\n\n---\n\n## 10. Common Mistakes\n\nEach book has its \"don't\" list. The overlap is instructive — these are the canonical retail-options errors.\n\n### McMillan's list\n\n1. **Buying out-of-the-money options \"because they're cheap.\"** Low premium ≠ high expected value. OTM options have low probability of profit and high theta percentage decay.\n2. **Holding losers and selling winners.** Standard prospect-theory error. Have a cut-loss plan **before** entry.\n3. **Selling naked options without margin awareness.** A 10x margin spike during a vol event can force liquidation at the worst time.\n4. **Ignoring early-assignment risk on ITM short calls before ex-dividend.** If the dividend exceeds the time value remaining, you will be assigned.\n5. **Trading illiquid options.** Wide bid/ask spreads can cost 20–30% on round-trip.\n\n### Overby's \"5 mistakes new options traders make\"\n\n1. **Trading too big.** New traders typically risk 5–10% per trade; they should risk 1–2%.\n2. **Trading too short DTE.** Weeklies feel exciting but gamma punishes mistakes immediately. Start at 45 DTE.\n3. **Not knowing the risk graph before entry.** If you can't sketch the payoff diagram from memory, you'll panic when the position moves.\n4. **Trading in low-liquidity underlyings.** Bid/ask spreads eat all the edge in obscure tickers. Stick to liquid names.\n5. **Never closing winners early.** A short option at 50% of max profit has used 80% of the time but holds 50% of the remaining risk. Close at 50% and redeploy.\n\n> **Rule (Overby):** **Never trade a strategy you can't draw on paper.** If you can't sketch the risk graph from memory, you'll panic when the position moves against you. (Overby)\n\n### Natenberg's list\n\n1. **Confusing IV with HV.** They measure different things. Sell premium when IV >> HV; buy premium when IV << HV.\n2. **Underestimating skew.** OTM puts in equities are systematically more expensive than OTM calls. Pretending they're symmetric leads to mispriced credit spreads.\n3. **Ignoring early-exercise risk on American options.** ITM puts can be optimally exercised early when interest rates are high; calls before dividends.\n4. **Believing Black-Scholes prices the wings correctly.** It doesn't. The model assumes lognormal returns; reality has fat tails. Always check fat-tail-adjusted models for OTM wings.\n5. **Trading vol without a vol forecast.** \"Vol is high\" is not a trade; \"vol will be 18% over the next 30 days versus 22% priced\" is a trade.\n\n> **Rule (Natenberg):** A 30-DTE ATM option's price is approximately `S × σ × √(T/365) × 0.4`. Memorize this — it lets you sanity-check option quotes mentally. If a quote diverges from the back-of-envelope estimate by >30%, something's off (wrong contract, illiquidity, mispriced vol). (Natenberg)\n\n### Sinclair's list\n\n1. **Over-fitting GARCH on small samples.** Vol forecasts from <2 years of data are essentially noise.\n2. **Sizing by intuition rather than Kelly fraction.** Most retail traders are 2-3x too large.\n3. **Trading low-edge structures (ATM straddles) as if they're high-edge.** ATM straddles are nearly market-neutral on vol; the edge is small.\n4. **Holding through earnings on long premium positions.** IV crush dominates direction.\n5. **Ignoring transaction costs.** Bid/ask spreads + commission + slippage often eat 15–25% of expected edge on retail options trades.\n\n> **Rule (Sinclair):** **Volatility trading is statistics, not directional speculation.** If your trade thesis doesn't include a number (forecast vol, expected variance, IV percentile threshold), you're not vol trading — you're directional trading with options on top. (Sinclair)\n\n---\n\n## Appendix: Quick decision card\n\nWhen the user asks \"should I trade options on X?\" — run this checklist:\n\n| Step | Check | Source |\n|---|---|---|\n| 1 | What's the IV percentile? (≤20 → buy; ≥80 → sell; 20–80 → spread) | McMillan |\n| 2 | What's the term structure? (Backwardation → upcoming event; contango → calm) | Natenberg |\n| 3 | What's the put skew? (Steep → sell put spreads; flat → buy puts outright) | Sinclair |\n| 4 | Earnings inside DTE? (If yes → assume IV crush will dominate) | McMillan |\n| 5 | What target delta for short legs? (Match the strategy: see table §2) | Overby |\n| 6 | What DTE? (45 default for short premium; 60–90 for calendars) | Overby |\n| 7 | Position size: ≤2% account on defined-risk; ≤5% margin on undefined | McMillan/Overby |\n| 8 | Can I draw the risk graph from memory? If no → don't trade it | Overby |\n| 9 | What's my exit rule (% profit and % loss) before entry? | All books |\n| 10 | What adjustment will I make if it moves against me, and at what trigger? | McMillan |\n\nIf you can answer all 10 with concrete numbers, the trade is well-specified. If any answer is \"I don't know\" — wait, study, or skip the trade.\n\n---\n\n## 11. Pricing Model Limitations\n\nWhen does Black-Scholes lie? Often. Knowing where the model breaks tells you where the edge lives.\n\n### Where Black-Scholes is reliable\n\n| Condition | BS quality |\n|---|---|\n| ATM, liquid, 30–90 DTE | Excellent — model and market agree to within bid/ask |\n| Far OTM puts in equities | **Poor** — market prices fat-tail risk that BS understates |\n| Far OTM calls in equities | Often overpriced vs BS (squeeze/takeover premium) |\n| Short-dated (<7 DTE) | **Poor** — jump-diffusion effects dominate Brownian motion assumption |\n| Right before earnings | **Poor** — market prices an event-jump that BS can't represent |\n| In high-rates / dividend regimes | OK for European; poor for American without early-exercise adjustment |\n\n> **Rule (Natenberg):** Black-Scholes assumes (a) lognormal returns, (b) no jumps, (c) constant volatility, (d) constant interest rate, (e) continuous trading, (f) no transaction costs. Real markets violate every assumption. The model is most-wrong at the tails (far OTM) and around events. **The model's \"implied volatility\" is not a forecast — it's the volatility that makes the (wrong) BS formula match the (right) market price.** (Natenberg)\n\n### The volatility smile = BS error map\n\nA volatility smile or skew is literally a map of where Black-Scholes is wrong. If BS were correct, all strikes on the same expiry would have the same IV.\n\n> **Rule (Sinclair):** A useful mental model: BS-implied IV at strike K is a **probability-weighted average** of vol scenarios in which the underlying ends near K. Steep put skew → market assigns high probability to crash scenarios. Flat skew → market assigns symmetric outcome probabilities. **Don't trade against the skew without understanding why it's there.** (Sinclair)\n\n### When to use jump-diffusion or stochastic-vol models\n\n> **Rule (Natenberg):** For OTM wings and binary-event-pricing (earnings, FDA approvals, court rulings), use a **jump-diffusion model** (Merton, SVJ) or a **Heston-style stochastic-vol model**. BS systematically under-prices tail risk by 30–60% in equities. The retail trader's cheap edge: **buying OTM tail wings when implied skew is at the 10th percentile.** (Natenberg)\n\n---\n\n## 12. The Trading Plan Template\n\nBefore opening any options trade, fill in these blanks. If you can't, don't trade.\n\n| Field | Example |\n|---|---|\n| Underlying | SPY |\n| Strategy | Iron condor |\n| Outlook | Range-bound between 590 and 620 over next 30 days |\n| IV environment | IV percentile = 62 (mid-range, slight premium-sell bias) |\n| Earnings inside DTE? | No earnings until Q2 next quarter |\n| Strikes | -2σ put / +2σ call (each ~0.16 delta) |\n| DTE | 38 |\n| Net credit | $1.20 |\n| Max loss | $3.80 (= $5 wing − $1.20 credit) |\n| Max profit | $1.20 |\n| Win rate (probability of full credit) | ~68% (1 − 2 × 0.16) |\n| Position size (contracts) | 1 (= 1% of $38k account at max loss) |\n| Profit-take exit | Close at 50% of max profit ($0.60) |\n| Stop-loss exit | Close at 2x credit loss ($2.40) |\n| Adjustment trigger | If one side reaches ~30 delta, roll untested side for credit |\n| Roll cap | 1 roll maximum |\n| Time-stop | Close at 21 DTE regardless of P&L |\n\n> **Rule (McMillan):** Writing this down is not bureaucracy — it's the difference between a trade and a gamble. If you can't fill in the **stop-loss** and **time-stop** lines, your \"trade idea\" is actually an open-ended bet, which is the structural cause of most account drawdowns. (McMillan)\n\n---\n\n## 13. Behavioral Pitfalls (cross-cutting)\n\nThe four traps that recur in all four books.\n\n### 1. Anchoring to entry price\n\nOnce a trade is open, your reference price should be **current market** — not your entry. A short put at $1.20 credit, now trading $0.40 to close, is the same risk-reward as opening a new short put at $0.40 with $0.40 max profit, $4.60 max loss. You'd never open that trade fresh. Close it.\n\n> **Rule (Overby):** **The 50% profit-take rule (close at half of max profit) is the single highest-Sharpe behavior change a short-premium trader can adopt.** It exploits the asymmetry that early profits are easy to capture, while the last 20–30% of premium carries 50%+ of the remaining gamma risk. (Overby)\n\n### 2. Doubling down on losers\n\n> **Rule (McMillan):** \"Averaging down\" works for value investors who can hold indefinitely. In options it is **the textbook way to blow up an account**. Each leg's max loss is bounded; each addition adds new max loss; theta works against you on all of them. Cut, don't average. (McMillan)\n\n### 3. Selling cheap options for \"safety\"\n\nSelling a 0.05-delta put feels safe — 95% probability of profit. But the premium is tiny, and one black-swan event wipes out 20+ \"winning\" trades. The math: 95% × $10 + 5% × $-500 = +$9.50 − $25 = **−$15.50 expected value.** Negative-EV with high win rate is the most common trap in options.\n\n> **Rule (Sinclair):** Win rate is meaningless without expected value. A 99% win rate strategy is a disaster if the 1% loss is 200x the average win. Calculate expected value, not win rate. (Sinclair)\n\n### 4. Trading because you're bored\n\n> **Rule (Overby):** The single most expensive psychological state in options is **boredom**. There is no penalty for sitting in cash. There is enormous penalty for trading sub-optimal setups to feel productive. (Overby)\n\n---\n\n## Cross-references\n\n- For the strategy catalog (long call, iron condor, jade lizard, etc.) with payoff structures: [`strategies.md`](strategies.md)\n- For Greeks interpretation (delta, gamma, vega, theta, rho): [`greeks_primer.md`](greeks_primer.md)\n- For the wheel-strategy roll-vs-assign decision tree: [`wheel_strategy.md`](wheel_strategy.md)\n- For IBKR/connectivity errors: [`troubleshooting.md`](troubleshooting.md)\n\nFile v0.2.6:references/strategies.md\n\n# Options Strategy Library\n\nCombined library from Larry McMillan's *Options as a Strategic Investment* and Brian Overby's *The Options Playbook*. The `options_analyzer.py` script selects from this set based on **outlook × risk_profile × IV environment**.\n\n## Table of Contents\n\n- [How to read this doc](#how-to-read-this-doc)\n- [IV environment guidance](#iv-environment-guidance)\n- [Selection matrix](#selection-matrix-outlook--risk_profile)\n- [Tier 1 — Rookie (single-leg)](#tier-1--rookie-single-leg)\n- [Tier 2 — Intermediate (two-leg spreads)](#tier-2--intermediate-two-leg-spreads)\n- [Tier 3 — Advanced (3–4 leg)](#tier-3--advanced-34-leg)\n- [Tier 4 — Expert (ratio & synthetic)](#tier-4--expert-ratio--synthetic)\n\n---\n\n## How to read this doc\n\nEach strategy entry has:\n\n| Field | Meaning |\n|---|---|\n| **Name (EN / CN)** | English / Chinese name. |\n| **Direction** | `bullish` / `bearish` / `neutral` / `volatile` market view. |\n| **Construction** | Legs (`BUY`/`SELL`, `Call`/`Put`, strike offset relative to ATM). |\n| **When to use** | The setup this strategy is built for. |\n| **IV preference** | `low` (buy premium) · `high` (sell premium) · `neutral` (spreads). |\n| **Max profit / loss** | Per 1 contract; multiply by 100 for $ on US equity options. |\n| **Risk profile** | `conservative` / `moderate` / `aggressive` — who should consider it. |\n\nStrike offsets are measured in **strike steps** (the gap between adjacent listed strikes). `0` = ATM, `+2` = two strikes OTM call side, `-2` = two strikes OTM put side, etc.\n\n---\n\n## IV environment guidance\n\n`options_analyzer.py --iv-context` compares the current average IV across the chain to 20-day realized volatility and returns one of three regimes:\n\n| Regime | Trigger | Bias |\n|---|---|---|\n| **IV high** | `IV / HV > 1.3` | Sell premium — credit spreads, CSPs, covered calls, iron condors. |\n| **IV neutral** | `0.8 ≤ IV / HV ≤ 1.3` | Spread-driven — directional debit/credit spreads. |\n| **IV low** | `IV / HV < 0.8` | Buy premium — long options, straddles/strangles, ratio backspreads. |\n\nThe analyzer re-ranks candidates inside a given outlook × risk_profile cell so that IV-matched strategies come first.\n\n---\n\n## Selection matrix (outlook × risk_profile)\n\nThis is the literal mapping inside `options_analyzer.py` — the first strategy in each cell is the default suggestion.\n\n| Outlook | Conservative | Moderate | Aggressive |\n|---|---|---|---|\n| **Bullish** | Covered Call · Cash-Secured Put · Collar | Bull Call Spread · Bull Put Spread | Long Call · Call Ratio Backspread · Risk Reversal |\n| **Bearish** | Protective Put · Bear Call Spread | Bear Put Spread | Long Put · Put Ratio Backspread |\n| **Neutral** | Covered Call · Iron Condor | Iron Condor · Iron Butterfly · Jade Lizard | Short Straddle · Short Strangle |\n| **Volatile** | Long Strangle | Long Straddle · Long Strangle | Long Straddle · Call Ratio Backspread |\n\n> **Note on \"Aggressive Bearish\":** selling unhedged calls (Short Call) is intentionally excluded because of unlimited upside risk. Use a defined-risk bear call spread instead.\n\n---\n\n## Tier 1 — Rookie (single-leg)\n\n### Long Call · 买入看涨\n\n- **Direction:** bullish · aggressive.\n- **Construction:** BUY 1 Call ATM.\n- **When to use:** strong directional conviction, expecting a sharp move up before expiry.\n- **IV preference:** low (you're long vega).\n- **Max profit:** unlimited.\n- **Max loss:** premium paid.\n- **Breakeven:** strike + premium.\n\n### Long Put · 买入看跌\n\n- **Direction:** bearish · aggressive.\n- **Construction:** BUY 1 Put ATM.\n- **When to use:** strong downside conviction.\n- **IV preference:** low.\n- **Max profit:** strike − premium (down to zero).\n- **Max loss:** premium paid.\n- **Breakeven:** strike − premium.\n\n### Cash-Secured Put (CSP) · 现金担保卖出看跌\n\n- **Direction:** bullish (or neutral-to-bullish) · conservative / moderate.\n- **Construction:** SELL 1 Put, typically 2 strikes OTM; reserve cash to buy 100 shares at the strike.\n- **When to use:** willing to own the stock at a discount; collect premium otherwise. **Stage 1 of the wheel.**\n- **IV preference:** high.\n- **Max profit:** premium collected.\n- **Max loss:** (strike − premium) × 100 if the stock goes to zero.\n- **Breakeven:** strike − premium.\n\n### Covered Call · 备兑看涨\n\n- **Direction:** bullish (mildly) · conservative.\n- **Construction:** OWN 100 shares + SELL 1 OTM Call.\n- **When to use:** generate yield on existing stock; OK with capping upside. **Stage 3 of the wheel.**\n- **IV preference:** high.\n- **Max profit:** (call_strike − cost_basis + premium) × 100.\n- **Max loss:** stock fall − premium (downside is the same as owning the stock, minus what you collected).\n- **Breakeven:** cost_basis − premium.\n\n### Protective Put · 保护性看跌\n\n- **Direction:** neutral (insurance) · conservative.\n- **Construction:** OWN 100 shares + BUY 1 OTM Put.\n- **When to use:** worried about a near-term drawdown but don't want to sell.\n- **IV preference:** low.\n- **Max profit:** unlimited (stock upside) − premium.\n- **Max loss:** capped at (cost_basis − put_strike + premium) × 100.\n\n---\n\n## Tier 2 — Intermediate (two-leg spreads)\n\n### Bull Call Spread · 牛市看涨价差\n\n- **Direction:** bullish · moderate.\n- **Construction:** BUY Call at ATM, SELL Call 3 strikes higher.\n- **When to use:** moderate upside view; want to cap cost vs. long call.\n- **IV preference:** neutral.\n- **Max profit:** (width − net_debit) × 100.\n- **Max loss:** net_debit × 100.\n- **Breakeven:** long_strike + net_debit.\n\n### Bear Put Spread · 熊市看跌价差\n\n- **Direction:** bearish · moderate.\n- **Construction:** BUY Put at ATM, SELL Put 3 strikes lower.\n- **When to use:** moderate downside view; cheaper than long put.\n- **IV preference:** neutral.\n- **Max profit:** (width − net_debit) × 100.\n- **Max loss:** net_debit × 100.\n- **Breakeven:** long_strike − net_debit.\n\n### Bull Put Spread (credit) · 牛市看跌价差\n\n- **Direction:** bullish · moderate.\n- **Construction:** SELL Put 1 strike OTM, BUY Put 4 strikes OTM.\n- **When to use:** bullish AND high IV — get paid to be right.\n- **IV preference:** high.\n- **Max profit:** net_credit × 100.\n- **Max loss:** (width − net_credit) × 100.\n- **Breakeven:** short_put_strike − net_credit.\n\n### Bear Call Spread (credit) · 熊市看涨价差\n\n- **Direction:** bearish · moderate (conservative-friendly).\n- **Construction:** SELL Call 1 strike OTM, BUY Call 4 strikes OTM.\n- **When to use:** bearish-to-neutral AND high IV.\n- **IV preference:** high.\n- **Max profit:** net_credit × 100.\n- **Max loss:** (width − net_credit) × 100.\n- **Breakeven:** short_call_strike + net_credit.\n\n### Long Straddle · 买入跨式\n\n- **Direction:** volatile · moderate / aggressive.\n- **Construction:** BUY Call ATM + BUY Put ATM.\n- **When to use:** expecting a big move, unsure direction (e.g. binary event).\n- **IV preference:** low (vega risk — IV crush on earnings kills it).\n- **Max profit:** unlimited (up); large (down).\n- **Max loss:** total premium paid.\n- **Breakeven:** strike ± total_premium.\n\n### Short Straddle · 卖出跨式\n\n- **Direction:** neutral · aggressive (unlimited risk).\n- **Construction:** SELL Call ATM + SELL Put ATM.\n- **When to use:** expecting tight range; high IV that will collapse.\n- **IV preference:** high.\n- **Max profit:** total premium received.\n- **Max loss:** unlimited.\n- **Breakeven:** strike ± total_premium.\n\n### Long Strangle · 买入宽跨式\n\n- **Direction:** volatile · moderate.\n- **Construction:** BUY OTM Call (+2) + BUY OTM Put (−2).\n- **When to use:** big move expected, cheaper than straddle but needs larger move.\n- **IV preference:** low.\n- **Max profit:** unlimited.\n- **Max loss:** total premium.\n- **Breakeven:** call_strike + prem · put_strike − prem.\n\n### Short Strangle · 卖出宽跨式\n\n- **Direction:** neutral · moderate / aggressive.\n- **Construction:** SELL OTM Call (+3) + SELL OTM Put (−3).\n- **When to use:** range-bound with high IV; wider safety than short straddle.\n- **IV preference:** high.\n- **Max profit:** total premium.\n- **Max loss:** unlimited (both sides).\n- **Breakeven:** call_strike + prem · put_strike − prem.\n\n### Collar · 领口策略\n\n- **Direction:** neutral (hedged) · conservative.\n- **Construction:** OWN stock + BUY OTM Put (−2) + SELL OTM Call (+2). Often near zero cost.\n- **When to use:** lock in a gain; protect against a drop without paying for the put.\n- **IV preference:** neutral.\n- **Max profit:** capped at call_strike − cost_basis ± net_credit.\n- **Max loss:** capped at cost_basis − put_strike ∓ net_credit.\n\n---\n\n## Tier 3 — Advanced (3–4 leg)\n\n### Iron Condor · 铁秃鹰\n\n- **Direction:** neutral · conservative / moderate.\n- **Construction:** SELL OTM Put + BUY further OTM Put **AND** SELL OTM Call + BUY further OTM Call.\n- **When to use:** range-bound stock, want defined risk on a short strangle.\n- **IV preference:** high.\n- **Max profit:** net_credit × 100.\n- **Max loss:** (max(put_width, call_width) − net_credit) × 100.\n- **Breakeven:** short_put − net_credit · short_call + net_credit.\n\n### Iron Butterfly · 铁蝶式\n\n- **Direction:** neutral · moderate.\n- **Construction:** SELL ATM Put + SELL ATM Call + BUY OTM Put (−3) + BUY OTM Call (+3).\n- **When to use:** stock will pin near ATM by expiry; want bigger credit than iron condor.\n- **IV preference:** high.\n- **Max profit:** net_credit × 100 (at ATM at expiry).\n- **Max loss:** (wing_width − net_credit) × 100.\n\n### Long Call Butterfly · 买入蝶式\n\n- **Direction:** neutral · moderate (defined risk).\n- **Construction:** BUY 1 ITM Call (−3) + SELL 2 ATM Calls + BUY 1 OTM Call (+3).\n- **When to use:** pin play, low cost. Loves time decay if price stays near middle strike.\n- **IV preference:** neutral.\n- **Max profit:** at middle strike at expiry — (wing_width − net_debit) × 100.\n- **Max loss:** net_debit × 100.\n\n### Jade Lizard · 翡翠蜥蜴\n\n- **Direction:** bullish (with upside protection) · moderate.\n- **Construction:** SELL OTM Put + SELL OTM Call + BUY further OTM Call. Net credit ≥ call spread width → **no upside risk**.\n- **When to use:** bullish AND high IV, but want a hedge in case of upside gap.\n- **IV preference:** high.\n- **Max profit:** net_credit × 100 (in the no-touch range).\n- **Max loss:** put-side: strike_put − net_credit. Upside loss zero by construction.\n\n---\n\n## Tier 4 — Expert (ratio & synthetic)\n\n### Call Ratio Backspread · 看涨比率反向价差\n\n- **Direction:** bullish (sharp move) · aggressive.\n- **Construction:** SELL 1 Call near ATM + BUY 2 Calls 3 strikes OTM.\n- **When to use:** convex upside bet; profits on big rallies, small loss on tight range.\n- **IV preference:** low (long vega net).\n- **Max profit:** unlimited.\n- **Max loss:** between strikes (zone of pain). Bounded.\n\n### Put Ratio Backspread · 看跌比率反向价差\n\n- **Direction:** bearish (sharp drop) · aggressive.\n- **Construction:** SELL 1 Put near ATM + BUY 2 Puts 3 strikes OTM.\n- **When to use:** crash protection / convex downside bet.\n- **IV preference:** low.\n- **Max profit:** large (down to zero).\n- **Max loss:** between strikes.\n\n### Risk Reversal · 风险反转\n\n- **Direction:** bullish · aggressive.\n- **Construction:** BUY OTM Call (+2) + SELL OTM Put (−2). Often near zero cost.\n- **When to use:** strong upside conviction, willing to be assigned at the put strike. Synthetic long stock with a gap.\n- **IV preference:** neutral.\n- **Max profit:** unlimited.\n- **Max loss:** put_strike × 100 (if stock goes to zero, minus net credit).\n\n---\n\n## Cheat sheet — choose by intent\n\n| If you want to… | Look at |\n|---|---|\n| Get paid to wait for a buy entry | Cash-Secured Put |\n| Earn yield on stock you own | Covered Call |\n| Hedge a winning stock position | Collar / Protective Put |\n| Bet on direction cheaply | Long Call / Long Put |\n| Bet on direction with capped cost | Bull/Bear Call/Put Spreads |\n| Get paid for range-bound view (defined risk) | Iron Condor / Iron Butterfly |\n| Get paid for range-bound view (max premium) | Short Straddle / Strangle |\n| Bet on a big move (direction unknown) | Long Straddle / Strangle |\n| Convex bullish or bearish bet | Ratio Backspread |\n| Bullish with disaster hedge upside | Jade Lizard |\n\nFile v0.2.6:references/trading.md\n\n# Trading Mode — `scripts/trade.py`\n\n> **⚠️ WARNING — This script CAN move real money.**\n>\n> The rest of the toolkit is read-only by design. `trade.py` is the **only** script\n> that calls `ib.placeOrder()`. Before you point it at a live account, test it\n> against a **paper account** (`IBKR_PORT=4002`). Lose money on the paper account\n> first so you don't lose it on the real one.\n\n---\n\n## How to enable trading\n\nBy default the toolkit is read-only. To send orders you must perform three\none-time setup steps, then satisfy two gates on every invocation.\n\n### One-time setup\n\n1. **Disable Gateway's Read-Only API toggle**\n\n   In IB Gateway:\n\n   ```\n   Configure → Settings → API → Settings\n   ```\n\n   - **UN**check **\"Read-Only API\"**\n   - Keep **\"Enable ActiveX and Socket Clients\"** checked\n   - Keep **\"Allow connections from localhost only\"** checked (safer)\n   - Click **OK** and **restart Gateway**\n\n   If Read-Only API stays on, IBKR rejects orders with Error 2105. `trade.py`\n   surfaces this clearly under `checks.gateway_readonly_off: false` and refuses\n   to place an order.\n\n2. **Use a username with trading rights**\n\n   If you use a secondary user (recommended — see Operations Guide in the main\n   README), make sure the secondary user has **trading rights**, not just\n   view-only. You set this when creating the secondary user in Client Portal.\n\n3. **Set `IBKR_TRADING_ENABLED=1` in your shell**\n\n   ```bash\n   export IBKR_TRADING_ENABLED=1\n   ```\n\n   Or add to your `.env` file (`.env.example` documents it). This is Gate 1.\n\n---\n\n## Two-gate safety design\n\nEvery order command checks **both gates**. Either gate failing → dry-run preview\nonly, no `placeOrder()` call. This is by design.\n\n| Gate | What | Where it lives |\n|---|---|---|\n| 1 | `IBKR_TRADING_ENABLED=1` env var | Set once per shell session (or in `.env`) |\n| 2 | `--confirm-trade` CLI flag | Pass per invocation. Must be re-typed each time. |\n\nWhy two? Gate 1 prevents accidentally running a trade command while you only\n*meant* to query data. Gate 2 prevents a copy-pasted command from an old shell\nhistory (where the env var is still set) from firing an order without your\nexplicit per-call consent.\n\n### Dry-run output\n\nWhen gates fail (or you're testing), you get JSON like:\n\n```json\n{\n  \"mode\": \"dry_run\",\n  \"order\": { ... },\n  \"contract\": { ... },\n  \"checks\": {\n    \"trading_env_enabled\": false,\n    \"confirm_flag_passed\": false,\n    \"gateway_readonly_off\": true,\n    ...\n    \"notes\": [\n      \"Gate 1 not passed: set IBKR_TRADING_ENABLED=1 ...\",\n      \"Gate 2 not passed: add --confirm-trade ...\"\n    ]\n  },\n  \"result\": \"DRY_RUN_NO_ORDER_PLACED\"\n}\n```\n\n`mode` is `\"dry_run\"` or `\"live\"`. **Always check this field** in any\nautomated pipeline.\n\n---\n\n## Hard guardrails\n\nThe script refuses orders that match any of these unless you pass `--allow-large`:\n\n| Guardrail | Threshold |\n|---|---|\n| Notional > **$100,000** | Estimated as `qty × price × multiplier` (multiplier=100 for options) |\n| Stock quantity > **10,000 shares** | |\n| Option quantity > **1,000 contracts** | |\n| Symbol in `IBKR_TRADING_BLOCKLIST` env var (comma-separated, e.g. `TSLA,GME`) | No override — must remove from list |\n\nStop-loss missing on LMT/MKT orders is only a **warning** (some MKT orders are\nintentional). It appears in `checks.notes`.\n\n### Blocklist example\n\n```bash\nexport IBKR_TRADING_BLOCKLIST=\"TSLA,GME,AMC\"\n```\n\nAny symbol on this list rejects with `blocklist_ok: false`. To trade it,\nremove it from the env var.\n\n---\n\n## Subcommand examples\n\n### Stock\n\n```bash\n# Dry run (no env, no flag)\npython scripts/trade.py stock AAPL 100 --action BUY --order-type MKT\n\n# Live buy at limit\nIBKR_TRADING_ENABLED=1 python scripts/trade.py stock AAPL 100 \\\n    --action BUY --order-type LMT --limit-price 250.50 --tif GTC \\\n    --confirm-trade\n```\n\n### Single-leg option\n\n```bash\n# Sell 2 cash-secured puts at $14.50 limit\nIBKR_TRADING_ENABLED=1 python scripts/trade.py option MU 2026-06-12 720 P 2 \\\n    --action SELL --order-type LMT --limit-price 14.50 \\\n    --confirm-trade\n```\n\n`EXPIRY` accepts both `2026-06-12` and `20260612`. `RIGHT` is `C` or `P`.\n\n### Multi-leg combo (bull put spread)\n\n```bash\n# Sell the 600 put, buy the 590 put → net credit $2.50\nIBKR_TRADING_ENABLED=1 python scripts/trade.py combo \\\n    --leg \"SPY 2026-06-26 600 P SELL 1\" \\\n    --leg \"SPY 2026-06-26 590 P BUY 1\" \\\n    --order-type LMT --limit-price 2.50 \\\n    --confirm-trade\n```\n\nEach `--leg` is `\"SYMBOL EXPIRY STRIKE RIGHT ACTION QTY\"`. All legs must share\nthe same underlying. `--limit-price` is the **net** debit (positive) or credit\n(negative) per spread unit.\n\n### Futures\n\n```bash\n# Buy 1 ES front-month at market\nIBKR_TRADING_ENABLED=1 python scripts/trade.py future ES 1 \\\n    --action BUY --order-type MKT --confirm-trade\n\n# Specific contract month\nIBKR_TRADING_ENABLED=1 python scripts/trade.py future ES 1 \\\n    --last-trade-month 202609 --action BUY --order-type LMT --limit-price 6200 \\\n    --confirm-trade\n```\n\n### Forex\n\n```bash\nIBKR_TRADING_ENABLED=1 python scripts/trade.py forex EURUSD 25000 \\\n    --action BUY --order-type LMT --limit-price 1.0850 \\\n    --confirm-trade\n```\n\n---\n\n## Managing open orders\n\n### List\n\n```bash\npython scripts/trade.py list-orders\n```\n\n(No gates needed — listing is read-only.)\n\nOutput:\n\n```json\n{\n  \"open_orders\": [\n    {\n      \"order_id\": 7,\n      \"symbol\": \"AAPL\",\n      \"sec_type\": \"STK\",\n      \"action\": \"BUY\",\n      \"order_type\": \"LMT\",\n      \"quantity\": 100,\n      \"limit_price\": 250.50,\n      \"tif\": \"GTC\",\n      \"status\": \"Submitted\",\n      \"filled\": 0,\n      \"remaining\": 100\n    }\n  ],\n  \"count\": 1\n}\n```\n\n### Cancel\n\n```bash\npython scripts/trade.py cancel 7\n```\n\n(No gates needed — cancelling reduces risk.)\n\n---\n\n## What happens on a real `placeOrder`\n\nAfter both gates pass and all pre-flight checks succeed, `trade.py`:\n\n1. Calls `ib.placeOrder(contract, order)`\n2. Waits up to 8 seconds for an initial status update\n3. Returns the result block:\n\n```json\n{\n  \"mode\": \"live\",\n  \"order\": { ... },\n  \"contract\": { ... },\n  \"checks\": { ... },\n  \"result\": {\n    \"order_id\": 12,\n    \"perm_id\": 1862341087,\n    \"status\": \"Submitted\",\n    \"filled_qty\": 0,\n    \"remaining_qty\": 100,\n    \"avg_fill_price\": 0,\n    \"log\": [ ... last 5 status updates ... ]\n  }\n}\n```\n\nIf the status is still `PreSubmitted` or `Submitted` when we return, the order\nis **alive on IBKR's side** — use `list-orders` to track it, or use Gateway's\nown Orders panel.\n\n---\n\n## Concerns & FAQ\n\n**Q: Why `readonly=False` on the IBKR connection?**\nA: To place orders. `ib_client.ib_connect()` defaults to `readonly=True`; we\nexplicitly override for this script and only this script. The 13 read-only\nscripts all stay `readonly=True`.\n\n**Q: What if the order partially fills?**\nA: The 8-second wait returns whatever state the order is in. If `status` is\n`Submitted` with `remaining > 0`, the order is still working — re-poll via\n`list-orders` or cancel via `cancel ORDER_ID`.\n\n**Q: Combo legs all on the same side?**\nA: Each `ComboLeg` carries its own `action` (BUY/SELL). The outer order on the\n`Bag` is always `BUY 1` of the spread — the *bag's* action is just the\ndirection of \"buy this combination as defined by the legs\". For a spread you\nsell (credit spread), set the legs as documented in `parsed_legs`.\n\n**Q: Can I cancel-all?**\nA: Not as one command — pull `list-orders`, then loop `cancel ORDER_ID` per row.\nThis is deliberate to avoid wiping a portfolio with a typo.\n\n---\n\n## 中文版\n\n> **⚠️ 警告 —— 此脚本会动真金白银。**\n>\n> 工具包其它脚本全部只读。`trade.py` 是**唯一**会调 `ib.placeOrder()` 的脚本。\n> 在指向实盘账户之前，先用**模拟账户**（`IBKR_PORT=4002`）跑通。先在模拟盘亏过\n> 钱，实盘就不会亏同一笔。\n\n---\n\n### 开启交易模式\n\n工具包默认只读。要发单，需做三步一次性配置，然后每次调用满足两道闸门。\n\n#### 一次性配置\n\n1. **关掉 Gateway 的 \"Read-Only API\" 选项**\n\n   IB Gateway 里：\n\n   ```\n   Configure → Settings → API → Settings\n   ```\n\n   - **取消勾选** **\"Read-Only API\"**\n   - 保留勾选 **\"Enable ActiveX and Socket Clients\"**\n   - 保留勾选 **\"Allow connections from localhost only\"**（更安全）\n   - 点 **OK**，**重启 Gateway**\n\n   如果 Read-Only API 还开着，IBKR 会返回 Error 2105 拒单。`trade.py` 会在\n   `checks.gateway_readonly_off: false` 字段里清楚提示，并拒绝下单。\n\n2. **使用有交易权限的用户名**\n\n   如果你用副用户（推荐做法，见主 README 的 Operations Guide），确保副用户\n   有**交易权限**而不是只读。这个在 Client Portal 创建副用户时设置。\n\n3. **shell 里设置 `IBKR_TRADING_ENABLED=1`**\n\n   ```bash\n   export IBKR_TRADING_ENABLED=1\n   ```\n\n   或写进 `.env`（参考 `.env.example`）。这是闸门 1。\n\n---\n\n### 两道闸门安全设计\n\n每次下单命令都会同时检查**两道闸门**，任一不过 → 仅 dry-run 预览，**不会**调\n`placeOrder()`。这是设计如此。\n\n| 闸门 | 内容 | 位置 |\n|---|---|---|\n| 1 | 环境变量 `IBKR_TRADING_ENABLED=1` | 每个 shell 会话设一次（或写在 `.env`） |\n| 2 | CLI 标志 `--confirm-trade` | **每次**调用必须重新输入 |\n\n为什么两道？闸门 1 防止你只想查数据时不小心跑了交易命令。闸门 2 防止从旧 shell\n历史里粘出来的命令（环境变量还在）不经你当次明确同意就把单子发出去。\n\n### Dry-run 输出示例\n\n闸门不过（或你在测试）时，JSON 输出长这样：\n\n```json\n{\n  \"mode\": \"dry_run\",\n  \"order\": { ... },\n  \"contract\": { ... },\n  \"checks\": {\n    \"trading_env_enabled\": false,\n    \"confirm_flag_passed\": false,\n    ...\n    \"notes\": [\n      \"Gate 1 not passed: set IBKR_TRADING_ENABLED=1 ...\",\n      \"Gate 2 not passed: add --confirm-trade ...\"\n    ]\n  },\n  \"result\": \"DRY_RUN_NO_ORDER_PLACED\"\n}\n```\n\n`mode` 取 `\"dry_run\"` 或 `\"live\"`。**自动化流程一定要检查这个字段**。\n\n---\n\n### 硬性风控\n\n下列任一条件触发即拒单，除非加 `--allow-large`：\n\n| 风控项 | 阈值 |\n|---|---|\n| 名义金额 > **$100,000** | 估算 `数量 × 价 × 乘数`（期权乘数 = 100） |\n| 股票数量 > **10,000 股** | |\n| 期权数量 > **1,000 合约** | |\n| 标的在 `IBKR_TRADING_BLOCKLIST`（逗号分隔，比如 `TSLA,GME`） | 不可强行覆盖，必须从列表移除 |\n\nLMT/MKT 单子没设止损只会**警告**（有些 MKT 是有意为之），不会拒单。警告会在\n`checks.notes` 里出现。\n\n#### 黑名单示例\n\n```bash\nexport IBKR_TRADING_BLOCKLIST=\"TSLA,GME,AMC\"\n```\n\n名单内标的会 `blocklist_ok: false`。要交易就从环境变量里删掉。\n\n---\n\n### 子命令示例\n\n#### 股票\n\n```bash\n# 干跑（既没设环境变量也没加 flag）\npython scripts/trade.py stock AAPL 100 --action BUY --order-type MKT\n\n# 实盘限价买\nIBKR_TRADING_ENABLED=1 python scripts/trade.py stock AAPL 100 \\\n    --action BUY --order-type LMT --limit-price 250.50 --tif GTC \\\n    --confirm-trade\n```\n\n#### 单腿期权\n\n```bash\n# 卖 2 张现金担保 put，限价 $14.50\nIBKR_TRADING_ENABLED=1 python scripts/trade.py option MU 2026-06-12 720 P 2 \\\n    --action SELL --order-type LMT --limit-price 14.50 \\\n    --confirm-trade\n```\n\n`EXPIRY` 接受 `2026-06-12` 或 `20260612`。`RIGHT` 取 `C` 或 `P`。\n\n#### 多腿组合（牛市价差）\n\n```bash\n# 卖 600 put，买 590 put → 净收 $2.50\nIBKR_TRADING_ENABLED=1 python scripts/trade.py combo \\\n    --leg \"SPY 2026-06-26 600 P SELL 1\" \\\n    --leg \"SPY 2026-06-26 590 P BUY 1\" \\\n    --order-type LMT --limit-price 2.50 \\\n    --confirm-trade\n```\n\n每个 `--leg` 格式 `\"SYMBOL EXPIRY STRIKE RIGHT ACTION QTY\"`。所有腿必须同标的。\n`--limit-price` 是每份组合的**净**借方（正）或贷方（负）。\n\n#### 期货\n\n```bash\n# 买 1 张 ES 主力，市价\nIBKR_TRADING_ENABLED=1 python scripts/trade.py future ES 1 \\\n    --action BUY --order-type MKT --confirm-trade\n\n# 指定合约月\nIBKR_TRADING_ENABLED=1 python scripts/trade.py future ES 1 \\\n    --last-trade-month 202609 --action BUY --order-type LMT --limit-price 6200 \\\n    --confirm-trade\n```\n\n#### 外汇\n\n```bash\nIBKR_TRADING_ENABLED=1 python scripts/trade.py forex EURUSD 25000 \\\n    --action BUY --order-type LMT --limit-price 1.0850 \\\n    --confirm-trade\n```\n\n---\n\n### 管理在场订单\n\n#### 列出\n\n```bash\npython scripts/trade.py list-orders\n```\n\n（不需闸门，列单本来就只读。）\n\n#### 撤单\n\n```bash\npython scripts/trade.py cancel 7\n```\n\n（不需闸门，撤单是降风险动作。）\n\n---\n\n### 实盘 `placeOrder` 发生了什么\n\n两道闸门 + 所有 pre-flight 检查都通过后，`trade.py`：\n\n1. 调 `ib.placeOrder(contract, order)`\n2. 最多等 8 秒拿到首个状态更新\n3. 返回 `result` 块（包含 `order_id`、`status`、`filled_qty` 等）\n\n如果返回时状态还是 `PreSubmitted` 或 `Submitted`，说明订单**已经在 IBKR 那边\n挂着**——用 `list-orders` 跟踪，或者直接在 Gateway 的 Orders 面板看。\n\n---\n\n### 常见疑问\n\n**问：为什么连接用 `readonly=False`？**\n答：因为要发单。`ib_client.ib_connect()` 默认 `readonly=True`，我们**只在这一\n个脚本**显式覆盖。其它 13 个只读脚本保持 `readonly=True`。\n\n**问：部分成交怎么办？**\n答：8 秒等待返回时拿到的就是当时的状态。如果是 `Submitted` 且 `remaining > 0`，\n单子还在工作——用 `list-orders` 重新查，或 `cancel ORDER_ID` 撤掉。\n\n**问：能一键全撤吗？**\n答：不能。需要先 `list-orders` 然后循环 `cancel ORDER_ID`。这是故意的，避免一\n个手误把整个组合都炸了。\n\nFile v0.2.6:references/troubleshooting.md\n\n# Troubleshooting\n\nA reference for every error this toolkit can throw at you. Issues are grouped by category. If you hit something not listed here, please open an issue with the full stderr log.\n\n## Table of Contents\n\n- [Connection errors](#connection-errors)\n- [Contract / market-data errors](#contract--market-data-errors)\n- [Greeks and IV problems](#greeks-and-iv-problems)\n- [Read-only mode (intentional)](#read-only-mode-intentional)\n- [Performance & pacing](#performance--pacing)\n- [Getting Gateway logs](#getting-gateway-logs)\n- [IBKR-side configuration checklist](#ibkr-side-configuration-checklist)\n\n---\n\n## Connection errors\n\n### `ConnectionRefusedError` / \"Connection refused\"\n\nThe script can't reach IB Gateway at all.\n\n**Diagnostic order:**\n\n1. **Is Gateway running?** Check the dock / system tray. A logged-out Gateway is **not** accepting connections — re-login.\n2. **Is the port right?**\n   - Gateway live: `4001`\n   - Gateway paper: `4002`\n   - TWS live: `7496`\n   - TWS paper: `7497`\n3. **Is the API enabled?** `Configure → Settings → API → Settings → Enable ActiveX and Socket Clients` must be checked.\n4. **Is `127.0.0.1` in Trusted IPs?** Same panel. Add it explicitly.\n5. **Did you restart Gateway after enabling the API?** API settings do not apply live — Gateway must be restarted.\n\nQuick sanity check (Mac / Linux):\n\n```bash\nnc -zv 127.0.0.1 4001\n```\n\nIf `nc` fails: the problem is Gateway, not this toolkit.\n\n### `TimeoutError` after a long pause\n\nGateway is alive but not responding within `CONNECT_TIMEOUT` (10s). Causes:\n\n- Gateway is mid-restart or mid-login (banner showing 2FA challenge).\n- A previous client with the same clientId is hanging — wait 30 seconds for the server to time it out, or restart Gateway.\n- Firewall (Little Snitch on Mac, Windows Defender) is blocking the socket.\n\n### `clientId X already in use`\n\nTwo connections collided on the same clientId. Possible causes:\n\n- You re-ran a script faster than the previous run could disconnect.\n- Two scripts somehow ended up with the same offset (shouldn't happen — check that no one edited `CLIENT_ID_OFFSET` constants).\n- Another application (your TWS workstation, a third-party bot) is using that clientId.\n\n**Fix:** raise `IBKR_CLIENT_ID_BASE` in `.env` to a value that doesn't collide:\n\n```ini\nIBKR_CLIENT_ID_BASE=51\n```\n\nThis shifts all script clientIds (51+7 through 51+16). Confirm no other app uses anything in that range.\n\n---\n\n## Contract / market-data errors\n\n### `Error 200: No security definition has been found for the request`\n\nThe contract didn't resolve. The error from IBKR's API is unhelpful — here's how to debug.\n\n**Causes ranked by frequency:**\n\n1. **Typo in the symbol.** `BRK.B` should be `BRK B` (space, not dot) in some routes.\n2. **Wrong asset class.** Trying to fetch an option on a ticker that doesn't have listed options.\n3. **Expired option.** The expiration date is in the past.\n4. **Non-standard strike.** The strike doesn't exist on that expiration — chains sometimes have $0.50 strikes near ATM but $1.00 strikes farther out.\n5. **Wrong exchange.** Some tickers must be routed to a specific exchange instead of `SMART`:\n   - European stocks → `--exchange LSEETF` (London) or similar\n   - Some Chinese ADRs at certain times\n   - Cash-settled indexes → `--exchange CBOE`\n6. **Future / option on future** missing `multiplier`. CME futures options need `multiplier=50` etc.\n\n**Debug command:**\n\n```bash\npython scripts/market_quote.py SYM       # if even the underlying fails, problem is symbol/exchange\npython scripts/options_chain.py SYM      # if underlying works but chain fails, problem is expiration/strike\n```\n\n### `Error 10091: Requested market data requires additional subscription`\n\nSelf-explanatory: your IBKR account doesn't have a subscription for the exchange / data type you're requesting.\n\n**Two fixes:**\n\n1. **Switch to delayed data** (free, ~15 min lag). Edit `.env`:\n\n   ```ini\n   IBKR_MARKET_DATA_TYPE=3\n   ```\n\n   Restart the script. Quotes will be delayed but free.\n\n2. **Subscribe.** Account Management → Settings → User Settings → Market Data Subscriptions. Common subscriptions:\n   - **US Securities Snapshot and Futures Value Bundle** — $10/mo, real-time US stocks/ETFs.\n   - **OPRA (US Option Exchanges)** — $1.50/mo (no professional), needed for option Greeks live.\n   - **NASDAQ Last Sale (NLS)** — covers many Nasdaq tickers.\n\n### `Error 354: Requested market data is not subscribed`\n\nVariant of 10091 — same fix.\n\n### `Error 162: Historical market data Service error message`\n\n`reqHistoricalData` failed. Causes:\n\n- **Pacing violation:** \"more than 6 same-contract historical requests in 2 seconds\". The toolkit's `req_historical_safe()` enforces a 0.35s minimum interval — but if you've also got TWS running and pulling the same data, you can exceed the cap. Wait a minute and retry.\n- **Outside data range:** asking for 5-year history on a ticker that IPO'd 6 months ago.\n- **Wrong `whatToShow`:** `MIDPOINT` works for FX, `TRADES` for stocks; mismatching gets you 162.\n\n---\n\n## Greeks and IV problems\n\n### `modelGreeks is None`\n\nThe `options_chain.py` or `portfolio_positions.py` output shows `delta: null, iv: null, ...`.\n\n**Why it happens:**\n\n- The market is **closed** *and* you're using `IBKR_MARKET_DATA_TYPE=1` (realtime). Without a live tick, the server has no current Greeks to deliver. The same call during market hours returns Greeks correctly.\n- Far-OTM strike with no trading activity — sometimes the server simply hasn't computed Greeks for an option no one's quoting.\n- Wrong feed: deep OTM weeklies on illiquid names can lack Greeks even live.\n\n**Fixes:**\n\n1. Wait for the market to open (best signal quality).\n2. Use **delayed-frozen** to serve the last cached delayed Greeks from the previous session:\n\n   ```ini\n   IBKR_MARKET_DATA_TYPE=4\n   ```\n\n3. Move to a more liquid strike or a more liquid expiry.\n\n### IV looks wrong (zero, NaN, or jumping)\n\nStock and option ticks arrive asynchronously. Right when you connect, the chain returns an IV computed against a stale stock price. If you re-run the script 5 seconds later, IV will be sane.\n\n`options_analyzer.py` waits ~3 seconds for ticks to settle before computing IV context. If you're calling `options_chain.py` directly, give it a moment.\n\n---\n\n## Read-only mode (intentional)\n\nIf you see in the stderr log:\n\n```\n🔄 Connecting to IB Gateway 127.0.0.1:4001 (clientId=18, readonly=True) ...\n```\n\n…**this is by design.** The toolkit always connects with `readonly=True` so it cannot place, modify, or cancel orders even if some downstream library tried. We additionally recommend enabling the Gateway-side **Read-Only API** setting for double safety:\n\n- `Configure → Settings → API → Settings → Read-Only API` — **enable**.\n\nThis way, even if your `.env` got tampered with, Gateway would still refuse any order attempt.\n\n> If you ever want to write a tool in this repo that places orders, you would need to (a) set `readonly=False` in `ib_connect()` and (b) disable Read-Only API in Gateway. The toolkit deliberately makes that hard.\n\n---\n\n## Performance & pacing\n\n### Scripts feel slow\n\nTypical baseline:\n\n| Operation | Expected wall time |\n|---|---|\n| `market_quote.py SPY` | 2–4 sec (cold connect + 1 tick) |\n| `options_chain.py SPY` (3 expirations) | 8–20 sec |\n| `portfolio_positions.py` (20 positions) | 6–12 sec |\n| `options_analyzer.py SPY --iv-context` | 10–25 sec |\n\nIf you see > 60 sec, suspect:\n\n- Pacing throttle (too many historical requests recently).\n- A laggy connection (geographic distance from IBKR data center).\n- Subscription mismatch causing fallbacks.\n\n### `Pacing violation` warnings\n\nThe toolkit enforces a 0.35s minimum interval between historical-data calls (see `req_historical_safe` in `ib_client.py`). If you still hit pacing limits, you're likely running another tool concurrently. Stop everything, wait 60 seconds, retry.\n\n---\n\n## Getting Gateway logs\n\nWhen opening a bug report or a support ticket, Gateway logs make all the difference.\n\n**Location:**\n\n- macOS: `~/Jts/<gateway-version>/`, files named `api.<date>.log` and `ibgateway.<date>.log`\n- Linux: `~/Jts/<gateway-version>/`\n- Windows: `C:\\Jts\\<gateway-version>\\`\n\n**What to grep for:**\n\n```bash\ngrep -E \"ERROR|WARN|10091|^Error 200\" ~/Jts/*/api.*.log | tail -50\n```\n\nThe interesting errors are usually the last 50 lines.\n\n**Enable verbose API logging** (helpful when contracts fail to resolve):\n\n`Configure → Settings → API → Settings → Logging Level → Detail`. Restart Gateway.\n\n---\n\n## IBKR-side configuration checklist\n\nIf something feels broken in a way none of the above explains, walk this list:\n\n- [ ] Gateway is logged in (not paused at a 2FA / \"agreement updated\" screen).\n- [ ] `Configure → Settings → API → Settings → Enable ActiveX and Socket Clients` ✅\n- [ ] `Configure → Settings → API → Settings → Read-Only API` ✅ (matches our convention)\n- [ ] `Configure → Settings → API → Settings → Socket port` = value in your `.env`\n- [ ] `Configure → Settings → API → Settings → Trusted IPs` includes `127.0.0.1`\n- [ ] **Restart Gateway** after changing any API setting (settings are not live-applied).\n- [ ] Account Management → Market Data Subscriptions includes the exchanges you query.\n- [ ] No other client (a second Python script, an old TWS instance, another bot) is using a clientId in the toolkit's range (`base+7` … `base+16`).\n\nIf everything on this list is green and the toolkit still fails: open an issue with the failing command, the stderr output, and a redacted Gateway log line. Most repeat issues come back to one of the items above.\n\nFile v0.2.6:references/wheel_strategy.md\n\n# The Wheel Strategy — Full Guide\n\nThe Wheel is a four-stage premium-selling cycle that turns a willingness to own a stock into a recurring income stream. `wheel_tracker.py` in this toolkit tracks each cycle from entry to exit.\n\n## Table of Contents\n\n- [What is the Wheel?](#what-is-the-wheel)\n- [The four stages](#the-four-stages)\n- [When the wheel works (and when it fails)](#when-the-wheel-works-and-when-it-fails)\n- [Strike selection](#strike-selection)\n- [DTE selection](#dte-selection)\n- [Roll vs. accept assignment](#roll-vs-accept-assignment-decision-tree)\n- [Cost basis math](#cost-basis-math)\n- [Position sizing](#position-sizing)\n- [How `wheel_tracker.py` helps](#how-wheel_trackerpy-helps)\n- [Pitfalls](#pitfalls)\n\n---\n\n## What is the Wheel?\n\nPick a stock you genuinely want to own. Sell a cash-secured put. Collect premium. If the put expires worthless, sell another. If it gets assigned, take the shares and sell covered calls against them. If the calls get assigned, take the gain plus all the premium and start the next cycle.\n\n```\n   ┌────────────────────────────────────────────────────────┐\n   │                                                        │\n   ▼                                                        │\n[Stage 1] Sell cash-secured put                            │\n   │                                                        │\n   │ ─ Put expires OTM ──► collect premium, back to Stage 1│\n   │                                                        │\n   ▼ Put expires ITM                                        │\n[Stage 2] Assigned 100 shares at the put strike            │\n   │                                                        │\n   ▼                                                        │\n[Stage 3] Sell covered call against the shares             │\n   │                                                        │\n   │ ─ Call expires OTM ──► collect premium, repeat Stage 3│\n   │                                                        │\n   ▼ Call expires ITM                                       │\n[Stage 4] Called away — shares sold at the call strike     │\n   │                                                        │\n   └────────────────────────────────────────────────────────┘\n   Cycle complete: total P&L = stock P&L + all premium collected\n```\n\nThe Wheel pays the trader to wait — first to enter, then to exit.\n\n---\n\n## The four stages\n\n| Stage | What's happening | Greeks profile | Risk |\n|---|---|---|---|\n| **1. Short Put** | Selling premium, hoping put expires worthless. | Long delta · short gamma · short vega · long theta. | Stock drops below strike → assignment at a paper loss. |\n| **2. Assigned** | Hold 100 shares per contract at strike − total_premium_collected effective cost. | Long delta (100 per contract) · no option Greeks. | Stock keeps falling — full stock-ownership risk. |\n| **3. Covered Call** | Selling premium against the stock you now own. | Long delta (capped) · short gamma · short vega · long theta. | Stock rips above strike → called away, capped upside. |\n| **4. Called Away** | Shares sold at call_strike. Cycle ends. | Cash. | Re-entry timing — IV may be low when you want back in. |\n\n---\n\n## When the wheel works (and when it fails)\n\n### Works\n\n- **Range-bound, mildly bullish quality names** (think large-cap dividend payers, ETFs you'd hold anyway).\n- **High but not extreme IV** — enough premium to be worth the risk, not so much that it signals a regime change.\n- **Sufficient capital** to take assignment without forced liquidation.\n- **Patience**: the wheel is slow. 1–2% per cycle is typical.\n\n### Fails\n\n- **Falling knives** — a stock that drops 30% leaves you with a stock position so far underwater that covered calls can't pay you enough above your cost basis to be worth selling. *You can't wheel out of a bad pick.*\n- **Earnings dates inside the cycle** — IV crush hands you a paper win but also volatile assignment risk. `earnings_calendar.py` will flag these.\n- **Acquisitions / spin-offs** — corporate actions break the option contracts and can leave you stuck.\n- **Concentration** — wheeling one ticker with 50% of capital. One bad event ruins the entire portfolio.\n\n**Rule:** never sell a put on a stock you wouldn't be happy to own for two years.\n\n---\n\n## Strike selection\n\nThe dominant convention is **delta-based strike selection**:\n\n| Delta band | Probability of assignment | Premium | Use when |\n|---|---|---|---|\n| 0.15 – 0.20 | ~15–20% | low | You really don't want assignment; just want income. |\n| **0.20 – 0.30** | **~20–30%** | **balanced** | **Default wheel band.** Good income, fair assignment probability. |\n| 0.30 – 0.40 | ~30–40% | high | Want assignment; using the put as a buy order. |\n| > 0.40 | ATM-ish | highest | Aggressive; effectively buying the stock with a discount. |\n\n**Why delta and not \"% OTM\"?** Delta normalizes for IV. A 5%-OTM put on a low-IV stock is far less risky than a 5%-OTM put on a high-IV stock; their deltas reflect that.\n\n**Strike workflow with the toolkit:**\n\n```bash\npython scripts/options_chain.py SYM --dte-min 25 --dte-max 45\n# read the chain; find the put whose delta is closest to your target band\n```\n\n`options_chain.py` returns per-strike delta, so you don't have to estimate.\n\n---\n\n## DTE selection\n\n| DTE band | Theta/day | Gamma risk | Roll flexibility | Notes |\n|---|---|---|---|---|\n| 0–14 days | high (last-week curve) | severe | low | Gamma is the enemy; one earnings gap is disaster. |\n| **30–45 days** | **good** | **manageable** | **good** | **Sweet spot for most wheelers.** |\n| 60–90 days | moderate | low | great | Tied up longer; useful if VIX is elevated and you want to lock in vol. |\n| > 90 days | low | minimal | maximum | Effectively a synthetic long position; rare for wheel. |\n\n**Default:** 30–45 DTE puts, roll/close at 21 DTE or 50% max profit, whichever comes first. This is the tastytrade-popularized convention; it concentrates theta in the steepest part of the curve while leaving room to react.\n\n---\n\n## Roll vs. accept assignment (decision tree)\n\nWhen a short put is ITM and approaching expiry:\n\n```\nShort put ITM at 5 DTE?\n│\n├── Q1: Is the thesis on the stock still intact?\n│   │\n│   ├── No  → Close the position. Take the loss. Move on.\n│   │         (Wheeling a broken story is throwing good money after bad.)\n│   │\n│   └── Yes → continue to Q2\n│\n├── Q2: Can I roll for a net credit, to a later date, at the same or lower strike?\n│   │\n│   ├── Yes → Roll. Document the new strike/DTE/credit in wheel_tracker.\n│   │         Typical: roll 30 days out, same strike, collect more premium.\n│   │\n│   └── No  → continue to Q3\n│\n├── Q3: Am I willing to own 100 shares at this strike given my current portfolio?\n│   │\n│   ├── Yes → Accept assignment. Begin Stage 2. Switch to covered calls.\n│   │\n│   └── No  → Close the put at market. Move on. Don't roll defensively into a worse position.\n```\n\n**Rolling rules:**\n\n- **Never roll for a debit.** If you can't collect more premium, the trade is signaling that you should close.\n- **Never roll inverted** (strike above current price for a put). It feels like a hedge but it locks in a loss with extra obligation.\n- **Cap rolls at 2.** If a position has been rolled twice and is still in trouble, the thesis is wrong.\n\n---\n\n## Cost basis math\n\nThis is what new wheelers miss: your effective cost is **not** the strike, it's the strike minus all premium ever collected on that ticker in this cycle.\n\n```\nEffective cost basis = strike - Σ (all puts and calls collected in this cycle)\n```\n\n**Example:**\n\n| Trade | Premium |\n|---|---|\n| Sold 30 DTE put, strike 100 | +$1.50 |\n| Rolled out 30 days, strike 100 | +$0.80 |\n| Assigned at 100 | — |\n| Sold 30 DTE covered call at 105 | +$1.20 |\n| Called away at 105 | — |\n\n```\nEffective cost basis = 100 - 1.50 - 0.80 - 1.20 = 96.50\nFinal P&L per share = 105 (call away) - 96.50 = +8.50  ≈ +8.8%\n```\n\n`wheel_tracker.py summary` does this math automatically per cycle.\n\n---\n\n## Position sizing\n\nHard rules:\n\n- **No single wheel > 10% of account.** A single position blowing up shouldn't be portfolio-defining.\n- **No single sector > 30%.** Energy and tech can correlate to near-1 in a sell-off.\n- **Total wheel margin usage < 50% of buying power.** Leaves room to respond to assignments without forced sells.\n\nIf you're full on wheels, the answer to \"should I wheel this great new ticker?\" is \"close an existing one first.\"\n\n---\n\n## How `wheel_tracker.py` helps\n\nThe script reads `~/.ibkr_wheel_journal.json` (your manual entries) and cross-references live positions from IBKR to figure out which stage each wheel is in.\n\n**Add a new wheel entry:**\n\n```bash\npython scripts/wheel_tracker.py add-entry SYM STRIKE EXPIRY PREMIUM\n# e.g.\npython scripts/wheel_tracker.py add-entry MU 100 2026-06-19 1.45\n```\n\n**Get a summary:**\n\n```bash\npython scripts/wheel_tracker.py summary\n```\n\nOutput (one row per active wheel):\n\n```json\n[\n  {\n    \"symbol\": \"MU\",\n    \"stage\": \"short_put\",\n    \"current_strike\": 100,\n    \"current_dte\": 32,\n    \"premium_collected\": 1.45,\n    \"effective_cost_basis\": 98.55,\n    \"days_in_cycle\": 8,\n    \"annualized_yield_pct\": 16.5\n  }\n]\n```\n\nUse this weekly to spot wheels that are stuck (no progress in 60+ days) or that have under-collected premium relative to the time they've consumed.\n\n---\n\n## Pitfalls\n\n| Pitfall | Why it hurts | Fix |\n|---|---|---|\n| Wheeling into earnings without realizing | IV crush + gap risk on assignment | `earnings_calendar.py` before every new put |\n| Picking high-IV junk for premium | The premium is high because the stock is broken | Quality > yield. Filter by fundamentals first. |\n| Rolling defensively forever | You compound a bad position | Cap rolls at 2; then close or accept. |\n| Selling covered calls below cost basis | Locks in a loss when called away | Always set the call strike ≥ effective cost basis. |\n| No exit plan at 50% max profit | Letting winners turn into losers | Close shorts at 50% of max profit on rolls of comparable strikes/DTEs. |\n| Concentration in one ticker | One earnings miss = catastrophic | Position-size limits above. |\n\n---\n\nThe wheel is a slow, mechanical strategy. Done badly it's a way to compound mistakes. Done well it's a 10–15% annualized strategy with defined exits at every stage. Use the tools, log every cycle, and let the math be the decider — not the urge to \"make back\" a losing leg.\n\nFile v0.2.6:CHANGELOG.md\n\n# Changelog\n\nAll notable changes to this project will be documented in this file.\n\nThe format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),\nand this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).\n\n## [Unreleased]\n\n## [0.2.6] - 2026-05-15\n\n### Added\n- **`status_dashboard.py`** — at-a-glance snapshot of the entire IBKR\n  Options Assistant state with three renderings from the same data:\n    - `--output ansi` (default): colored, aligned ASCII for terminals\n    - `--output telegram`: emoji-driven Markdown that survives non-monospace\n      fonts (chat clients, mobile)\n    - `--output json`: structured data for agents to recompose freely\n  Quick mode is one IBKR session (~5s) covering portfolio Greeks,\n  positions with ITM flags, this-week expiries, and Wheel stages.\n  `--full` adds IV environment per held symbol and recent realized P&L.\n  ClientId offset 20.\n- README \"At a glance\" section in EN + 中文 with example output.\n- SKILL.md workflow entry: \"What's my account state right now?\" / \"Status\n  update\" tells the agent to use `status_dashboard.py` for one-glance\n  account snapshots.\n\n### Why\nA user-facing snapshot that works equally well in three contexts:\nsitting at the terminal, chatting in Telegram with Atlas, or any other\nagent that wants the data raw. Single source of truth (one builder + three\nrenderers) avoids the maintenance overhead of separate scripts.\n\n## [0.2.5] - 2026-05-14\n\n### Fixed\n- **ITM/OTM judgement bug (root cause was schema, not math).** Earlier\n  versions of `portfolio_positions.py` and `options_daily.py` exposed the\n  *option contract's* mid price as `market_price` at the top of every OPT\n  entry while burying the *underlying spot* inside `greeks.und_price`.\n  Agents reading the JSON compared the two top-level numbers (`market_price`\n  vs `strike`) and reported the wrong ITM/OTM status. Each OPT entry now\n  emits `option_price` (explicit rename of the contract price), `und_price`,\n  `itm`, and `moneyness` (= `und_price - strike`) at the top level.\n  `options_daily.py` propagates the same fields into the `expiry_warning`\n  payload. When Greeks are unavailable, `und_price` and `itm` are `null`\n  (never silently `false`).\n- **Short-put `max_loss` formula** in `options_daily.py`. Was\n  `-strike * 100`; correct is `-(strike - premium) * 100` (the credit\n  received offsets the assignment-cost loss). Previously over-reported the\n  worst case by the full premium amount on every short-put recommendation.\n- **`options_chain.py` data freshness lie.** `data_type` was hard-coded to\n  `\"realtime\"` regardless of `IBKR_MARKET_DATA_TYPE` or whether IBKR\n  actually upgraded the feed. Now reflects the ticker's real\n  `marketDataType` (`realtime` / `frozen` / `delayed` / `delayed-frozen`).\n- **Double-counting between session and Flex fills** in `cost_basis.py` and\n  `pnl_analytics.py`. When a Flex CSV overlapped the IBKR session's ~2-day\n  window, the same fill landed in both lists, doubling premiums collected\n  and realized P&L. Both scripts now deduplicate by\n  `(symbol, right, strike, expiration, side, qty, price, trade_date)` with\n  a per-tuple occurrence index, so legitimate same-day partial fills at the\n  same price (TWS splits market orders across exchanges) are preserved.\n- **`options_analyzer.py` falsy bugs**: `not all(prices)` rejected legal\n  `price=0.0` (far-OTM bids) — switched to `is None` check. `type` field\n  no longer claims `\"credit\"` when `all_priced=False`. `probability_of_profit`\n  renamed to `pop_approx_first_leg` on multi-leg strategies to flag that\n  it's a single-leg heuristic.\n- **`wheel_tracker._current_stage`** now returns `\"closed\"` for the\n  no-positions-but-has-journal case (was `\"called_away\"`, which is\n  unverifiable from positions alone).\n- **`trade.py` RTH auto-detection** — documented the early-close edge case\n  (Black Friday / Christmas Eve / day before July 4 close at 13:00 ET).\n  Auto-detection still uses the regular 09:30–16:00 window; use\n  `--outside-rth` explicitly on those ~3 days/year.\n\n### Why\nAtlas (the consuming agent) reported reading wrong ITM/OTM status from\nposition output. Root-cause analysis showed it wasn't a math bug — the\nscript never told consumers *where to find* the underlying spot price.\nFixing this with schema (lift `und_price` to the top, add an explicit\n`itm` boolean) prevents the next agent from making the same inference.\n\n## [0.2.4] - 2026-05-14\n\n### Changed\n- **Renamed** the project from `ibkr-trader-toolkit` to `ibkr-options-assistant`.\n  - GitHub repo renamed (old URL 301-redirects to the new one).\n  - `SKILL.md` frontmatter `name:` updated; description, scripts, and behavior unchanged.\n  - README titles and all references updated.\n\n### Why\nThe old name overlapped with order-execution / bot-style IBKR skills and\nburied the toolkit's actual positioning. This is an options-analysis\nassistant designed to be driven by Claude (or another AI agent), not a\ntrading bot — the new name makes that distinction visible in search\nresults and skill catalogs.\n\n## [0.2.3] - 2026-05-14\n\n### Docs\n- New \"Security Model\" section in `README.md` and `README.zh-CN.md` covering\n  what the toolkit can do, the two trust boundaries the user controls\n  (Gateway login + `trade.py` dual gates), how output data should be\n  treated, and a recommended setup. No code changes.\n\n### Why\nClawScan ASI03 (Identity and Privilege Abuse) and ASI06 (Memory and\nContext Poisoning) flag the toolkit's intrinsic broker-account access\nand JSON output as risk surface. Both are design-intent rather than\ndefects — ClawScan itself notes \"purpose-aligned\" on ASI06. Documenting\nthe security model explicitly lets users and reviewers see that the\ntrust boundaries are deliberate and where they can be tightened\nfurther. The `clawscan-note` published alongside this release covers\nthe same ground for automated review.\n\n## [0.2.2] - 2026-05-14\n\n### Security\n- `alerts_monitor.py` no longer uses `eval()` to evaluate rule conditions.\n  Conditions are now parsed with `ast.parse(mode=\"eval\")` and walked by a\n  small interpreter that only accepts: the documented variables\n  (`price`, `delta`, `iv`, `dte`, `unrealized_pnl`), numeric literals,\n  comparisons (`< <= > >= == !=`), boolean operators (`and / or / not`),\n  arithmetic (`+ - * /`, unary `-`), and the calls `abs / min / max /\n  round`. Attribute access, indexing, other function calls, lambdas, and\n  comprehensions are rejected at parse time, eliminating the\n  ClawScan ASI05 \"unrevised eval()\" finding.\n\n### Why\nClawScan flagged the eval-based path as high-risk even with restricted\nglobals, because eval-based alert rules are materially riskier than a\nrestricted parser, especially for a script documented as cron-friendly.\nThe new evaluator preserves every condition shown in the docs while\nremoving the attack surface.\n\n## [0.2.1] - 2026-05-14\n\n### Added\n- `trade.py` now supports extended-hours order routing. By default, the\n  script auto-detects whether the current time is inside US/Eastern Regular\n  Trading Hours (09:30–16:00 weekdays) and sets `outsideRth=True` on the\n  order when placed off-hours. Two explicit flags override this:\n    - `--outside-rth` — force outsideRth=True (pre/post-market, overnight)\n    - `--rth-only` — force outsideRth=False (RTH-only routing)\n  Both flags work for `stock`, `option`, `combo`, `future`, and `forex`\n  subcommands.\n- Order payload JSON now includes an `outside_rth` field, and the dry-run\n  preview shows the resolved value plus the reason (auto-detection or\n  explicit flag).\n\n### Why\nWithout `outsideRth=True`, orders submitted off-hours sit on IBKR's gateway\nuntil 09:30 ET (Warning 399). With it, orders can route to ECNs during the\npre/post-market sessions (04:00–09:30 and 16:00–20:00 ET) and to overnight\nsessions where supported. Auto-detection is the default so users don't\nhave to remember the flag in normal use.\n\n## [0.2.0] - 2026-05-14\n\n### Added\n- **`cost_basis.py`** — premium-adjusted effective cost basis for wheel positions\n  (subtracts collected premium from broker avg cost). Discovers held stocks via\n  `--portfolio-file` or accepts symbols positionally. Pulls option fills from\n  `ib.fills()` and optional `~/.ibkr_flex/*.csv`. ClientId offset 17.\n- **`concentration.py`** — HHI, top-3/top-5 concentration %, sector breakdown\n  with built-in ~70-ticker GICS map, plus actionable warnings (top-3 > 30%,\n  any sector > 20%, single position > 20%). Reuses `portfolio_positions` fetch.\n  ClientId offset 18.\n- **`flex_import.py`** — parses both CSV and XML IBKR Flex Statement files via\n  `ibflex` library (or plain `csv` fallback). Normalizes trades into a unified\n  JSON schema consumable by `pnl_analytics.py` / `cost_basis.py`. Supports\n  `--since` and `--symbol` filters.\n- **`trade.py`** — opt-in order execution for stocks, single-leg options,\n  multi-leg combos (BAG/ComboLeg), futures, and FX. **Dual-gate safety**:\n  refuses to place orders unless both `IBKR_TRADING_ENABLED=1` is set AND\n  `--confirm-trade` is passed. Subcommands: `stock`, `option`, `combo`,\n  `future`, `forex`, `cancel`, `list-orders`. Guardrails: notional > $100k,\n  options qty > 1000, stock qty > 10000 require `--allow-large`; blocklist\n  via `IBKR_TRADING_BLOCKLIST`. ClientId offset 19; the only script that uses\n  `readonly=False`.\n- **`references/trading.md`** — bilingual (EN + 中文) documentation of trading\n  setup, both safety gates, the Gateway \"Read-Only API\" toggle, and full\n  examples for each subcommand.\n- **`references/options_book_summary.md`** — 500-line operational-rules\n  reference distilled from McMillan / Overby / Natenberg / Sinclair. 13\n  sections covering IV environment playbook, strike/DTE selection, adjustment\n  decision trees, position sizing, skew interpretation, earnings IV crush,\n  volatility estimators, Greeks-vs-Greeks math, common mistakes.\n- **`README.zh-CN.md`** — full Chinese translation of the README. Both\n  versions cross-link from the top.\n- 5th SKILL.md workflow: \"Should I roll position X?\" — covers portfolio\n  confirm, roll candidate chain survey, and decision tree pointer.\n- `Trading Mode (Optional)` section in README pointing to `references/trading.md`.\n- `CHANGELOG.md` (this file) at repo root.\n- Module-level constant `IBKR_REALIZED_PNL_SENTINEL_THRESHOLD` in\n  `pnl_analytics.py` documenting the IBKR sentinel-value cutoff.\n\n### Changed\n- **All scripts normalized to English-first.** Module docstrings, `log()`\n  strings, inline comments, and argparse help text translated from Chinese\n  to English. The Chinese strategy display names in `options_analyzer.py`'s\n  `STRATEGIES[*].name_cn` JSON output keys are intentionally preserved.\n- `risk_simulator.py` concentration warning threshold lowered from 50% to 30% to\n  match the SKILL.md workflow documentation.\n- `wheel_tracker.py` annualized-return math no longer multiplies capital by the\n  number of journal entries (rolls reuse capital, they don't multiply it). Now\n  uses the latest entry's strike × 100 as the open-leg capital.\n- README's `IBKR_MARKET_DATA_TYPE` default documented as `3` in both the Quick\n  Start example and the Configuration table, matching `.env.example`.\n- README API setup step clarified: \"Leave 'Allow connections from localhost\n  only' checked — it's safer and the toolkit doesn't need it disabled.\"\n- GitHub repo description updated to remove the stale \"Streamlit dashboard\"\n  mention.\n- `references/wheel_strategy.md` examples now use the actual positional\n  subcommand syntax (`wheel_tracker.py add-entry ...` and\n  `wheel_tracker.py summary`) instead of the non-existent `--add-entry` flag.\n- `requirements.txt` adds `ibflex>=0.16` and upper bounds on `pandas` (<3) and\n  `numpy` (<3).\n- SKILL.md Operating Constraints table updated: \"Smart data type\" replaces\n  the stale \"Real-time by default\" claim that contradicted the `=3` default.\n\n## [0.1.4] - 2026-05-14\n\n### Added\n- Operations Guide section in README: second-user setup to keep Gateway alive\n  when using the mobile app, launchd/systemd auto-restart recipes, and triage\n  for the `ushmds` (US historical-data farm) outage.\n\n## [0.1.3] - 2026-05-14\n\n### Added\n- Comprehensive IBKR market data subscription guide in README: per-feature\n  subscription requirements, recommended bundles, commission-waiver math.\n\n## [0.1.2] - 2026-05-14\n\n### Changed\n- Default `IBKR_MARKET_DATA_TYPE` is now `3` (delayed-smart). IBKR auto-upgrades\n  to realtime for subscribed instruments and falls back to delayed otherwise,\n  avoiding Error 10089 (\"subscription required\") on day one.\n\n## [0.1.1] - 2026-05-13\n\n### Changed\n- SKILL.md rewritten for readability on the ClawHub web view.\n\n### Removed\n- Streamlit dashboard (out of scope for a Claude Code skill; the toolkit emits\n  JSON for the agent to reason about, not a UI to look at).\n\n### Fixed\n- `earnings_calendar.py` now uses the Nasdaq public API instead of the\n  deprecated yahoo-earnings-calendar source.\n- `options_analyzer.py` no longer crashes when a strategy's max-loss is\n  unlimited (e.g. naked calls).\n\n## [0.1.0] - 2026-05-12\n\n### Added\n- Initial release of IBKR Trader Toolkit.\n- 13 Python scripts covering market quotes, option chains, portfolio Greeks,\n  McMillan/Overby strategy recommender, P&L analytics, risk simulator, wheel\n  tracker, earnings calendar, technical indicators, and YAML-driven alerts.\n- Shared `ib_client.py` connection layer with readonly safety, per-script\n  clientId offsets, and historical-data pacing.\n- SKILL.md so Claude Code can use the toolkit directly.\n- Reference docs: full strategy library, Greeks primer, wheel strategy guide,\n  troubleshooting.\n\n[Unreleased]: https://github.com/AlexLiu0130/ibkr-options-assistant/compare/v0.2.6...HEAD\n[0.2.6]: https://github.com/AlexLiu0130/ibkr-options-assistant/releases/tag/v0.2.6\n[0.2.5]: https://github.com/AlexLiu0130/ibkr-options-assistant/releases/tag/v0.2.5\n[0.2.4]: https://github.com/AlexLiu0130/ibkr-options-assistant/releases/tag/v0.2.4\n[0.2.3]: https://github.com/AlexLiu0130/ibkr-options-assistant/releases/tag/v0.2.3\n[0.2.2]: https://github.com/AlexLiu0130/ibkr-options-assistant/releases/tag/v0.2.2\n[0.2.1]: https://github.com/AlexLiu0130/ibkr-options-assistant/releases/tag/v0.2.1\n[0.2.0]: https://github.com/AlexLiu0130/ibkr-options-assistant/releases/tag/v0.2.0\n[0.1.4]: https://github.com/AlexLiu0130/ibkr-options-assistant/releases/tag/v0.1.4\n[0.1.3]: https://github.com/AlexLiu0130/ibkr-options-assistant/releases/tag/v0.1.3\n[0.1.2]: https://github.com/AlexLiu0130/ibkr-options-assistant/releases/tag/v0.1.2\n[0.1.1]: https://github.com/AlexLiu0130/ibkr-options-assistant/releases/tag/v0.1.1\n[0.1.0]: https://github.com/AlexLiu0130/ibkr-options-assistant/releases/tag/v0.1.0\n\nFile v0.2.6:README.zh-CN.md\n\n# IBKR 期权助手 (IBKR Options Assistant)\n\n> 一套完整的 Interactive Brokers 期权与股票交易助手——实时 Greeks、McMillan/Overby 策略库、盈亏分析、Wheel 跟踪、财报预警、风险模拟。设计成可直接作为 Skill 接入 Claude Code。\n\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n[![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)\n[![IBKR](https://img.shields.io/badge/broker-Interactive%20Brokers-red.svg)](https://www.interactivebrokers.com/)\n\n> [English README](README.md)\n\n<!-- screenshot: hero -->\n\n---\n\n## 目录\n\n- [功能特性](#-功能特性)\n- [一眼看全 — status_dashboard.py](#-一眼看全--status_dashboardpy)\n- [环境要求](#-环境要求)\n- [IBKR 行情订阅](#-ibkr-行情订阅)\n- [快速开始](#-快速开始)\n- [运维指南（双用户、自动重启）](#-运维指南)\n- [安全模型](#-安全模型)\n- [Claude Code 集成](#-claude-code-集成)\n- [命令参考](#-命令参考)\n- [配置](#-配置)\n- [故障排查](#-故障排查)\n- [进阶](#-进阶)\n- [贡献](#-贡献)\n- [许可证](#-许可证)\n- [免责声明](#-免责声明)\n\n---\n\n## ✨ 功能特性\n\n13 个专注的 Python 脚本。每个脚本都输出 JSON，便于 Claude（或其他 Agent）做推理；工具本身不会给出买卖信号。\n\n**数据与行情**\n- `market_quote.py` — 股票、ETF、期权的实时 bid/ask/last/IV/volume。\n- `contracts.py` — 通用合约解析器（`SPY`、`AAPL 2026-06-19 200 C` 等）。\n- `technical_indicators.py` — RSI、MA(20/50/200)、Bollinger、ATR，附文字摘要。\n\n**期权分析**\n- `options_chain.py` — 含 Greeks、OI、volume、IV 的完整期权链（按到期日组织）。\n- `options_analyzer.py` — McMillan/Overby 策略推荐（4 层共 20+ 策略，IV 环境感知）。\n- `options_daily.py` — 收盘后期权日报：预警、IV 环境、对应持仓的具体建议。\n\n**组合与盈亏**\n- `portfolio_positions.py` — 实时持仓 + 每条腿和组合级 Greeks。\n- `pnl_analytics.py` — 已实现盈亏、胜率、最佳/最差交易（来自 `ib.executions` + 可选 Flex CSV）。\n- `risk_simulator.py` — \"加上这笔交易会怎样？\"——执行前预览 Greeks 变化。\n\n**策略自动化**\n- `wheel_tracker.py` — 跟踪 wheel 周期（short put → 指派 → covered call → called away），含累计权利金与年化收益率。\n- `earnings_calendar.py` — 组合标的的下一次财报日期，标记跨越财报的期权仓位。\n- `alerts_monitor.py` — 基于 YAML 的阈值告警（delta、IV 分位、DTE、P&L），适合 cron 调度。\n\n**连接层**\n- `ib_client.py` — 共享的 IB Gateway 连接，自带 readonly 安全、按脚本 clientId 偏移、历史数据节流。\n\n---\n\n## 📺 一眼看全 — `status_dashboard.py`\n\n一个命令、三种渲染，同一份数据。可以当终端快速健康检查，可以接 Telegram bot，也可以喂 JSON 给 agent。\n\n```bash\nstatus_dashboard.py                     # 终端彩色 ANSI\nstatus_dashboard.py --output telegram   # Telegram 友好的 Markdown\nstatus_dashboard.py --output json       # 给 agent 用的结构化数据\nstatus_dashboard.py --full              # 多跑 IV 环境 + 近期盈亏\n```\n\nTelegram 渲染特意用 emoji 驱动，不依赖等宽对齐：\n\n```\n🤖 IBKR Options Assistant\n🟢 2026-05-15 09:32 ET (RTH)\n\n组合 Greeks\nΔ +1240 · Γ -45 · Vega -380 · Θ +210\n🟢 未实现 $+2,340.50\n\n持仓 (1 stk + 2 opt)\n📊 SPY +100 STK 🟢 $+1,240\n🟢 MU -1P 110 05/23 Δ-32 🟢 $+220\n🔴 AAPL -2P 200 06/19 Δ-65 🔴 $-380\n\n本周到期 (≤7d)\n⏰ MU -P 110 DTE 5 🟢\n\nWheel 状态\n🟡 AAPL short_put · 累计 $1,450 · 年化 18.3%\n🔵 SPY covered_call · 累计 $820 · 年化 12.7%\n```\n\nANSI 输出在终端里带彩色，JSON 输出方便 agent 自由组织回复。\n\n---\n\n## 📋 环境要求\n\n| 要求 | 备注 |\n|---|---|\n| **Python** | 3.10 或更高 |\n| **IBKR 账户** | Live 或 paper 均可。Paper 账户用于学习已足够。 |\n| **IB Gateway** | 从 [IBKR 官网](https://www.interactivebrokers.com/en/trading/ibgateway-stable.php) 免费下载。TWS 也行（端口不同）。 |\n| **行情订阅** | 见[下一节](#-ibkr-行情订阅) —— 实时报价与 Greeks 需要订阅。延迟数据免费。 |\n| **操作系统** | macOS / Linux / Windows。所有脚本都是纯 Python。 |\n\n> **为什么用 IB Gateway，不用 TWS？** Gateway 是无界面的，内存占用低，是程序化访问的首选。TWS 也可以——把 `IBKR_PORT` 设为 `7497`（paper）或 `7496`（live）。\n\n---\n\n## 💳 IBKR 行情订阅\n\n工具的价值在很大程度上取决于 **IBKR 给你推送什么数据**。订阅是按账户配置的：Client Portal → Settings → User Settings → Market Data Subscriptions。\n\n### 各功能对订阅的需求\n\n| 功能 | 所需订阅 | 延迟数据可用？ |\n|---|---|---|\n| 股票/ETF 价格 (`market_quote.py`) | 无 —— 实时需要 Snapshot 套餐，否则使用延迟 | ✅ 可用 |\n| 组合持仓与 P&L (`portfolio_positions.py`、`pnl_analytics.py`) | 无 —— 账户数据始终可用 | ✅ 可用 |\n| 期权链 bid/ask (`options_chai\n\nArchive v0.2.5: 30 files, 135906 bytes\n\nFiles: CHANGELOG.md (13505b), LICENSE (1068b), README.md (28437b), README.zh-CN.md (24403b), references/greeks_primer.md (6944b), references/options_book_summary.md (34351b), references/strategies.md (12384b), references/trading.md (13720b), references/troubleshooting.md (9693b), references/wheel_strategy.md (10838b), requirements.txt (104b), scripts/alerts_monitor.py (10503b), scripts/concentration.py (8904b), scripts/contracts.py (13074b), scripts/cost_basis.py (12893b), scripts/earnings_calendar.py (7536b), scripts/flex_import.py (11588b), scripts/ib_client.py (4059b), scripts/market_quote.py (3503b), scripts/options_analyzer.py (29555b), scripts/options_chain.py (9735b), scripts/options_daily.py (13481b), scripts/pnl_analytics.py (11150b), scripts/portfolio_positions.py (6601b), scripts/risk_simulator.py (7813b), scripts/technical_indicators.py (6054b), scripts/trade.py (35987b), scripts/wheel_tracker.py (7071b), SKILL.md (7147b), _meta.json (141b)\n\nArchive v0.2.4: 30 files, 131980 bytes\n\nFiles: CHANGELOG.md (10428b), LICENSE (1068b), README.md (28437b), README.zh-CN.md (24403b), references/greeks_primer.md (6944b), references/options_book_summary.md (34351b), references/strategies.md (12384b), references/trading.md (13720b), references/troubleshooting.md (9693b), references/wheel_strategy.md (10838b), requirements.txt (104b), scripts/alerts_monitor.py (10503b), scripts/concentration.py (8904b), scripts/contracts.py (13074b), scripts/cost_basis.py (10531b), scripts/earnings_calendar.py (7536b), scripts/flex_import.py (11588b), scripts/ib_client.py (4059b), scripts/market_quote.py (3503b), scripts/options_analyzer.py (29515b), scripts/options_chain.py (9427b), scripts/options_daily.py (12351b), scripts/pnl_analytics.py (9185b), scripts/portfolio_positions.py (5600b), scripts/risk_simulator.py (7813b), scripts/technical_indicators.py (6054b), scripts/trade.py (35695b), scripts/wheel_tracker.py (6727b), SKILL.md (7152b), _meta.json (141b)","readmeExcerpt":"Skill: Ibkr Options Assistant Owner: alexliu0130 Summary: Interactive Brokers options & stock trading assistant. Provides real-time portfolio Greeks, option chain analysis, McMillan/Overby strategy recommendations,... Tags: claude-code:0.2.4, greeks:0.2.4, ibkr:0.2.4, interactive-brokers:0.2.4, latest:0.2.6, options:0.2.4, portfolio:0.2.4, quantitative-finance:0.2.4, trading:0.2.4, trading-assistant:0.2.4, wheel-stra","codeSnippets":[],"executableExamples":[{"language":"bash","snippet":"status_dashboard.py --output telegram   # in chat-style channels\nstatus_dashboard.py --output json       # parse and recompose freely\nstatus_dashboard.py                     # rich ANSI for terminals"},{"language":"bash","snippet":"risk_simulator.py --add \"SYM STRIKE EXPIRY R ACTION QTY\""},{"language":"bash","snippet":"wheel_tracker.py summary"},{"language":"bash","snippet":"status_dashboard.py                     # rich ANSI for terminals\nstatus_dashboard.py --output telegram   # Telegram-friendly markdown\nstatus_dashboard.py --output json       # structured for agents\nstatus_dashboard.py --full              # also fetch IV env + recent P&L"},{"language":"text","snippet":"🤖 IBKR Options Assistant\n🟢 2026-05-15 09:32 ET (RTH)\n\n组合 Greeks\nΔ +1240 · Γ -45 · Vega -380 · Θ +210\n🟢 未实现 $+2,340.50\n\n持仓 (1 stk + 2 opt)\n📊 SPY +100 STK 🟢 $+1,240\n🟢 MU -1P 110 05/23 Δ-32 🟢 $+220\n🔴 AAPL -2P 200 06/19 Δ-65 🔴 $-380\n\n本周到期 (≤7d)\n⏰ MU -P 110 DTE 5 🟢\n\nWheel 状态\n🟡 AAPL short_put · 累计 $1,450 · 年化 18.3%\n🔵 SPY covered_call · 累计 $820 · 年化 12.7%"},{"language":"bash","snippet":"git clone https://github.com/AlexLiu0130/ibkr-options-assistant.git\ncd ibkr-options-assistant\n\npython -m venv .venv\nsource .venv/bin/activate            # Windows: .venv\\Scripts\\activate\n\npip install -r requirements.txt"}],"parameters":null,"dependencies":[],"permissions":[],"extractedFiles":[{"path":"SKILL.md","content":"---\nname: ibkr-options-assistant\ndescription: Interactive Brokers options & stock trading assistant. Provides real-time portfolio Greeks, option chain analysis, McMillan/Overby strategy recommendations, P&L statistics, Wheel strategy tracking, earnings warnings, risk simulation, and a complete toolkit for options traders. Use this skill whenever the user asks about specific options trades, position risk, buy/sell recommendations, IV environment, P&L, wheel strategy, earnings impact on options, or any IBKR account data — even if they don't explicitly mention \"IBKR\". For stock price queries, always use market_quote.py instead of web search.\n---\n\n# IBKR Trader Toolkit\n\nReal-time data, options analysis, and portfolio risk for Interactive Brokers — all via JSON-emitting CLI scripts.\n\n**Core rule:** Scripts produce data. You (the model) produce the analysis.\n\n---\n\n## When to trigger this skill\n\n| User asks about... | Example phrasing |\n|---|---|\n| Stock / ETF prices | \"What's SPY at?\" \"Current AAPL price\" |\n| Option chains, Greeks, IV | \"Show me AAPL puts for next month\" |\n| Strategy ideas | \"Should I sell a put on MU?\" |\n| Position risk | \"Am I too long delta?\" |\n| P&L, win rate, history | \"How are my wheel trades doing?\" |\n| Earnings risk | \"Does ARM report before my call expires?\" |\n| Alerts / monitoring | \"Warn me if SPY IV > 80%ile\" |\n\nFire **even if the user doesn't mention IBKR** — if they're asking about *their* positions or P&L, this skill is the source of truth.\n\n**Critical:** For stock prices, always use `market_quote.py`. **Never** web-search a stock price — the web is minutes-to-hours stale.\n\n---\n\n## Workflows\n\n### \"What's my account state right now?\" / \"Status update\"\n\nFor a one-glance snapshot (positions, Greeks, ITM, this-week expiries, wheel\nstages):\n\n```bash\nstatus_dashboard.py --output telegram   # in chat-style channels\nstatus_dashboard.py --output json       # parse and recompose freely\nstatus_dashboard.py                     # rich ANSI for terminals\n```\n\nAdd `--full` to also include IV environment per held symbol and recent P&L\n(slower — extra IBKR calls). Use `--output json` when you (the agent) want\nto organize the reply yourself instead of inheriting the script's layout.\n\n### \"Should I sell a put on $SYM?\"\n\nRun these in order, then synthesize:\n\n| Step | Command | Why |\n|------|---------|-----|\n| 1 | `portfolio_positions.py` | Know existing exposure first |\n| 2 | `earnings_calendar.py SYM --days 60` | Avoid earnings inside DTE |\n| 3 | `options_analyzer.py SYM --outlook bullish --risk-profile conservative --iv-context` | Get IV environment + candidate strikes |\n| 4 | `options_chain.py SYM --dte-min 25 --dte-max 45` | Live mid prices for chosen strikes |\n\n**Your recommendation must include:** strike • delta • premium • breakeven • annualized yield • earnings/IV warnings.\n\n---\n\n### \"What's my portfolio looking like?\"\n\n| Step | Command |\n|------|---------|\n| 1 | `portfolio_positions.py` → positions + Greeks |\n| 2 | `options_daily.p"},{"path":"README.md","content":"# IBKR Options Assistant\n\n> A complete options & stock trading assistant for Interactive Brokers — real-time Greeks, McMillan/Overby strategy library, P&L analytics, Wheel tracking, earnings warnings, and risk simulation. Designed to plug straight into Claude Code as a skill.\n\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n[![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)\n[![IBKR](https://img.shields.io/badge/broker-Interactive%20Brokers-red.svg)](https://www.interactivebrokers.com/)\n\n> [中文版 README](README.zh-CN.md)\n\n<!-- screenshot: hero -->\n\n---\n\n## Table of Contents\n\n- [Features](#-features)\n- [At a glance — status_dashboard.py](#-at-a-glance--status_dashboardpy)\n- [Requirements](#-requirements)\n- [IBKR Market Data Subscriptions](#-ibkr-market-data-subscriptions)\n- [Quick Start](#-quick-start)\n- [Operations Guide (Second User, Auto-Restart)](#-operations-guide)\n- [Trading Mode (Optional)](#-trading-mode-optional)\n- [Security Model](#-security-model)\n- [Claude Code Integration](#-claude-code-integration)\n- [Command Reference](#-command-reference)\n- [Configuration](#-configuration)\n- [Troubleshooting](#-troubleshooting)\n- [Advanced](#-advanced)\n- [Contributing](#-contributing)\n- [License](#-license)\n- [Disclaimer](#-disclaimer)\n\n---\n\n## ✨ Features\n\n17 focused Python scripts. Read-only scripts output JSON so Claude (or any other agent) can reason about the data. Only `trade.py` can place orders, and only when both safety gates are explicitly opened.\n\n**Data & quotes**\n- `market_quote.py` — Real-time bid/ask/last/IV/volume for stocks, ETFs, options.\n- `contracts.py` — Universal contract resolver (`SPY`, `AAPL 2026-06-19 200 C`, etc.).\n- `technical_indicators.py` — RSI, MA(20/50/200), Bollinger, ATR with text summary.\n\n**Options analysis**\n- `options_chain.py` — Full option chain with Greeks, OI, volume, IV per expiry.\n- `options_analyzer.py` — McMillan/Overby strategy recommender (20+ strategies across 4 tiers, IV-aware).\n- `options_daily.py` — End-of-day options report: warnings, IV environment, position-specific suggestions.\n\n**Portfolio & P&L**\n- `portfolio_positions.py` — Live positions with per-leg and portfolio-level Greeks.\n- `pnl_analytics.py` — Realized P&L, win rate, best/worst trades (from `ib.executions` + optional Flex CSV).\n- `flex_import.py` — Parse IBKR Flex Statement CSV/XML history into normalized JSON.\n- `cost_basis.py` — **Premium-adjusted** effective cost basis (the wheel-trader number IBKR doesn't compute).\n- `concentration.py` — HHI, sector mix, top-N concentration risk metrics.\n- `risk_simulator.py` — \"What if I add this trade?\" Greeks delta preview before execution.\n\n**Strategy automation**\n- `wheel_tracker.py` — Track wheel cycles (short put → assignment → covered call → called away) with cumulative premium and annualized yield.\n- `earnings_calendar.py` — Next earnings date for portfolio symbols, flags optio"},{"path":"_meta.json","content":"{\n  \"ownerId\": \"kn7d98bzsjt5mkh9hb3rj3arm983z82x\",\n  \"slug\": \"ibkr-options-assistant\",\n  \"version\": \"0.2.6\",\n  \"publishedAt\": 1778834152261\n}"},{"path":"references/greeks_primer.md","content":"# Greeks Primer — Practical Interpretation\n\nThe \"Greeks\" measure how an option's price moves when something else moves. The toolkit reports them per-position and aggregates them across the portfolio in `portfolio_positions.py`. This is a working interpretation, not a textbook derivation.\n\n## The five Greeks at a glance\n\n| Greek | Measures | Per-unit move | Sign for long call | Sign for long put |\n|---|---|---|---|---|\n| **Delta** | Price sensitivity to underlying | $1 move in underlying | + (0 → +1) | − (0 → −1) |\n| **Gamma** | How fast delta changes | $1 move in underlying | + | + |\n| **Vega** | Price sensitivity to implied vol | 1 vol-point (1% IV) | + | + |\n| **Theta** | Time decay | 1 calendar day | − | − |\n| **Rho** | Sensitivity to interest rates | 1 percentage point | + | − |\n\nShort positions flip the sign of all Greeks (short call: negative delta, negative gamma, negative vega, positive theta).\n\n---\n\n## Delta — the directional one\n\n**What it tells you:** *\"If the stock moves $1, my option moves $delta.\"* For a 0.30-delta call: stock +$1 → call +$0.30 (× 100 shares = $30 per contract).\n\n**Common rules of thumb:**\n\n- Delta is also a rough probability of finishing ITM at expiry. A 0.30-delta put has ≈30% probability of expiring ITM — this is what wheel sellers use to pick strikes.\n- ATM options sit near ±0.50 delta. Deep ITM approach ±1.00. Deep OTM approach 0.\n- Stock has delta 1.00 per share (100 per round lot).\n\n**Portfolio level (`portfolio_positions.py`'s `net_delta`):**\n\n> *\"Net delta = +1,200\" means your account moves like +1,200 shares of the underlying basket.* If SPY drops $1, you lose ≈$1,200. Always reconcile this with your sizing.\n\n**When delta matters most:**\n\n- Directional trades — it's literally your directional exposure.\n- Wheel selection — pick the strike whose delta matches your acceptable assignment probability (typical wheel: 0.20–0.30 delta short put).\n\n---\n\n## Gamma — delta's accelerator\n\n**What it tells you:** *\"Delta itself isn't constant. Gamma is how much delta changes per $1 move.\"*\n\nLong options have **positive gamma**: a good thing — your delta increases when the move goes your way and decreases when it goes against you. Short options have **negative gamma**: brutal in fast moves.\n\n**Where it bites:**\n\n- **Gamma scalping** is the upside of long options.\n- **Gamma risk** on short options near expiry is the downside: a 0.20-delta short put can turn into a 0.70-delta short put overnight on an earnings gap.\n\n**Rule:** gamma is highest for **ATM options close to expiry**. If you're short premium with under a week to expiry, the gamma is screaming and a single bad day can blow through weeks of theta.\n\n---\n\n## Vega — the IV gauge\n\n**What it tells you:** *\"For every 1 percentage point increase in implied vol, the option price changes by $vega.\"* Long options are long vega; short options are short vega.\n\n**Worked example:**\n\n> If your portfolio shows `net_vega = +500`, then a 1% IV drop costs you $500. A 1% IV rise gains"},{"path":"references/options_book_summary.md","content":"# Options Book Summary — Operational Rules\n\nA lookup of operational rules distilled from four canonical options books, written as decision-ready heuristics rather than theory. Use this when reasoning about strategy selection, position sizing, adjustment, or risk.\n\n**Sources cited per rule:**\n- **(McMillan)** — Lawrence McMillan, *Options as a Strategic Investment*, 5th ed.\n- **(Overby)** — Brian Overby, *The Options Playbook* (TastyTrade lineage).\n- **(Natenberg)** — Sheldon Natenberg, *Option Volatility & Pricing*, 2nd ed.\n- **(Sinclair)** — Euan Sinclair, *Volatility Trading*, 2nd ed.\n\nThis is a **rule book**, not a textbook. For mechanics of Greeks see [`greeks_primer.md`](greeks_primer.md); for the strategy catalog see [`strategies.md`](strategies.md).\n\n---\n\n## Table of Contents\n\n1. [IV Environment Playbook](#1-iv-environment-playbook)\n2. [Strike Selection Rules](#2-strike-selection-rules)\n3. [DTE Selection Rules](#3-dte-selection-rules)\n4. [Adjustment Decision Tree](#4-adjustment-decision-tree)\n5. [Position Sizing](#5-position-sizing)\n6. [Skew Interpretation](#6-skew-interpretation)\n7. [Earnings IV Crush](#7-earnings-iv-crush)\n8. [Volatility Estimation](#8-volatility-estimation)\n9. [Greeks-vs-Greeks Relationships](#9-greeks-vs-greeks-relationships)\n10. [Common Mistakes (each book's \"don't\")](#10-common-mistakes)\n\n---\n\n## 1. IV Environment Playbook\n\nThe single most important question before opening an options trade: **is implied volatility rich or cheap?** Get this wrong and a directionally correct view still loses money.\n\n### Core rule\n\n> **Rule (McMillan):** When current IV is in the bottom 20% of its trailing-1-year range, **buy** premium (long straddle, long calendar, long single leg). When in the top 20%, **sell** premium (short strangle, iron condor, credit spread). Middle 60%: use **spreads** — debit spreads when you have directional conviction at low IV, credit spreads when you have directional conviction at high IV. (McMillan)\n\n### IV percentile vs IV rank — use both\n\n| Metric | Definition | When it helps |\n|---|---|---|\n| **IV rank** | (current IV − 52w low) / (52w high − 52w low) | Quick sense of where IV sits in its full year range |\n| **IV percentile** | % of trading days in the past year where IV was below today's | More robust to single-day spikes (e.g. earnings) |\n\n> **Rule (Sinclair):** Prefer IV percentile to IV rank in symbols with episodic volatility spikes (earnings, biotech catalysts). A single-day Vol spike inflates IV rank but barely moves IV percentile. (Sinclair)\n\n### Strategy → IV environment matrix\n\n| IV environment | Bullish | Bearish | Neutral | Volatile (expect a move) |\n|---|---|---|---|---|\n| **Low IV** (≤20%ile) | Long call, call debit spread, call ratio backspread | Long put, put debit spread | Long calendar, long butterfly | Long straddle, long strangle |\n| **Mid IV** (20–80%ile) | Bull call spread | Bear put spread | Iron condor (mild), short strangle (wide) | Long strangle |\n| **High IV** (≥80%ile) | Cash"}],"languages":[],"docsSourceLabel":"CLAWHUB","editorialOverview":"Interactive Brokers options & stock trading assistant. Provides real-time portfolio Greeks, option chain analysis, McMillan/Overby strategy recommendations,... Skill: Ibkr Options Assistant Owner: alexliu0130 Summary: Interactive Brokers options & stock trading assistant. Provides real-time portfolio Greeks, option chain analysis, McMillan/Overby strategy recommendations,... Tags: claude-code:0.2.4, greeks:0.2.4, ibkr:0.2.4, interactive-brokers:0.2.4, latest:0.2.6, options:0.2.4, portfolio:0.2.4, quantitative-finance:0.2.4, trading:0.2.4, trading-assistant:0.2.4, wheel-stra","editorialQuality":{"score":100,"threshold":65,"status":"ready","wordCount":2063,"uniquenessScore":45,"reasons":[]}},"media":{"evidence":{"source":"no-media","verified":false,"confidence":"low","updatedAt":"2026-10-11T03:43:05.882Z","emptyReason":"No screenshots, media assets, or demo links are available."},"primaryImageUrl":null,"mediaAssetCount":0,"assets":[],"demoUrl":null},"ownerResources":{"evidence":{"source":"unclaimed","verified":false,"confidence":"low","updatedAt":"2026-10-11T03:43:05.882Z","emptyReason":"This page has not been claimed by the agent owner."},"hasCustomPage":false,"customPageUpdatedAt":null,"customLinks":[],"structuredLinks":{"docsUrl":null,"demoUrl":null,"supportUrl":null,"pricingUrl":null,"statusUrl":null},"customPage":null},"relatedAgents":{"evidence":{"source":"protocol-neighbors","verified":false,"confidence":"medium","updatedAt":"2026-10-11T07:41:44.774Z","emptyReason":null},"items":[{"id":"8ebccd8e-3863-4187-8355-c3f14e1f9edf","entityType":"agent","canonicalPath":"/agent/iofficeai-aionui","slug":"iofficeai-aionui","name":"AionUi","description":"Free, local, open-source 24/7 Cowork app and OpenClaw for Gemini CLI, Claude Code, Codex, OpenCode, Qwen Code, Goose CLI, Auggie, and more | 🌟 Star if you like it!","url":"https://github.com/iOfficeAI/AionUi","homepage":"https://www.aionui.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-10-09T19:11:12.944Z","createdAt":"2026-02-25T03:38:16.584Z","downloads":null},{"id":"b917f68a-ebff-438e-84f8-3f4b2494c0bc","entityType":"agent","canonicalPath":"/agent/activepieces-activepieces","slug":"activepieces-activepieces","name":"activepieces","description":"AI Agents & MCPs & AI Workflow Automation • (~400 MCP servers for AI agents) • AI Automation / AI Agent with MCPs • AI Workflows & AI Agents • MCPs for AI Agents","url":"https://github.com/activepieces/activepieces","homepage":"https://www.activepieces.com","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-15T02:22:12.426Z","createdAt":"2026-02-25T03:38:12.412Z","downloads":null},{"id":"5cb26759-3a39-483f-94cf-276a98c13bb8","entityType":"agent","canonicalPath":"/agent/cherryhq-cherry-studio","slug":"cherryhq-cherry-studio","name":"cherry-studio","description":"AI productivity studio with smart chat, autonomous agents, and 300+ assistants. Unified access to frontier LLMs","url":"https://github.com/CherryHQ/cherry-studio","homepage":"https://cherry-ai.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-11T14:38:40.986Z","createdAt":"2026-02-25T03:38:19.379Z","downloads":null},{"id":"6f6582d0-5d76-4f0f-b81d-86520247950b","entityType":"agent","canonicalPath":"/agent/copilotkit-copilotkit","slug":"copilotkit-copilotkit","name":"CopilotKit","description":"The Frontend for Agents & Generative UI. React + Angular","url":"https://github.com/CopilotKit/CopilotKit","homepage":"https://docs.copilotkit.ai","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-03-25T09:50:57.846Z","createdAt":"2026-02-25T03:39:14.617Z","downloads":null}],"links":{"hub":"/agent","source":"/agent/source/clawhub","protocols":[{"label":"OpenClaw","href":"/agent/protocol/openclew"}]}}}