Orchestration & Agents
LangGraph StateGraph — a structured multi-agent debate before every trade. No signal reaches execution without surviving research, critique, adversarial review, and a sanity check.
Three-Layer Architecture
LangGraph State Machine
GraphOrchestrator — StateGraph topology
Router — After debate_agent
dissent_score > 0.7 AND loop_count < 3→ deep_research (loop_count++) → back to debate_agent
dissent_score < 0.2→ allocator_agent (high conviction, no deep dive needed)
else (dissent 0.2–0.7, or loop_count ≥ 3)→ END — uncertain_end, no trade submitted
The 7 Graph Nodes
research_agentresearch_node()Calls Perplexity sonar-pro to fetch a real-time market narrative for the ticker. Synthesises news, social tone, macro context, and earnings expectations into a structured summary injected into AgentState.
market_narrativedebate_agentdebate_node()Runs a structured Bull / Bear / Neutral debate using ML ensemble signals and market_narrative. Computes dissent_score [0–1] — degree of disagreement. High dissent (>0.7) triggers deep_research re-entry. Low dissent (<0.2) fast-paths to allocator.
dissent_scoredeep_researchdeep_research_node()Full Perplexity deep-dive triggered only when dissent_score > 0.7 AND loop_count < 3. Injects heavyweight context to break the deadlock. loop_count increments after each call; control returns to debate_agent.
market_narrative (updated)allocator_agentallocator_node()Runs the PortfolioOptimizer (half-Kelly sizing, 4-constraint enforcement). Returns AllocationResult with approved flag, position_size_pct, stop_loss, take_profit. approved=False blocks all further execution.
allocation_resultred_team_nodered_team_node()Passes the full AgentState to adversarial GPT-3.5-turbo: 'Find every reason this trade should NOT be taken.' Returns veto=bool, kill_reason, risk_flags[]. Sets red_team_veto in AgentState.
red_team_vetosanity_guard_nodesanity_guard_node()Hard reality check: if |LLM-referenced price − live price| / live price > 5%, veto='price_hallucination'. Also validates order size vs. current liquidity. Any failure sets sanity_veto=True — execution never proceeds.
sanity_vetoexecution_agentexecution_node()Calls DecisionGateway.create_decision(). Confidence >0.85 → AUTO_EXECUTE. 0.65–0.85 → TRADER_REVIEW (5-min). <0.65 → SENIOR_REVIEW (10-min). Timeout always means auto-reject.
final_decisionAgentState — TypedDict
Persists across all graph nodes. Key routing-critical fields:
| Field | Type | Set By | Used By |
|---|---|---|---|
dissent_score | float [0–1] | debate_agent | Router (deep dive decision) |
allocation_result | AllocationResult | allocator_agent | Router (approved flag) |
red_team_veto | bool | red_team_node | Execution gate |
sanity_veto | bool | sanity_guard_node | Execution gate |
loop_count | int (max 3) | deep_research | Router (infinite loop guard) |
market_narrative | str | research_agent | debate_agent, allocator_agent |
final_decision | dict | execution_agent | DecisionGateway output |
Human-in-the-Loop Approval Tiers
| Tier | Confidence | Approver | Timeout | Delivery |
|---|---|---|---|---|
AUTO_EXECUTE | > 0.85 | System (no human) | Window-based override | — |
TRADER_REVIEW | 0.65 – 0.85 | Trading desk trader | 5 minutes | WebSocket + Telegram |
SENIOR_REVIEW | < 0.65 | Senior trader | 10 minutes | WebSocket + Telegram |
Circuit Breakers
| Breaker | Trigger Condition | Reset |
|---|---|---|
| Drawdown Breaker | Daily PnL drawdown > 5% | Manual only (CIO/Risk) |
| Failure Breaker | 3+ execution failures in 5 minutes | Auto-reset after cool-down |
| Latency Breaker | Configurable response time threshold exceeded | Auto-reset |
| Manual Breaker | CIO/Risk manager command via API | Manual only |
APScheduler — 20 Timed Jobs
AsyncIOScheduler in UTC timezone. Jobs are the heartbeat of the entire system — data ingestion, signal scans, EOD reconciliation, and weekly model retraining.
| Job Name | Interval | Purpose |
|---|---|---|
crypto_ingestion | 5 min | Fetches latest crypto OHLCV from Binance CCXT |
trade_lifecycle | 5 min | Checks open order status; updates fills from broker |
signal_generation | 5 min | Triggers SuperIntel engine for autonomous signal scan |
position_limits | 5 / 15 min | Enforces max position size limits across portfolio |
nav_scanning | 5 min | Scans NAV arbitrage opportunities (GBTC/BTC pairs) |
pnl_snapshot | 15 min | Writes portfolio PnL snapshot to TimescaleDB |
model_health | 1 hour | Reviews model scoring; flags underperforming models |
equity_ingestion | 1 hour | Fetches equity OHLCV from YFinance |
eod_reconciliation | EOD step 1 | Reconciles broker fills with internal position records |
data_quality_gate | EOD step 2 | 5-check quality validation sweep on all day's ingested data |
feature_computation | EOD step 3 | Computes all ML features from raw OHLCV data |
eod_pipeline | EOD step 4 | EOD data pipeline — aggregations, rolling statistics |
arbitrage_discovery | EOD step 5 | Scans for intraday arbitrage opportunities |
correlation_refresh | EOD step 6 | Refreshes rolling cross-asset correlation matrix |
cointegration_refresh | EOD step 7 | Re-tests cointegration pairs with fresh data |
intraday_pipeline | 09:00–16:00 UTC | Intraday data ingestion and feature update (Mon-Fri) |
Regime-Adaptive Thresholds
The RegimeAdaptiveOrchestrator maintains per-regime threshold profiles. On regime detection, thresholds switch live — no restart required.
| Regime | Confidence Threshold | Max Position | Consensus Required |
|---|---|---|---|
| HIGH_VOLATILITY | 0.90 | 1% of NAV | 0.80 — near-unanimous |
| LOW_VOLATILITY | 0.70 | 3% of NAV | 0.65 — standard |
| TRENDING | 0.75 | 2% of NAV | 0.70 — allows trend-following pairs |