Files
dzentra_bot/docs/migrations/build_059_5.md

555 lines
11 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 059.5 — Internal Candle Close Event Model
**Проект:** Dzentra
**Подсистема:** Market Data Acquisition
**Этап:** 059.5
**Статус:** Completed
---
# Цель
Добавить внутреннюю immutable-модель уведомления о закрытии OHLC-свечи.
Модель должна представлять уже проверенное WebSocket-событие внутри Dzentra, но не должна заменять каноническую модель:
```text
Candle
```
Причина разделения заключается в том, что фактическое событие Dzengi WebSocket:
```text
ohlc.event
```
содержит:
```text
symbol
interval
type
t
o
h
l
c
```
но не содержит:
```text
volume
```
Поэтому WebSocket OHLC-событие не является полноценной OHLCV-свечой.
---
# Причина изменения
После Build 059.4 проект умеет:
1. структурно проверять входящее WebSocket-сообщение;
2. преобразовывать его в transport-модель;
3. проверять предметную допустимость значений.
Подготовленная цепочка выглядит так:
```text
Raw WebSocket message
ValidatedWebSocketOhlcDocument
DzengiWebSocketOhlcEvent
Value Validation
```
Однако transport-модель:
```text
DzengiWebSocketOhlcEvent
```
принадлежит адаптеру конкретного внешнего источника Dzengi.
Перед дальнейшим использованием в runtime требуется источник-независимая внутренняя модель Dzentra.
---
# Реализовано
Создан файл:
```text
src/market_data/acquisition/models/candle_close.py
```
Добавлена модель:
```text
CandleCloseEvent
```
---
# Структура модели
Модель содержит следующие поля:
```text
symbol
interval
candle_type
open_time
received_at
open_price
high_price
low_price
close_price
source
```
Полное назначение модели:
```text
внутреннее уведомление Dzentra
о завершении OHLC-свечи,
требующее последующего REST reconciliation
для получения полной OHLCV-свечи
```
---
# Контракт модели
Модель объявлена как:
```text
frozen=True
slots=True
```
Это обеспечивает:
- неизменяемость;
- отсутствие динамического `__dict__`;
- уменьшение вероятности случайного изменения события;
- компактное представление в памяти;
- предсказуемый runtime-контракт.
---
# Отличие от transport-модели
Transport-модель:
```text
DzengiWebSocketOhlcEvent
```
отражает внешний контракт Dzengi.
Она содержит:
```text
open_time: int
OHLC: str | int | float
```
Внутренняя модель:
```text
CandleCloseEvent
```
содержит:
```text
open_time: datetime
received_at: datetime
OHLC: Decimal
source: str
```
Таким образом transport-особенности внешнего API не распространяются на внутренние слои Dzentra.
---
# Отличие от канонической Candle
Каноническая модель:
```text
Candle
```
представляет полноценную OHLCV-свечу.
Она содержит:
```text
volume: Decimal
```
Модель:
```text
CandleCloseEvent
```
не содержит `volume`.
Это преднамеренное архитектурное решение.
WebSocket-событие не должно:
- подставлять фиктивный нулевой объём;
- использовать nullable volume;
- притворяться полной OHLCV-свечой;
- наследоваться от `Candle`;
- передаваться потребителям, ожидающим каноническую свечу.
Полная `Candle` будет получена только после REST reconciliation.
---
# Поля времени
## open_time
Поле:
```text
open_time
```
представляет время открытия завершённой свечи.
Для минутной свечи это начало минутного интервала, к которому относится событие.
Тип:
```text
datetime
```
Ожидаемая timezone:
```text
UTC
```
---
## received_at
Поле:
```text
received_at
```
представляет момент получения события системой Dzentra.
Оно не равно `open_time`.
Разделение двух времён необходимо для:
- измерения задержки WebSocket;
- диагностики запоздавших сообщений;
- определения порядка фактической обработки;
- runtime-метрик;
- журналирования;
- анализа качества источника данных.
---
# Поля OHLC
Внутренняя модель использует:
```text
Decimal
```
для:
```text
open_price
high_price
low_price
close_price
```
Это исключает дальнейшее распространение внешних типов:
```text
str
int
float
```
Преобразование transport-значений в `Decimal` будет реализовано в следующем этапе:
```text
Build 059.6 — Mapper
```
---
# Поле candle_type
Поле:
```text
candle_type
```
сохраняет тип серии свечей.
Подтверждённые runtime-значения:
```text
classic
heikin-ashi
```
Для production-интеграции Candles Feed основной интерес представляет:
```text
classic
```
Поскольку именно классические свечи будут использоваться для REST reconciliation с каноническими OHLCV-свечами.
`heikin-ashi` остаётся поддерживаемым внутренним типом события, но не должен автоматически преобразовываться в обычную каноническую `Candle`.
---
# Поле source
Поле:
```text
source
```
фиксирует происхождение внутреннего события.
Пример:
```text
dzengi_websocket_ohlc
```
Это позволит в дальнейшем:
- различать источники;
- поддерживать несколько адаптеров;
- вести диагностику;
- применять источник-зависимую политику reconciliation;
- не встраивать имя Dzengi в общую доменную модель.
---
# Новый внутренний конвейер
После Build 059.5 архитектура выглядит так:
```text
Raw WebSocket message
Schema Validation
ValidatedWebSocketOhlcDocument
Parser
DzengiWebSocketOhlcEvent
Value Validation
Mapper
CandleCloseEvent
REST reconciliation
Canonical Candle
```
На текущем этапе модель `CandleCloseEvent` уже существует, но mapper ещё не реализован.
---
# Unit Tests
Создан файл:
```text
tests/unit/market_data/acquisition/models/test_candle_close.py
```
Проверяются:
- сохранение всех полей;
- неизменяемость модели;
- использование `slots`;
- отсутствие `__dict__`;
- отсутствие наследования от `Candle`;
- отсутствие поля `volume`;
- поддержка типа `heikin-ashi`;
- раздельное хранение `open_time` и `received_at`.
Всего выполнено:
```text
7 tests
```
---
# Проверка синтаксиса
Выполнена команда:
```bash
python -m compileall \
src/market_data/acquisition/models/candle_close.py \
tests/unit/market_data/acquisition/models/test_candle_close.py
```
Результат:
```text
успешно
```
---
# Целевые тесты
Выполнена команда:
```bash
python -m pytest -q \
tests/unit/market_data/acquisition/models/test_candle_close.py
```
Результат:
```text
7 passed in 0.01s
```
---
# Регрессия слоя моделей
Выполнена команда:
```bash
python -m pytest -q \
tests/unit/market_data/acquisition/models
```
Результат:
```text
42 passed in 0.02s
```
---
# Проверка форматирования
Выполнена команда:
```bash
git diff --check
```
Ошибок форматирования не обнаружено.
---
# Созданные файлы
```text
src/market_data/acquisition/models/candle_close.py
tests/unit/market_data/acquisition/models/test_candle_close.py
docs/migrations/build_059_5.md
```
---
# Совместимость
Изменение полностью обратно совместимо.
Не изменены:
- каноническая модель `Candle`;
- transport-модель Dzengi;
- REST Candles Feed;
- parser;
- value validation;
- WebSocket Adapter;
- ExchangeService;
- runtime;
- Market Analysis;
- Trading.
Новая модель пока не подключена к runtime и не влияет на работающий бот.
---
# Ограничения этапа
Build 059.5 не выполняет:
- преобразование transport-модели;
- преобразование timestamp;
- преобразование OHLC в `Decimal`;
- установку реального `received_at`;
- mapping;
- WebSocket Adapter;
- REST reconciliation;
- проверку соответствия REST и WebSocket OHLC;
- создание канонической `Candle`;
- публикацию события в runtime.
---
# Итог
Build 059.5 добавляет источник-независимую внутреннюю модель:
```text
CandleCloseEvent
```
Она представляет подтверждённое уведомление о завершении OHLC-свечи без фиктивного объёма.
Модель создаёт архитектурную границу между:
```text
внешним Dzengi WebSocket контрактом
```
и:
```text
внутренним runtime Dzentra
```
Следующий этап:
```text
Build 059.6 — Mapper
```