Files
dzentra_bot/docs/migrations/build_060_12.md

36 KiB
Raw Permalink Blame History

Build 060.12 — WebSocket Trade Value Validation

Engineering Migration Report


Контроль документа

Свойство Значение
Build 060.12
Название WebSocket Trade Value Validation
Статус Completed
Проект Dzentra
Подсистема Market Data Acquisition
Компонент Trades Feed
Версия 1.0

Цель Build

После завершения Build 060.11 система получила полностью реализованный уровень WebSocket Trade Parser, преобразующий структурно корректный документ

ValidatedWebSocketTradeDocument

в транспортную модель

DzengiWebSocketTradeEvent

Parser гарантирует корректное построение транспортного объекта и минимальную проверку типов, необходимую для создания модели.

Однако после завершения Parsing транспортная модель ещё не может считаться пригодной для дальнейшего использования в системе.

Несмотря на корректность структуры и типов, отдельные значения транспортной модели могут оставаться недопустимыми с точки зрения предметной области.

Например:

  • цена сделки может быть равна нулю;
  • объём сделки может быть отрицательным;
  • timestamp может иметь недопустимое значение;
  • идентификатор сделки может отсутствовать либо быть неположительным;
  • строковые поля могут содержать только пробельные символы;
  • числовые значения могут содержать NaN или бесконечность.

Подобные ошибки уже не относятся к структуре документа и не должны обрабатываться Parser.

Для их обработки в архитектуре Dzentra предусмотрен отдельный уровень Pipeline — Value Validation.

Build 060.12 реализует данный уровень для WebSocket Trade.

Основная задача Build — проверить корректность содержимого транспортной модели без выполнения каких-либо преобразований данных и без создания новых объектов.

Данный Build ограничивается исключительно проверкой значений транспортной модели и не затрагивает:

  • Schema Validation;
  • Parser;
  • Mapper;
  • Runtime;
  • Routing;
  • Trades Feed.

Предпосылки

К началу Build архитектура подсистемы Market Data Acquisition уже содержала полноценный конвейер обработки транспортных моделей Quote, OHLC и REST Trade.

Для каждого из них использовалось одинаковое разделение ответственности между уровнями Pipeline.

Общая последовательность обработки выглядела следующим образом.

Raw Source
        │
        ▼
Schema Validation
        │
        ▼
Transport Model
        │
        ▼
Value Validation
        │
        ▼
Mapper
        │
        ▼
Domain Model

После завершения Build 060.11 аналогичный транспортный уровень появился и для WebSocket Trade.

ValidatedWebSocketTradeDocument
        │
        ▼
Trade Parser
        │
        ▼
DzengiWebSocketTradeEvent

Однако следующий обязательный этап — проверка корректности самих значений транспортной модели — ещё отсутствовал.

Таким образом WebSocket-конвейер обработки сделок оставался архитектурно незавершённым.


Архитектурное основание

Одним из базовых принципов архитектуры Dzentra является строгое разделение ответственности между последовательными уровнями Pipeline.

Каждый уровень отвечает только за одну категорию задач.

Для WebSocket Trade это разделение выглядит следующим образом.

Schema Validation

отвечает исключительно за проверку структуры документа.

Она гарантирует:

  • наличие транспортной оболочки;
  • наличие объекта payload;
  • присутствие обязательных полей;
  • соответствие ожидаемым типам транспортного документа.

Следующий уровень —

Parser

выполняет транспортное преобразование.

Он:

  • извлекает значения из payload;
  • переименовывает транспортные поля;
  • создаёт immutable transport model.

После этого ответственность Parser полностью заканчивается.

Проверка корректности самих значений транспортной модели относится уже к следующему уровню —

Value Validation

Именно Value Validation отвечает за проверку предметной допустимости данных.

На данном уровне анализируются:

  • допустимость числовых значений;
  • диапазоны значений;
  • корректность строковых идентификаторов;
  • невозможность использования специальных числовых значений (NaN, Infinity);
  • другие ограничения транспортного контракта.

При этом Value Validation принципиально не выполняет:

  • преобразование типов;
  • Mapping;
  • создание модели Trade;
  • бизнес-логику;
  • обработку Runtime.

