Files
dzentra_bot/docs/migrations/build_037.md

15 KiB
Raw Blame History

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() использует canonical Quote;
  • 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() строится из canonical Quote;
  • 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