Files
dzentra_bot/docs/migrations/build_045.md

17 KiB
Raw Blame History

Build 045 — регистрация канонического Candles Feed

Статус

Завершён


Цель Build

Продолжить поэтапную миграцию OHLCV Feed в утверждённую архитектуру Market Data Acquisition после завершения фундаментального слоя Candles Feed в Build 044.

Build 045 добавляет реестр канонических источников свечей и завершает следующий минимальный архитектурный шаг:

Candles Feed
    ↓
CandlesFeedRegistry

При этом:

  • существующий runtime не переключается;
  • ExchangeService.get_klines() не изменяется;
  • legacy-путь получения свечей продолжает работать;
  • новая архитектура остаётся изолированной от существующего торгового runtime;
  • обратная совместимость полностью сохраняется.

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

До Build 045 проект уже содержал фундамент канонического Candles Feed, созданный в Build 044:

REST /api/v1/klines
    ↓
DzengiCandlesDocumentSource
    ↓
validate_candles_schema()
    ↓
parse_candles()
    ↓
validate_candles_values()
    ↓
map_candles()
    ↓
Candle
    ↓
DzengiCandlesDocumentHandler
    ↓
CandlesFeed

Также существовали:

  • каноническая модель Candle;
  • транспортная raw-модель Dzengi для свечей;
  • REST document source;
  • schema validation;
  • parser;
  • value validation;
  • mapper;
  • document handler;
  • CandlesFeed;
  • протоколы Candles Feed;
  • специализированные исключения;
  • unit-тесты фундаментального слоя.

Однако отсутствовал реестр, позволяющий регистрировать и выбирать конкретный CandlesFeed по имени источника.


Объём изменений

Build 045 изменяет только следующие файлы:

src/market_data/acquisition/exceptions.py
src/market_data/acquisition/registry.py
tests/unit/market_data/acquisition/test_registry.py
docs/migrations/build_045.md

Build не изменяет:

src/market_data/acquisition/service.py
src/integrations/exchange/service.py
src/integrations/exchange/models.py
src/trading/
src/telegram/

1. Исключение CandleFeedRegistryError

В файл:

src/market_data/acquisition/exceptions.py

добавлено специализированное исключение:

class CandleFeedRegistryError(MarketDataAcquisitionError):
    pass

Назначение исключения — изолировать ошибки регистрации и получения Candles Feed от других ошибок подсистемы Market Data Acquisition.

Иерархия:

MarketDataAcquisitionError
    ↓
CandleFeedRegistryError

2. Реестр CandlesFeedRegistry

В файл:

src/market_data/acquisition/registry.py

добавлен класс:

CandlesFeedRegistry

Реестр отвечает исключительно за регистрацию и получение реализаций:

CandlesFeedProtocol

Реестр не выполняет:

  • REST-запросы;
  • schema validation;
  • parsing;
  • value validation;
  • mapping;
  • хранение свечей;
  • управление runtime;
  • переключение legacy-потребителей.

3. Контракт реестра

CandlesFeedRegistry предоставляет только операции регистрации и получения Candles Feed.

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

register()
get()

Внутренняя нормализация имени источника выполняется методом:

_normalize_source_name()

Концептуально:

source name
    ↓
CandlesFeedRegistry
    ↓
CandlesFeedProtocol

Пример:

"dzengi"
    ↓
CandlesFeedRegistry
    ↓
CandlesFeed

Реестр принимает только объекты, соответствующие каноническому контракту:

CandlesFeedProtocol

4. Нормализация имени источника

Имена источников нормализуются перед использованием.

Поддерживается удаление внешних пробелов:

"dzengi"
"  dzengi  "

После нормализации оба значения соответствуют одному ключу:

dzengi

Пустые имена источников не допускаются.

Регистр символов сохраняется. Имена источников являются case-sensitive:

"dzengi"

и:

"DZENGI"

считаются разными именами источников.


5. Защита от некорректной регистрации

CandlesFeedRegistry отклоняет:

  • пустое имя источника;
  • имя, состоящее только из пробелов;
  • объект, не соответствующий CandlesFeedProtocol;
  • повторную регистрацию уже существующего нормализованного имени источника.

