4ffde8cc06
- 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
254 lines
7.0 KiB
Python
254 lines
7.0 KiB
Python
"""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
|