Files
dzentra_bot/docs/migrations/build_059_3.md

593 lines
13 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.3 — WebSocket OHLC Parser
**Проект:** Dzentra
**Подсистема:** Market Data Acquisition
**Этап:** 059.3
**Статус:** Completed
---
# Цель
Добавить parser для структурно проверенного события Dzengi WebSocket OHLC.
Parser должен преобразовывать:
```text
ValidatedWebSocketOhlcDocument
```
в:
```text
DzengiWebSocketOhlcEvent
```
При этом parser не должен выполнять:
- предметную проверку значений;
- проверку поддерживаемых интервалов;
- проверку допустимого типа свечи;
- преобразование timestamp в `datetime`;
- преобразование цен в `Decimal`;
- проверку OHLC-инвариантов;
- mapping во внутреннюю модель Dzentra.
---
# Причина изменения
После Build 059.2 проект умеет проверять структуру сообщения Dzengi WebSocket:
```json
{
"status": "OK",
"destination": "ohlc.event",
"payload": {
"symbol": "BTC/USD_LEVERAGE",
"interval": "1m",
"type": "classic",
"t": 1784224740000,
"o": 63992.0,
"h": 64032.55,
"l": 63984.0,
"c": 64032.55
}
}
```
Однако структурно проверенный документ ещё не преобразовывался в transport-модель адаптера Dzengi.
Build 059.3 добавляет отдельный parsing-слой между schema validation и value validation.
---
# Реализованные изменения
## Parser
В файл:
```text
src/market_data/acquisition/adapters/dzengi/parser.py
```
добавлена функция:
```text
parse_dzengi_websocket_ohlc()
```
Она принимает:
```text
ValidatedWebSocketOhlcDocument
```
и возвращает:
```text
DzengiWebSocketOhlcEvent
```
---
## Исключение parser-слоя
В файл:
```text
src/market_data/acquisition/exceptions.py
```
добавлено исключение:
```text
CandleWebSocketParseError
```
Оно используется только при невозможности преобразовать структурно проверенный WebSocket OHLC-документ в transport-модель адаптера.
---
## Unit-тесты
Создан файл:
```text
tests/unit/market_data/acquisition/adapters/dzengi/test_websocket_ohlc_parser.py
```
Он покрывает успешное преобразование и ошибки транспортных типов.
---
# Соответствие полей
Parser выполняет следующее преобразование:
| WebSocket payload | Transport model |
|---|---|
| `symbol` | `symbol` |
| `interval` | `interval` |
| `type` | `candle_type` |
| `t` | `open_time` |
| `o` | `open_price` |
| `h` | `high_price` |
| `l` | `low_price` |
| `c` | `close_price` |
Parser не переименовывает и не интерпретирует значения предметно. Он только переносит их в явную transport-модель адаптера.
---
# Проверка базовых транспортных типов
## Строковые поля
Следующие поля обязаны быть строками:
```text
symbol
interval
type
```
Если одно из них не является строкой, выбрасывается:
```text
CandleWebSocketParseError
```
Пример ошибки:
```text
$.payload.symbol должен быть строкой
```
---
## Timestamp
Поле:
```text
t
```
должно быть целым числом Python:
```text
int
```
Не принимаются:
```text
None
bool
float
str
list
```
`bool` отклоняется отдельно, несмотря на то что в Python он является подклассом `int`.
Parser не проверяет, является ли timestamp положительным или реалистичным. Это относится к Value Validation.
---
## Поля OHLC
Поля:
```text
o
h
l
c
```
могут быть представлены как:
```text
str
int
float
```
Это соответствует существующему транспортному типу:
```text
DzengiRawNumeric
```
Такой контракт необходим, поскольку внешнее API может передавать числовые значения как JSON-числа или строки.
Не принимаются:
```text
None
bool
list
dict
object
```
---
# Сохранение исходных числовых типов
Parser не преобразует цены.
Например, документ:
```json
{
"o": "63992.00",
"h": 64033,
"l": 63984.0,
"c": "64032.55"
}
```
преобразуется в transport-модель с теми же исходными типами:
```text
open_price = str
high_price = int
low_price = float
close_price = str
```
Преобразование в `Decimal` будет выполняться только на mapping-этапе.
---
# Поддержка типов свечей
Parser сохраняет значение поля:
```text
type
```
в поле transport-модели:
```text
candle_type
```
Поддерживаются на уровне базового транспортного типа любые строки.
Например:
```text
classic
heikin-ashi
unknown
```
Parser не определяет допустимость значения.
Проверка, что значение входит в подтверждённый runtime-набор:
```text
classic
heikin-ashi
```
будет реализована в Build 059.4 — Value Validation.
---
# Отсутствие предметной валидации
Parser намеренно пропускает значения, которые имеют допустимый транспортный тип, но являются предметно некорректными.
Пример:
```text
symbol = ""
interval = "unsupported"
candle_type = "unknown"
open_time = -1
open_price = "NaN"
high_price = -10
low_price = 100
close_price = 0
```
Такой документ успешно преобразуется в `DzengiWebSocketOhlcEvent`.
Это ожидаемое поведение.
Следующий слой должен проверить:
- непустой символ;
- допустимый интервал;
- допустимый тип свечи;
- положительный timestamp;
- конечность чисел;
- положительность цен;
- OHLC-инварианты.
---
# Игнорирование metadata envelope
Parser использует только:
```text
document.payload
```
Поля внешнего envelope:
```text
status
destination
correlation_id
```
не участвуют в создании `DzengiWebSocketOhlcEvent`.
Это обеспечивает разделение ответственности:
```text
Schema Validation
проверяет структуру envelope и payload
Parser
преобразует payload в transport-модель
Value Validation
проверяет предметную допустимость значений
```
---
# Новый конвейер
После Build 059.3 подготовленная часть конвейера выглядит так:
```text
Raw WebSocket message
validate_dzengi_websocket_ohlc_schema()
ValidatedWebSocketOhlcDocument
parse_dzengi_websocket_ohlc()
DzengiWebSocketOhlcEvent
Value Validation
Internal Close Event
REST reconciliation
Canonical Candle
```
На текущем этапе реализована часть до `DzengiWebSocketOhlcEvent` включительно.
---
# Unit Tests
Добавлен файл:
```text
tests/unit/market_data/acquisition/adapters/dzengi/test_websocket_ohlc_parser.py
```
Проверяются следующие сценарии:
- успешное создание transport-модели;
- корректное соответствие всех полей;
- сохранение типа `classic`;
- сохранение типа `heikin-ashi`;
- сохранение исходных числовых типов;
- отклонение нестрокового `symbol`;
- отклонение нестрокового `interval`;
- отклонение нестрокового `type`;
- отклонение `None` в timestamp;
- отклонение `bool` в timestamp;
- отклонение `float` в timestamp;
- отклонение строкового timestamp;
- отклонение коллекции вместо timestamp;
- отклонение некорректных типов для `o`;
- отклонение некорректных типов для `h`;
- отклонение некорректных типов для `l`;
- отклонение некорректных типов для `c`;
- отсутствие предметной валидации;
- игнорирование metadata внешнего envelope.
Всего выполнено:
```text
36 tests
```
---
# Проверка синтаксиса
Выполнена команда:
```bash
python -m compileall \
src/market_data/acquisition/exceptions.py \
src/market_data/acquisition/adapters/dzengi/parser.py \
tests/unit/market_data/acquisition/adapters/dzengi/test_websocket_ohlc_parser.py
```
Результат:
```text
успешно
```
---
# Целевые тесты
Выполнена команда:
```bash
python -m pytest -q \
tests/unit/market_data/acquisition/adapters/dzengi/test_websocket_ohlc_parser.py
```
Результат:
```text
36 passed in 0.03s
```
---
# Регрессия parser-слоя
Выполнена команда:
```bash
python -m pytest -q \
tests/unit/market_data/acquisition/adapters/dzengi/test_parser.py \
tests/unit/market_data/acquisition/adapters/dzengi/test_quote_parser.py \
tests/unit/market_data/acquisition/adapters/dzengi/test_websocket_quote_parser.py \
tests/unit/market_data/acquisition/adapters/dzengi/test_candle_parser.py \
tests/unit/market_data/acquisition/adapters/dzengi/test_websocket_ohlc_parser.py
```
Результат:
```text
80 passed in 0.05s
```
---
# Проверка форматирования
Выполнена команда:
```bash
git diff --check
```
Ошибок форматирования не обнаружено.
---
# Изменённые файлы
```text
src/market_data/acquisition/adapters/dzengi/parser.py
src/market_data/acquisition/exceptions.py
```
Создан файл:
```text
tests/unit/market_data/acquisition/adapters/dzengi/test_websocket_ohlc_parser.py
```
Документация этапа:
```text
docs/migrations/build_059_3.md
```
---
# Совместимость
Изменение полностью обратно совместимо.
Не изменены:
- REST Candles Feed;
- REST parser свечей;
- Quotes Feed;
- WebSocket Quote parser;
- WebSocket Quote Adapter;
- ExchangeService;
- Market Analysis;
- Trading;
- runtime.
Новый parser пока не подключён к рабочему WebSocket runtime и не влияет на действующий бот.
---
# Ограничения этапа
Build 059.3 не выполняет:
- проверку значения `status`;
- проверку значения `destination`;
- проверку допустимых интервалов;
- проверку допустимого типа свечи;
- проверку timestamp;
- проверку конечности OHLC;
- проверку положительности OHLC;
- проверку OHLC-инвариантов;
- преобразование в `Decimal`;
- преобразование времени в UTC `datetime`;
- создание внутреннего close event;
- REST reconciliation;
- выпуск канонической `Candle`.
Эти обязанности остаются за последующими подпунктами Build 059.
---
# Итог
Build 059.3 завершает parsing-слой Dzengi WebSocket OHLC.
Проект теперь умеет преобразовывать структурно проверенный документ:
```text
ValidatedWebSocketOhlcDocument
```
в transport-модель:
```text
DzengiWebSocketOhlcEvent
```
без смешивания parsing, value validation и domain mapping.
Следующий этап:
```text
Build 059.4 — Value Validation
```