Ошибки представлены через:

CandleFeedRegistryError

6. Защита от повторной регистрации

Повторная регистрация одного и того же нормализованного имени источника запрещена.

Пример:

register("dzengi", feed_a)
    ↓
dzengi → feed_a

Повторная регистрация:

register("dzengi", feed_b)
    ↓
CandleFeedRegistryError

Исходный Feed при ошибке повторной регистрации не заменяется.

Для замены зарегистрированного Feed требуется отдельное явное изменение архитектурного контракта. В Build 045 такая возможность не добавлялась.


7. Получение зарегистрированного Feed

Зарегистрированный Candles Feed может быть получен по имени источника.

Концептуально:

registry.get("dzengi")
    ↓
CandlesFeedProtocol

При успешном получении реестр возвращает тот же объект Feed, который был ранее зарегистрирован:

feed = CandlesFeed(...)

registry.register("dzengi", feed)

registry.get("dzengi") is feed
    ↓
True

Попытка получить неизвестный источник приводит к:

CandleFeedRegistryError

8. Ограниченный публичный контракт

Публичный контракт CandlesFeedRegistry в Build 045 ограничен двумя операциями:

register()
get()

В Build 045 намеренно не добавлены:

contains()
remove()
replace()
clear()

Реестр не предоставляет управление жизненным циклом зарегистрированных Feed и не выполняет их запуск или остановку.

Такое ограничение соответствует принципу минимального безопасного Build: добавляется только функциональность, необходимая для последующей интеграции Candles Feed в сервисный слой.


9. Изоляция от Acquisition Service

В рамках Build 045 намеренно не добавлялись:

CandlesAcquisitionService

или метод:

load_candles()

в существующий:

src/market_data/acquisition/service.py

Архитектурная проверка:

grep -RIn \
  --exclude-dir="__pycache__" \
  --exclude="*.pyc" \
  "CandlesAcquisitionService\|load_candles" \
  src/market_data/acquisition/service.py

Результат:

пусто

Это подтверждает, что Build 045 ограничен добавлением реестра и не выполняет преждевременную интеграцию сервисного слоя.


10. Изоляция от legacy runtime

Build 045 не изменяет существующий runtime-путь получения свечей:

Trading / Market Analysis
    ↓
ExchangeService.get_klines()
    ↓
legacy parsing
    ↓
KlineBatch

После Build 045 этот путь продолжает работать без изменений.

Новый канонический путь пока существует параллельно:

DzengiCandlesDocumentSource
    ↓
DzengiCandlesDocumentHandler
    ↓
CandlesFeed
    ↓
CandlesFeedRegistry

Таким образом, в системе временно существуют два пути:

Legacy runtime path
    +
Canonical Candles Feed path

Это ожидаемое переходное состояние безопасной поэтапной миграции.


11. Unit-тесты

Расширен файл:

tests/unit/market_data/acquisition/test_registry.py

Добавлено покрытие для:

  • создания CandlesFeedRegistry;
  • регистрации Candles Feed;
  • получения зарегистрированного Feed;
  • нормализации внешних пробелов имени источника;
  • case-sensitive поведения имён источников;
  • отклонения пустого имени;
  • отклонения имени, состоящего только из пробелов;
  • отклонения объекта, не соответствующего CandlesFeedProtocol;
  • защиты от повторной регистрации;
  • проверки, что повторная регистрация не заменяет исходный Feed;
  • получения неизвестного источника;
  • сохранения identity зарегистрированного Feed;
  • отсутствия вызова load_candles() при регистрации Feed;
  • отсутствия вызова load_candles() при получении Feed;
  • соответствия зарегистрированного объекта CandlesFeedProtocol;
  • корректной работы специализированного CandleFeedRegistryError.

12. Результаты targeted-тестов

Выполнена команда:

python -m pytest -q \
  tests/unit/market_data/acquisition/test_registry.py

Результат:

61 passed in 0.04s

13. Результаты полного набора тестов

Выполнена команда:

python -m pytest -q

Результат:

707 passed in 2.87s

Все unit-тесты проекта проходят успешно.


14. Архитектурная проверка реестра

Выполнена команда:

