Files
dzentra_bot/docs/migrations/build_034.md

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