Files
dzentra_bot/docs/migrations/build_060_11.md

1014 lines
32 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 060.11 — WebSocket Trade Parser
**Engineering Migration Report**
---
# Контроль документа
| Свойство | Значение |
|----------|----------|
| Build | 060.11 |
| Название | WebSocket Trade Parser |
| Статус | Completed |
| Проект | Dzentra |
| Подсистема | Market Data Acquisition |
| Компонент | Trades Feed |
| Версия | 1.0 |
---
# Цель Build
После завершения Build 060.10 система получила завершённый уровень **Schema Validation** для WebSocket-событий канала `internal.trade`.
Структурная корректность входящего сообщения теперь гарантируется объектом
```text
ValidatedWebSocketTradeDocument
```
Следующим обязательным этапом развития WebSocket-конвейера является реализация слоя **Parser**, отвечающего за преобразование структурно корректного документа в транспортную модель адаптера Dzengi.
Build 060.11 вводит механизм **WebSocket Trade Parser**.
Основная задача Build — изолировать знания о транспортном формате WebSocket-сообщения внутри Parser и предоставить последующим уровням Pipeline готовую transport-модель.
Данный Build ограничивается исключительно транспортным преобразованием документа и не затрагивает:
- Schema Validation;
- Value Validation;
- Mapper;
- Adapter;
- Runtime;
- Routing;
- Trades Feed.
---
# Предпосылки
К моменту начала Build архитектура Dzentra уже содержала завершённые Parser для остальных типов WebSocket-событий.
## WebSocket Quote
```text
Raw WebSocket Quote
Schema Validation
ValidatedWebSocketQuoteDocument
Quote Parser
DzengiWebSocketQuoteResponse
```
## WebSocket OHLC
```text
Raw WebSocket OHLC
Schema Validation
ValidatedWebSocketOhlcDocument
OHLC Parser
DzengiWebSocketOhlcEvent
```
После завершения Build 060.10 появился документ
```text
ValidatedWebSocketTradeDocument
```
однако между ним и транспортной моделью
```text
DzengiWebSocketTradeEvent
```
отсутствовал собственный слой Parsing.
В результате WebSocket-конвейер обработки сделок оставался незавершённым и отличался от уже реализованных конвейеров Quote и OHLC.
---
# Архитектурное основание
В архитектуре Dzentra каждый уровень Pipeline имеет строго определённую область ответственности.
Parser располагается между Schema Validation и Value Validation и отвечает исключительно за транспортное преобразование документа.
На данном уровне выполняется:
- извлечение обязательных полей из `payload`;
- минимальная проверка типов, необходимая для построения транспортной модели;
- переименование транспортных полей;
- создание immutable transport object.
Parser принципиально **не выполняет**:
- проверку диапазонов значений;
- проверку корректности timestamp;
- проверку корректности цены;
- проверку корректности объёма;
- бизнес-валидацию;
- Mapping;
- создание канонической модели `Trade`.
Такое разделение позволяет каждому уровню Pipeline выполнять одну строго определённую задачу и исключает смешивание ответственности между компонентами.
---
# Результаты архитектурного аудита
Перед началом реализации был выполнен аудит существующей подсистемы Parsing.
Подтверждено наличие полностью реализованных компонентов:
- `parse_dzengi_websocket_quote()`;
- `parse_dzengi_websocket_ohlc()`;
- `DzengiWebSocketQuoteResponse`;
- `DzengiWebSocketOhlcEvent`.
Также подтверждено существование транспортной модели:
```text
DzengiWebSocketTradeEvent
```
и завершённого уровня Schema Validation:
```text
ValidatedWebSocketTradeDocument
```
Одновременно подтверждено отсутствие собственного Parser для WebSocket Trade.
Таким образом Build 060.11 полностью соответствует утверждённой дорожной карте серии 060 и закрывает третий этап WebSocket-ветки обработки сделок.
---
# Архитектурное решение
По итогам аудита было принято решение не проектировать отдельную архитектуру для Trade.
Вместо этого реализован третий экземпляр уже существующего архитектурного шаблона.
В систему добавлена функция
```text
parse_dzengi_websocket_trade(...)
```
которая преобразует
```text
ValidatedWebSocketTradeDocument
```
в
```text
DzengiWebSocketTradeEvent
```
Архитектура всех WebSocket-конвейеров стала полностью симметричной.
```text
Quote
ValidatedWebSocketQuoteDocument
Quote Parser
DzengiWebSocketQuoteResponse
OHLC
ValidatedWebSocketOhlcDocument
OHLC Parser
DzengiWebSocketOhlcEvent
Trade
ValidatedWebSocketTradeDocument
Trade Parser
DzengiWebSocketTradeEvent
```
Build 060.11 не изменяет существующее поведение Quote и OHLC, а лишь расширяет существующую архитектуру новым типом рыночных данных.
---
# Реализованный Parser
В файл
```text
src/market_data/acquisition/adapters/dzengi/parser.py
```
добавлена новая функция транспортного преобразования:
```text
parse_dzengi_websocket_trade(...)
```
Parser получает результат успешной структурной проверки
```text
ValidatedWebSocketTradeDocument
```
и создаёт транспортную модель
```text
DzengiWebSocketTradeEvent
```
Parser является единственным компонентом системы, который знает транспортный формат WebSocket-сообщения Dzengi.
Все последующие уровни Pipeline работают исключительно с транспортной моделью и полностью изолированы от структуры исходного JSON-документа.
---
# Почему используется отдельный Parser
`DzengiWebSocketTradeEvent` не создаётся непосредственно во время Schema Validation.
Подобное разделение соответствует архитектурному принципу Dzentra, согласно которому каждый уровень Pipeline отвечает только за одну задачу.
Schema Validation гарантирует корректность структуры документа.
Parser преобразует структуру документа в транспортную модель.
Value Validation анализирует корректность самих значений.
Mapper преобразует транспортную модель в каноническую модель предметной области.
Такое разделение ответственности уже используется для Quote и OHLC и полностью повторено для Trade.
---
# Входной документ Parser
Parser принимает единственный аргумент
```text
ValidatedWebSocketTradeDocument
```
Документ гарантирует:
- корректную структуру транспортной оболочки;
- наличие объекта `payload`;
- наличие обязательных транспортных полей;
- неизменяемость содержимого `payload`.
Благодаря этому Parser не выполняет повторную структурную проверку сообщения и не анализирует наличие обязательных полей.
Эти гарантии уже обеспечены предыдущим уровнем Pipeline.
---
# Формируемая транспортная модель
Результатом успешной работы Parser является объект
```python
@dataclass(frozen=True, slots=True)
class DzengiWebSocketTradeEvent:
trade_id: int
price: DzengiRawNumeric
size: DzengiRawNumeric
timestamp: int
symbol: str
buyer: bool
order_id: str
```
Экземпляр представляет собой неизменяемую транспортную модель одного события биржи.
Объект полностью соответствует транспортному контракту WebSocket Trade и используется последующими этапами обработки без дополнительного обращения к исходному JSON-документу.
---
# Выполняемое преобразование полей
Parser извлекает значения исключительно из объекта
```text
payload
```
При создании транспортной модели выполняется переименование отдельных транспортных полей.
| Поле WebSocket | Поле модели |
|---------------|-------------|
| `id` | `trade_id` |
| `price` | `price` |
| `size` | `size` |
| `symbol` | `symbol` |
| `ts` | `timestamp` |
| `buyer` | `buyer` |
| `orderId` | `order_id` |
Все остальные значения сохраняются без изменения.
Подобное переименование позволяет транспортной модели использовать единый стиль именования, принятый во всём проекте Dzentra.
---
# Сохранение исходных значений
Build 060.11 принципиально не преобразует содержимое транспортных полей.
В частности Parser:
- не преобразует цену в `Decimal`;
- не преобразует объём в `Decimal`;
- не преобразует timestamp в `datetime`;
- не изменяет строковое представление символа;
- не интерпретирует направление сделки.
Все значения сохраняются в том виде, в котором они были получены от биржи.
Это позволяет полностью отделить транспортный уровень от уровня предметной валидации.
---
# Почему Parser не переносит транспортную оболочку
В ходе архитектурного аудита отдельно рассматривался вопрос о необходимости переноса полей транспортной оболочки
```text
status
destination
correlationId
```
в объект
```text
DzengiWebSocketTradeEvent
```
По итогам анализа принято решение отказаться от подобного переноса.
После успешного завершения Schema Validation транспортная оболочка полностью выполняет свою задачу и больше не участвует в обработке рыночного события.
Последующие уровни Pipeline работают исключительно с содержимым объекта `payload`.
Таким образом транспортная модель содержит только данные, непосредственно описывающие совершённую сделку.
Подобный подход уже используется в существующих Parser для Quote и OHLC и полностью сохраняет архитектурную симметрию подсистемы Market Data Acquisition.
---
# Использование TradeParseError
Для всех ошибок, возникающих на этапе Parsing, используется существующее исключение
```text
TradeParseError
```
Build не вводит новых типов исключений.
Это сохраняет единую иерархию обработки ошибок Trade и полностью соответствует архитектуре Dzentra.
Parser использует `TradeParseError` исключительно для ошибок транспортного преобразования и проверки типов, необходимых для построения транспортной модели.
Ошибки предметной корректности значений остаются областью ответственности Build 060.12.
---
# Целевой конвейер обработки WebSocket Trade
После завершения Build 060.11 конвейер обработки принимает следующий вид.
```text
Raw WebSocket Object
WebSocket Trade Schema Validation
ValidatedWebSocketTradeDocument
WebSocket Trade Parser
DzengiWebSocketTradeEvent
Build 060.12 — WebSocket Trade Value Validation
Validated Trade Transport Event
Build 060.13 — WebSocket Trade Mapper
Trade
```
Таким образом Build 060.11 завершает третий архитектурный уровень WebSocket-конвейера обработки сделок.
---
# Соотношение с предыдущим Build
Build 060.10 и Build 060.11 реализуют два различных архитектурных уровня.
```text
Build 060.10
```
вводит документ
```text
ValidatedWebSocketTradeDocument
```
который гарантирует структурную корректность входящего WebSocket-сообщения.
```text
Build 060.11
```
вводит Parser
```text
parse_dzengi_websocket_trade(...)
```
который преобразует проверенный документ в транспортную модель
```text
DzengiWebSocketTradeEvent
```
Таким образом последовательность обработки становится следующей.
```text
Raw JSON
ValidatedWebSocketTradeDocument
DzengiWebSocketTradeEvent
Trade
```
Каждый компонент относится к собственному архитектурному уровню и не дублирует ответственность другого.
---
# Изменённые файлы
В рамках Build были изменены только два файла.
## Parser
```text
src/market_data/acquisition/adapters/dzengi/parser.py
```
Добавлены:
```text
parse_dzengi_websocket_trade(...)
_websocket_trade_required_string(...)
_websocket_trade_required_int(...)
_websocket_trade_required_bool(...)
_websocket_trade_required_raw_numeric(...)
```
При этом существующие Parser для Quote и OHLC, импорты и поведение файла не изменялись.
---
## Unit-тесты
```text
tests/unit/market_data/acquisition/adapters/dzengi/test_websocket_trade_parser.py
```
Добавлен полный набор unit-тестов нового Parser.
---
# Добавленные тесты
В рамках Build реализовано двадцать девять unit-тестов, полностью покрывающих функциональность нового Parser.
## Проверка успешного Parsing
Тест
```text
test_parse_websocket_trade_returns_transport_event
```
проверяет:
- успешное создание `DzengiWebSocketTradeEvent`;
- корректное заполнение всех полей;
- создание неизменяемой транспортной модели.
---
## Проверка переименования полей
Тест
```text
test_parse_websocket_trade_renames_transport_fields
```
подтверждает корректное преобразование:
- `id → trade_id`;
- `ts → timestamp`;
- `orderId → order_id`.
---
## Проверка сохранения raw-значений
Тест
```text
test_parse_websocket_trade_preserves_raw_numeric_values
```
подтверждает, что Parser не изменяет:
- цену;
- объём.
Значения сохраняются в исходном виде без каких-либо преобразований.
---
## Проверка сохранения buyer
Тест
```text
test_parse_websocket_trade_preserves_buyer_flag
```
подтверждает корректную передачу направления сделки в транспортную модель.
---
## Игнорирование транспортной оболочки
Тест
```text
test_parse_websocket_trade_ignores_transport_envelope
```
подтверждает, что поля
- `status`;
- `destination`;
- `correlationId`;
не входят в состав транспортной модели и не используются Parser после успешного прохождения Schema Validation.
---
## Дополнительные поля payload
Тест
```text
test_parse_websocket_trade_ignores_additional_payload_fields
```
подтверждает, что дополнительные поля WebSocket-сообщения не влияют на результат Parsing.
Parser использует только обязательные поля транспортного контракта.
---
## Проверка обязательных типов
Реализована серия параметризованных тестов, проверяющих корректность типов каждого обязательного поля транспортной модели.
При несоответствии ожидаемому типу Parser генерирует
```text
TradeParseError
```
с указанием пути к некорректному элементу.
---
## Проверка отсутствующих значений
Реализована серия тестов, подтверждающих генерацию
```text
TradeParseError
```
при невозможности построить транспортную модель из-за отсутствия требуемого значения.
---
## Проверка отсутствия Value Validation
Отдельные тесты подтверждают архитектурный принцип Build.
Parser выполняет исключительно транспортное преобразование и не анализирует корректность самих значений.
Проверка диапазонов, семантики и бизнес-ограничений полностью переносится на следующий этап дорожной карты.
---
# Результаты тестирования
Выполнен целевой запуск нового набора unit-тестов.
```bash
python -m pytest \
tests/unit/market_data/acquisition/adapters/dzengi/test_websocket_trade_parser.py \
-q
```
Результат:
```text
29 passed in 0.03s
```
Все проверки новой функциональности успешно завершены.
Следует отметить, что в процессе разработки была обнаружена неточность в первоначальной версии unit-тестов.
При проверке сообщений исключений использовался параметр
```python
pytest.raises(..., match=expected_path)
```
где в качестве шаблона передавался JSONPath, например
```text
$.payload.id
```
Поскольку параметр `match` интерпретирует строку как регулярное выражение, символы `$` и `.` требовали экранирования.
После замены
```python
match=expected_path
```
на
```python
match=re.escape(expected_path)
```
тесты стали корректно проверять текст сообщений исключений.
Данное изменение затронуло исключительно тестовый код и не потребовало каких-либо изменений реализации Parser.
---
# Регрессионное тестирование
После завершения реализации выполнен полный запуск набора unit-тестов проекта.
```bash
python -m pytest -q
```
Результат:
```text
1161 passed in 2.63s
```
Регрессий существующей функциональности не обнаружено.
Все ранее реализованные Build продолжают работать без изменений.
---
# Проверка компиляции
Выполнена проверка компиляции изменённых файлов.
```bash
python -m compileall \
src/market_data/acquisition/adapters/dzengi/parser.py \
tests/unit/market_data/acquisition/adapters/dzengi/test_websocket_trade_parser.py
```
Компиляция завершилась успешно.
Синтаксические ошибки отсутствуют.
---
# Проверка Git diff
Выполнена финальная проверка изменений.
```bash
git diff --check
```
Ошибок не обнаружено.
Это подтверждает отсутствие:
- trailing whitespace;
- конфликтов окончания строк;
- ошибок форматирования diff.
---
# Scope Build 060.11
В рамках данного Build реализовано только
```text
WebSocket Trade Parser
```
Build **не включает**:
- WebSocket Trade Schema Validation;
- WebSocket Trade Value Validation;
- WebSocket Trade Mapper;
- WebSocket Trade Adapter;
- Runtime Integration;
- Unified Routing;
- Trades Feed.
Это полностью соответствует принципу атомарной реализации Build.
---
# Архитектурный результат
После завершения Build система содержит завершённый уровень Parser для всех поддерживаемых WebSocket-событий.
```text
Quote
ValidatedWebSocketQuoteDocument
Quote Parser
DzengiWebSocketQuoteResponse
OHLC
ValidatedWebSocketOhlcDocument
OHLC Parser
DzengiWebSocketOhlcEvent
Trade
ValidatedWebSocketTradeDocument
Trade Parser
DzengiWebSocketTradeEvent
```
Архитектура Parsing стала полностью симметричной.
---
# Состояние WebSocket Trade Pipeline
После завершения Build 060.11 конвейер имеет следующий вид.
```text
Raw WebSocket Trade Document
ValidatedWebSocketTradeDocument
DzengiWebSocketTradeEvent
Value Validation
Mapper
Trade
```
Статус реализации компонентов:
| Компонент | Build | Статус |
|-----------|-------|--------|
| Canonical Trade Model | 060.1 | ✔ Completed |
| WebSocket Trade Transport Model | 060.9 | ✔ Completed |
| WebSocket Trade Schema Validation | 060.10 | ✔ Completed |
| WebSocket Trade Parser | 060.11 | ✔ Completed |
| WebSocket Trade Value Validation | 060.12 | Pending |
| WebSocket Trade Mapper | 060.13 | Pending |
| WebSocket Trade Adapter | 060.14 | Pending |
| Unified WebSocket Routing | 060.15 | Pending |
---
# Соблюдение архитектурных принципов
В рамках Build полностью сохранены архитектурные инварианты Dzentra.
## Локальность изменений
Изменены только:
- Parser;
- unit-тесты нового Parser.
---
## Повторное использование архитектуры
Новая реализация полностью повторяет существующий шаблон Quote и OHLC.
Новая архитектура не проектировалась.
---
## Разделение ответственности
Parser отвечает исключительно за транспортное преобразование документа.
Schema Validation,
Value Validation,
Mapper
и Runtime остаются полностью независимыми уровнями Pipeline.
---
## Отсутствие бизнес-логики
Build не выполняет:
- Value Validation;
- преобразование числовых значений;
- проверку диапазонов;
- Mapping;
- Runtime Integration.
Это полностью соответствует архитектуре Dzentra.
---
## Обратная совместимость
Существующая обработка Quote,
OHLC
и REST Trade
не изменилась.
Новая функциональность добавлена изолированно и не влияет на ранее реализованные Build.
---
# Критерии завершения Build
Build 060.11 считается завершённым,
поскольку выполнены все поставленные задачи.
- ✔ реализована функция `parse_dzengi_websocket_trade()`;
- ✔ реализовано преобразование `ValidatedWebSocketTradeDocument` в `DzengiWebSocketTradeEvent`;
- ✔ реализовано переименование транспортных полей:
- `id → trade_id`;
- `ts → timestamp`;
- `orderId → order_id`;
- ✔ реализована минимальная проверка типов, необходимая для построения транспортной модели;
- ✔ используются существующие исключения `TradeParseError`;
- ✔ транспортная модель остаётся неизменяемой (`frozen=True`);
- ✔ реализовано двадцать девять unit-тестов;
- ✔ все целевые тесты успешно проходят;
- ✔ полное регрессионное тестирование успешно завершено;
- ✔ компиляция выполнена без ошибок;
-`git diff --check` не выявил замечаний;
- ✔ изменения не выходят за пределы согласованного scope.
---
# Следующий этап
Следующим этапом дорожной карты является
```text
Build 060.12 — WebSocket Trade Value Validation
```
Цель Build:
- проверка корректности значений транспортной модели;
- проверка цены сделки;
- проверка объёма сделки;
- проверка временной метки;
- проверка символа;
- проверка идентификатора сделки;
- проверка идентификатора ордера;
- создание валидированной транспортной модели.
После завершения Build 060.12 конвейер примет следующий вид.
```text
Raw WebSocket Object
Schema Validation
ValidatedWebSocketTradeDocument
WebSocket Trade Parser
DzengiWebSocketTradeEvent
WebSocket Trade Value Validation
ValidatedTradeTransportEvent
```
Build 060.12 по-прежнему не будет выполнять:
- Mapping в каноническую модель `Trade`;
- Runtime Integration;
- Routing;
- обработку Trade Feed.
Все перечисленные задачи будут реализованы на последующих этапах дорожной карты серии 060.
---
# Итог
Build 060.11 завершил формирование уровня **Parser** для WebSocket Trade и сделал архитектуру транспортного преобразования всех поддерживаемых WebSocket-событий Dzentra полностью симметричной.
Новая реализация основана на существующем шаблоне Quote и OHLC, использует единый подход к транспортному преобразованию сообщений, повторно применяет существующую иерархию исключений и не изменяет ранее реализованное поведение системы.
Parser изолирует знания о транспортном формате WebSocket-сообщений Dzengi, выполняет минимально необходимую проверку типов для построения транспортной модели и передаёт дальнейшую обработку следующему архитектурному уровню — **Value Validation**.
Build ограничен согласованным scope, успешно прошёл целевое и полное регрессионное тестирование и создаёт необходимый фундамент для следующего этапа — **Build 060.12 — WebSocket Trade Value Validation**.