feat: autonomous trading engine — full implementation

- Database migration 018 with 13 tables for trading engine state
- Trading engine service (services/trading/) with 12 pure computation modules:
  position sizer, stop-loss manager, reserve pool, circuit breaker,
  risk tier controller, correlation matrix, tax lots, trading window,
  gradual entry, notifications, micro-trading, backtester
- Core TradingEngine with pre-trade evaluation pipeline and integration wiring
- FastAPI HTTP service with 14 endpoints (health, config, decisions, metrics, backtest)
- Performance tracker with Sharpe ratio, drawdown, profit factor computation
- 194 Python tests (165 property-based + 29 integration)
- Frontend: 13 TanStack Query hooks, 7 dashboard panels, tabbed Trading Engine page
- Helm chart entry, network policy, nginx proxy, ingress for trading-engine
- Shared infrastructure: enums, Redis keys, TradingConfig in AppConfig
This commit is contained in:
Celes Renata
2026-04-15 16:12:22 +00:00
parent da86132f0c
commit 4ffde8cc06
58 changed files with 14168 additions and 1 deletions
+253
View File
@@ -0,0 +1,253 @@
"""Core data models for the autonomous trading engine.
Defines dataclasses for risk tier configuration, portfolio state,
trading decisions, position sizing results, stop levels, and
performance metrics used across all trading engine components.
"""
from __future__ import annotations
from dataclasses import dataclass, field
from datetime import datetime, timedelta
# ---------------------------------------------------------------------------
# Risk Tier Configuration
# ---------------------------------------------------------------------------
@dataclass
class RiskTierConfig:
"""Parameters for a named risk tier (conservative/moderate/aggressive)."""
name: str
min_confidence: float
max_position_pct: float
stop_loss_atr_multiplier: float
reward_risk_ratio: float
max_sector_pct: float
max_portfolio_heat: float
RISK_TIER_DEFAULTS: dict[str, RiskTierConfig] = {
"conservative": RiskTierConfig(
name="conservative",
min_confidence=0.75,
max_position_pct=0.05,
stop_loss_atr_multiplier=1.5,
reward_risk_ratio=2.0,
max_sector_pct=0.20,
max_portfolio_heat=0.10,
),
"moderate": RiskTierConfig(
name="moderate",
min_confidence=0.55,
max_position_pct=0.10,
stop_loss_atr_multiplier=2.0,
reward_risk_ratio=1.5,
max_sector_pct=0.30,
max_portfolio_heat=0.20,
),
"aggressive": RiskTierConfig(
name="aggressive",
min_confidence=0.40,
max_position_pct=0.15,
stop_loss_atr_multiplier=2.5,
reward_risk_ratio=1.2,
max_sector_pct=0.40,
max_portfolio_heat=0.30,
),
}
# ---------------------------------------------------------------------------
# Portfolio State
# ---------------------------------------------------------------------------
@dataclass
class PortfolioState:
"""Snapshot of the current portfolio used for decision-making."""
positions: list = field(default_factory=list)
total_value: float = 0.0
cash: float = 0.0
active_pool: float = 0.0
reserve_pool: float = 0.0
sector_exposure: dict[str, float] = field(default_factory=dict)
portfolio_heat: float = 0.0
open_position_count: int = 0
# ---------------------------------------------------------------------------
# Trading Decision
# ---------------------------------------------------------------------------
@dataclass
class TradingDecision:
"""Record of a trading decision (act or skip), persisted for audit trail."""
id: str
recommendation_id: str | None
decision: str
skip_reason: str | None
ticker: str
computed_position_size: float | None
computed_share_quantity: int | None
risk_tier_at_decision: str
portfolio_heat_at_decision: float | None
active_pool_at_decision: float | None
reserve_pool_at_decision: float | None
circuit_breaker_status: str
correlation_check_result: dict = field(default_factory=dict)
sector_exposure_check_result: dict = field(default_factory=dict)
earnings_proximity_flag: bool = False
is_micro_trade: bool = False
decision_trace: dict = field(default_factory=dict)
created_at: datetime = field(default_factory=datetime.utcnow)
# ---------------------------------------------------------------------------
# Position Sizing
# ---------------------------------------------------------------------------
@dataclass
class PositionSizeResult:
"""Output of the position sizer computation."""
dollar_amount: float
share_quantity: int
allocation_pct: float
adjustments: list[str] = field(default_factory=list)
rejected: bool = False
rejection_reason: str = ""
# ---------------------------------------------------------------------------
# Stop-Loss / Take-Profit Levels
# ---------------------------------------------------------------------------
@dataclass
class StopLevels:
"""Current stop-loss and take-profit levels for an open position."""
stop_loss_price: float
take_profit_price: float
trailing_stop_active: bool
atr_value: float
atr_multiplier: float
reward_risk_ratio: float
last_updated: datetime = field(default_factory=datetime.utcnow)
# ---------------------------------------------------------------------------
# Open / Closed Positions
# ---------------------------------------------------------------------------
@dataclass
class OpenPosition:
"""Representation of a currently held position."""
ticker: str
quantity: int
entry_price: float
current_price: float
unrealized_pnl: float
market_value: float
sector: str
stop_loss_price: float
take_profit_price: float
signal_confidence: float
is_micro_trade: bool = False
@dataclass
class ClosedTrade:
"""Record of a completed (closed) trade."""
ticker: str
entry_price: float
exit_price: float
quantity: int
pnl: float
pnl_pct: float
hold_duration: timedelta
recommendation_id: str | None = None
is_micro_trade: bool = False
# ---------------------------------------------------------------------------
# Performance Metrics
# ---------------------------------------------------------------------------
@dataclass
class PerformanceMetrics:
"""Portfolio-wide performance metrics computed periodically."""
total_portfolio_value: float
active_pool: float
reserve_pool: float
unrealized_pnl: float
realized_pnl: float
daily_pnl: float
win_count: int
loss_count: int
win_rate: float
avg_win: float
avg_loss: float
profit_factor: float
sharpe_ratio: float
max_drawdown: float
current_drawdown_pct: float
portfolio_heat: float
computed_at: datetime = field(default_factory=datetime.utcnow)
# ---------------------------------------------------------------------------
# Circuit Breaker
# ---------------------------------------------------------------------------
@dataclass
class CircuitBreakerState:
"""Current state of the circuit breaker safety mechanism."""
active: bool = False
trigger_type: str | None = None
triggered_at: datetime | None = None
cooldown_expires: datetime | None = None
ticker_cooldowns: dict[str, datetime] = field(default_factory=dict)
# ---------------------------------------------------------------------------
# Reserve Pool
# ---------------------------------------------------------------------------
@dataclass
class ReservePoolState:
"""Current state of the reserve pool."""
balance: float = 0.0
total_deposits: float = 0.0
total_withdrawals: float = 0.0
last_updated: datetime = field(default_factory=datetime.utcnow)
# ---------------------------------------------------------------------------
# Stop Trigger
# ---------------------------------------------------------------------------
@dataclass
class StopTrigger:
"""A triggered stop-loss or take-profit event for a position."""
ticker: str
trigger_type: str # "stop_loss" or "take_profit"
current_price: float
trigger_price: float