13 KiB
Build 038 — Перевод strategy и runtime-потребителей на canonical Quote
Dzentra Market Data Migration
Контроль документа
| Свойство | Значение |
|---|---|
| Документ | Build 038 — Перевод strategy и runtime-потребителей на canonical Quote |
| Тип документа | Build Record |
| Версия | 1.0 |
| Статус | Completed |
| Подсистема | Market Data Acquisition |
| Проект | Dzentra |
| Язык | Русский |
| Предыдущий этап | Build 037 — Перевод execution-потребителей |
| Результат полной регрессии | 626 passed |
1. Назначение Build 038
Build 038 завершает перевод выбранных strategy- и runtime-потребителей с legacy snapshot API на каноническую модель рыночной котировки:
Quote
Цель этапа — исключить использование словарных market snapshot в следующих потребителях:
src/trading/auto/signal_runtime.py
src/trading/strategies/trend.py
src/trading/strategies/scalp.py
и перевести их на единый типизированный источник текущей рыночной котировки:
ExchangeService.get_quote()
↓
Quote
2. Контекст предыдущих Build
Build 038 является продолжением последовательной миграции Market Data:
Build 031
↓
Canonical Quote model
Build 032
↓
Quote acquisition pipeline
Build 033
↓
Quote Store
Build 034
↓
Dzengi WebSocket quote parsing и adapter
Build 035
↓
Market runtime переведён на Quotes Feed
Build 036
↓
Read-only и UI-потребители переведены на canonical Quote
Build 037
↓
Execution-потребители переведены на typed execution snapshot
Build 038
↓
Strategy и runtime-потребители переведены на canonical Quote
В результате Build 038 каноническая модель Quote становится непосредственным источником текущей рыночной котировки для выбранных runtime- и strategy-компонентов.
3. Каноническая модель Quote
Используется модель:
@dataclass(frozen=True, slots=True)
class Quote:
symbol: str
last_price: Decimal
bid_price: Decimal
ask_price: Decimal
exchange_timestamp: datetime | None
received_at: datetime
source: str
Модель расположена в:
src/market_data/acquisition/models/quote.py
Основные свойства модели:
- независимость от конкретного поставщика рыночных данных;
- типизированные цены через
Decimal; - отсутствие словарного доступа к ценовым полям;
- наличие времени биржи;
- наличие времени получения данных;
- явное указание источника.
4. Изменённые runtime-потребители
4.1. Auto Signal Runtime
Файл:
src/trading/auto/signal_runtime.py
Legacy-путь:
ExchangeService.get_market_snapshot()
↓
dict[str, object]
↓
snapshot.get("bid_price")
snapshot.get("ask_price")
snapshot.get("last_price")
Новый путь:
ExchangeService.get_quote()
↓
Quote
↓
quote.bid_price
quote.ask_price
quote.last_price
В результате runtime больше не зависит от словарного представления текущей рыночной котировки.
5. Изменённые strategy-потребители
5.1. Trend Strategy
Файл:
src/trading/strategies/trend.py
Стратегия переведена с legacy market snapshot на canonical Quote.
Новый источник:
ExchangeService.get_quote(
symbol,
runtime_key="auto",
)
Ценовые данные теперь читаются непосредственно из типизированной модели:
quote.last_price
quote.bid_price
quote.ask_price
Сохранена существующая логика выбора цены анализа:
1. midpoint между bid и ask;
2. last_price;
3. 0.0 при отсутствии пригодной цены.
Midpoint остаётся предпочтительной ценой анализа:
(bid + ask) / 2
Это позволяет уменьшить зависимость анализа от случайного последнего исполнения сделки.
5.2. Scalp Strategy
Файл:
src/trading/strategies/scalp.py
Стратегия также переведена на:
ExchangeService.get_quote(
symbol,
runtime_key="auto",
)
Ценовые поля теперь получаются через:
quote.last_price
quote.bid_price
quote.ask_price
Сохранены:
- существующая логика определения analysis price;
- midpoint между bid и ask;
- fallback на
last_price; - safe fallback;
- существующие strategy payload;
- существующие торговые пороги;
- существующая логика принятия решений.
6. Обработка Decimal
Canonical Quote использует:
Decimal
для полей:
last_price
bid_price
ask_price
Существующие strategy helper-функции _safe_float() ранее принимали:
NumericLike | None
где Decimal не входил в контракт NumericLike.
Это приводило к ошибкам статической типизации Pylance:
Аргумент типа "Decimal" нельзя присвоить параметру "value"
типа "NumericLike | None"
В рамках Build 038 контракт локальных strategy helper-функций расширен до:
value: NumericLike | Decimal | None
Глобальный тип:
NumericLike
не изменялся.
Это сохраняет локальность изменения и не расширяет общий типовой контракт проекта без необходимости.
Архитектурная граница имеет вид:
canonical Quote
↓
Decimal
↓
strategy helper
↓
float
↓
существующие strategy calculations и payload
7. Что намеренно не изменялось
Build 038 не изменяет:
- структуру canonical
Quote; QuoteStore;- acquisition pipeline;
- WebSocket adapter;
- REST adapter;
- market runtime producer;
- execution pricing semantics;
- торговые пороги;
- логику открытия позиции;
- логику закрытия позиции;
- flip-логику;
- risk management;
- journal payload contracts;
- strategy payload keys;
- Telegram UI;
- структуру каталогов проекта.
Build 038 является локальным этапом миграции потребителей, а не изменением торговой логики.
8. Контроль legacy-зависимостей
После выполнения Build 038 выполнен контрольный поиск:
grep -RIn \
--exclude-dir="__pycache__" \
--exclude="*.pyc" \
-E "get_market_snapshot\(|get_fresh_market_snapshot\(|get_execution_snapshot\(|get_price\(|snapshot\.get\(|quote\.get\(|runtime_key" \
src/trading/auto/signal_runtime.py \
src/trading/strategies/trend.py \
src/trading/strategies/scalp.py
Результат:
src/trading/auto/signal_runtime.py:881: runtime_key="auto",
src/trading/strategies/trend.py:244: runtime_key="auto",
src/trading/strategies/scalp.py:64: runtime_key="auto",
Legacy-вызовы не обнаружены.
В проверенных файлах отсутствуют рабочие зависимости от:
get_market_snapshot()
get_fresh_market_snapshot()
get_execution_snapshot()
get_price()
snapshot.get(...)
quote.get(...)
Оставшиеся:
runtime_key="auto"
являются ожидаемой частью вызова get_quote() и не представляют legacy-зависимость.
9. Проверка синтаксиса
Выполнена проверка:
python -m py_compile \
src/trading/auto/signal_runtime.py \
src/trading/strategies/trend.py \
src/trading/strategies/scalp.py
Результат:
успешно
Ошибки синтаксиса отсутствуют.
10. Целевые тесты
После исправления типизации Decimal выполнены целевые тесты:
python -m pytest \
tests/unit/trading/strategies/test_trend_quote.py \
tests/unit/trading/strategies/test_scalp_quote.py \
-q
Результат:
...... [100%]
6 passed in 0.09s
11. Полная регрессия
Выполнена полная проверка проекта:
python -m pytest -q
Результат:
626 passed in 0.31s
Регрессий не обнаружено.
Для сравнения:
После Build 037: 618 passed
После Build 038: 626 passed
Количество тестов увеличено на:
8
12. Итоговая архитектура после Build 038
После завершения Build 038 путь текущей рыночной котировки для мигрированных strategy- и runtime-потребителей выглядит следующим образом:
Dzengi WebSocket
↓
DzengiWebSocketQuoteAdapter
↓
canonical Quote
↓
Quote Store
↓
ExchangeService.get_quote()
├── Auto Signal Runtime
├── Trend Strategy
└── Scalp Strategy
Для execution-контура сохраняется специализированная типизированная граница, введённая в Build 037:
canonical Quote
↓
ExchangeService
↓
ExecutionPriceSnapshot
↓
Execution consumers
Таким образом, после Build 038 разделены два типа потребления:
Market / Strategy / Runtime
↓
canonical Quote
Execution
↓
ExecutionPriceSnapshot
13. Архитектурный результат
Build 038 устраняет ещё один слой legacy market snapshot API из рабочего торгового контура.
До Build 038:
Market Data
↓
legacy dict snapshot
↓
snapshot.get(...)
↓
runtime / strategies
После Build 038:
Market Data
↓
canonical Quote
↓
typed attributes
↓
runtime / strategies
Это обеспечивает:
- единый канонический контракт текущей котировки;
- статическую типизацию;
- отказ от строковых ключей для доступа к ценам;
- явную работу с
Decimal; - уменьшение зависимости trading layer от legacy exchange representations;
- подготовку к дальнейшему удалению legacy snapshot API.
14. Критерии завершения
Build 038 считается завершённым, поскольку выполнены все критерии:
signal_runtime.pyпереведён на canonicalQuote;trend.pyпереведён на canonicalQuote;scalp.pyпереведён на canonicalQuote;- legacy
get_market_snapshot()удалён из мигрированных путей; - словарный доступ
snapshot.get(...)к текущей котировке удалён; - типизация
Decimalобработана явно; - глобальный
NumericLikeне изменён; - существующая торговая логика сохранена;
- strategy payload contracts сохранены;
py_compileпроходит успешно;- целевые тесты проходят успешно;
- полная регрессия проходит успешно;
- итоговый результат — 626 passed.
15. Статус
Build 038: COMPLETED
Build 038 завершён и зафиксирован.
Система готова к следующему этапу миграции.