Track significant decisions to avoid re-debating. Move superseded decisions to
docs/archive/decisions-archive.md.
Date: 2025-02-04 | Status: Decided | Rationale: Full options support (CSPs, bear call spreads, covered calls), free paper trading, institutional-grade reliability, comprehensive market data included. Decision: Interactive Brokers (IBKR) Consequences: Need IBKR account, must run TWS or IB Gateway locally, more complex API integration than Alpaca.
Date: 2025-02-04 | Status: Decided | Rationale: Developer's strong Azure expertise, existing subscription, excellent .NET 8 support, serverless consumption model keeps costs low. Decision: Azure (Functions, Cosmos DB, Key Vault, Application Insights) Consequences: Monthly cost ~$20-40. Deployment via Bicep templates.
Date: 2025-02-04 | Status: Decided | Rationale: AI excels at nuanced analysis; rules are better for deterministic execution. Cost-effective at ~$15-50/month. Decision: Hybrid -- Claude AI for complex analysis (market regime, quality audits, candidate ranking), rule-based execution for orders, position sizing, stop losses, drift calculation, technical signals. Consequences: Two parallel paths in strategy evaluation, need fallback if Claude API fails.
Date: 2025-02-04 | Status: Decided | Rationale: Free, rich embed formatting, mobile notifications, simple webhook implementation. Decision: Discord webhooks Consequences: Human creates Discord server and webhook. Reports formatted as embeds.
Date: 2025-02-04 | Status: Decided | Rationale: Earnings timing is critical for avoiding costly surprises. Reliability worth $29/month. Decision: Polygon.io ($29/month) Consequences: Additional monthly cost, human signs up for Polygon.io account.
Date: 2025-02-04 | Status: Decided (implementation details TBD for Phase 2) | Rationale: Avoids additional costs, IBKR provides historical data, more control over methodology. Decision: Calculate IV Rank/Percentile from IBKR historical volatility data. Consequences: Need to implement calculation in Phase 2 (Week 13-14). Consider whether 1-year lookback is sufficient.
Date: 2025-02-04 | Status: Decided | Rationale: Quarterly frequency means latency acceptable. Claude can synthesize from multiple sources. Free (part of existing API budget). Decision: Claude web search during quarterly audits. Consequences: Quality data may not be 100% accurate -- human should verify. Audit reports should cite sources.
Date: 2025-02-04 | Status: Decided | Rationale: Feature branches isolate work, PR reviews ensure quality, human merge control prevents accidental deployments. Decision: Feature branches off main. All changes via PR. Human reviews and merges.
Date: 2025-02-04 | Status: Decided | Rationale: Conservative defaults with single equity/spread slightly raised for better position sizing. Decision:
| Parameter | Value |
|---|---|
| Per-trade risk | 0.4% |
| Daily stop | 2% |
| Weekly stop | 4% |
| Max single equity | 7.5% (raised from 5%) |
| Max single spread | 3% (raised from 2%) |
| Max gross leverage | 1.2x |
| Issuer cap | 10% |
| Category cap | 40% |
| Consequences: Tunable based on paper trading. Any changes require human approval. |
Date: 2025-02-04 | Status: Decided | Rationale: 12 weeks provides reasonable sample size. "OR S&P 500" allows validation even in down markets. Decision: Minimum 12 weeks. Profitable OR outperform S&P 500. Informational metrics: hit rate ≥ 45%, profit factor ≥ 1.3, max drawdown ≤ 15%. Consequences: Live trading earliest at Week 27. Human approval still required.
Date: 2026-02-09 | Status: Decided | Rationale: The 30% sleeve is focused on multi-leg options strategies (credit spreads, iron condors, CSPs, calendar spreads), not equity swing trades. Name should reflect actual strategy. Decision: Rename "Tactical Sleeve" to "Options Sleeve" throughout the codebase and docs. Consequences: Swing trades may become a future third sleeve. All code references updated.
Date: 2026-02-09 | Status: Decided | Rationale: Claude AI for regime detection is high value/low cost (~1 call/day, $2-5/mo). Screening/ranking candidates algorithmically is sufficient and avoids expensive per-candidate API calls. Decision: Claude AI limited to (1) daily market regime detection for options strategy selection, (2) quarterly income quality audits. All scanning, filtering, entry/exit, position sizing is algorithmic. Consequences: Total Claude API cost ~$2-10/month. System must have rule-only fallback if Claude unavailable.
Date: 2026-02-09 | Status: Decided | Rationale: Options are the core of the 30% sleeve, not an add-on. The system can't function without them. Phase 1 expanded from 8 to 10 weeks to accommodate. Decision: Credit spreads, iron condors, CSPs, and calendar spreads are Phase 1 MVP features. Phase 1 is 10 weeks. Consequences: More complex Phase 1, but the system is complete at end of Phase 1 (not partially functional).
Date: 2026-02-09 | Status: Decided | Rationale: Trading logic errors can lose real money. Non-critical code (notifications, reporting) doesn't need the same rigor. Decision: Rigorous testing (unit + integration + E2E) for trading-critical code (risk engine, order generation, position sizing, options calculations, IV rank). Standard testing (unit + integration) for everything else. Consequences: More test code for core trading logic. PR reviews required for trading-critical changes.
Date: 2026-02-09 | Status: Decided | Rationale: Keep operational costs sustainable. Estimate: Azure ~$10-30, Polygon.io $29, Claude API ~$2-10 = $40-65 total. Decision: Total monthly infrastructure cost must stay under $100. Track costs in logs with alerts if approaching ceiling. Consequences: Constrains AI usage (no expensive per-candidate analysis). May need to revisit if Polygon.io price increases.
Date: 2026-02-10 | Status: Decided | Rationale: Polygon.io is an external data source with its own HTTP client, rate limiting, and DTOs. Separate project keeps boundaries clean and allows independent testing.
Decision: TradingSystem.MarketData.Polygon as a separate project referencing Core.
Consequences: Additional project in solution. Clean dependency graph.
Date: 2026-02-10 | Status: Decided | Rationale: The service orchestrates broker calls with caching and regime detection — it's strategy-layer logic, not broker-layer.
Decision: CachingMarketDataService lives in TradingSystem.Strategies/Services/.
Consequences: Strategies project depends on Core interfaces only, not on IBKR directly.
Date: 2026-02-10 | Status: Decided | Rationale: IV history is expensive to fetch (1-year of daily data from IBKR). Caching to JSON avoids repeated API calls within the same trading day.
Decision: IV history persisted to JSON files per symbol, expires daily (stale if LastUpdated.Date < DateTime.Today).
Consequences: Requires TradingSystem.Storage dependency. First call each day is slow; subsequent calls are fast.
Date: 2026-02-10 | Status: Decided | Rationale: IBKR enforces 50 concurrent market data requests. Need headroom for other data needs. Decision: SemaphoreSlim(45) + 100ms delay between option snapshot requests. Consequences: Option chain retrieval is throttled but stays within IBKR limits. Full chain scan takes ~5-15 seconds depending on strike count.
Date: 2026-02-16 | Status: Decided | Rationale: Fixed 70/30 live allocation is too rigid. Sleeves should earn live capital through paper validation, and activation may be staged. Decision: Run both sleeves in paper validation. For live trading, activate one or both sleeves based on validation results. Human chooses final capital split at live transition. Expected deployable capital range is ~$100,000-$400,000 at decision time, with a minimum of $100,000 per active sleeve account. Consequences: System must provide sleeve-level readiness scorecards and allocation recommendations. Live path must not hard-code 70/30.
Date: 2026-02-16 | Status: Decided | Rationale: Capital movement decisions require human context (taxes, external cash needs, account constraints). Decision: System provides rebalance/transfer/withdrawal recommendations; human executes actual rebalancing and cash movement. For options sleeve, only free cash may be withdrawn (not cash reserved against open options positions). For income sleeve, cash withdrawals and occasional stock sales for withdrawals are allowed. Consequences: Reporting must include recommendation rationale and collateral-aware free-cash calculations. No automatic rebalance/capital-transfer execution.
Date: 2026-02-16 | Status: Decided | Rationale: Unknowns should not stall implementation, but dependent automation must pause for owner input at defined gates. Decision: Add explicit phase-gated checkpoints where Claude prompts the owner before proceeding with dependent automation (options lifecycle rules, recommendation format, paper validation criteria, live activation split, post-live tuning). Consequences: Roadmap/progress docs must maintain gate checkpoints. Claude should stop and prompt at each gate before advancing.
Date: 2026-02-16 | Status: Decided | Rationale: Platform cost control and brokerage activity costs behave differently and should be tracked separately. Decision: The <$100 monthly ceiling applies to platform costs (Azure + Polygon.io + Claude API). Brokerage commissions/fees are tracked and forecasted separately (conservative per contract-side model in reporting). Consequences: Reports must break out platform vs brokerage costs and include activity-based fee forecasts.
Date: 2026-02-16 | Status: Decided | Rationale: Week 8 wiring needs to land before Week 9 risk engine is complete. Scheduled pre-market runs should not hard-fail while IRiskManager is still missing.
Decision: DailyOrchestrator attempts options sleeve execution each pre-market run, but if required options dependencies cannot be resolved, it logs a warning and skips options execution for that run. Broker connect/disconnect handling remains explicit and safe.
Consequences: Timer runs stay healthy during staged integration and retain a defensive skip path for future DI regressions. Options sleeve runtime activation now depends on concrete registrations being present (including IRiskManager).
Date: 2026-02-16 | Status: Decided | Rationale: Stop logic based only on current unrealized P&L is too noisy and does not track true account drawdown over time.
Decision: RiskManager uses ISnapshotRepository baselines for daily/weekly P&L and computes high-water mark/current/max drawdown from persisted snapshots. Stop alerts are sent through IRiskAlertService only on state transitions (new trigger events) to avoid duplicate alert spam.
Consequences: Risk metrics now require snapshot persistence registration in DI. Discord webhook configuration is required for external alert delivery; without it alerts degrade to logs.
Date: 2026-04-07 | Status: Decided | Rationale: OptiTrade (Python options backtest system) and TradingSystem (C#/.NET 8 two-sleeve platform) overlap in scope but TradingSystem is far more mature (418+ tests, working IBKR/risk/options/income infrastructure vs 5-file Python scaffold). Maintaining two repos doubles effort for no benefit. OptiTrade's backtest pipeline (Python scripts driving QC REST API) is the only asset worth preserving.
Decision: TradingSystem is the primary repo. OptiTrade is archived (tagged v1.0-archive). Backtest pipeline migrated to tools/backtest/. Iron condor findings inform options sleeve parameters. SPX backtesting is the next critical path.
Consequences: All future trading work in this repo. Python tooling lives in tools/backtest/ with its own requirements.txt. The backtest pipeline is a developer tool, not part of the .NET runtime.
Date: 2026-04-07 | Status: Decided | Rationale: User's goals differ by life phase. While working full-time (next ~5 years), primary goal is generating alpha (beating S&P 500). In retirement, goal shifts to 5-8% consistent yield with drawdown protection. System should support both modes via configurable profiles. Decision: Build Mode A (alpha-seeking) first. Options sleeve is the primary alpha engine, not a supplement. SPX options (commission-efficient) are the focus. Income sleeve is secondary while working. The 70/30 income/options split from the original design may invert to 30/70 or 50/50 for Mode A. Mode B (income+protection) can reuse the same infrastructure with different allocation weights. Consequences: Options sleeve priority increases. SPX iron condor backtest is the immediate next step. Sleeve allocation weights become configurable. Return targets recalibrated: alpha-seeking benchmarked against SPY, not absolute yield targets.
Date: 2026-04-07 | Status: Decided | Rationale: 8 OptiTrade backtests (2019-2025) proved SPY iron condors produce +0.07% CAGR on $400K — essentially breakeven. The edge is real (PF 2.0, 72% win rate) but commission drag ($2.60/spread vs $1.86-2.40 credit) consumes it. SPX (100x multiplier) should eliminate this drag.
Decision: SPY iron condor parameters locked: IV>=18% ATM, PT=70%, MinCredit=$2.00, SL=2.0x, Wing=10pt, Delta=0.16. These are reference parameters for the options sleeve. SPX iron condor backtest is the highest priority — same logic, 10x better commission-to-credit ratio. If SPX passes gate with meaningful CAGR, iron condors become a core strategy. If not, iron condors are demoted to minor/inactive.
Consequences: SPX backtest determines whether iron condors are worth running in production. tools/backtest/algorithms/IronCondorBaseline.cs preserves the validated SPY algorithm. Pipeline in tools/backtest/ is ready for SPX variant.
Date: 2026-05-29 | Status: Decided
Rationale: The Claude Gateway (subscription-priced CLI bridge) runs as a local process on localhost:3131 on the same trusted host as the Functions worker. ClaudeService reaches it over plaintext HTTP, authenticating with a static Bearer token (Claude:GatewayApiKey). The question is whether this transport is acceptable or whether it needs TLS / a non-network IPC channel.
Decision: Keep plaintext HTTP over loopback (http://localhost:3131/) with the static Bearer token. This is acceptable because the listener is bound to the loopback interface only — traffic never leaves the host, so there is no on-wire interception surface, and the Bearer token guards against other local processes that lack the secret. The named ClaudeGateway HttpClient is created via IHttpClientFactory with a short configurable timeout (GatewayTimeoutSeconds, default 8s) so a hung gateway fails fast to the metered direct API (which itself fails closed to deterministic rules when no key is present). This ADR DOCUMENTS the current stance only — it does NOT introduce TLS or named-pipe transport in this change. (Updated S3-003, 2026-05-29) The named ClaudeGateway client timeout default is now 35s (was 8s), sized to cover Claude CLI cold-start for the ~1/day regime call (tiny prompt, MaxTokens=500); the gateway INTEGRATION guide requires a client timeout ≥35s. The metered direct-API fallback now ships disabled by default (DirectApiFallbackEnabled=false), so the gateway is the only AI path in the default posture; a gateway miss fails safe to deterministic rules with no metered call and no cap consumption. When explicitly enabled, the S2-002 MaxDirectApiCallsPerDay fail-closed cap is unchanged.
Alternatives considered:
- HTTPS with a self-signed certificate on loopback — DEFERRED. Adds certificate generation, trust-store management, and rotation overhead for a channel that never leaves the host; no meaningful confidentiality gain over a loopback-bound socket. Revisit only if the gateway is ever moved off-box.
- Windows named pipe (or Unix domain socket) IPC — DEFERRED. Removes the network surface entirely and is the strongest option, but requires a different client/transport abstraction in both the gateway and
ClaudeService. Out of scope for this refactor; a candidate if a future threat model rules out any local TCP listener. - No auth token (rely on loopback binding alone) — REJECTED. Any local process could then call the subscription-priced gateway; the static Bearer token is a cheap defense-in-depth layer worth keeping.
Consequences: Gateway base address and timeout are bound from the
Claudeconfig section, so the loopback URL and fail-fast timeout are tunable without code changes. If the gateway is ever relocated to another host, this ADR must be superseded — plaintext + static token is NOT acceptable off-loopback. The deferred TLS/named-pipe options remain explicitly un-built. (Updated S3-003) Default posture = gateway-or-rules (no metered spend), aligning with the standing external_api_spend deny. The loopback-only + static-Bearer transport stance is unchanged.
Date: 2026-05-29 | Status: Decided Rationale: Backtesting complex/options strategies in this system has proven unreliable as a go/no-go signal: (1) data-reliability and aggregation doubts in the QC pipeline make results hard to trust at the precision a gate needs; (2) runs are slow, lengthening the feedback loop; (3) the SPX iron-condor backtest came back inconclusive — NOT a demotion of iron condors, just not a clean pass/fail. Forward paper trading in SANDBOX exercises the real execution path (IBKR, screening, lifecycle, risk) on live data and is the more trustworthy validation gate. Decision: Paper trading (SANDBOX, forward) is the validation gate for options and complex multi-leg strategies. Backtesting is a research/sanity aid, not the activation gate. The SPX iron-condor result is treated as inconclusive (iron condors are neither promoted nor demoted on backtest evidence alone). EXCEPTION: simple stock-trade strategies may still use backtesting as a reasonable gate, since their fills/aggregation are well-modeled. The backtest-distillation / gate-evaluation work is SHELVED (see backlog). Alternatives considered:
- Keep SPX backtest as the go/no-go gate (status quo per ADR-026/028) — REJECTED for complex strategies. Data-reliability/aggregation doubts and an inconclusive SPX run mean a backtest pass/fail would gate capital on a signal we do not trust.
- Invest to harden the backtest pipeline (fix aggregation, speed) until it is gate-grade — DEFERRED. High effort against a tool whose modeling of multi-leg fills is the core doubt; not worth it before paper validation has run. Distillation work shelved to backlog, not deleted.
- No formal gate; activate on judgment — REJECTED. A defined forward-paper gate is needed
before any SANDBOX→LIVE step (ties into PDR-004/PDR-005 sleeve thresholds).
Consequences: Supersedes the "SPX backtest is the next critical path / go-no-go" stance in
ADR-026 and ADR-028 for options/complex strategies — those ADRs' SPX-gate language is now
historical.
tools/backtest/remains for research and the simple-stock-trade exception; it is no longer on the activation critical path. Phase 3 paper validation (PDR-004/005 thresholds) becomes the gate to define numerically. Iron-condor parameters in ADR-028 remain valid reference parameters; only their gating role changes.
Date: 2026-06-10 | Status: Decided
Rationale: The 12-week SANDBOX paper-validation run (ADR-030, PDR-004) needs the Azure
Functions isolated worker actually running on a schedule. Both of the worker's live
dependencies are loopback-only by design: TWS paper exposes its API socket on
127.0.0.1:7497, and claude-gateway listens on localhost:3131 (plaintext loopback HTTP
per ADR-029). An Azure-hosted worker cannot reach either, and exposing either off-box would
violate the ADR-029 transport stance. The question is where the worker runs for the
validation window.
Decision: Host the Functions worker locally on the dev box, co-resident with TWS and
claude-gateway (func start / dotnet run from src/TradingSystem.Functions). The four
NCRONTAB timers (pre-market 0 0 13 * * 1-5, EOD 0 30 20 * * 1-5, income monthly reinvest
0 30 13 1-7 * 1-5, income quarterly audit 0 0 14 1-7 1,4,7,10 1-5, all UTC) fire only
while the worker is up — the dev box must be on across the timer windows during market days.
(Updated S6-003, 2026-06-10: originally written as "the two NCRONTAB timers" — the two
income-sleeve timers were always registered on the same worker and are now counted; no cron
changed and no decision content is altered.)
Operational procedure (preflight, schedule, triage, posture) lives in
docs/paper-validation-runbook.md; that runbook's Run Log is the system of record for the
validation start date.
Alternatives considered:
- Azure-hosted Functions (the deploy target the project was scaffolded for) — REJECTED for the validation window. It cannot reach loopback-bound TWS/gateway, and exposing either off the host (port forward, public webhook) violates ADR-029's loopback-only transport stance.
- Relay/tunnel from Azure to the dev box (reverse proxy, VPN, hybrid connection) — DEFERRED. Operational complexity plus a new attack surface on the broker API for zero validation benefit — the dev box still has to be on for TWS anyway.
- Dedicated always-on VM hosting all three (worker + TWS + gateway) — DEFERRED on cost.
Revisit if dev-box uptime proves inadequate mid-run (chronic gap days in the Run Log).
Consequences: Validation continuity depends on dev-box uptime. Missed timer firings do
not catch up; a missed EOD run is visible as a same-date gap in
data/snapshots.jsonand a missing daily report, and is tolerated by the ≥12-week window rather than treated as an incident. (Updated S6-003, 2026-06-10) A missed monthly-reinvest firing is tolerated the same way: drift-based plans are self-correcting, so next month's gate day catches the drift. The quarterly-audit timer is a documented no-op until implemented (S7+) — its firing produces a Warning log line and nothing else (S6-007). The Azure deployment path (Key Vault, App Insights cloud hosting) remains intact for a future LIVE posture decision — this ADR governs the paper-validation window only.
Blocking: Options roll/close timing | Needs: Paper trading results from Phase 1 Start with daily batch, assess need for intraday monitoring (especially near-expiry positions). Deferred to post-Phase 1.
Resolution: ADR-026 — use OptiTrade's QuantConnect cloud pipeline (migrated to tools/backtest/). No custom backtesting engine needed. QC REST API automates compile/run/collect. Python scripts drive it.
Blocking: Nothing (independent) | Needs: Options sleeve proven in live trading Potential future addition after options sleeve is validated.
Resolution: Resolved in code by S4-001 (PR #81), owner-confirmed 2026-06-09 — per-sleeve paper gate: hit rate ≥45%, profit factor ≥1.3, max drawdown ≤15%, ≥12 weeks observed, profitable-OR-beat-SPY (strict >), $100k minimum live capital per sleeve. Values of record in src/TradingSystem.Core/Configuration/SleeveValidationThresholds.cs; evaluation-only via the IConfigRepository settings seam (key "sleeveValidationThresholds"), never on any order/execution path; consumed by the S4-002 scorecard. PDR-005 (live sleeve set/capital split) remains pending.
Blocking: Live transition execution plan | Needs: Paper validation outputs + owner decision Select which sleeve(s) activate first and final initial capital split/account mapping at live transition.
Phase: 3 — Paper Validation, running since 2026-06-11 (ADR-030/031). 12-week window; earliest gate evaluation on/after 2026-09-03. 632 tests passing.
| Phase | Weeks | Status | Goal |
|---|---|---|---|
| 1. Foundation | 1-10 | Done | IBKR, sleeves, risk, orchestration, Claude regime |
| 2. Integration + SPX Backtests | 11-16 | Closed as superseded (ADR-030: backtesting demoted to research aid; pipeline migrated, gate role removed) | Migrate backtest pipeline (done), SPX backtests, strategy lockdown |
| 3. Paper Validation | 17-28 | In progress — started 2026-06-11, locally hosted worker per ADR-031 | 12+ weeks autonomous paper trading |
| 4. Live Transition | 29-32 | Pending | Staged go-live with human approval |
| 5. Stabilization | 33-44+ | Pending | Tuning, performance reviews |
- Weeks 1-8: IBKR connection, market data, storage, orders, income sleeve, option chains, IV rank, screening, Polygon.io calendar, multi-leg orders, options lifecycle, execution service, orchestration wiring, pre-market tests
- Week 9: Concrete
RiskManagerwith per-trade checks, stop-halt, position/cap enforcement, no-trade windows; snapshot-backed drawdown tracking; Discord stop alerts viaIRiskAlertService; Azure.Identity upgraded to 1.17.1 - 2026-04-07: OptiTrade consolidated (ADR-026). Backtest pipeline migrated to
tools/backtest/. Iron condor findings recorded (ADR-028). - Completed through S5 (2026-06-10): sprints S1–S5 merged and archived — see the sprint archive in SPRINT.md for the detailed per-sprint record (this snapshot does not duplicate it).
None — both 2026-04-07 blockers cleared: Discord webhook resolved (day-0 wiring, test alert delivered — see KD-001); Claude API key resolved by re-scoping (gateway key provisioned, metered key not required while DirectApiFallbackEnabled=false — see KD-002).
- Monitor the paper-validation run per
docs/paper-validation-runbook.md(its Run Log is the system of record) - S6 protect/instrument items (host-boot CI gate, gap-day monitor, reinvest wiring)
- Gate evaluation on/after 2026-09-03 — PDR-005 then becomes the live-transition decision
| ID | Description | Impact | Logged |
|---|---|---|---|
| KD-001 | ✅ RESOLVED by S5-004 day-0 wiring (2026-06-10). local.settings.json; test alert delivered (HTTP 204) through the production guard path (see docs/paper-validation-runbook.md Run Log) |
Stop alerts silently drop — closed | 2026-02-16 |
| KD-002 | Claude API key not provisioned — NOT required under default posture: ADR-029/030 gateway-or-rules with DirectApiFallbackEnabled=false means zero metered spend (gateway bearer key provisioned via S5-004). Becomes relevant only if the owner explicitly enables the metered fallback |
Conditional — regime integration shipped, degrades to deterministic rules | 2026-02-16 |
| KD-003 | Backtest pipeline paths use Python (not .NET) | Must install Python + deps separately for backtesting | 2026-04-07 |
| KD-004 | ✅ RESOLVED 2026-05-29 (S3-001, PR #70). ~~CachingMarketDataService.cs ~360 lines, exceeds 300-line architecture-fitness threshold (grew across S2-001/003/005/006)~~ — decomposed into a 125-line facade + new 280-line MarketRegimeProvider (internal composition, no DI change, zero behavior change) per ADR-017 | Maintainability — closed | 2026-05-29 |
| KD-005 | ApplicationInsights 2.x→3.x upgrade gate (S5-004r). Microsoft.ApplicationInsights.WorkerService is pinned to the classic 2.x line (2.23.0): AI 3.x is OTel-based and removed classic API types (ITelemetryInitializer) that Microsoft.Azure.Functions.Worker.ApplicationInsights 2.50.0 is compiled against — pairing them crashes the isolated worker at DI bootstrap with TypeLoadException. Upgrade is BLOCKED until the Functions Worker AI package ships a 3.x-compatible release; when unblocking, re-evaluate the OpenTelemetry.Api pin removed in S5-004r (see comment in TradingSystem.Functions.csproj) and clear KD-006 in the same change |
Stuck on classic 2.x telemetry SDK; no OTel-native pipeline. Boot-blocking if upgraded prematurely | 2026-06-10 |
| KD-006 | discord.com URI-redaction gate before enabling App Insights (S5-004r). AI 2.x dependency telemetry records the full request URL of outbound HTTP calls — for the Discord named clients that URL IS the token-bearing webhook URL. This path bypasses the System.Net.Http.HttpClient ILogger filter in Program.cs (that filter only covers log telemetry) and is dormant solely because APPLICATIONINSIGHTS_CONNECTION_STRING is unset everywhere. Do NOT set that variable until a telemetry processor/initializer that redacts or drops discord.com dependency URLs is in place (or AI 3.x with OTel redaction supersedes it — KD-005) |
Secret-leak risk into App Insights if telemetry is ever enabled without redaction | 2026-06-10 |
| KD-007 | Optional-null ctor dependency pattern — undecided (S6-001 judge deferral). Recurring shape across S5-001/S5-003/S6-001: optional constructor dependencies accepted as null with a logged null-skip, vs required dependencies failing at boot — decide once, portfolio-wide; S6-002's host-boot CI gate partially mitigates accidental de-registration | A de-registered dependency degrades to a logged skip instead of failing loudly; pattern decision pending | 2026-06-10 |
OptiTrade (Python options backtest system) was consolidated into TradingSystem in April 2026 (ADR-026). The following records the architectural decisions and research outcomes from OptiTrade that are not already captured above. The Python runtime decisions (uv, hatchling, pydantic-settings, SQLAlchemy) are OptiTrade-internal and are archived in
research/optitrade-phase1/rather than carried forward — TradingSystem uses C#/.NET 8 for its runtime. The backtest pipeline decisions (ADR-020 through ADR-024 below) are substantive and inform how the QC cloud pipeline intools/backtest/was designed.
Date: 2026-04-03 | Status: Superseded by tools/backtest/ consolidation (ADR-026)
Decision: Automate backtesting via QuantConnect REST API (scripts/run_cloud_backtest.py) instead of manual browser copy-paste workflow.
Rationale: Manual workflow required copy-pasting C# into QC browser, waiting 15-20 min, then clicking through the UI to download artifacts. The REST API supports file push, compile, backtest creation, polling, log download, and result collection — all scriptable. (This became the basis for tools/backtest/ in TradingSystem.)
Alternatives considered: LEAN CLI (lean cloud backtest) — broken on Python 3.14 due to click version conflict; local LEAN via Docker — requires solving options data sourcing; Playwright browser automation — works but fragile.
Date: 2026-04-03 | Status: Applied (fixes carried into tools/backtest/ algorithms)
Decision: Replace ConstantFeeModel(0.65) with InteractiveBrokersFeeModel() and reduce ConstantSlippageModel from 0.05 (5% of option price) to 0.005 (0.5%).
Rationale: ConstantFeeModel charged $0.65 per fill (not per contract) — undercharging commission by 5x. $17.50/contract), far exceeding the intended $0.05/contract. Combined: old model over-penalized slippage and under-penalized commission. Corrected baseline CAGR moved from -1.09% to -0.52%.ConstantSlippageModel(0.05) applied 5% of option price as slippage (
Date: 2026-04-03 | Status: Historical (both files archived in research/optitrade-phase1/)
Decision: backtests/QC_CloudBacktest.cs is the canonical, evolved algorithm. backtests/lean/Main.cs was not synced and should not be used.
Rationale: Cloud version has critical bug fixes: correct slippage multiplier (×contracts not ×1), strike-based fallback when Greeks are zero, Minute resolution for better data coverage, correct combo order sizing. Local Main.cs is missing all of these.
Date: 2026-04-07 | Status: Active — applies to options sleeve parameters
Decision: Entry IV filter uses ATM option implied volatility read directly from the option chain (contract.ImpliedVolatility), not IV Rank (IVR).
Rationale: IVR requires a rolling 52-week IV history not directly available in the LEAN option chain. ATM IV from the chain is immediately available and achieves the same economic goal: filtering entries when options price in minimal risk. The ivr_min: 25 parameter existed in YAML/StrategyConstants for months but was never wired up — the algorithm was entering in all vol environments. Fixing this (via EntryMinAtmIv = 0.18) was the key lever that moved CAGR from -0.52% toward the gate-passing +0.07%.
Tradeoff accepted: ATM IV is an absolute level, not rank — it doesn't capture "high vol relative to recent history." Acceptable for Phase 1; paper validation may reveal the need for a proper IVR indicator.
Alternatives considered: IVR via custom rolling indicator (complex, warmup data required); VIX threshold via AddData (adds secondary symbol dependency); keeping unimplemented IVR (economically broken).
Date: 2026-04-07 | Status: Active — reference parameters per ADR-028
Decision: Lock Phase 1 baseline parameters: entry_min_atm_iv: 0.18, profit_target_pct: 0.70, min_credit_to_width_ratio: 0.20 ($2.00 min on $10 wings), stop_loss_credit_multiple: 2.0, wing_width_spy: 10, short_delta_target: 0.16.
Results: CAGR +0.07%, Profit Factor 2.0, Win Rate 72.22%, Max Drawdown 1.07%, IS/OOS delta 0.42pp, 18 trades over 2019-2025. Slippage drag 4.52% (well below 30% gate). parameter_hash: f32c6bb59a1432156890dca414c7bafc5fcd637cc6d8cd04a37351c500ebccbd
Rationale: 8 backtest iterations with economically motivated changes only. Key findings: (1) removing stop loss is wrong — worsens outcomes; (2) ivr_min was never wired in C# — fixed via ATM IV; (3) 20pt wings are worse than 10pt; (4) IV=18% is the sweet spot — IV=20% filters too many quality OOS trades; (5) PT=70% is near-optimal — PT=75% degrades to 0.00% CAGR.
Alternatives considered (all rejected): IV=16% (-0.26% CAGR), IV=20% (only 9 trades/7yr, killed OOS), PT=65% (-0.04%), PT=50% (-0.26%), no stop loss (-0.89%), 20pt wings (-0.91%).
Note: These are SPY parameters. The SPX variant (100x multiplier, ~10x commission efficiency) is the next research step per ADR-027/028, now gated behind paper validation per ADR-030.
Recorded for historical reference. TradingSystem's canonical state is the Project State Snapshot above.
Phase 1 gate: PASSED (2026-04-07, Run 7, IV=18%/PT=70%/MinCred=$2.00)
Phase 2-4: Pending; Phase 2 unblocked by Phase 1 gate, now superseded by paper trading path (ADR-030)
Open PRs at consolidation: PR #8 (YAML configs, main branch) and PR #9 (scripts + LEAN scaffold) — both are now archived in research/optitrade-phase1/; no action needed
Known debt carried forward: none — KD-001/002/003 resolved; KD-004/005 moot (local LEAN not used)