1169 lines
40 KiB
Markdown
1169 lines
40 KiB
Markdown
# Build 060.13 — WebSocket Trade Mapper
|
||
|
||
**Engineering Migration Report**
|
||
|
||
---
|
||
|
||
# Контроль документа
|
||
|
||
| Свойство | Значение |
|
||
|----------|----------|
|
||
| Build | 060.13 |
|
||
| Название | WebSocket Trade Mapper |
|
||
| Статус | Completed |
|
||
| Проект | Dzentra |
|
||
| Подсистема | Market Data Acquisition |
|
||
| Компонент | Trades Feed |
|
||
| Версия | 1.0 |
|
||
|
||
---
|
||
|
||
# Цель Build
|
||
|
||
После завершения Build 060.12 система получила полностью реализованный уровень **WebSocket Trade Value Validation**, подтверждающий корректность всех значений транспортной модели
|
||
|
||
```text
|
||
DzengiWebSocketTradeEvent
|
||
```
|
||
|
||
На этом этапе Pipeline гарантирует:
|
||
|
||
- корректную структуру транспортного документа;
|
||
- успешное построение transport model;
|
||
- корректность всех обязательных значений;
|
||
- отсутствие недопустимых числовых представлений;
|
||
- корректность строковых идентификаторов.
|
||
|
||
Однако даже после успешного прохождения всех перечисленных этапов транспортная модель ещё не может использоваться остальной частью системы.
|
||
|
||
Несмотря на корректность структуры и значений, объект
|
||
|
||
```text
|
||
DzengiWebSocketTradeEvent
|
||
```
|
||
|
||
по-прежнему остаётся транспортной моделью биржи Dzengi.
|
||
|
||
Он содержит особенности конкретного источника данных:
|
||
|
||
- транспортные числовые представления;
|
||
- транспортное поле `size`;
|
||
- транспортное поле `buyer`;
|
||
- транспортное поле `order_id`;
|
||
- транспортное представление времени в миллисекундах Unix Epoch.
|
||
|
||
Использование подобных моделей за пределами слоя адаптера противоречит базовым архитектурным принципам Dzentra.
|
||
|
||
Внутренние компоненты системы не должны зависеть от особенностей API конкретной биржи.
|
||
|
||
Для решения данной задачи архитектура Dzentra предусматривает следующий обязательный уровень Pipeline —
|
||
|
||
**Mapper**.
|
||
|
||
Именно Mapper выполняет преобразование транспортной модели источника данных в единую каноническую модель предметной области.
|
||
|
||
Build 060.13 реализует данный уровень для WebSocket Trade.
|
||
|
||
Основная задача Build — преобразовать проверенную транспортную модель
|
||
|
||
```text
|
||
DzengiWebSocketTradeEvent
|
||
```
|
||
|
||
в каноническую immutable-модель
|
||
|
||
```text
|
||
Trade
|
||
```
|
||
|
||
с выполнением всех необходимых преобразований типов данных.
|
||
|
||
При этом Build не затрагивает:
|
||
|
||
- Schema Validation;
|
||
- Parser;
|
||
- Value Validation;
|
||
- WebSocket Runtime;
|
||
- Routing;
|
||
- Trades Feed.
|
||
|
||
---
|
||
|
||
# Предпосылки
|
||
|
||
К началу Build архитектура Market Data Acquisition уже содержала полностью реализованные Mapper для остальных типов рыночных данных.
|
||
|
||
Аналогичный уровень преобразования уже существовал для:
|
||
|
||
- REST Quote;
|
||
- WebSocket Quote;
|
||
- WebSocket OHLC;
|
||
- REST Aggregate Trade.
|
||
|
||
Во всех случаях использовалась одинаковая архитектурная схема обработки.
|
||
|
||
```text
|
||
Transport Model
|
||
│
|
||
▼
|
||
Mapper
|
||
│
|
||
▼
|
||
Canonical Model
|
||
```
|
||
|
||
После завершения Build 060.12 аналогичный транспортный конвейер появился и для WebSocket Trade.
|
||
|
||
```text
|
||
ValidatedWebSocketTradeDocument
|
||
│
|
||
▼
|
||
Trade Parser
|
||
│
|
||
▼
|
||
DzengiWebSocketTradeEvent
|
||
│
|
||
▼
|
||
Value Validation
|
||
│
|
||
▼
|
||
DzengiWebSocketTradeEvent
|
||
```
|
||
|
||
Однако следующий обязательный уровень — преобразование транспортной модели в каноническую модель системы — ещё отсутствовал.
|
||
|
||
Таким образом WebSocket-конвейер обработки сделок оставался архитектурно незавершённым.
|
||
|
||
---
|
||
|
||
# Архитектурное основание
|
||
|
||
Одним из базовых принципов архитектуры Dzentra является полная изоляция внутренних компонентов системы от формата данных конкретной биржи.
|
||
|
||
Любые особенности транспортного протокола должны оставаться исключительно внутри слоя адаптера.
|
||
|
||
Общий конвейер обработки рыночных данных имеет следующий вид.
|
||
|
||
```text
|
||
Raw Source
|
||
│
|
||
▼
|
||
Schema Validation
|
||
│
|
||
▼
|
||
Transport Model
|
||
│
|
||
▼
|
||
Value Validation
|
||
│
|
||
▼
|
||
Mapper
|
||
│
|
||
▼
|
||
Domain Model
|
||
```
|
||
|
||
Каждый уровень Pipeline отвечает только за одну категорию задач.
|
||
|
||
Для WebSocket Trade это разделение выглядит следующим образом.
|
||
|
||
```text
|
||
Schema Validation
|
||
```
|
||
|
||
гарантирует корректность структуры транспортного документа.
|
||
|
||
---
|
||
|
||
```text
|
||
Parser
|
||
```
|
||
|
||
создаёт транспортную модель
|
||
|
||
```text
|
||
DzengiWebSocketTradeEvent
|
||
```
|
||
|
||
без изменения типов данных.
|
||
|
||
---
|
||
|
||
```text
|
||
Value Validation
|
||
```
|
||
|
||
подтверждает корректность значений транспортной модели без выполнения каких-либо преобразований.
|
||
|
||
---
|
||
|
||
Следующий уровень —
|
||
|
||
```text
|
||
Mapper
|
||
```
|
||
|
||
выполняет преобразование транспортной модели в каноническую модель предметной области.
|
||
|
||
Именно Mapper отвечает за:
|
||
|
||
- преобразование транспортных числовых представлений в `Decimal`;
|
||
- преобразование транспортного timestamp в `datetime`;
|
||
- преобразование транспортных признаков сделки в канонические перечисления;
|
||
- переименование транспортных полей;
|
||
- создание immutable-модели `Trade`.
|
||
|
||
При этом Mapper принципиально **не выполняет**:
|
||
|
||
- повторную Validation;
|
||
- анализ структуры JSON;
|
||
- Runtime-логику;
|
||
- бизнес-логику;
|
||
- маршрутизацию событий.
|
||
|
||
Такое разделение ответственности позволяет каждому уровню Pipeline оставаться независимым, повторно используемым и легко тестируемым.
|
||
|
||
---
|
||
|
||
# Результаты архитектурного аудита
|
||
|
||
Перед реализацией Build был выполнен аудит существующего слоя Mapper.
|
||
|
||
В ходе анализа подтверждено наличие полностью сформированной архитектуры преобразования транспортных моделей.
|
||
|
||
Для различных типов рыночных данных уже реализованы функции:
|
||
|
||
```text
|
||
map_dzengi_quote_to_quote(...)
|
||
|
||
map_dzengi_websocket_quote_to_quote(...)
|
||
|
||
map_dzengi_websocket_ohlc_to_candle_close_event(...)
|
||
|
||
map_dzengi_rest_agg_trades_to_trades(...)
|
||
```
|
||
|
||
Все существующие Mapper используют одинаковые архитектурные принципы.
|
||
|
||
Преобразование транспортных типов выполняется исключительно внутри Mapper.
|
||
|
||
Для этого повторно используются существующие helper-функции проекта.
|
||
|
||
Одновременно аудит подтвердил наличие общего исключения
|
||
|
||
```text
|
||
TradeMappingError
|
||
```
|
||
|
||
используемого всеми существующими Mapper при невозможности построения канонической модели.
|
||
|
||
При этом отдельный Mapper для транспортной модели
|
||
|
||
```text
|
||
DzengiWebSocketTradeEvent
|
||
```
|
||
|
||
в системе отсутствовал.
|
||
|
||
Таким образом единственным отсутствующим элементом архитектурной цепочки являлся собственный уровень Mapping для WebSocket Trade.
|
||
|
||
Build 060.13 полностью закрывает данный пробел и завершает следующий обязательный уровень Pipeline серии Build 060.
|
||
|
||
---
|
||
|
||
# Архитектурное решение
|
||
|
||
По результатам проведённого аудита было принято решение полностью повторить архитектурный шаблон, уже используемый Mapper остальных типов рыночных данных.
|
||
|
||
В систему добавлена функция
|
||
|
||
```text
|
||
map_dzengi_websocket_trade_to_trade(...)
|
||
```
|
||
|
||
которая принимает транспортную модель
|
||
|
||
```text
|
||
DzengiWebSocketTradeEvent
|
||
```
|
||
|
||
и создаёт каноническую immutable-модель
|
||
|
||
```text
|
||
Trade
|
||
```
|
||
|
||
Во время преобразования выполняются все необходимые преобразования транспортных типов данных.
|
||
|
||
После успешного завершения Mapping транспортная модель больше не используется последующими уровнями системы.
|
||
|
||
Конвейер WebSocket Trade принимает следующий вид.
|
||
|
||
```text
|
||
Raw WebSocket Trade
|
||
│
|
||
▼
|
||
WebSocket Trade Schema Validation
|
||
│
|
||
▼
|
||
ValidatedWebSocketTradeDocument
|
||
│
|
||
▼
|
||
WebSocket Trade Parser
|
||
│
|
||
▼
|
||
DzengiWebSocketTradeEvent
|
||
│
|
||
▼
|
||
WebSocket Trade Value Validation
|
||
│
|
||
▼
|
||
DzengiWebSocketTradeEvent
|
||
│
|
||
▼
|
||
WebSocket Trade Mapper
|
||
│
|
||
▼
|
||
Trade
|
||
```
|
||
|
||
Build 060.13 не изменяет архитектуру ранее реализованных компонентов и завершает следующий обязательный уровень транспортного Pipeline.
|
||
|
||
# Реализованный уровень Mapper
|
||
|
||
В файл
|
||
|
||
```text
|
||
src/market_data/acquisition/adapters/dzengi/mapper.py
|
||
```
|
||
|
||
добавлена новая функция
|
||
|
||
```text
|
||
map_dzengi_websocket_trade_to_trade(...)
|
||
```
|
||
|
||
Функция получает транспортную модель
|
||
|
||
```text
|
||
DzengiWebSocketTradeEvent
|
||
```
|
||
|
||
и выполняет построение канонической модели
|
||
|
||
```text
|
||
Trade
|
||
```
|
||
|
||
Во время выполнения Mapping создаётся новый immutable-объект предметной области.
|
||
|
||
Транспортная модель при этом остаётся неизменной.
|
||
|
||
Таким образом следующий уровень Pipeline получает уже не транспортную модель биржи, а полностью независимую внутреннюю модель системы.
|
||
|
||
---
|
||
|
||
# Почему Mapper создаёт новую модель
|
||
|
||
Во время архитектурного проектирования отдельно рассматривался вопрос о возможности повторного использования объекта
|
||
|
||
```text
|
||
DzengiWebSocketTradeEvent
|
||
```
|
||
|
||
на последующих уровнях системы.
|
||
|
||
По результатам анализа было принято решение полностью отказаться от подобного подхода.
|
||
|
||
Основные причины:
|
||
|
||
- транспортная модель отражает структуру конкретной биржи;
|
||
- транспортная модель содержит поля, отсутствующие в предметной области;
|
||
- транспортная модель использует транспортные представления числовых данных;
|
||
- транспортная модель использует транспортные соглашения о наименовании полей;
|
||
- внутренние компоненты системы не должны зависеть от API биржи.
|
||
|
||
Поэтому Mapper всегда создаёт новый экземпляр
|
||
|
||
```text
|
||
Trade
|
||
```
|
||
|
||
который становится единственной моделью, используемой за пределами слоя адаптера.
|
||
|
||
Подобное решение полностью соответствует базовому архитектурному принципу Dzentra — полной изоляции внутренних компонентов от транспортных контрактов внешних источников данных.
|
||
|
||
---
|
||
|
||
# Преобразуемая транспортная модель
|
||
|
||
Преобразование выполняется над объектом
|
||
|
||
```python
|
||
@dataclass(frozen=True, slots=True)
|
||
class DzengiWebSocketTradeEvent:
|
||
trade_id: int
|
||
price: DzengiRawNumeric
|
||
size: DzengiRawNumeric
|
||
timestamp: int
|
||
symbol: str
|
||
buyer: bool
|
||
order_id: str
|
||
```
|
||
|
||
После выполнения Mapping создаётся объект
|
||
|
||
```python
|
||
@dataclass(frozen=True, slots=True)
|
||
class Trade:
|
||
symbol: str
|
||
trade_id: int
|
||
price: Decimal
|
||
quantity: Decimal
|
||
executed_at: datetime
|
||
aggressor_side: TradeAggressorSide
|
||
source: str
|
||
```
|
||
|
||
Таким образом Mapper полностью устраняет зависимость системы от транспортной модели биржи.
|
||
|
||
---
|
||
|
||
# Преобразование идентификатора сделки
|
||
|
||
Поле
|
||
|
||
```text
|
||
trade_id
|
||
```
|
||
|
||
имеет одинаковую семантику в транспортной и канонической модели.
|
||
|
||
Поэтому Mapper переносит его без изменения значения.
|
||
|
||
Дополнительных преобразований не выполняется.
|
||
|
||
---
|
||
|
||
# Преобразование цены сделки
|
||
|
||
Поле
|
||
|
||
```text
|
||
price
|
||
```
|
||
|
||
в транспортной модели может быть представлено в нескольких форматах.
|
||
|
||
Например:
|
||
|
||
```text
|
||
"63992.50"
|
||
|
||
63992
|
||
|
||
63992.50
|
||
```
|
||
|
||
Во время Mapping используется существующий helper проекта, преобразующий транспортное представление в
|
||
|
||
```text
|
||
Decimal
|
||
```
|
||
|
||
После завершения Mapping каноническая модель всегда содержит внутренний числовой тип системы независимо от исходного представления данных.
|
||
|
||
---
|
||
|
||
# Преобразование количества сделки
|
||
|
||
Транспортная модель использует поле
|
||
|
||
```text
|
||
size
|
||
```
|
||
|
||
которое отражает терминологию API биржи.
|
||
|
||
В канонической модели используется единое наименование
|
||
|
||
```text
|
||
quantity
|
||
```
|
||
|
||
Во время Mapping выполняются одновременно два действия:
|
||
|
||
- преобразование транспортного значения в `Decimal`;
|
||
- переименование транспортного поля в соответствии с внутренней моделью предметной области.
|
||
|
||
После завершения Mapping дальнейшая работа системы полностью абстрагируется от терминологии конкретной биржи.
|
||
|
||
---
|
||
|
||
# Преобразование временной метки
|
||
|
||
Поле
|
||
|
||
```text
|
||
timestamp
|
||
```
|
||
|
||
в транспортной модели представляет собой количество миллисекунд, прошедших с начала эпохи Unix.
|
||
|
||
Подобное представление удобно для передачи данных по сети, однако не является внутренним представлением времени в Dzentra.
|
||
|
||
Во время Mapping используется существующая helper-функция преобразования времени.
|
||
|
||
В результате каноническая модель получает объект
|
||
|
||
```text
|
||
datetime
|
||
```
|
||
|
||
в часовом поясе UTC.
|
||
|
||
Таким образом все внутренние компоненты системы используют единый формат представления времени независимо от способа передачи данных биржей.
|
||
|
||
---
|
||
|
||
# Преобразование стороны агрессора
|
||
|
||
Во время архитектурного аудита отдельно анализировалась семантика транспортного поля
|
||
|
||
```text
|
||
buyer
|
||
```
|
||
|
||
В WebSocket API Dzengi данное поле определяет сторону покупателя сделки.
|
||
|
||
Однако внутренняя модель Dzentra использует перечисление
|
||
|
||
```text
|
||
TradeAggressorSide
|
||
```
|
||
|
||
Поэтому Mapper выполняет явное преобразование транспортного признака в каноническое перечисление.
|
||
|
||
Используется следующее соответствие.
|
||
|
||
```text
|
||
buyer = True
|
||
│
|
||
▼
|
||
TradeAggressorSide.BUY
|
||
```
|
||
|
||
```text
|
||
buyer = False
|
||
│
|
||
▼
|
||
TradeAggressorSide.SELL
|
||
```
|
||
|
||
Подобное преобразование делает внутреннюю модель полностью независимой от конкретного транспортного соглашения биржи.
|
||
|
||
---
|
||
|
||
# Преобразование источника данных
|
||
|
||
Каноническая модель
|
||
|
||
```text
|
||
Trade
|
||
```
|
||
|
||
содержит поле
|
||
|
||
```text
|
||
source
|
||
```
|
||
|
||
которое используется для идентификации происхождения события.
|
||
|
||
Во время Mapping данное поле получает фиксированное значение
|
||
|
||
```text
|
||
dzengi_websocket_trade
|
||
```
|
||
|
||
Использование отдельного идентификатора источника позволяет последующим уровням системы различать происхождение канонических моделей без анализа транспортного Pipeline.
|
||
|
||
---
|
||
|
||
# Почему order_id отсутствует в канонической модели
|
||
|
||
Транспортная модель WebSocket содержит дополнительное поле
|
||
|
||
```text
|
||
order_id
|
||
```
|
||
|
||
которое используется исключительно транспортным контрактом биржи.
|
||
|
||
Во время архитектурного проектирования отдельно анализировался вопрос необходимости переноса данного значения в каноническую модель.
|
||
|
||
По результатам анализа было принято решение отказаться от подобного преобразования.
|
||
|
||
Основные причины:
|
||
|
||
- идентификатор ордера отсутствует в модели предметной области;
|
||
- последующие уровни системы не используют данное значение;
|
||
- сохранение транспортного идентификатора нарушило бы независимость канонической модели.
|
||
|
||
В результате поле
|
||
|
||
```text
|
||
order_id
|
||
```
|
||
|
||
полностью завершается на уровне адаптера и не попадает в модель
|
||
|
||
```text
|
||
Trade
|
||
```
|
||
|
||
---
|
||
|
||
# Повторное использование существующих helper-функций
|
||
|
||
Build 060.13 не вводит новых механизмов преобразования числовых значений и времени.
|
||
|
||
Вместо этого повторно используются уже существующие helper-функции проекта.
|
||
|
||
Для преобразования числовых представлений применяется существующий механизм преобразования в
|
||
|
||
```text
|
||
Decimal
|
||
```
|
||
|
||
Для преобразования временной метки используется существующая функция построения объекта
|
||
|
||
```text
|
||
datetime
|
||
```
|
||
|
||
Подобный подход обеспечивает единообразное поведение всех Mapper проекта независимо от типа источника данных.
|
||
|
||
---
|
||
|
||
# Использование TradeMappingError
|
||
|
||
Все ошибки преобразования используют существующее исключение
|
||
|
||
```text
|
||
TradeMappingError
|
||
```
|
||
|
||
Build не вводит новых типов исключений.
|
||
|
||
Это сохраняет единый механизм обработки ошибок Mapping во всей подсистеме Market Data Acquisition.
|
||
|
||
Value Validation продолжает использовать
|
||
|
||
```text
|
||
TradeValueError
|
||
```
|
||
|
||
а Mapper использует исключительно
|
||
|
||
```text
|
||
TradeMappingError
|
||
```
|
||
|
||
Тем самым достигается чёткое разделение ошибок проверки данных и ошибок преобразования транспортной модели.
|
||
|
||
---
|
||
|
||
# Изменённые файлы
|
||
|
||
В рамках Build были изменены только два файла.
|
||
|
||
## Mapper
|
||
|
||
```text
|
||
src/market_data/acquisition/adapters/dzengi/mapper.py
|
||
```
|
||
|
||
Добавлена функция
|
||
|
||
```text
|
||
map_dzengi_websocket_trade_to_trade(...)
|
||
```
|
||
|
||
а также вспомогательная функция преобразования стороны агрессора WebSocket Trade.
|
||
|
||
Существующая логика Mapping Quote, OHLC и REST Trade не изменялась.
|
||
|
||
---
|
||
|
||
## Unit-тесты
|
||
|
||
```text
|
||
tests/unit/market_data/acquisition/adapters/dzengi/test_websocket_trade_mapper.py
|
||
```
|
||
|
||
Добавлен полный набор unit-тестов нового уровня Mapping.
|
||
|
||
---
|
||
|
||
# Добавленные тесты
|
||
|
||
В рамках Build реализовано двадцать два unit-теста, полностью покрывающих новую функциональность.
|
||
|
||
## Проверка корректного Mapping
|
||
|
||
Подтверждается успешное создание канонической модели
|
||
|
||
```text
|
||
Trade
|
||
```
|
||
|
||
из полностью корректной транспортной модели.
|
||
|
||
---
|
||
|
||
## Проверка преобразования стороны агрессора
|
||
|
||
Отдельные тесты подтверждают корректное преобразование обоих допустимых значений:
|
||
|
||
- `buyer=True`;
|
||
- `buyer=False`.
|
||
|
||
---
|
||
|
||
## Проверка преобразования числовых представлений
|
||
|
||
Параметризованные тесты подтверждают корректную обработку:
|
||
|
||
- строк;
|
||
- целых чисел;
|
||
- чисел с плавающей точкой.
|
||
|
||
для полей:
|
||
|
||
- `price`;
|
||
- `size`.
|
||
|
||
---
|
||
|
||
## Проверка преобразования времени
|
||
|
||
Подтверждается корректное построение объекта
|
||
|
||
```text
|
||
datetime
|
||
```
|
||
|
||
в часовом поясе UTC.
|
||
|
||
---
|
||
|
||
## Проверка канонических имён полей
|
||
|
||
Отдельные тесты подтверждают:
|
||
|
||
- преобразование `size → quantity`;
|
||
- удаление пробельных символов из `symbol`;
|
||
- заполнение поля `source`;
|
||
- отсутствие поля `order_id` в канонической модели.
|
||
|
||
---
|
||
|
||
## Проверка неизменяемости моделей
|
||
|
||
Отдельные тесты подтверждают:
|
||
|
||
- неизменяемость транспортной модели после Mapping;
|
||
- неизменяемость созданной модели `Trade`.
|
||
|
||
---
|
||
|
||
## Проверка ошибок преобразования
|
||
|
||
Реализованы проверки генерации
|
||
|
||
```text
|
||
TradeMappingError
|
||
```
|
||
|
||
при невозможности преобразования:
|
||
|
||
- числовых значений;
|
||
- специальных числовых представлений;
|
||
- недопустимого значения timestamp.
|
||
|
||
# Результаты тестирования
|
||
|
||
После завершения реализации выполнен целевой запуск нового набора unit-тестов.
|
||
|
||
```bash
|
||
python -m pytest \
|
||
tests/unit/market_data/acquisition/adapters/dzengi/test_websocket_trade_mapper.py \
|
||
-q
|
||
```
|
||
|
||
Результат:
|
||
|
||
```text
|
||
22 passed in 0.04s
|
||
```
|
||
|
||
Все проверки новой функциональности успешно завершены.
|
||
|
||
Новый набор тестов полностью покрывает:
|
||
|
||
- успешное построение канонической модели `Trade`;
|
||
- преобразование транспортных числовых представлений;
|
||
- преобразование временной метки в `datetime`;
|
||
- преобразование стороны агрессора;
|
||
- переименование транспортных полей;
|
||
- заполнение источника данных;
|
||
- генерацию исключений для всех типов ошибок Mapping;
|
||
- неизменяемость транспортной и канонической моделей.
|
||
|
||
Параметризованные тесты позволили существенно сократить объём тестового кода без уменьшения покрытия и обеспечили единообразную проверку различных вариантов входных данных.
|
||
|
||
---
|
||
|
||
# Регрессионное тестирование
|
||
|
||
После завершения реализации выполнен полный запуск набора unit-тестов проекта.
|
||
|
||
```bash
|
||
python -m pytest -q
|
||
```
|
||
|
||
Результат:
|
||
|
||
```text
|
||
1230 passed in 2.00s
|
||
```
|
||
|
||
Регрессий существующей функциональности не обнаружено.
|
||
|
||
Все ранее реализованные Build продолжают работать без каких-либо изменений.
|
||
|
||
Это подтверждает, что добавленная функциональность полностью изолирована и не влияет на существующие конвейеры обработки Quote, OHLC, REST Trade и остальные подсистемы проекта.
|
||
|
||
---
|
||
|
||
# Проверка компиляции
|
||
|
||
После завершения реализации выполнена полная проверка компиляции проекта.
|
||
|
||
```bash
|
||
python -m compileall src tests
|
||
```
|
||
|
||
Компиляция завершилась успешно.
|
||
|
||
Ошибок синтаксиса не обнаружено.
|
||
|
||
Все изменённые файлы успешно компилируются и не нарушают целостность проекта.
|
||
|
||
---
|
||
|
||
# Проверка Git diff
|
||
|
||
После завершения реализации выполнена финальная проверка изменений.
|
||
|
||
```bash
|
||
git diff --check
|
||
```
|
||
|
||
Результат:
|
||
|
||
```text
|
||
без замечаний
|
||
```
|
||
|
||
Проверка подтвердила отсутствие:
|
||
|
||
- trailing whitespace;
|
||
- ошибок окончания строк;
|
||
- конфликтов diff;
|
||
- нарушений форматирования.
|
||
|
||
---
|
||
|
||
# Scope Build 060.13
|
||
|
||
В рамках данного Build реализован исключительно уровень
|
||
|
||
```text
|
||
WebSocket Trade Mapper
|
||
```
|
||
|
||
Build **не включает**:
|
||
|
||
- WebSocket Trade Schema Validation;
|
||
- WebSocket Trade Parser;
|
||
- WebSocket Trade Value Validation;
|
||
- WebSocket Trade Adapter;
|
||
- Runtime Integration;
|
||
- Unified Routing;
|
||
- Trades Feed.
|
||
|
||
Подобное ограничение полностью соответствует принятому принципу атомарной реализации Build.
|
||
|
||
Каждый этап дорожной карты реализует только один архитектурный уровень Pipeline.
|
||
|
||
---
|
||
|
||
# Архитектурный результат
|
||
|
||
После завершения Build система содержит полностью реализованный транспортный Pipeline WebSocket Trade вплоть до создания канонической модели предметной области.
|
||
|
||
Конвейер обработки принимает следующий вид.
|
||
|
||
```text
|
||
Raw WebSocket Trade
|
||
│
|
||
▼
|
||
WebSocket Trade Schema Validation
|
||
│
|
||
▼
|
||
ValidatedWebSocketTradeDocument
|
||
│
|
||
▼
|
||
WebSocket Trade Parser
|
||
│
|
||
▼
|
||
DzengiWebSocketTradeEvent
|
||
│
|
||
▼
|
||
WebSocket Trade Value Validation
|
||
│
|
||
▼
|
||
DzengiWebSocketTradeEvent
|
||
│
|
||
▼
|
||
WebSocket Trade Mapper
|
||
│
|
||
▼
|
||
Trade
|
||
```
|
||
|
||
Таким образом архитектура WebSocket Trade теперь полностью повторяет ранее реализованные конвейеры обработки Quote, OHLC и REST Trade.
|
||
|
||
После завершения Mapping дальнейшие уровни системы больше не используют транспортную модель биржи.
|
||
|
||
Все последующие компоненты работают исключительно с канонической моделью
|
||
|
||
```text
|
||
Trade
|
||
```
|
||
|
||
что полностью соответствует базовым архитектурным принципам Dzentra.
|
||
|
||
---
|
||
|
||
# Состояние WebSocket Trade Pipeline
|
||
|
||
После завершения Build 060.13 конвейер имеет следующий вид.
|
||
|
||
```text
|
||
Raw WebSocket Trade
|
||
│
|
||
▼
|
||
Schema Validation
|
||
│
|
||
▼
|
||
ValidatedWebSocketTradeDocument
|
||
│
|
||
▼
|
||
Parser
|
||
│
|
||
▼
|
||
DzengiWebSocketTradeEvent
|
||
│
|
||
▼
|
||
Value Validation
|
||
│
|
||
▼
|
||
DzengiWebSocketTradeEvent
|
||
│
|
||
▼
|
||
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 | ✔ Completed |
|
||
| WebSocket Trade Mapper | 060.13 | ✔ Completed |
|
||
| WebSocket Trade Adapter | 060.14 | Pending |
|
||
| Unified WebSocket Routing | 060.15 | Pending |
|
||
|
||
---
|
||
|
||
# Соблюдение архитектурных принципов
|
||
|
||
В рамках Build полностью сохранены архитектурные инварианты Dzentra.
|
||
|
||
## Локальность изменений
|
||
|
||
Изменены только:
|
||
|
||
- `adapters/dzengi/mapper.py`;
|
||
- unit-тесты нового уровня Mapping.
|
||
|
||
Существующая логика Quote, OHLC и REST Trade не изменялась.
|
||
|
||
---
|
||
|
||
## Повторное использование архитектуры
|
||
|
||
Новая реализация полностью повторяет существующий архитектурный шаблон Mapper.
|
||
|
||
Новая архитектура не проектировалась.
|
||
|
||
Использован уже существующий подход, применяемый для остальных типов рыночных данных.
|
||
|
||
---
|
||
|
||
## Повторное использование инфраструктуры
|
||
|
||
Для преобразования числовых значений, временных меток и канонических перечислений повторно использованы существующие helper-функции проекта.
|
||
|
||
Build не вводит новых механизмов преобразования и не дублирует уже реализованную функциональность.
|
||
|
||
Это обеспечивает единообразное поведение всех Mapper проекта.
|
||
|
||
---
|
||
|
||
## Разделение ответственности
|
||
|
||
Mapper отвечает исключительно за преобразование транспортной модели в каноническую модель предметной области.
|
||
|
||
Build не выполняет:
|
||
|
||
- Schema Validation;
|
||
- Value Validation;
|
||
- Runtime Integration;
|
||
- бизнес-логику;
|
||
- маршрутизацию событий.
|
||
|
||
Все перечисленные задачи остаются ответственностью предыдущих либо последующих уровней Pipeline.
|
||
|
||
---
|
||
|
||
## Обратная совместимость
|
||
|
||
Существующая обработка:
|
||
|
||
- Quote;
|
||
- OHLC;
|
||
- REST Trade;
|
||
|
||
не изменилась.
|
||
|
||
Добавленная функциональность полностью изолирована и не оказывает влияния на ранее реализованные компоненты системы.
|
||
|
||
---
|
||
|
||
# Архитектурные решения Build (ADR)
|
||
|
||
## ADR-060.13-001
|
||
|
||
**Mapper всегда создаёт новую каноническую модель.**
|
||
|
||
После завершения преобразования транспортная модель больше не используется последующими уровнями системы.
|
||
|
||
Это обеспечивает полную изоляцию внутренней архитектуры от API конкретной биржи.
|
||
|
||
---
|
||
|
||
## ADR-060.13-002
|
||
|
||
**Все преобразования транспортных типов выполняются исключительно внутри Mapper.**
|
||
|
||
Преобразование транспортных числовых представлений в `Decimal`, временной метки в `datetime` и транспортных признаков сделки в канонические перечисления не допускается ни на одном другом уровне Pipeline.
|
||
|
||
---
|
||
|
||
## ADR-060.13-003
|
||
|
||
**Транспортные поля, отсутствующие в предметной области, не переносятся в каноническую модель.**
|
||
|
||
Поле
|
||
|
||
```text
|
||
order_id
|
||
```
|
||
|
||
является частью транспортного контракта биржи и не включается в модель
|
||
|
||
```text
|
||
Trade
|
||
```
|
||
|
||
---
|
||
|
||
## ADR-060.13-004
|
||
|
||
**Mapper использует существующее исключение TradeMappingError.**
|
||
|
||
Build не вводит новых типов исключений.
|
||
|
||
Все ошибки преобразования продолжают использовать единый механизм обработки ошибок Mapping.
|
||
|
||
---
|
||
|
||
# Критерии завершения Build
|
||
|
||
Build 060.13 считается завершённым, поскольку выполнены все поставленные задачи.
|
||
|
||
- ✔ реализована функция `map_dzengi_websocket_trade_to_trade()`;
|
||
- ✔ реализовано преобразование транспортной модели в каноническую модель `Trade`;
|
||
- ✔ реализовано преобразование транспортных числовых представлений в `Decimal`;
|
||
- ✔ реализовано преобразование временной метки в `datetime`;
|
||
- ✔ реализовано преобразование стороны агрессора;
|
||
- ✔ реализовано заполнение поля `source`;
|
||
- ✔ исключено транспортное поле `order_id`;
|
||
- ✔ повторно использованы существующие helper-функции;
|
||
- ✔ используется существующее исключение `TradeMappingError`;
|
||
- ✔ транспортная модель остаётся неизменяемой;
|
||
- ✔ реализовано 22 unit-теста;
|
||
- ✔ целевой набор тестов успешно проходит;
|
||
- ✔ полное регрессионное тестирование успешно завершено;
|
||
- ✔ проект успешно компилируется;
|
||
- ✔ `git diff --check` не выявил замечаний;
|
||
- ✔ изменения полностью укладываются в согласованный scope Build.
|
||
|
||
---
|
||
|
||
# Следующий этап
|
||
|
||
Следующим этапом дорожной карты является
|
||
|
||
```text
|
||
Build 060.14 — WebSocket Trade Adapter
|
||
```
|
||
|
||
Цель следующего Build:
|
||
|
||
- объединить Schema Validation, Parser, Value Validation и Mapper в единый адаптер;
|
||
- реализовать единую точку обработки WebSocket Trade;
|
||
- завершить адаптер получения канонической модели `Trade` из сырого WebSocket-сообщения;
|
||
- подготовить основу для последующей интеграции в Unified WebSocket Routing.
|
||
|
||
---
|
||
|
||
# Итог
|
||
|
||
Build 060.13 завершил реализацию уровня **WebSocket Trade Mapper** и сделал транспортный Pipeline WebSocket Trade полностью независимым от формата данных биржи Dzengi.
|
||
|
||
Новая реализация основана на уже существующих архитектурных принципах Dzentra, повторно использует существующую инфраструктуру преобразования данных, создаёт каноническую модель предметной области и сохраняет строгое разделение ответственности между уровнями Pipeline.
|
||
|
||
Build ограничен согласованным scope, успешно прошёл целевое и полное регрессионное тестирование, подтвердил отсутствие регрессий и завершил построение транспортного конвейера WebSocket Trade до уровня канонической модели.
|
||
|
||
Следующим этапом развития серии является **Build 060.14 — WebSocket Trade Adapter**, который объединит все реализованные уровни Pipeline в единый компонент обработки входящих WebSocket-сообщений. |