# app/src/trading/decision/models.py from __future__ import annotations from dataclasses import dataclass, field from src.trading.market_intelligence.common.enums import EngineStatus from src.trading.market_intelligence.common.models import CoordinatorResult from src.trading.market_intelligence.common.reasons import ReasonCode from src.trading.market_intelligence.common.scores import ( EngineConfidence, EngineScore, ) from src.trading.market_intelligence.common.types import ( ContextDict, DiagnosticMessages, DurationMs, PayloadDict, ) @dataclass(frozen=True, slots=True) class TradingDiagnostics: reason: ReasonCode = ReasonCode.UNKNOWN details: ContextDict = field(default_factory=dict) warnings: DiagnosticMessages = field(default_factory=list) errors: DiagnosticMessages = field(default_factory=list) @property def has_warnings(self) -> bool: return bool(self.warnings) @property def has_errors(self) -> bool: return bool(self.errors) @dataclass(frozen=True, slots=True) class TradingEvaluationMeta: trading_version: str calculated_at: float | None = None duration_ms: DurationMs | None = None @dataclass(frozen=True, slots=True) class TradingDecision: coordinator_result: CoordinatorResult diagnostics: TradingDiagnostics = field(default_factory=TradingDiagnostics) meta: TradingEvaluationMeta | None = None payload: PayloadDict = field(default_factory=dict) status: EngineStatus = EngineStatus.UNKNOWN score: EngineScore = field(default_factory=EngineScore) confidence: EngineConfidence = field(default_factory=EngineConfidence) reason: ReasonCode = ReasonCode.UNKNOWN @property def is_usable(self) -> bool: return self.status in { EngineStatus.OK, EngineStatus.PARTIAL, EngineStatus.STALE, } @property def has_errors(self) -> bool: return self.diagnostics.has_errors