# Trading Engine Decision Loop ```mermaid flowchart TD subgraph ENGINE["Trading Engine\nservices/trading/engine.py"] direction TB TASKS["5 Concurrent Async Tasks"] T1["_decision_loop()\n60s polling interval"] T2["_stop_loss_monitor()"] T3["_performance_loop()"] T4["_risk_tier_scheduler()"] T5["_rebalance_scheduler()"] TASKS --> T1 & T2 & T3 & T4 & T5 end T1 --> POLL["Poll recommendations table\naction IN (buy, sell)\nmode IN (paper_eligible, live_eligible)\ngenerated_at > NOW() − 2h"] POLL --> EVAL["evaluate_recommendation()"] EVAL --> CHK_A subgraph PRETRADE["Pre-Trade Check Sequence\n(first failure short-circuits)"] direction TB CHK_A["a. Circuit Breaker active?\nservices/trading/circuit_breaker.py\nTriggers: daily_loss, single_position, volatility"] CHK_B["b. Trading Window?\nis_within_trading_window()"] CHK_C["c. Confidence Gate\nconfidence ≥ risk_tier.min_confidence"] CHK_D["d. Deduplication\nRec ID in processed set?\nRedis: stonks:dedupe:trading:*"] CHK_E["e. Declining Positions\n> 50% positions down > 2%"] CHK_F["f. Max Open Positions\nopen_count ≥ max (default 10)"] CHK_A -->|"pass"| CHK_B CHK_B -->|"pass"| CHK_C CHK_C -->|"pass"| CHK_D CHK_D -->|"pass"| CHK_E CHK_E -->|"pass"| CHK_F end CHK_A & CHK_B & CHK_C & CHK_D & CHK_E & CHK_F -->|"fail"| SKIP["TradingDecision\ndecision = skip\n+ skip_reason"] CHK_F -->|"pass"| SIZER subgraph SIZER["Position Sizing\nservices/trading/position_sizer.py"] direction TB SZ1["Base sizing\nrisk_tier.max_position_pct × 0.5\n× (confidence / min_confidence)"] SZ2["Correlation reduction\nweighted avg corr > 0.8 → reject\n> 0.5 → proportional reduction"] SZ3["Sector exposure\ncap at risk_tier.max_sector_pct"] SZ4["Diversification bonus\n1.2× for new sector (< 3 sectors)"] SZ5["Earnings proximity\n≤ 1 day → reject\n≤ 3 days → 50% reduction"] SZ6["Absolute position cap"] SZ7["Portfolio heat check\nmax_portfolio_heat × active_pool"] SZ8["Share rounding\nfloor(dollar / price)"] SZ1 --> SZ2 --> SZ3 --> SZ4 --> SZ5 --> SZ6 --> SZ7 --> SZ8 end SIZER -->|"rejected"| SKIP SIZER -->|"approved"| ACT["TradingDecision\ndecision = act\nshares, dollar amount"] ACT --> PERSIST_TD["Persist to\ntrading_decisions"] ACT --> ORDER["Build order job\n{ticker, action, side,\nquantity, order_type}"] ORDER -->|"rpush"| Q_BROKER["stonks:queue:broker_orders"] Q_BROKER --> BROKER["Broker Adapter\nAlpaca paper trading\nservices/adapters/broker_adapter.py"] BROKER --> AUDIT subgraph AUDIT["Audit Trail — PostgreSQL"] AU1["orders"] AU2["positions"] AU3["portfolio_snapshots"] end subgraph CB_DETAIL["Circuit Breaker Detail\nservices/trading/circuit_breaker.py"] CB1["daily_loss\nportfolio loss > 5%\ncooldown: volatility_pause_hours"] CB2["single_position\nposition loss > 15%\ncooldown: ticker_cooldown_hours (48h)"] CB3["volatility\n≥ 3 stop-losses in 30min\ncooldown: volatility_pause_hours (2h)"] CB4["Redis state\nstonks:trading:circuit_breaker:*"] end subgraph RESERVE["Reserve Pool\nservices/trading/reserve_pool.py"] RP1["Profit siphoning: 20%"] RP2["High-water rebalance: 30%"] RP3["Emergency liquidation"] RP4["reserve_pool_ledger"] end subgraph RISK_TIER["Risk Tier Auto-Adjustment\nservices/trading/risk_tier_controller.py"] RT1["Evaluate: Sharpe ratio,\ndrawdown, win rate"] RT2["conservative → moderate → aggressive"] RT3["risk_tier_history"] end ```