Такое разделение позволяет каждому уровню Pipeline оставаться независимым и легко тестируемым.


Результаты архитектурного аудита

Перед реализацией Build был выполнен аудит существующей подсистемы проверки значений.

В ходе анализа подтверждено наличие следующих компонентов.

Для Quote уже реализованы:

validate_dzengi_websocket_quote_values(...)

Для OHLC реализованы:

validate_dzengi_websocket_ohlc_values(...)

Для REST Trade реализованы:

validate_rest_agg_trade_values(...)

Также подтверждено существование общего набора вспомогательных функций проверки:

_trade_positive_int(...)

_trade_positive_decimal(...)

Указанные helper-функции уже используются существующей реализацией REST Trade и полностью соответствуют требованиям нового Build.

Одновременно аудит подтвердил отсутствие отдельной проверки значений транспортной модели

DzengiWebSocketTradeEvent

Таким образом единственным отсутствующим элементом архитектурной цепочки являлся собственный уровень Value Validation для WebSocket Trade.

Build 060.12 полностью закрывает данный пробел и завершает ещё один архитектурный уровень серии Build 060.


Архитектурное решение

По итогам проведённого аудита было принято решение не создавать новую модель данных и не вводить дополнительный слой между Parser и Mapper.

Вместо этого реализован тот же архитектурный шаблон, который уже используется для Quote, OHLC и REST Trade.

В систему добавлена функция

validate_dzengi_websocket_trade_values(...)

которая принимает

DzengiWebSocketTradeEvent

и выполняет проверку корректности значений транспортной модели.

При успешном завершении проверки объект не изменяется и продолжает использоваться последующими этапами Pipeline.

Таким образом транспортная модель проходит дополнительный уровень контроля без создания промежуточных объектов и без нарушения существующей архитектуры.

Конвейер WebSocket Trade принимает следующий вид.

Raw WebSocket Object
        │
        ▼
WebSocket Trade Schema Validation
        │
        ▼
ValidatedWebSocketTradeDocument
        │
        ▼
WebSocket Trade Parser
        │
        ▼
DzengiWebSocketTradeEvent
        │
        ▼
WebSocket Trade Value Validation
        │
        ▼
DzengiWebSocketTradeEvent

Build 060.12 не изменяет архитектуру ранее реализованных компонентов и лишь завершает следующий обязательный уровень транспортного Pipeline.

Реализованный уровень Value Validation

В файл

src/market_data/acquisition/validation/values.py

добавлена новая функция

validate_dzengi_websocket_trade_values(...)

Функция получает транспортную модель

DzengiWebSocketTradeEvent

и подтверждает корректность всех значений, необходимых для последующего Mapping.

После успешного завершения проверки функция не изменяет объект и не создаёт новую транспортную модель.

Таким образом следующий уровень Pipeline получает тот же экземпляр

DzengiWebSocketTradeEvent

который ранее был создан Parser.


Почему Value Validation не создаёт новую модель

Во время архитектурного проектирования отдельно рассматривался вопрос о необходимости введения дополнительной модели

ValidatedTradeTransportEvent

которая могла бы использоваться после проверки значений.

По результатам анализа было принято решение отказаться от подобного решения.

Основные причины:

  • транспортная модель уже является immutable;
  • проверка значений не изменяет содержимое объекта;
  • повторное создание объекта не приносит дополнительных архитектурных преимуществ;
  • аналогичный подход уже используется для Quote, OHLC и REST Trade.

В результате Value Validation подтверждает корректность существующего объекта и не создаёт новый экземпляр.

Подобное решение уменьшает количество транспортных моделей в системе и делает Pipeline более простым без потери архитектурной строгости.


Проверяемая транспортная модель

Проверка выполняется над объектом

@dataclass(frozen=True, slots=True)
class DzengiWebSocketTradeEvent:
    trade_id: int
    price: DzengiRawNumeric
    size: DzengiRawNumeric
    timestamp: int
    symbol: str
    buyer: bool
    order_id: str

Value Validation рассматривает данный объект исключительно как транспортную модель.

Никаких преобразований типов при этом не выполняется.


Проверка идентификатора сделки

Поле

trade_id

обязательно должно содержать положительный целочисленный идентификатор сделки.

