15 KiB
Build 034 — Dzengi WebSocket quote parsing и адаптер
Статус: Завершён
Подсистема: Market Data
Контур: Market Data Acquisition / Quotes Feed
Проект: Dzentra
Язык документации: Русский
1. Цель Build
Цель Build 034 — создать специализированный контур обработки WebSocket-сообщений котировок Dzengi и преобразования их в каноническую модель Quote.
Build должен был изолировать знание транспортных форматов Dzengi WebSocket от канонического слоя Market Data и подготовить архитектурную основу для последующего перевода market runtime на новый Quotes Feed.
В рамках Build реализована цепочка:
Dzengi WebSocket message
↓
schema validation
↓
parser
↓
DzengiWebSocketQuoteResponse
↓
value validation
↓
mapper
↓
DzengiWebSocketQuoteAdapter
↓
canonical Quote
2. Архитектурный результат
После Build 034 обработка WebSocket-котировок Dzengi получила специализированный адаптерный контур внутри:
src/market_data/acquisition/
Транспортные особенности Dzengi WebSocket больше не должны распространяться на каноническую модель Quote и будущих потребителей Quotes Feed.
Архитектурная граница имеет следующий вид:
Dzengi-specific transport formats
↓
adapters/dzengi
↓
canonical Quote
↓
Quotes Feed / Quote Store / consumers
Каноническая модель:
src/market_data/acquisition/models/quote.py
остаётся независимой от:
payload
Payload
symbolName
bid
ask
ofr
bids
asks
price
p
bidPrice
askPrice
Эти имена являются особенностями внешнего транспорта Dzengi и обрабатываются внутри адаптерного слоя.
3. Изменённые файлы
В рамках Build 034 изменены следующие файлы:
src/market_data/acquisition/adapters/dzengi/models.py
src/market_data/acquisition/adapters/dzengi/parser.py
src/market_data/acquisition/adapters/dzengi/mapper.py
src/market_data/acquisition/validation/schema.py
src/market_data/acquisition/validation/values.py
Добавлен специализированный WebSocket-адаптер:
src/market_data/acquisition/adapters/dzengi/websocket.py
4. Добавленные тесты
Добавлены следующие специализированные тестовые файлы:
tests/unit/market_data/acquisition/validation/test_websocket_quote_schema.py
tests/unit/market_data/acquisition/validation/test_websocket_quote_values.py
tests/unit/market_data/acquisition/adapters/dzengi/test_websocket_quote_parser.py
tests/unit/market_data/acquisition/adapters/dzengi/test_websocket_quote_mapper.py
tests/unit/market_data/acquisition/adapters/dzengi/test_websocket_quote_adapter.py
5. Поддерживаемые WebSocket-форматы
Новый адаптерный контур поддерживает транспортные варианты, существовавшие в legacy-реализации Dzengi WebSocket.
5.1. Оболочки сообщения
Поддерживаются:
payload
Payload
а также вложенная двойная оболочка.
Примеры допустимой структуры:
{
"payload": {
"symbolName": "BTC/USD_LEVERAGE",
"bid": "64159.45",
"ask": "64159.55"
}
}
и:
{
"Payload": {
"Payload": {
"symbolName": "BTC/USD_LEVERAGE",
"bids": [
["64159.45", "1.0"]
],
"asks": [
["64159.55", "1.0"]
]
}
}
}
6. Поддерживаемые поля символа
Адаптер поддерживает следующие транспортные имена символа:
symbolName
symbol
После обработки внешнее представление преобразуется в каноническое поле:
Quote.symbol
7. Поддерживаемые представления bid и ask
Поддерживаются прямые поля:
bid
ask
вариант Dzengi:
bid
ofr
а также depth-представление:
bids
asks
Для элементов depth поддерживаются представления в виде:
list
dict
Поддерживаемые имена поля цены внутри depth-элементов:
price
p
bidPrice
askPrice
8. Семантика last_price для depth-сообщений
Для WebSocket depth-сообщений, содержащих лучшие цены bid и ask, сохранена legacy-семантика:
last_price = midpoint(best_bid, best_ask)
То есть каноническое значение Quote.last_price определяется как середина между лучшей ценой покупки и лучшей ценой продажи.
Это решение сохраняет обратную совместимость с существующим поведением market runtime до его последующего архитектурного перевода.
9. Обработка timestamp
WebSocket timestamp является необязательным.
Если транспортное сообщение содержит допустимый timestamp биржи, он преобразуется в:
Quote.exchange_timestamp
Если timestamp отсутствует, каноническая модель допускает:
exchange_timestamp = None
Время фактического получения и обработки котировки фиксируется отдельно:
Quote.received_at
Таким образом, сохраняется разделение двух временных характеристик:
exchange_timestamp
время события по данным биржи
received_at
время получения котировки системой Dzentra
10. Schema validation
Schema validation отвечает исключительно за структурную корректность WebSocket-документа.
На этом этапе проверяется возможность извлечения необходимых частей сообщения без переноса бизнес-логики в транспортный слой.
Schema validation не должна:
создавать canonical Quote
выполнять mapping
управлять runtime
записывать данные в Quote Store
обращаться к MarketPriceCache
11. Parser
Parser преобразует структурно проверенный WebSocket-документ в специализированную raw-модель Dzengi:
DzengiWebSocketQuoteResponse
Parser сохраняет границу между:
сырой внешний документ
и:
типизированное транспортное представление Dzengi
Parser не создаёт канонический Quote.
12. Value validation
Value validation проверяет семантическую допустимость извлечённых значений.
В частности, контур должен обеспечивать корректность значений, необходимых для построения канонической котировки:
symbol
bid price
ask price
timestamp, если присутствует
Проверка значений выполняется до mapping в каноническую модель.
13. Mapper
Mapper преобразует проверенную raw-модель Dzengi WebSocket в:
Quote
На этой границе происходит переход:
Dzengi-specific representation
↓
canonical Dzentra representation
После mapping потребитель не должен зависеть от исходного формата WebSocket-сообщения.
14. DzengiWebSocketQuoteAdapter
Специализированный адаптер инкапсулирует полный конвейер обработки одного WebSocket-сообщения:
raw document
↓
schema validation
↓
parsing
↓
value validation
↓
mapping
↓
Quote
Результатом успешной обработки является канонический объект:
Quote
Адаптер не отвечает за:
поддержание WebSocket-соединения
reconnect
runtime lifecycle
регистрацию market runtime
запись в Quote Store
legacy MarketPriceCache facade
Эти обязанности принадлежат другим архитектурным слоям.
15. Что намеренно не изменялось
В Build 034 не изменялись runtime-файлы:
src/integrations/exchange/ws_client.py
src/integrations/exchange/market_stream.py
src/integrations/exchange/market_data_runner.py
Также Build 034 не выполнял переключение:
market runtime → Quotes Feed
и не удалял legacy-механизмы.
Это принципиальная граница Build.
Build 034 создаёт новый специализированный адаптерный контур, но не переключает на него существующий runtime.
Перевод runtime предусмотрен следующим этапом:
Build 035 — Перевод market runtime на Quotes Feed
16. Обратная совместимость
В Build 034 сохранены существующие транспортные варианты legacy WebSocket-контура:
payload / Payload
двойная оболочка
symbolName / symbol
bid + ask
bid + ofr
bids + asks
depth item list
depth item dict
price / p / bidPrice / askPrice
необязательный timestamp
Для depth-сообщений сохранено существующее правило:
last_price = midpoint(best_bid, best_ask)
Таким образом, Build не требует одномоментного удаления legacy runtime и подготавливает безопасный переход к новой архитектуре.
17. Проверка компиляции
Выполнена проверка:
python -m py_compile \
src/market_data/acquisition/adapters/dzengi/models.py \
src/market_data/acquisition/adapters/dzengi/parser.py \
src/market_data/acquisition/adapters/dzengi/mapper.py \
src/market_data/acquisition/adapters/dzengi/websocket.py \
src/market_data/acquisition/validation/schema.py \
src/market_data/acquisition/validation/values.py \
tests/unit/market_data/acquisition/validation/test_websocket_quote_schema.py \
tests/unit/market_data/acquisition/validation/test_websocket_quote_values.py \
tests/unit/market_data/acquisition/adapters/dzengi/test_websocket_quote_parser.py \
tests/unit/market_data/acquisition/adapters/dzengi/test_websocket_quote_mapper.py \
tests/unit/market_data/acquisition/adapters/dzengi/test_websocket_quote_adapter.py
Результат:
успешно
18. Специализированные тесты
Выполнена команда:
python -m pytest \
tests/unit/market_data/acquisition/validation/test_websocket_quote_schema.py \
tests/unit/market_data/acquisition/validation/test_websocket_quote_values.py \
tests/unit/market_data/acquisition/adapters/dzengi/test_websocket_quote_parser.py \
tests/unit/market_data/acquisition/adapters/dzengi/test_websocket_quote_mapper.py \
tests/unit/market_data/acquisition/adapters/dzengi/test_websocket_quote_adapter.py \
-q
Результат:
24 passed in 0.04s
19. Полная регрессия
Выполнена команда:
python -m pytest -q
Результат:
602 passed in 0.30s
Количество тестов до Build 034:
578 passed
Количество тестов после Build 034:
602 passed
Добавлено:
24 теста
Полная регрессия подтверждает отсутствие обнаруженных регрессий в существующем коде проекта.
20. Итог Build
Build 034 завершён полностью.
Реализованы:
специализированная WebSocket raw-модель Dzengi
WebSocket schema validation
WebSocket parser
WebSocket value validation
WebSocket mapper
DzengiWebSocketQuoteAdapter
преобразование WebSocket-сообщения в canonical Quote
поддержка legacy-вариантов формата Dzengi
24 специализированных теста
Не выполнялись:
переключение market runtime
изменение ws_client.py
изменение market_stream.py
изменение market_data_runner.py
удаление legacy WebSocket parsing
удаление MarketPriceCache
Архитектурный результат:
Dzengi WebSocket transport
↓
Dzengi-specific validation / parsing / mapping
↓
canonical Quote
21. Следующий Build
Следующий этап:
Build 035 — Перевод market runtime на Quotes Feed
Его задача — подключить существующий market runtime к новому каноническому контуру котировок, используя созданные ранее:
Quote
Quote Store
Quotes Feed
Dzengi REST Quotes Feed
Dzengi WebSocket quote adapter
При этом переход должен выполняться без преждевременного удаления legacy-механизмов и с сохранением работоспособности существующего бота до завершения последующих этапов миграции.