17 KiB
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 является небольшим изолированным архитектурным шагом и не изменяет поведение существующего рабочего торгового бота.