grep -RIn \
  --exclude-dir="__pycache__" \
  --exclude="*.pyc" \
  "CandlesFeedRegistry\|CandleFeedRegistryError" \
  src tests

Результат подтверждает, что новые сущности находятся только в ожидаемых областях:

src/market_data/acquisition/registry.py
src/market_data/acquisition/exceptions.py
tests/unit/market_data/acquisition/test_registry.py

Неожиданных зависимостей не обнаружено.


15. Проверка отсутствия преждевременной сервисной интеграции

Выполнена команда:

grep -RIn \
  --exclude-dir="__pycache__" \
  --exclude="*.pyc" \
  "CandlesAcquisitionService\|load_candles" \
  src/market_data/acquisition/service.py

Результат:

пусто

Это подтверждает, что Build 045 не расширяет MarketDataAcquisitionService и не переключает runtime.


16. Проверка синтаксиса

Выполнена команда:

python -m compileall \
  src/market_data/acquisition/exceptions.py \
  src/market_data/acquisition/registry.py \
  tests/unit/market_data/acquisition/test_registry.py

Результат:

успешно

Ошибок синтаксиса не обнаружено.


17. Проверка форматирования diff

Первоначальная проверка:

git diff --check

обнаружила одну лишнюю пустую строку в конце:

app/tests/unit/market_data/acquisition/test_registry.py:691: new blank line at EOF.

После удаления лишней пустой строки необходимо повторно выполнить:

git diff --check

Финальный ожидаемый результат:

пустой вывод

До создания commit эта проверка должна быть подтверждена.


18. Итоговая архитектура после Build 045

После завершения Build 045 канонический Candles Feed имеет следующую структуру:

Dzengi REST /api/v1/klines
    ↓
DzengiCandlesDocumentSource
    ↓
validate_candles_schema()
    ↓
parse_candles()
    ↓
validate_candles_values()
    ↓
map_candles()
    ↓
Candle
    ↓
DzengiCandlesDocumentHandler
    ↓
CandlesFeed
    ↓
CandlesFeedRegistry

При этом существующий production/runtime-путь остаётся неизменным:

Trading / Market Analysis
    ↓
ExchangeService.get_klines()
    ↓
legacy parsing
    ↓
KlineBatch

19. Что намеренно не входит в Build 045

Build 045 намеренно не выполняет:

  • интеграцию Candles Feed в MarketDataAcquisitionService;
  • изменение ExchangeService.get_klines();
  • изменение Kline;
  • изменение KlineBatch;
  • переключение trading/market_analysis;
  • переключение HTF-анализа;
  • удаление legacy parser свечей;
  • добавление постоянного Candle Store;
  • изменение runtime;
  • изменение Telegram UI;
  • изменение торговой логики.

Эти ограничения являются частью стратегии безопасной миграции.


20. Следующий Build

Следующий минимальный безопасный этап:

Build 046 — интеграция канонического Candles Feed в MarketDataAcquisitionService

Предполагаемая цель:

CandlesFeedRegistry
    ↓
MarketDataAcquisitionService
    ↓
load_candles(...)
    ↓
tuple[Candle, ...]

Build 046 должен:

  • добавить поддержку CandlesFeedRegistry в сервисный слой Market Data Acquisition;
  • добавить публичный метод загрузки свечей через канонический сервис;
  • сохранить существующие Instrument Reference Data и Quotes Feed без изменений;
  • не переключать ExchangeService.get_klines();
  • не удалять legacy Kline и KlineBatch;
  • не изменять торговую логику;
  • сохранить полную обратную совместимость.

Итог

Build 045 завершает регистрацию канонического Candles Feed.

Достигнуто состояние:

OHLCV Feed foundation
    ✓ Candle model
    ✓ REST document source
    ✓ schema validation
    ✓ parser
    ✓ value validation
    ✓ mapper
    ✓ document handler
    ✓ Candles Feed
    ✓ CandlesFeedRegistry
    ☐ Acquisition Service integration
    ☐ ExchangeService compatibility bridge
    ☐ Consumer migration
    ☐ Legacy Kline removal

Build 045 является небольшим изолированным архитектурным шагом и не изменяет поведение существующего рабочего торгового бота.