Во время проверки подтверждается:

  • значение является целым числом;
  • значение больше нуля.

При нарушении любого условия генерируется

TradeValueError

с указанием пути

$.payload.id

Проверка цены сделки

Поле

price

может поступать в различных транспортных представлениях.

Например:

"63992.50"

63992

63992.50

Во время проверки подтверждается:

  • возможность корректного преобразования в Decimal;
  • отсутствие NaN;
  • отсутствие Infinity;
  • значение больше нуля.

При этом сама транспортная модель не изменяется.

Строковое значение остаётся строковым.

Преобразование в Decimal будет выполняться только на этапе Mapper.


Проверка объёма сделки

Поле

size

проверяется аналогично цене.

Подтверждается:

  • корректность числового представления;
  • отсутствие специальных значений;
  • положительное значение.

При нарушении любого ограничения генерируется

TradeValueError

с указанием пути

$.payload.size

Проверка временной метки

Поле

timestamp

должно содержать положительное целое число.

Value Validation подтверждает:

  • корректность типа;
  • значение больше нуля.

Следует отметить, что Build 060.12 не анализирует, соответствует ли timestamp реальному времени.

Подобные проверки относятся уже к предметной области и могут появиться на более высоких уровнях системы.


Проверка символа

Поле

symbol

обязательно должно содержать непустую строку.

Проверяется результат после применения

strip()

Таким образом значения

""

" "

"\t"

"\n"

считаются недопустимыми.


Проверка идентификатора ордера

Аналогичная проверка выполняется для поля

order_id

После удаления пробельных символов строка должна оставаться непустой.

В противном случае генерируется

TradeValueError

Почему поле buyer не проверяется

Во время архитектурного аудита отдельно анализировался вопрос дополнительной проверки поля

buyer

Было принято решение не выполнять каких-либо дополнительных ограничений.

Причины следующие.

Parser уже гарантирует:

bool

В транспортном контракте биржи оба значения

True

False

являются допустимыми.

Следовательно Value Validation не содержит никакой дополнительной логики для данного поля.

Это полностью соответствует принципу разделения ответственности между Parser и Value Validation.


Повторное использование существующих helper-функций

Build 060.12 не вводит новых механизмов проверки числовых значений.

Вместо этого используются уже существующие функции проекта.

_trade_positive_int(...)

используется для проверки:

  • trade_id;
  • timestamp.

_trade_positive_decimal(...)

используется для проверки:

  • price;
  • size.

Подобный подход обеспечивает единое поведение всех механизмов проверки Trade независимо от источника получения данных.


Использование TradeValueError

Все ошибки проверки значений используют существующее исключение

TradeValueError

Build не вводит новых типов исключений.

Это сохраняет единую архитектуру обработки ошибок Trade.

Parser продолжает использовать

TradeParseError

а Value Validation использует исключительно

TradeValueError

Тем самым достигается чёткое разделение транспортных ошибок и ошибок корректности данных.


Изменённые файлы

В рамках Build были изменены только два файла.

Value Validation

src/market_data/acquisition/validation/values.py

Добавлена функция

validate_dzengi_websocket_trade_values(...)

Существующая логика проверки Quote, OHLC и REST Trade не изменялась.


Unit-тесты

tests/unit/market_data/acquisition/validation/test_websocket_trade_values.py

Добавлен полный набор unit-тестов нового уровня Value Validation.


Добавленные тесты

В рамках Build реализовано сорок семь unit-тестов, полностью покрывающих новую функциональность.

Проверка корректных событий

Подтверждается успешное прохождение проверки полностью корректной транспортной модели.


Проверка buyer

Подтверждается корректная работа для обоих допустимых значений:

  • True;
  • False.

Проверка различных представлений чисел

Отдельная серия тестов подтверждает корректную обработку:

  • строк;
  • целых чисел;
  • чисел с плавающей точкой.

для полей:

  • price;
  • size.

Проверка неположительных значений

Реализованы параметризованные тесты для:

  • trade_id;
  • timestamp;
  • price;
  • size.

Подтверждается генерация

TradeValueError

при попытке использования нуля либо отрицательных значений.


Проверка специальных числовых значений

Отдельная группа тестов подтверждает отклонение:

NaN

