Files
dzentra_bot/docs/migrations/build_047.md

14 KiB
Raw Blame History

Build 047 — Переключение ExchangeService.get_klines() на канонический Candles Feed

Статус: Completed
Дата: 2026-07-15
Подсистема: Market Data Acquisition / OHLCV Feed
Тип изменения: Миграция legacy-потребителя на канонический Acquisition pipeline


1. Цель Build

Цель Build 047 — переключить существующий публичный метод:

ExchangeService.get_klines()

с прямого получения и самостоятельной обработки ответа Dzengi /api/v1/klines на канонический pipeline подсистемы:

src/market_data/acquisition/

При этом необходимо сохранить существующий публичный контракт ExchangeService.get_klines() и обратную совместимость с текущими потребителями legacy-слоя.


2. Исходное состояние

До Build 047 метод:

ExchangeService.get_klines()

самостоятельно:

  1. выполнял прямой REST-запрос к /api/v1/klines;
  2. извлекал элементы ответа;
  3. разбирал отдельные свечи;
  4. создавал legacy-модели Kline;
  5. формировал KlineBatch.

В ExchangeService существовали собственные legacy-функции обработки свечей:

_parse_klines_payload()
_extract_klines_items()
_parse_kline_item()

Таким образом, после появления канонического Candles Feed в системе существовали два независимых пути получения и обработки OHLCV-данных.

Это создавало дублирование ответственности между:

src/integrations/exchange/

и:

src/market_data/acquisition/

3. Границы Build

В Build 047 выполнено:

  1. переключение внутренней реализации ExchangeService.get_klines() на канонический Candles Feed;
  2. сохранение публичного контракта ExchangeService.get_klines();
  3. сохранение legacy-моделей Kline и KlineBatch;
  4. добавление внутреннего адаптационного преобразования Candle -> Kline;
  5. удаление прямого REST-запроса /api/v1/klines из ExchangeService;
  6. удаление legacy-функций:
    • _parse_klines_payload();
    • _extract_klines_items();
    • _parse_kline_item();
  7. добавление специализированных unit-тестов для ExchangeService.get_klines() и его интеграции с каноническим Acquisition pipeline.

В Build 047 не выполнялось:

  • изменение публичного контракта ExchangeService.get_klines();
  • изменение legacy-потребителей в trading/market_analysis;
  • удаление моделей Kline и KlineBatch;
  • прямое переключение trading/market_analysis на CandlesAcquisitionService;
  • изменение архитектуры других Market Data feeds;
  • изменение runtime-компонентов Acquisition.

4. Изменённые production-файлы

4.1. src/integrations/exchange/service.py

Метод:

ExchangeService.get_klines()

сохранён как публичный compatibility-контракт.

Внутренний путь получения данных изменён.

До Build 047:

ExchangeService.get_klines()
    ↓
прямой REST-запрос /api/v1/klines
    ↓
_parse_klines_payload()
    ↓
_extract_klines_items()
    ↓
_parse_kline_item()
    ↓
Kline
    ↓
KlineBatch

После Build 047:

ExchangeService.get_klines()
    ↓
_load_candles_via_acquisition()
    ↓
DzengiCandlesDocumentSource
    ↓
DzengiCandlesDocumentHandler
    ↓
CandlesFeed
    ↓
CandlesFeedRegistry
    ↓
CandlesAcquisitionService
    ↓
Candle
    ↓
_kline_from_candle()
    ↓
Kline
    ↓
KlineBatch

5. Канонический путь получения свечей

После Build 047 единственный production-путь прямого обращения к endpoint:

/api/v1/klines

расположен в:

src/market_data/acquisition/adapters/dzengi/rest.py

Это соответствует архитектурному разделению ответственности:

Exchange-specific transport
    ↓
Market Data Acquisition
    ↓
Canonical Candle
    ↓
Legacy compatibility boundary
    ↓
Kline / KlineBatch

ExchangeService больше не владеет транспортной логикой получения OHLCV-данных от Dzengi.


6. Добавленные внутренние методы

6.1. _load_candles_via_acquisition()

Добавлен внутренний compatibility-helper:

ExchangeService._load_candles_via_acquisition()

Его ответственность:

  1. создать DzengiCandlesDocumentSource;
  2. создать DzengiCandlesDocumentHandler;
  3. создать CandlesFeed;
  4. зарегистрировать feed в CandlesFeedRegistry;
  5. создать CandlesAcquisitionService;
  6. вызвать канонический load_candles();
  7. вернуть immutable-набор моделей Candle.

Метод является внутренней границей между legacy ExchangeService и канонической подсистемой Market Data Acquisition.

6.2. _kline_from_candle()

Добавлен внутренний адаптер:

ExchangeService._kline_from_candle()

Преобразование выполняется по следующему правилу:

Candle.symbol       -> Kline.symbol
Candle.interval     -> Kline.interval
Candle.open_time    -> Kline.open_time
Candle.open_price   -> Kline.open_price
Candle.high_price   -> Kline.high_price
Candle.low_price    -> Kline.low_price
Candle.close_price  -> Kline.close_price
Candle.volume       -> Kline.volume

Это позволяет сохранить существующий legacy-контракт без переноса legacy-моделей внутрь market_data/acquisition.


7. Удалённая legacy-логика

