# Build 059.4 — WebSocket OHLC Value Validation **Проект:** Dzentra **Подсистема:** Market Data Acquisition **Этап:** 059.4 **Статус:** Completed --- # Цель Добавить предметную проверку значений транспортной модели: ```text DzengiWebSocketOhlcEvent ``` После выполнения Build 059.3 проект умеет преобразовывать структурно проверенный WebSocket-документ в transport-модель адаптера. Build 059.4 проверяет, что значения этой модели допустимы для дальнейшей обработки. На данном этапе не выполняются: - преобразование timestamp в `datetime`; - преобразование цен в `Decimal` для внутренней модели; - создание внутреннего события закрытия свечи; - mapping; - REST reconciliation; - создание канонической `Candle`; - runtime-интеграция. --- # Причина изменения Parser проверяет только базовые транспортные типы. Например, он допускает следующие значения: ```text symbol = "" interval = "unsupported" candle_type = "unknown" open_time = -1 open_price = "NaN" high_price = -10 low_price = 100 close_price = 0 ``` Они корректны с точки зрения базовых Python-типов, но недопустимы с точки зрения предметного контракта OHLC. Поэтому необходим отдельный слой Value Validation. --- # Реализованные изменения Изменён файл: ```text src/market_data/acquisition/validation/values.py ``` Добавлена функция: ```text validate_dzengi_websocket_ohlc_values() ``` Она принимает: ```text DzengiWebSocketOhlcEvent ``` и проверяет предметную допустимость всех его полей. --- # Новое исключение В файл: ```text src/market_data/acquisition/exceptions.py ``` добавлено специализированное исключение: ```text CandleWebSocketValueError ``` Оно используется только для ошибок значений WebSocket OHLC-событий. Ошибки WebSocket OHLC теперь разделены по слоям: ```text CandleWebSocketSchemaError CandleWebSocketParseError CandleWebSocketValueError ``` Это сохраняет явное разделение ответственности: ```text Schema Validation ↓ проверка структуры JSON Parser ↓ проверка транспортных типов Value Validation ↓ проверка предметной допустимости ``` --- # Поддерживаемые интервалы В Value Validation зафиксирован набор интервалов, который уже поддерживается действующим Candles Feed: ```text 1m 5m 15m 1h ``` Допустимые значения хранятся в immutable-наборе: ```text _SUPPORTED_WEBSOCKET_OHLC_INTERVALS ``` Значения сравниваются без автоматической нормализации. Поэтому отклоняются: ```text "" "1s" "4h" "1M" " 1m " ``` Это преднамеренное поведение. Parser и validator не должны незаметно исправлять внешний контракт. --- # Поддерживаемые типы свечей По результатам runtime-исследования Build 058 подтверждены два допустимых значения: ```text classic heikin-ashi ``` Они зафиксированы в immutable-наборе: ```text _SUPPORTED_WEBSOCKET_OHLC_TYPES ``` Отклоняются: ```text "" "bid" "ask" "Classic" "unknown" " classic " ``` REST-параметр: ```text priceType = bid | ask ``` не является WebSocket-параметром типа свечи. WebSocket использует: ```text type = classic | heikin-ashi ``` --- # Проверка символа Поле: ```text symbol ``` должно содержать хотя бы один непробельный символ. Отклоняются: ```text "" " " "\t" "\n" ``` Value Validation не выполняет: - нормализацию символа; - проверку существования инструмента; - преобразование alias; - обращение к Instrument Registry. На этом слое проверяется только непустое значение. --- # Проверка timestamp Поле: ```text open_time ``` должно быть больше нуля. Отклоняются: ```text 0 -1 -1784224740000 ``` Проверка базового типа `int` уже была выполнена parser-слоем в Build 059.3. Value Validation не преобразует timestamp в `datetime`. --- # Проверка OHLC Поля: ```text open_price high_price low_price close_price ``` принимают транспортный тип: ```text DzengiRawNumeric ``` То есть могут быть представлены как: ```text str int float ``` На этапе Value Validation каждое значение временно преобразуется в `Decimal` только для проверки. Transport-модель при этом не изменяется. --- # Проверка корректности числовых значений Каждое поле OHLC должно быть корректным числом. Отклоняются: ```text "" "invalid" "--1" ``` Для таких значений выбрасывается: ```text CandleWebSocketValueError ``` с указанием точного JSON-пути. Пример: ```text $.payload.o должно быть корректным числом ``` --- # Проверка конечности Каждая цена должна быть конечным числом. Отклоняются: ```text "NaN" "Infinity" "-Infinity" float("nan") float("inf") float("-inf") ``` Это предотвращает проникновение специальных значений в mapping и downstream-анализ. --- # Проверка положительности Все цены OHLC должны быть строго больше нуля. Отклоняются: ```text 0 -1 "-0.01" ``` Проверка выполняется отдельно для: ```text $.payload.o $.payload.h $.payload.l $.payload.c ``` --- # OHLC-инварианты После преобразования цен во временные `Decimal` проверяются стандартные инварианты свечи. ## High не меньше Low Должно выполняться: ```text high >= low ``` Иначе: ```text $.payload.h не должно быть меньше $.payload.l ``` --- ## High не меньше Open Должно выполняться: ```text high >= open ``` Иначе: ```text $.payload.h не должно быть меньше $.payload.o ``` --- ## High не меньше Close Должно выполняться: ```text high >= close ``` Иначе: ```text $.payload.h не должно быть меньше $.payload.c ``` --- ## Low не выше Open Должно выполняться: ```text low <= open ``` Иначе: ```text $.payload.l не должно превышать $.payload.o ``` --- ## Low не выше Close Должно выполняться: ```text low <= close ``` Иначе: ```text $.payload.l не должно превышать $.payload.c ``` --- # Поддержка плоской свечи Допускается свеча, у которой: ```text open = high = low = close ``` Например: ```text 64000 64000 64000 64000 ``` Такая свеча удовлетворяет всем OHLC-инвариантам и является допустимой. --- # Отсутствие изменения transport-модели Value Validation использует `Decimal` только как временный тип проверки. Исходный объект: ```text DzengiWebSocketOhlcEvent ``` не изменяется. Сохраняются исходные значения и их транспортные типы: ```text str int float ``` Постоянное преобразование во внутренние типы будет выполнено позже на mapping-этапе. --- # Новый конвейер После Build 059.4 подготовленная часть конвейера выглядит так: ```text Raw WebSocket message ↓ validate_dzengi_websocket_ohlc_schema() ↓ ValidatedWebSocketOhlcDocument ↓ parse_dzengi_websocket_ohlc() ↓ DzengiWebSocketOhlcEvent ↓ validate_dzengi_websocket_ohlc_values() ↓ проверенная transport-модель ↓ Internal Close Event Model ↓ Mapper ↓ REST reconciliation ↓ Canonical Candle ``` --- # Unit Tests Создан файл: ```text tests/unit/market_data/acquisition/validation/test_websocket_ohlc_values.py ``` Проверяются: - все поддерживаемые интервалы; - оба поддерживаемых типа свечей; - строковые, целые и вещественные представления цен; - пустые символы; - неподдерживаемые интервалы; - неподдерживаемые типы свечей; - неположительный timestamp; - нулевые цены; - отрицательные цены; - `NaN`; - положительная и отрицательная бесконечность; - некорректные числовые строки; - `high < low`; - `high < open`; - `high < close`; - `low > open`; - `low > close`; - плоская свеча. Всего выполнено: ```text 84 tests ``` --- # Проверка синтаксиса Выполнена команда: ```bash python -m compileall \ src/market_data/acquisition/exceptions.py \ src/market_data/acquisition/validation/values.py \ tests/unit/market_data/acquisition/validation/test_websocket_ohlc_values.py ``` Результат: ```text успешно ``` --- # Целевые тесты Выполнена команда: ```bash python -m pytest -q \ tests/unit/market_data/acquisition/validation/test_websocket_ohlc_values.py ``` Результат: ```text 84 passed in 0.03s ``` --- # Регрессия value-validation слоя Выполнена команда: ```bash python -m pytest -q \ tests/unit/market_data/acquisition/validation/test_values.py \ tests/unit/market_data/acquisition/validation/test_quote_values.py \ tests/unit/market_data/acquisition/validation/test_websocket_quote_values.py \ tests/unit/market_data/acquisition/validation/test_candle_values.py \ tests/unit/market_data/acquisition/validation/test_websocket_ohlc_values.py ``` Результат: ```text 150 passed in 0.05s ``` --- # Проверка форматирования Выполнена команда: ```bash git diff --check ``` Ошибок форматирования не обнаружено. --- # Изменённые файлы ```text src/market_data/acquisition/exceptions.py src/market_data/acquisition/validation/values.py ``` Создан файл: ```text tests/unit/market_data/acquisition/validation/test_websocket_ohlc_values.py ``` Документация этапа: ```text docs/migrations/build_059_4.md ``` --- # Совместимость Изменение полностью обратно совместимо. Не изменены: - REST Candles Feed; - REST Candle validation; - Quote Feed; - WebSocket Quote validation; - parser WebSocket OHLC; - ExchangeService; - runtime; - Market Analysis; - Trading. Новая функция пока не подключена к рабочему WebSocket Adapter и не влияет на работающий бот. --- # Ограничения этапа Build 059.4 не выполняет: - преобразование timestamp в UTC `datetime`; - преобразование цен в постоянные `Decimal`; - создание внутреннего события закрытия свечи; - добавление `source`; - mapping; - WebSocket Adapter; - WebSocket subscription; - REST reconciliation; - проверку совпадения WebSocket и REST OHLC; - создание канонической `Candle`; - runtime-интеграцию. --- # Итог Build 059.4 завершает слой предметной проверки значений Dzengi WebSocket OHLC. Проект теперь умеет безопасно проверять: ```text DzengiWebSocketOhlcEvent ``` на: - допустимость символа; - допустимость интервала; - допустимость типа свечи; - корректность timestamp; - корректность чисел; - конечность цен; - положительность цен; - соблюдение OHLC-инвариантов. Следующий этап: ```text Build 059.5 — Internal Close Event Model ```