Development log

Geopolitical Trading Bot
Build History

A living record of every feature built, bug fixed, and improvement shipped — with full context on what each change does and why it matters.

25
Features shipped
8
In progress
31
Planned
3
Known bugs
Phase 1
Foundation & core architecture
✓ Complete
Mar 2026
Week 1
Core bot architecture
Full Python bot with signal cycle, corroboration filter, risk manager, trade arbiter, position tracker, and exit manager. Connected to Interactive Brokers via ib_insync on paper account port 7497.
main.pybroker.pyrisk_manager.pytrade_arbiter.py
Done
Mar 2026
Week 1
Instrument universe
Energy (USO, UNG, XLE), defense (LMT, RTX, NOC, GD, BA, ITA), safe havens (GLD, TLT), AI/semiconductors (NVDA, TSM, AMD, MSFT, GOOGL), AI energy infrastructure (VST, CEG, EQIX, CCJ, NEE). Each chosen for predictable geopolitical linkage.
config.pystrategy.py
Done
Mar 2026
Week 1
Tiered keyword taxonomy
Tier 1 (2.0× weight), Tier 2 (1.5×), Tier 3 (1.0×). Cross-cluster amplifier fires at 1.25× when two thematic clusters trigger simultaneously. Covers energy, defense, Taiwan/China, POTUS/policy, Israel/Middle East, AI sector.
signals/keywords.py
Done
Mar 2026
Week 1
Polymarket signal (35% weight)
Fetches prediction market YES prices every 15 min. Real money bets weighted as highest-conviction signal. 78 markets monitored across geopolitical themes.
signals/polymarket.py
Done
Mar 2026
Week 1
RSS feed signal (15% weight)
44 live news feeds across Reuters, defense, energy, and geopolitical sources. Refreshed every 2 minutes. VADER sentiment scoring with credibility weighting per source tier.
signals/rss.py
Done
Mar 2026
Week 1
News sentiment signal (20% weight)
AI-scored headline tone across all feeds. Global average sentiment score drives composite signal alongside per-instrument keyword matching.
signals/sentiment.py
Done
Mar 2026
Week 1
Telegram alerts + remote commands
Real-time alerts for every trade, rejection, and error. Remote commands: /status, /positions, /signals, /pause, /resume, /closeall.
telegram_handler.py
Done
Mar 2026
Week 1
SQLite database + dashboard
All signals, decisions, and trade outcomes written to local SQLite. Streamlit dashboard reads from DB, auto-refreshes every 30 seconds. Dark theme.
database.pydashboard.py
Done
Phase 2
Signal expansion & volatility engine
✓ Complete
Mar 2026
Week 2
OPRA options flow signal (15% weight)
Live options chain data from IBKR for LMT, RTX, USO, GLD, NVDA, TSM. Scores based on: unusual call/put volume (>2× 20-day average), put/call ratio direction, and IVR (implied volatility rank vs 52-week history). IVR ≥ 80 caps score at −0.3 as a volatility warning. Returns 0.0 on IBKR disconnection.
signals/options_flow.pydatabase.pydashboard.py
Done
Mar 2026
Week 2
Volatility arbitrage engine — Strategy 2
Three separate vol strategies running in parallel: (1) Oil dispersion — crude IV vs energy equity IV mismatch; (2) EM panic harvesting — sell overpriced puts on EWW/EPOL during temporary shocks; (3) Safe haven skew — GLD/FXY ratio spread when crisis pricing diverges.
vol_strategies/strategy_oil_dispersion.pyiv_fetcher.py
Done
Mar 2026
Week 2
6-signal weight model
Updated from 5 to 6 signals: PM 35%, Sent 20%, RSS 15%, OPRA 15%, Mom 10%, Gov 5%. Weights are starting estimates — optimizer adjusts based on real performance data.
config.pystrategy.py
Done
Mar 2026
Week 2
RSS live cache fix
Dashboard was showing stale zeros for RSS on startup because it read from DB (written every 15 min) instead of the live 2-min cache. Fixed: dashboard now calls fetch_rss_signal() directly for RSS column.
dashboard.py
Fixed
Phase 3
Self-improving AI loop
✓ Complete
Mar 2026
Week 3
Anthropic API optimizer loop
strategy_optimizer.py logs all signal scores, decisions, and trade outcomes to .jsonl files. Periodically sends full history to Claude via Anthropic API. Claude analyzes what's working and recommends updated parameter values (signal weights, profit targets, thresholds). Bot applies changes to config.py automatically.
strategy_optimizer.pyperformance_logger.pyconfig.py
Done
Mar 2026
Week 3
Thematic coverage scanner
Weekly scan: Claude analyzes last 7 days of RSS headlines, identifies thematic gaps in keyword coverage, proposes new keyword clusters and instrument baskets. Proposals written to thematic_proposals log for human review — not auto-applied.
strategy_optimizer.py
In progress
Mar 2026
Week 4
Layer 3 — Autonomous signal optimization loop Novel IP
Third AI layer added to bot_health.py, running every 6h. Completes the three-layer health stack: Layer 1 (deterministic diagnostics, instant) → Layer 2 (Claude health analysis, every 30 min) → Layer 3 (Claude parameter optimization, every 6h). Layer 3 ingests signal non-zero % over 48h, per-signal trade outcome attribution, Layer 2 health findings, and current market regime. Asks Claude specifically: "what parameter changes would improve signal quality right now?" Returns structured JSON proposals covering signal weights, corroboration thresholds, and profit targets. Changes staged to pending_optimizations table — weight changes auto-approved within bounds, threshold changes require human approval via dashboard. Applied changes hot-reload via importlib.reload(config) so the next signal cycle (up to 15 min later) picks up new values without restart. Guard rails: no single weight below 0.03 or above 0.50, weights must sum to 1.0 after rebalance, max 2 parameter changes per run, disabled during open positions, changes expire after 12h without approval. Full change history written to optimization_history.jsonl. /rollback command available via Telegram.
bot_health.pypending_optimizations DBconfig.pyimportlib.reloadoptimization_history.jsonl
Done
Fixed
Mar 24
Momentum signal returning 0 every cycle — missing timeout on reqHistoricalData
Root cause: ib_insync is an async library. reqHistoricalData() without a timeout parameter returns immediately with 0 bars when called from an APScheduler thread that has no running event loop — the response never arrives. Fix: added timeout=60 to the reqHistoricalData() call in signals/momentum.py. This forces ib_insync to block synchronously until IBKR responds (or 60s elapses), bypassing the event loop dependency entirely. Confirmed false positive: Error 326 (clientId conflict) seen in standalone testing was not a live-bot issue — it only fires when fetch_momentum_signal() is run in an isolated process without sharing the broker._ib singleton. In the live bot, broker.get_ib() returns the already-connected instance correctly. The live bot issue was solely the missing timeout.
signals/momentum.pyreqHistoricalData timeout=60bot_health.py Layer 2 diagnosed
Fixed
Phase 4
Institutional performance tracking
▶ In progress
Phase 4 progress 0 / 5 components shipped
Queued
Trade audit log (append-only)
Immutable per-trade record with: entry/exit timestamps, signal scores at time of decision, which sources agreed, VIX at entry, NAV at entry, exit reason, strategy attribution. Written on entry, updated on exit. Never edited — establishes provable track record.
performance/audit_log.py
Planned
Queued
Performance metrics calculator
Sharpe ratio (annualized, minimum 10 trades), max drawdown, win rate by symbol/strategy/signal source, average hold time (winning vs losing), profit factor, consecutive win/loss streaks, best/worst trade.
performance/metrics.py
Planned
Queued
Live readiness monitor
Tracks rolling 30-day window against go-live criteria: Sharpe ≥ 1.5, max drawdown < 10%, ≥ 20 trades, win rate ≥ 45%, no single day > 3% loss. Sends Telegram alert when all criteria met for 30 consecutive days. Never auto-switches — human confirmation required.
performance/readiness.py
Planned
Queued
Exportable performance report (PDF + CSV)
Generated weekly (Sunday 17:00 ET) and on demand. PDF: summary metrics, last 20 trades table, signal performance breakdown, readiness progress bar. CSV: full audit log with summary row. Both saved to data/reports/ and announced via Telegram.
performance/report.py
Planned
Queued
Performance dashboard tab
New tab in existing Streamlit dashboard showing all metrics, live readiness criteria checklist (Day 0/30), and last 10 closed trades. Read-only.
dashboard.py
Planned
Phase 5
Dual-instance architecture & DevOps
Planned
Planned
Live + dev dual instance model
Two parallel bot instances running simultaneously at all times. Live instance trades real capital on IBKR. Dev instance runs paper trading. Dev performance is directly comparable against live at any time — no guessing whether a change improves outcomes.
architectureibkrpaper vs live
Planned
Planned
Git branching model + automated promotion
Three-branch structure: main (live production), dev (active iteration), feature/x (isolated per-feature). Promotion path: feature → paper validation → dev → test suite → main. Instant rollback available at the code level at any point.
gitgithubCI/CD
Planned
Planned
Daily maintenance window at market close
Bot shuts down at market close each day for scheduled maintenance: automated test suite on pending updates, deploy validated code from dev to live, automated rollback if tests fail, system health checks before next open. If tests fail: operator alerted AND bot auto-reverts simultaneously.
schedulerdeploymentauto-rollback
Planned
Planned
Feature toggles — zero-redeployment A/B testing
New logic implemented as on/off switches. Toggle a feature on in the dev paper instance, compare performance against live baseline, flip it off if it underperforms. Enables rapid A/B testing of individual strategy components without touching the live bot.
config.pyfeature flags
Planned
Planned
Promotion criteria: dev to live
Before any update is promoted from dev to live it must: outperform the baseline paper account over a validation period (minor changes ~1 day, major features ~5+ days), pass all geopolitical tier stress tests, show no execution speed degradation, and receive explicit operator approval.
deploymentvalidation
Planned
Phase 6
Tiered geopolitical event database Novel IP
Planned
Planned
Nine-level severity classification system Novel IP
Historical geopolitical and macroeconomic events classified into three tiers × three sub-tiers = nine severity levels. Each level has corresponding real historical market data. Green 1–3: stable conditions, capital mostly parked in yield instruments. Yellow 1–3: elevated tension, capital shifting toward active deployment. Red 1–3: crisis conditions, full deployment mode. Used to stress-test the bot before any update goes live.
event_database.pystress_tester.py
Planned
Planned
Live distribution curve + today's risk marker Novel IP
The nine tiers map to a normal distribution curve. Most days cluster in the middle (Green and low Yellow). True crisis events (Red 3) are rare outliers on the far tail. The system displays where TODAY sits on this curve in real time — a live marker on the distribution showing current geopolitical risk score. This drives capital allocation decisions automatically.
risk_curve.pydashboard Tab 3
Planned
Planned
Outlier detection protocol + crisis capital reserve Novel IP
When conditions fall outside the normal distribution beyond Red 3 into true outlier territory, a dedicated outlier protocol fires. System cross-references closest historical analogues and executes with conviction while most participants are paralyzed. A dedicated capital reserve (10–15% of fund) is held specifically for outlier deployment and never touched in normal conditions. Outliers are the highest-earnings-potential events in the system.
outlier_protocol.pycapital_allocator.py
Planned
Planned
Self-reinforcing database from live trades Novel IP
Live trading signals that exceed a defined strength threshold — both positive and negative outcomes — are automatically written back into the historical event database. The database grows smarter from real execution data, not just manually curated history. Over time this compounds the accuracy of tier classification and stress-testing.
event_database.pywrite-back threshold configurable
Planned
Phase 7
Multi-AI benchmarking & collaborative refinement Novel IP
Planned
Planned
AI models competing in paper trading simultaneously Novel IP
Multiple AI models — Claude Opus, Claude Sonnet, ChatGPT, Gemini, Perplexity, Grok — run simultaneously in paper trading accounts, each generating signals independently. Performance compared in real time against the live baseline. Answers a question no platform currently asks: which AI model actually makes better trading decisions? Proven with real paper trading data, not benchmarks.
ai_benchmarker.pydashboard Tab 2multi-provider
Planned
Planned
Collaborative refinement mode Novel IP
Beyond competition, models operate collaboratively: one model generates a signal hypothesis, another critiques or refines it, the result feeds back to the first for iteration. Creates a cross-model feedback loop that catches blind spots individual models miss. All iterations logged for analysis and contribute to the signal optimization database.
ai_orchestrator.pycollaborative mode toggle
Planned
Planned
Secrets-based model-agnostic AI orchestration
API keys for each AI provider managed through Settings tab. System routes signal generation through whichever models are configured. Model-agnostic architecture — new models can be added as they emerge without structural changes.
settings.pydashboard Tab 4
Planned
Phase 8
Capital allocation engine & full dashboard
Planned
Planned
Always-deployed capital allocation module
Capital is always in one of three states: earning yield in liquid safe instruments, partially deployed in active positions, or fully deployed on strong signals. Zero idle cash. The allocation engine reads the current position on the geopolitical distribution curve and automatically adjusts the ratio between safe parking and active deployment as conditions shift. Green: majority in T-bills/HYSA/dividend ETFs. Yellow: capital migrating toward active. Red: maximum deployment. Outlier: crisis reserve fires.
capital_allocator.pytier-based migration
Planned
Planned
Signal-strength-proportional deployment sizing
Deployment percentage is proportional to signal strength. Weak Green signal → 5% of available capital. Strong Red signal → 50%. Outlier protocol → full crisis reserve. All thresholds configurable in Settings tab.
capital_allocator.pyconfig.py
Planned
Planned
Full 4-tab dashboard
Tab 1 — Strategy management: live trading column + dev/paper comparison columns (Strategy X, Y, Experimental). Tab 2 — AI benchmarking: each configured model's paper trading performance vs live baseline, collaborative mode toggle. Tab 3 — Historical curve explorer: interactive normal distribution with all historical events plotted, live today marker, click-through event details, dropdown filter by category. Tab 4 — Settings: IBKR params, AI API keys, risk thresholds, deployment ratios, notification prefs.
dashboard.pyTab 1–4streamlit
Planned
Competitive landscape
Novel features vs existing platforms
Reference
Feature This system NexusTrade QuantConnect Vortex AI SentinelXQuant
Tiered geopolitical stress testing (9-level, real historical data) Novel IP
Live distribution curve + today's risk marker Novel IP
Outlier detection + dedicated crisis capital reserve Novel IP
Self-reinforcing historical database from live trades Novel IP
Three-layer autonomous health + live parameter optimization (no-restart hot-reload) Novel IP
Claude API continuous signal optimization loop Novel IP
Multi-AI benchmarking in live paper trading Novel IP
Cross-model collaborative signal refinement Novel IP
Multi-column live vs paper comparison dashboard Novel IP
Tier-based automatic capital allocation (no idle cash)
Feature toggles for zero-redeployment A/B testing
Backtesting / historical simulation ✓ via stress testing
Paper trading ✓ Multiple simultaneous
Live trading via broker API ✓ IBKR / ib_insync
Active bugs
Known issues under investigation
2 open
Confirmed
Mar 20
Polymarket keyword false matches on sports/entertainment
Bare substring matching causes "war" to hit "Warriors" (NBA), "oil" to hit "Oilers" (NHL), "PLA" to hit "Playboi Carti". All 78 monitored markets return 0.0 score because genuine geopolitical signals are diluted by sports noise. Fix: whole-word regex + sports pre-filter.
signals/polymarket.pyroot cause confirmed
Bug
Confirmed
Mar 20
OPRA Error 10089 — market data subscription mismatch
OPRA subscription purchased on live account, not paper account. Paper account gets Error 10089 on every instrument. Fix: add ib.reqMarketDataType(3) to use delayed data (free, always available, sufficient for 15-min cycle) OR subscribe to OPRA on paper account separately in IBKR.
signals/options_flow.pyIBKR paper account
Bug
Confirmed
Mar 20
Unawaited coroutines — accountSummaryAsync + qualifyContractsAsync
RuntimeWarning fires every cycle: risk_manager.py:731 and main.py:571 call async versions of IBKR methods without await. Cosmetic but noisy. Fix: replace both with synchronous equivalents ib.accountSummary() and ib.qualifyContracts().
risk_manager.py:731main.py:571
Bug
Phase 9 — Roadmap
Thematic expansion & commercialization
Upcoming
✓ Shipped
Energy + oil geopolitics
Defense + military
AI + semiconductor wars
Safe haven flows
Emerging market shocks
POTUS / US policy
Volatility arbitrage engine
Self-improving AI loop
Comprehensive logging
▶ In progress
Performance audit trail
Sharpe + drawdown tracking
Live readiness monitor
Thematic gap scanner (Claude)
Desktop launcher (rich CLI)
Telegram /status + /closeall
Weekly PDF/CSV report
Git branching + promotion flow
○ Planned
9-tier geopolitical event DB
Live risk distribution curve
Outlier protocol + crisis reserve
Multi-AI benchmarking
Collaborative AI refinement
Capital allocation engine
4-tab full dashboard
Biotech / robotics / autonomy
Space / nuclear / quantum
Friends + family fund
Prop firm / fund licensing
90-day commercialization track — Day 1 of 90 Target: Sharpe ≥ 1.5 · Max DD < 10% · 30 consecutive days