Из:

src/integrations/exchange/service.py

удалены:

_parse_klines_payload()
_extract_klines_items()
_parse_kline_item()

Также удалён прямой вызов:

/api/v1/klines

из ExchangeService.

После Build 047 parsing, schema validation, value validation и mapping OHLCV-данных выполняются только канонической подсистемой:

src/market_data/acquisition/

8. Сохранённая обратная совместимость

Публичный контракт:

ExchangeService.get_klines(...)

сохранён.

Существующие production-потребители не изменялись:

src/trading/market_analysis/service.py
src/trading/market_analysis/htf.py

Они продолжают работать через:

ExchangeService.get_klines()

и получать:

KlineBatch

Таким образом, Build 047 меняет внутренний источник данных, но не требует одновременного переписывания legacy-потребителей.


9. Добавленные тесты

Добавлен специализированный файл:

tests/unit/integrations/exchange/test_service_klines.py

Тесты покрывают:

  • использование default_symbol;
  • нормализацию limit;
  • нормализацию interval;
  • отклонение неподдерживаемого interval;
  • передачу price_type;
  • обработку выключенной биржи;
  • обработку неизвестного символа;
  • передачу параметров в Acquisition pipeline;
  • преобразование Candle в Kline;
  • формирование KlineBatch;
  • обработку пустого набора свечей;
  • обработку исключений канонического Acquisition pipeline;
  • построение полного composition pipeline;
  • сохранение публичного legacy-контракта.

Результат targeted-проверки:

26 passed in 0.17s

10. Полная регрессионная проверка

Выполнено:

python -m pytest -q

Результат:

750 passed in 2.83s

Регрессий не обнаружено.


11. Контроль прямого использования /api/v1/klines

Команда:

grep -RIn \
  --exclude-dir="__pycache__" \
  --exclude="*.pyc" \
  '"/api/v1/klines"' \
  src

Результат:

src/market_data/acquisition/adapters/dzengi/rest.py:17:_KLINES_PATH = "/api/v1/klines"

Вывод:

Прямое знание endpoint /api/v1/klines находится только в каноническом Dzengi REST-адаптере.


12. Контроль удаления legacy-парсеров

Команда:

grep -RIn \
  --exclude-dir="__pycache__" \
  --exclude="*.pyc" \
  "_parse_klines_payload\|_extract_klines_items\|_parse_kline_item" \
  src tests

Результат:

пусто

Вывод:

Legacy-функции обработки kline payload полностью удалены.


13. Контроль оставшихся потребителей ExchangeService.get_klines()

Команда:

grep -RIn \
  --exclude-dir="__pycache__" \
  --exclude="*.pyc" \
  "\.get_klines(" \
  src tests

Production-потребители:

src/trading/market_analysis/service.py
src/trading/market_analysis/htf.py

Дополнительно присутствуют специализированные вызовы в:

tests/unit/integrations/exchange/test_service_klines.py

Вывод:

Публичный compatibility-контракт ExchangeService.get_klines() продолжает обслуживать существующие legacy-потребители.


14. Контроль интеграции с Acquisition pipeline

Команда:

grep -RIn \
  --exclude-dir="__pycache__" \
  --exclude="*.pyc" \
  "CandlesAcquisitionService\|CandlesFeedRegistry\|DzengiCandlesDocumentSource" \
  src/integrations/exchange/service.py

Результат подтверждает использование:

DzengiCandlesDocumentSource
CandlesFeedRegistry
CandlesAcquisitionService

внутри compatibility boundary ExchangeService.


15. Контроль качества diff

Выполнено:

git diff --check

Результат:

пусто

Whitespace-ошибок не обнаружено.


16. Архитектурный результат

После Build 047 путь OHLCV-данных имеет следующую структуру:

Dzengi REST API
    ↓
DzengiCandlesDocumentSource
    ↓
schema validation
    ↓
parser
    ↓
value validation
    ↓
mapper
    ↓
Candle
    ↓
CandlesFeed
    ↓
CandlesFeedRegistry
    ↓
CandlesAcquisitionService
    ↓
ExchangeService compatibility boundary
    ↓
Kline / KlineBatch
    ↓
legacy trading consumers

Главный архитектурный результат:

ExchangeService больше не получает и не разбирает
сырой ответ /api/v1/klines самостоятельно.

Владение получением и канонической обработкой OHLCV-данных теперь принадлежит:

src/market_data/acquisition/

17. Состояние после Build 047

На момент завершения Build:

Targeted tests: 26 passed
Full test suite: 750 passed
git diff --check: clean

Прямой endpoint:

/api/v1/klines

остался только в:

src/market_data/acquisition/adapters/dzengi/rest.py

Legacy parsing helpers:

_parse_klines_payload
_extract_klines_items
_parse_kline_item

полностью отсутствуют.

Публичный контракт:

ExchangeService.get_klines()

сохранён.


18. Итог Build

Build 047 завершён успешно.

Канонический Candles Feed интегрирован в существующий ExchangeService.get_klines() без изменения его публичного контракта.

Дублирующая legacy-логика получения и разбора /api/v1/klines удалена.

Существующие потребители продолжают работать без изменений.

Полная регрессионная проверка подтверждает отсутствие нарушений существующего поведения:

750 passed