build 039: complete Quotes Feed migration foundation

This commit is contained in:
2026-07-14 09:58:16 +03:00
parent 26deb861bc
commit 7b62873832
443 changed files with 80452 additions and 1335 deletions

View File

@@ -0,0 +1 @@
# app/src/trading/decision/__init__.py

View File

@@ -0,0 +1,19 @@
# app/src/trading/decision/exceptions.py
from __future__ import annotations
class TradingError(Exception):
"""Базовая ошибка Trading Layer."""
class InvalidTradingDecisionError(TradingError):
"""Trading Layer сформировал некорректное торговое решение."""
class TradingValidationError(TradingError):
"""Ошибка проверки входных данных Trading Layer."""
class TradingExecutionError(TradingError):
"""Ошибка выполнения Trading Layer."""

View File

@@ -0,0 +1,67 @@
# 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

View File

@@ -0,0 +1,19 @@
# app/src/trading/decision/protocol.py
from __future__ import annotations
from typing import Protocol
from src.trading.market_intelligence.common.models import CoordinatorResult
from src.trading.decision.models import TradingDecision
class TradingProtocol(Protocol):
"""Контракт Trading Layer."""
async def decide(
self,
coordinator_result: CoordinatorResult,
) -> TradingDecision:
"""Принять торговое решение на основе CoordinatorResult."""
...

View File

@@ -0,0 +1,65 @@
# app/src/trading/decision/rules.py
from __future__ import annotations
from src.trading.market_intelligence.common.enums import EngineStatus
from src.trading.market_intelligence.common.models import CoordinatorResult
from src.trading.decision.models import (
TradingDecision,
TradingDiagnostics,
TradingEvaluationMeta,
)
from src.trading.market_intelligence.common.reasons import ReasonCode
from src.trading.market_intelligence.common.scores import (
EngineConfidence,
EngineScore,
)
class TradingRules:
"""Правила формирования торгового решения."""
def decide(
self,
coordinator_result: CoordinatorResult,
) -> TradingDecision:
"""Сформировать TradingDecision."""
return TradingDecision(
coordinator_result=coordinator_result,
diagnostics=TradingDiagnostics(),
meta=TradingEvaluationMeta(
trading_version="1.0",
),
status=self._resolve_status(coordinator_result),
score=self._resolve_score(coordinator_result),
confidence=self._resolve_confidence(coordinator_result),
reason=self._resolve_reason(coordinator_result),
)
def _resolve_status(
self,
coordinator_result: CoordinatorResult,
) -> EngineStatus:
"""Определить итоговый статус Trading."""
return coordinator_result.status
def _resolve_score(
self,
coordinator_result: CoordinatorResult,
) -> EngineScore:
"""Вычислить итоговый Score."""
return EngineScore()
def _resolve_confidence(
self,
coordinator_result: CoordinatorResult,
) -> EngineConfidence:
"""Вычислить итоговый Confidence."""
return EngineConfidence()
def _resolve_reason(
self,
coordinator_result: CoordinatorResult,
) -> ReasonCode:
"""Определить причину принятого решения."""
return ReasonCode.UNKNOWN

View File

@@ -0,0 +1,29 @@
# app/src/trading/decision/service.py
from __future__ import annotations
from src.trading.market_intelligence.common.models import CoordinatorResult
from src.trading.decision.models import TradingDecision
from src.trading.decision.protocol import TradingProtocol
from src.trading.decision.rules import TradingRules
from src.trading.decision.validation import (
TradingValidation,
)
class TradingService(TradingProtocol):
"""Единая публичная точка входа Trading Layer."""
def __init__(self) -> None:
"""Создать Trading Service."""
self._validation = TradingValidation()
self._rules = TradingRules()
async def decide(
self,
coordinator_result: CoordinatorResult,
) -> TradingDecision:
"""Сформировать торговое решение."""
self._validation.validate(coordinator_result)
return self._rules.decide(coordinator_result)

View File

@@ -0,0 +1,51 @@
# app/src/trading/decision/validation.py
from __future__ import annotations
from src.trading.market_intelligence.common.models import CoordinatorResult
from src.trading.decision.exceptions import (
TradingValidationError,
)
class TradingValidation:
"""Проверка входного CoordinatorResult для Trading Layer."""
def validate(
self,
coordinator_result: CoordinatorResult,
) -> None:
"""Проверить CoordinatorResult перед принятием торгового решения."""
self._validate_result_exists(coordinator_result)
self._validate_result_usable(coordinator_result)
self._validate_result_has_no_errors(coordinator_result)
def _validate_result_exists(
self,
coordinator_result: CoordinatorResult,
) -> None:
"""Проверить, что CoordinatorResult передан."""
if coordinator_result is None:
raise TradingValidationError(
"CoordinatorResult is required for Trading."
)
def _validate_result_usable(
self,
coordinator_result: CoordinatorResult,
) -> None:
"""Проверить пригодность CoordinatorResult для принятия решения."""
if not coordinator_result.is_usable:
raise TradingValidationError(
"CoordinatorResult is not usable."
)
def _validate_result_has_no_errors(
self,
coordinator_result: CoordinatorResult,
) -> None:
"""Проверить отсутствие критических ошибок Coordinator."""
if coordinator_result.has_errors:
raise TradingValidationError(
"CoordinatorResult contains errors."
)