15 KiB
Build 037 — Перевод execution-потребителей на canonical Quote
Статус: завершён
Тип изменения: миграция / архитектурный рефакторинг
Подсистема: Market Data / Exchange Integration / Trading Execution
Дата завершения: 13 июля 2026
1. Цель Build
Цель Build 037 — перевести execution-потребителей с legacy-представлений рыночной котировки на каноническую модель Quote, сохранив существующее поведение торговой системы и обратную совместимость переходного периода.
Build продолжает миграционную последовательность:
Build 031 — Quotes Feed
↓
Build 032 — Канонический Quote Store
↓
Build 033 — Перенос MarketPriceCache на Quote Store
↓
Build 034 — Dzengi WebSocket quote parsing и адаптер
↓
Build 035 — Перевод market runtime на Quotes Feed
↓
Build 036 — Перевод read-only и UI-потребителей
↓
Build 037 — Перевод execution-потребителей
После завершения Build 037 execution-контур получает рыночную котировку через канонический Quote, а специализированный execution boundary предоставляет типизированное представление ExecutionPriceSnapshot.
2. Архитектурный принцип
В рамках Build 037 зафиксировано следующее направление зависимости:
Dzengi REST / WebSocket
↓
Market Data Acquisition
↓
canonical Quote
↓
Quote Store
↓
ExchangeService
↓
ExecutionPriceSnapshot
↓
Execution consumers
Execution-потребители не должны самостоятельно:
- разбирать сырой payload биржи;
- знать формат Dzengi REST или WebSocket;
- обращаться напрямую к
Quote Store; - зависеть от legacy
MarketPriceSnapshot; - использовать dict-based market snapshot там, где необходим типизированный execution-контракт;
- самостоятельно определять источник котировки.
Канонический объект рыночной котировки:
Quote
Типизированное представление для execution-контура:
ExecutionPriceSnapshot
3. Область изменений
В рамках Build 037 изменены следующие production-файлы:
src/integrations/exchange/service.py
src/trading/auto/execution_quality.py
src/trading/debug/execution.py
Добавлены специализированные тесты:
tests/unit/integrations/exchange/test_service_execution_quote.py
tests/unit/trading/auto/test_execution_quality.py
tests/unit/trading/debug/test_execution.py
Файл:
src/trading/execution/pricing.py
был проанализирован, но не потребовал production-изменений, поскольку уже использовал типизированный boundary:
ExchangeService().get_execution_snapshot(symbol)
4. Изменения в ExchangeService
4.1. Execution snapshot теперь строится из canonical Quote
Метод:
get_execution_snapshot()
переведён на получение канонической котировки через:
get_quote()
Таким образом, execution boundary больше не зависит от legacy MarketPriceSnapshot.
Целевая цепочка:
Quote Store
↓
canonical Quote
↓
ExchangeService.get_quote()
↓
ExchangeService.get_execution_snapshot()
↓
ExecutionPriceSnapshot
4.2. Сохранён типизированный execution-контракт
Execution-потребители получают:
ExecutionPriceSnapshot
с полями:
symbol
last_price
bid_price
ask_price
updated_at
source
is_fresh
age_seconds
Это позволяет execution-слою работать с явным типизированным контрактом вместо произвольного словаря.
4.3. Сохранена семантика freshness
При построении ExecutionPriceSnapshot сохраняется информация о возрасте котировки:
age_seconds
и состоянии актуальности:
is_fresh
Execution-контур продолжает использовать существующие ограничения максимального возраста котировки.
В частности:
_max_execution_snapshot_age_seconds = 5
остаётся execution-policy и не переносится в слой Market Data.
Это соответствует разделению ответственности:
Market Data
предоставляет Quote и объективный возраст данных
Execution
определяет, допустим ли этот возраст для исполнения сделки
5. Изменения в execution quality
Файл:
src/trading/auto/execution_quality.py
переведён с legacy dict-based market snapshot на типизированный:
ExecutionPriceSnapshot
Ранее execution quality зависел от:
get_market_snapshot()
и извлекал значения через:
snapshot.get("bid_price")
snapshot.get("ask_price")
snapshot.get("last_price")
snapshot.get("age_seconds")
snapshot.get("is_fresh")
После Build 037 используется типизированный execution boundary:
get_execution_snapshot()
и атрибуты:
snapshot.bid_price
snapshot.ask_price
snapshot.last_price
snapshot.age_seconds
snapshot.is_fresh
Это устраняет зависимость execution quality от legacy dict-based представления котировки.
6. Устранение legacy fallback через get_price()
В execution quality существовал fallback через:
ExchangeService().get_price(...)
В рамках Build 037 этот путь устранён из execution-потребителя.
Fallback теперь также проходит через типизированный execution boundary:
ExchangeService().get_execution_snapshot(...)
Таким образом, основной и fallback-пути используют единый контракт данных.
Целевая схема:
canonical Quote
↓
ExecutionPriceSnapshot
├── основной execution path
└── fallback execution path
7. Изменения debug execution
Файл:
src/trading/debug/execution.py
переведён с:
get_fresh_market_snapshot()
на:
get_execution_snapshot()
Debug execution теперь использует тот же типизированный execution boundary, что и production execution.
Это устраняет архитектурное расхождение:
production execution → ExecutionPriceSnapshot
debug execution → legacy dict snapshot
и заменяет его единым подходом:
production execution → ExecutionPriceSnapshot
debug execution → ExecutionPriceSnapshot
8. Side-aware execution pricing
Build 037 сохраняет существующую семантику выбора цены исполнения.
Для входа в LONG:
ask_price
↓ fallback
last_price
Для входа в SHORT:
bid_price
↓ fallback
last_price
Для выхода из LONG:
bid_price
↓ fallback
last_price
Для выхода из SHORT:
ask_price
↓ fallback
last_price
Для общего получения текущей рыночной цены:
last_price
Это поведение не изменялось в рамках Build 037.
9. Что намеренно не изменялось
Build 037 ограничен execution-потребителями.
В рамках данного Build намеренно не переводились:
src/trading/auto/signal_runtime.py
src/trading/strategies/trend.py
src/trading/strategies/scalp.py
Эти файлы относятся к следующему этапу:
Build 038 — Перевод strategy и runtime-потребителей на canonical Quote
Также не выполнялись:
- удаление legacy
get_market_snapshot(); - удаление legacy
get_fresh_market_snapshot(); - удаление
MarketPriceCache; - глобальная перестройка
ExchangeService; - изменение утверждённой структуры каталогов;
- изменение торговой стратегии;
- изменение execution thresholds;
- изменение логики открытия, закрытия или flip позиции.
10. Обратная совместимость
Build 037 выполнен как безопасный миграционный этап.
Legacy API не удалялись, поскольку некоторые потребители ещё используют переходные методы.
Сохраняются:
get_market_snapshot()
get_fresh_market_snapshot()
get_price()
MarketPriceCache
Их удаление допустимо только после полного перевода всех production-потребителей и отдельного контрольного grep.
11. Тестовое покрытие
Для Build 037 добавлены специализированные unit-тесты:
tests/unit/integrations/exchange/test_service_execution_quote.py
tests/unit/trading/auto/test_execution_quality.py
tests/unit/trading/debug/test_execution.py
Тестами подтверждено:
get_execution_snapshot()использует canonicalQuote;- execution service не зависит от legacy market snapshot;
- execution quality использует
ExecutionPriceSnapshot; - legacy
get_market_snapshot()не используется новым execution quality path; - debug execution использует
get_execution_snapshot(); - legacy
get_fresh_market_snapshot()не используется новым debug execution path; - сохраняется корректная передача
last_price; - сохраняется корректная передача
bid_price; - сохраняется корректная передача
ask_price; - сохраняется информация о возрасте котировки;
- сохраняется freshness semantics.
12. Результаты проверки
Проверка синтаксиса:
python -m py_compile \
src/integrations/exchange/service.py \
src/trading/auto/execution_quality.py \
src/trading/debug/execution.py \
tests/unit/integrations/exchange/test_service_execution_quote.py \
tests/unit/trading/auto/test_execution_quality.py \
tests/unit/trading/debug/test_execution.py
Результат:
успешно
Специализированные тесты:
python -m pytest \
tests/unit/integrations/exchange/test_service_execution_quote.py \
tests/unit/trading/auto/test_execution_quality.py \
tests/unit/trading/debug/test_execution.py \
-q
Результат:
4 passed in 0.08s
Полная регрессия:
python -m pytest -q
Результат:
618 passed in 0.28s
13. Изменение количества тестов
До Build 037:
614 passed
После Build 037:
618 passed
Добавлено:
4 теста
14. Итоговая архитектура после Build 037
После завершения Build 037 execution-контур выглядит следующим образом:
Dzengi REST / WebSocket
↓
Market Data Acquisition
↓
canonical Quote
↓
Quote Store
↓
ExchangeService.get_quote()
↓
ExchangeService.get_execution_snapshot()
↓
ExecutionPriceSnapshot
├── trading/execution/pricing.py
├── trading/auto/execution_quality.py
└── trading/debug/execution.py
Legacy market snapshot больше не является обязательным источником данных для переведённых execution-потребителей.
15. Критерии завершения Build 037
Build 037 считается завершённым, поскольку выполнены все обязательные условия:
get_execution_snapshot()строится из canonicalQuote;- execution quality переведён на
ExecutionPriceSnapshot; - debug execution переведён на
ExecutionPriceSnapshot; - legacy
get_price()устранён из изменённого execution fallback path; pricing.pyпроверен и уже использует typed execution boundary;- side-aware pricing сохранён;
- freshness semantics сохранена;
- legacy API не удалены преждевременно;
- специализированные тесты проходят;
- полная регрессия проходит;
- существующая торговая логика не изменена.
16. Следующий этап
Следующий этап миграции:
Build 038 — Перевод strategy и runtime-потребителей на canonical Quote
Основные кандидаты следующего Build:
src/trading/auto/signal_runtime.py
src/trading/strategies/trend.py
src/trading/strategies/scalp.py
Цель Build 038:
убрать зависимость strategy и runtime-потребителей
от legacy dict-based market snapshot и перевести их
на canonical Quote с сохранением существующей торговой семантики.
После Build 038 должен быть выполнен новый контрольный grep для определения оставшихся production-зависимостей от:
get_market_snapshot()
get_fresh_market_snapshot()
get_price()
MarketPriceCache
17. Статус
Build 037 — ЗАВЕРШЁН
Следующий Build:
Build 038 — Перевод strategy и runtime-потребителей на canonical Quote