System architecture¶
Updated: June 2026, after the overhaul towards the validated quantitative strategies (TB/FS/MC).
Overview¶
flowchart TB
subgraph BINANCE["📡 Binance Futures — data (free)"]
WS["WebSocket<br/>aggTrade · depth · forceOrder"]
REST["REST<br/>1h/1d klines · funding"]
end
WS --> DI[BinanceDataIngestion]
DI --> OBE[OrderBookEngine]
DI --> OFE[OrderflowEngine]
REST --> KP["KlineProvider<br/>(injectable: live = backtest)"]
OBE --> OFE
OFE --> RD[RegimeDetector]
RD --> SE[ScoringEngine]
KP --> STRAT["🎯 STRATEGIES<br/>TrendBreakdown · FundingSqueeze · MacroCore"]
SE -- "should_trade(strategy, regime)" --> STRAT
STRAT --> RM["🛡️ RiskManager<br/>3-factor sizing · gross cap · kill switch"]
RM --> OM["OrderManager + OrderRegistry<br/>market entry · SL retry · emergency close"]
OM --> DERIBIT["🏦 Deribit<br/>private REST"]
PM["PositionMonitor<br/>orphan cleanup 30s"] --> DERIBIT
OM --> TL["TradeLogger (journal.db)<br/>SignalLog · PositionLog"]
TL --> DASH["📊 Streamlit Dashboard<br/>separate process, 6 pages"]
DERIBIT -.->|read-only REST| DASH
Main process: src/async_trading_bot.py¶
Asyncio bot with concurrent tasks:
| Loop | Period | What it does |
|---|---|---|
| scan loop | 15 min | per strategy: ScoringEngine.should_trade → scan() → execute_entry() |
| management loop | 30 s | manage_positions() for every strategy + orphan-order cleanup (BTC+ETH) + restart-request flag |
| orderbook loop | continuous | depth snapshot + WS deltas (snapshot BEFORE deltas protocol) |
| outcome tracker | 30 min | resolves WIN/LOSS for SignalLog entries |
| positioning loop | 12 h | C8 archive: positioning data Binance only exposes for ~30 days |
| health loop | 5 s | FailureHandler: API down too long → emergency close |
Layers¶
src/core/ — venue and risk¶
- DeribitClient: authenticated REST (testnet/prod)
- OrderManager: market entry + reduce-only stop_market SL (3× retry, then EMERGENCY CLOSE — never naked positions) + reduce-only limit TP, all registered in the OrderRegistry for orphan cleanup
- PositionMonitor: venue positions, orphan-order checks
- RiskManager: 3-factor sizing, aggregate gross-exposure cap, daily kill switch (see 05_risk_sizing.md)
- FailureHandler: health checks and failure reactions
src/data/ — ingestion¶
- BinanceDataIngestion: tick-by-tick WS (trades, depth, liquidations)
- OrderBookEngine: reconstructed L2 book
- KlineProvider: CLOSED 1h/1d klines + funding via REST with a short cache. Injectable: backtests swap in a historical provider → the same strategy code runs live and in simulation
- PositioningCollector: archives positioning series (top trader L/S, OI, taker ratio) that the exchange only exposes for ~30 days
src/engine/ — features and gating¶
- OrderflowEngine: unified
MarketSnapshot(delta, multi-TF CVD, imbalance, Kyle's lambda) - RegimeDetector: TREND_UP/DOWN, RANGE, COMPRESSION, EXPANSION
- ScoringEngine:
should_trade(strategy, regime)called before EVERY scan; per-strategy regime rules + persisted rolling scoring
src/strategies/ — plugins¶
Immutable BaseStrategy interface: scan(), execute_entry(signal),
manage_positions(). The active ones (TB/FS/MC) are described in
02_strategies.md; legacy ones remain in the codebase
but disabled. Multi-symbol creates one instance per symbol.
src/journal/ + src/monitoring/ — observability¶
- TradeLogger →
data/journal.db(SQLite): every trade with full entry/exit context, P&L, R-multiple - SignalLog → executed AND blocked signals (with the reason)
- TelegramAlerts: notifications
- dashboard_app/: multi-page Streamlit dashboard (below)
Dashboard (src/monitoring/dashboard_app/)¶
A process separate from the bot. Reads journal.db (sqlite read-only),
state JSON files, .env and Deribit via REST.
| Page | Contents |
|---|---|
| Live trades | equity, positions with unrealized P&L and owning strategy, venue orders, reconciliation: orphan orders and SL-less positions highlighted in red |
| Risk & Exposure | gross-cap utilization, kill switch, vol-target bucket, per-symbol macro state, strategy×side enablement matrix |
| Trade history | closed trades with precise amounts, filters, aggregates (WR/PF/expectancy), CSV export, equity curve |
| Market context | funding history, positioning series (C8 archive), Fear & Greed, on-chain miner health + AI export snapshot |
| Settings | guard-railed .env editor: validated ranges as bounds, diff + confirmation, automatic backup, subprocess validation with auto-restore; secrets never displayed |
| Actions | manual kill switch, type-to-confirm position close (reduce-only), on-demand orphan cleanup — double confirmation + audit log |
Write actions go through flag files the bot re-reads in its loops — the dashboard never calls into the bot process.
Design invariants¶
- The
BaseStrategyinterface does not change — strategies are plugins. - An open position ALWAYS has a stop on the venue (retry + emergency close at order placement).
- The injectable data provider is the only data boundary of the validated strategies: identical code live/backtest.
- The dashboard core is read-only: every action goes through files the bot re-reads, never direct calls into the bot process.
- Active-strategy parameters are VALIDATED: changing them invalidates the backtest (re-run the validation pipeline).