Infinity

-Infinity

как в строковом виде, так и после передачи соответствующих значений типа float.


Проверка некорректных строк

Реализованы проверки для значений:

""

"invalid"

"--1"

Подтверждается корректная генерация исключений.


Проверка строковых полей

Отдельные тесты подтверждают отклонение пустых либо содержащих только пробельные символы значений:

  • symbol;
  • order_id.

Проверка неизменяемости транспортной модели

Отдельный тест подтверждает, что после успешной проверки объект

DzengiWebSocketTradeEvent

остаётся полностью неизменным.

Value Validation не модифицирует транспортную модель.

Результаты тестирования

После завершения реализации выполнен целевой запуск нового набора unit-тестов.

python -m pytest \
  tests/unit/market_data/acquisition/validation/test_websocket_trade_values.py \
  -q

Результат:

47 passed in 0.05s

Все проверки новой функциональности успешно завершены.

Новый набор тестов полностью покрывает:

  • успешную проверку корректной транспортной модели;
  • обработку допустимых представлений числовых значений;
  • генерацию исключений для всех типов некорректных данных;
  • неизменяемость транспортной модели после успешной проверки.

Параметризованные тесты позволили существенно сократить объём тестового кода без уменьшения покрытия и обеспечили единообразную проверку всех допустимых и недопустимых вариантов входных данных.


Регрессионное тестирование

После завершения реализации выполнен полный запуск набора unit-тестов проекта.

python -m pytest -q

Результат:

1208 passed in 2.70s

Регрессий существующей функциональности не обнаружено.

Все ранее реализованные Build продолжают работать без каких-либо изменений.

Это подтверждает, что добавленная функциональность полностью изолирована и не влияет на существующие конвейеры обработки Quote, OHLC, REST Trade и остальные подсистемы проекта.


Проверка компиляции

После завершения реализации выполнена полная проверка компиляции проекта.

python -m compileall src tests

Компиляция завершилась успешно.

Ошибок синтаксиса не обнаружено.

Все изменённые файлы успешно компилируются и не нарушают целостность проекта.


Проверка Git diff

После устранения замечаний форматирования выполнена финальная проверка изменений.

git diff --check

Результат:

без замечаний

Проверка подтвердила отсутствие:

  • trailing whitespace;
  • ошибок окончания строк;
  • конфликтов diff;
  • нарушений форматирования.

Scope Build 060.12

В рамках данного Build реализован исключительно уровень

WebSocket Trade Value Validation

Build не включает:

  • WebSocket Trade Schema Validation;
  • WebSocket Trade Parser;
  • WebSocket Trade Mapper;
  • WebSocket Trade Adapter;
  • Runtime Integration;
  • Unified Routing;
  • Trades Feed.

Подобное ограничение полностью соответствует принятому принципу атомарной реализации Build.

Каждый этап дорожной карты реализует только один архитектурный уровень Pipeline.


Архитектурный результат

После завершения Build система содержит полностью реализованные уровни транспортной обработки WebSocket Trade вплоть до проверки значений.

Конвейер обработки принимает следующий вид.

Raw WebSocket Trade
        │
        ▼
WebSocket Trade Schema Validation
        │
        ▼
ValidatedWebSocketTradeDocument
        │
        ▼
WebSocket Trade Parser
        │
        ▼
DzengiWebSocketTradeEvent
        │
        ▼
WebSocket Trade Value Validation
        │
        ▼
DzengiWebSocketTradeEvent

Таким образом архитектура WebSocket Trade полностью повторяет ранее реализованные конвейеры Quote и OHLC.

Каждый уровень Pipeline выполняет исключительно собственную задачу.


Состояние WebSocket Trade Pipeline

После завершения Build 060.12 конвейер имеет следующий вид.

Raw WebSocket Trade
        │
        ▼
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 ✔ Completed
WebSocket Trade Mapper 060.13 Pending
WebSocket Trade Adapter 060.14 Pending
Unified WebSocket Routing 060.15 Pending

Соблюдение архитектурных принципов

В рамках Build полностью сохранены архитектурные инварианты Dzentra.

Локальность изменений

Изменены только:

  • validation/values.py;
  • unit-тесты нового уровня Value Validation.

