Files
dzentra_bot/docs/migrations/build_047.md

573 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Build 047 — Переключение `ExchangeService.get_klines()` на канонический Candles Feed
**Статус:** Completed
**Дата:** 2026-07-15
**Подсистема:** Market Data Acquisition / OHLCV Feed
**Тип изменения:** Миграция legacy-потребителя на канонический Acquisition pipeline
---
## 1. Цель Build
Цель Build 047 — переключить существующий публичный метод:
```text
ExchangeService.get_klines()
```
с прямого получения и самостоятельной обработки ответа Dzengi `/api/v1/klines` на канонический pipeline подсистемы:
```text
src/market_data/acquisition/
```
При этом необходимо сохранить существующий публичный контракт `ExchangeService.get_klines()` и обратную совместимость с текущими потребителями legacy-слоя.
---
## 2. Исходное состояние
До Build 047 метод:
```text
ExchangeService.get_klines()
```
самостоятельно:
1. выполнял прямой REST-запрос к `/api/v1/klines`;
2. извлекал элементы ответа;
3. разбирал отдельные свечи;
4. создавал legacy-модели `Kline`;
5. формировал `KlineBatch`.
В `ExchangeService` существовали собственные legacy-функции обработки свечей:
```text
_parse_klines_payload()
_extract_klines_items()
_parse_kline_item()
```
Таким образом, после появления канонического Candles Feed в системе существовали два независимых пути получения и обработки OHLCV-данных.
Это создавало дублирование ответственности между:
```text
src/integrations/exchange/
```
и:
```text
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`
Метод:
```text
ExchangeService.get_klines()
```
сохранён как публичный compatibility-контракт.
Внутренний путь получения данных изменён.
До Build 047:
```text
ExchangeService.get_klines()
прямой REST-запрос /api/v1/klines
_parse_klines_payload()
_extract_klines_items()
_parse_kline_item()
Kline
KlineBatch
```
После Build 047:
```text
ExchangeService.get_klines()
_load_candles_via_acquisition()
DzengiCandlesDocumentSource
DzengiCandlesDocumentHandler
CandlesFeed
CandlesFeedRegistry
CandlesAcquisitionService
Candle
_kline_from_candle()
Kline
KlineBatch
```
---
## 5. Канонический путь получения свечей
После Build 047 единственный production-путь прямого обращения к endpoint:
```text
/api/v1/klines
```
расположен в:
```text
src/market_data/acquisition/adapters/dzengi/rest.py
```
Это соответствует архитектурному разделению ответственности:
```text
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:
```text
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()`
Добавлен внутренний адаптер:
```text
ExchangeService._kline_from_candle()
```
Преобразование выполняется по следующему правилу:
```text
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-логика
Из:
```text
src/integrations/exchange/service.py
```
удалены:
```text
_parse_klines_payload()
_extract_klines_items()
_parse_kline_item()
```
Также удалён прямой вызов:
```text
/api/v1/klines
```
из `ExchangeService`.
После Build 047 parsing, schema validation, value validation и mapping OHLCV-данных выполняются только канонической подсистемой:
```text
src/market_data/acquisition/
```
---
## 8. Сохранённая обратная совместимость
Публичный контракт:
```text
ExchangeService.get_klines(...)
```
сохранён.
Существующие production-потребители не изменялись:
```text
src/trading/market_analysis/service.py
src/trading/market_analysis/htf.py
```
Они продолжают работать через:
```text
ExchangeService.get_klines()
```
и получать:
```text
KlineBatch
```
Таким образом, Build 047 меняет внутренний источник данных, но не требует одновременного переписывания legacy-потребителей.
---
## 9. Добавленные тесты
Добавлен специализированный файл:
```text
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-проверки:
```text
26 passed in 0.17s
```
---
## 10. Полная регрессионная проверка
Выполнено:
```bash
python -m pytest -q
```
Результат:
```text
750 passed in 2.83s
```
Регрессий не обнаружено.
---
## 11. Контроль прямого использования `/api/v1/klines`
Команда:
```bash
grep -RIn \
--exclude-dir="__pycache__" \
--exclude="*.pyc" \
'"/api/v1/klines"' \
src
```
Результат:
```text
src/market_data/acquisition/adapters/dzengi/rest.py:17:_KLINES_PATH = "/api/v1/klines"
```
Вывод:
Прямое знание endpoint `/api/v1/klines` находится только в каноническом Dzengi REST-адаптере.
---
## 12. Контроль удаления legacy-парсеров
Команда:
```bash
grep -RIn \
--exclude-dir="__pycache__" \
--exclude="*.pyc" \
"_parse_klines_payload\|_extract_klines_items\|_parse_kline_item" \
src tests
```
Результат:
```text
пусто
```
Вывод:
Legacy-функции обработки kline payload полностью удалены.
---
## 13. Контроль оставшихся потребителей `ExchangeService.get_klines()`
Команда:
```bash
grep -RIn \
--exclude-dir="__pycache__" \
--exclude="*.pyc" \
"\.get_klines(" \
src tests
```
Production-потребители:
```text
src/trading/market_analysis/service.py
src/trading/market_analysis/htf.py
```
Дополнительно присутствуют специализированные вызовы в:
```text
tests/unit/integrations/exchange/test_service_klines.py
```
Вывод:
Публичный compatibility-контракт `ExchangeService.get_klines()` продолжает обслуживать существующие legacy-потребители.
---
## 14. Контроль интеграции с Acquisition pipeline
Команда:
```bash
grep -RIn \
--exclude-dir="__pycache__" \
--exclude="*.pyc" \
"CandlesAcquisitionService\|CandlesFeedRegistry\|DzengiCandlesDocumentSource" \
src/integrations/exchange/service.py
```
Результат подтверждает использование:
```text
DzengiCandlesDocumentSource
CandlesFeedRegistry
CandlesAcquisitionService
```
внутри compatibility boundary `ExchangeService`.
---
## 15. Контроль качества diff
Выполнено:
```bash
git diff --check
```
Результат:
```text
пусто
```
Whitespace-ошибок не обнаружено.
---
## 16. Архитектурный результат
После Build 047 путь OHLCV-данных имеет следующую структуру:
```text
Dzengi REST API
DzengiCandlesDocumentSource
schema validation
parser
value validation
mapper
Candle
CandlesFeed
CandlesFeedRegistry
CandlesAcquisitionService
ExchangeService compatibility boundary
Kline / KlineBatch
legacy trading consumers
```
Главный архитектурный результат:
```text
ExchangeService больше не получает и не разбирает
сырой ответ /api/v1/klines самостоятельно.
```
Владение получением и канонической обработкой OHLCV-данных теперь принадлежит:
```text
src/market_data/acquisition/
```
---
## 17. Состояние после Build 047
На момент завершения Build:
```text
Targeted tests: 26 passed
Full test suite: 750 passed
git diff --check: clean
```
Прямой endpoint:
```text
/api/v1/klines
```
остался только в:
```text
src/market_data/acquisition/adapters/dzengi/rest.py
```
Legacy parsing helpers:
```text
_parse_klines_payload
_extract_klines_items
_parse_kline_item
```
полностью отсутствуют.
Публичный контракт:
```text
ExchangeService.get_klines()
```
сохранён.
---
## 18. Итог Build
**Build 047 завершён успешно.**
Канонический Candles Feed интегрирован в существующий `ExchangeService.get_klines()` без изменения его публичного контракта.
Дублирующая legacy-логика получения и разбора `/api/v1/klines` удалена.
Существующие потребители продолжают работать без изменений.
Полная регрессионная проверка подтверждает отсутствие нарушений существующего поведения:
```text
750 passed
```