# 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 ```