Существующая логика Quote, OHLC и REST Trade не изменялась.


Повторное использование архитектуры

Новая реализация полностью повторяет существующий архитектурный шаблон проверки значений.

Новая архитектура не проектировалась.

Использован уже существующий подход, применяемый для остальных типов рыночных данных.


Повторное использование инфраструктуры

Для проверки числовых значений повторно использованы существующие helper-функции проекта.

Build не вводит новых механизмов проверки и не дублирует уже реализованную функциональность.

Это обеспечивает единообразие поведения всех уровней Value Validation.


Разделение ответственности

Value Validation отвечает исключительно за проверку корректности значений транспортной модели.

Build не выполняет:

  • преобразование транспортных данных;
  • Mapping;
  • создание модели Trade;
  • Runtime Integration;
  • бизнес-логику.

Все перечисленные задачи остаются ответственностью последующих Build.


Обратная совместимость

Существующая обработка:

  • Quote;
  • OHLC;
  • REST Trade;

не изменилась.

Добавленная функциональность полностью изолирована и не оказывает влияния на ранее реализованные компоненты системы.


Архитектурные решения Build (ADR)

ADR-060.12-001

Value Validation не создаёт новую транспортную модель.

После успешной проверки используется тот же экземпляр DzengiWebSocketTradeEvent, который ранее был создан Parser.

Создание дополнительной модели признано избыточным и не дающим архитектурных преимуществ.


ADR-060.12-002

Value Validation не выполняет преобразование типов.

Проверка подтверждает только допустимость значений.

Преобразование транспортных представлений (str, int, float) во внутренние типы (Decimal, datetime и другие) остаётся ответственностью Mapper.


ADR-060.12-003

Повторное использование существующих helper-функций является обязательным архитектурным принципом.

Для проверки числовых значений используются существующие функции:

_trade_positive_int()

_trade_positive_decimal()

Создание новых helper-функций признано необоснованным.


ADR-060.12-004

Parser и Value Validation используют разные классы исключений.

Parser отвечает за транспортное преобразование и использует:

TradeParseError

Value Validation отвечает исключительно за корректность значений и использует:

TradeValueError

Подобное разделение обеспечивает прозрачную классификацию ошибок Pipeline.


Критерии завершения Build

Build 060.12 считается завершённым, поскольку выполнены все поставленные задачи.

  • ✔ реализована функция validate_dzengi_websocket_trade_values();
  • ✔ реализована проверка всех обязательных полей транспортной модели;
  • ✔ реализована проверка положительных числовых значений;
  • ✔ реализована проверка конечности числовых значений;
  • ✔ реализована проверка строковых идентификаторов;
  • ✔ повторно использованы существующие helper-функции;
  • ✔ используются существующие исключения TradeValueError;
  • ✔ транспортная модель остаётся неизменяемой;
  • ✔ реализовано 47 unit-тестов;
  • ✔ целевой набор тестов успешно проходит;
  • ✔ полное регрессионное тестирование успешно завершено;
  • ✔ проект успешно компилируется;
  • git diff --check не выявил замечаний;
  • ✔ изменения полностью укладываются в согласованный scope Build.

Следующий этап

Следующим этапом дорожной карты является

Build 060.13 — WebSocket Trade Mapper

Цель следующего Build:

  • преобразование DzengiWebSocketTradeEvent в каноническую модель Trade;
  • преобразование транспортных числовых значений во внутренние типы;
  • формирование окончательной модели предметной области;
  • завершение транспортного конвейера обработки WebSocket Trade.

Итог

Build 060.12 завершил реализацию уровня Value Validation для WebSocket Trade и сделал архитектуру транспортной обработки сделок полностью симметричной существующим конвейерам Quote, OHLC и REST Trade.

Новая реализация основана на уже существующих архитектурных принципах Dzentra, повторно использует существующую инфраструктуру проверки значений, не создаёт дополнительных транспортных моделей и сохраняет строгое разделение ответственности между уровнями Pipeline.

Build ограничен согласованным scope, успешно прошёл целевое и полное регрессионное тестирование, подтвердил отсутствие регрессий и создаёт необходимую основу для следующего этапа дорожной карты — Build 060.13 — WebSocket Trade Mapper.