Files
dzentra_bot/docs/migrations/build_060_16.md

46 KiB
Raw Permalink Blame History

Build 060.16 — Trade Subscription Layer

Engineering Migration Report


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

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

Цель Build

После завершения Build 060.15 система получила полностью интегрированный механизм маршрутизации входящих WebSocket-сообщений.

К этому моменту архитектура уже обеспечивала:

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

Однако один важный уровень инфраструктуры всё ещё отсутствовал.

Система уже умела принимать сообщения о сделках, но ещё не обладала единым механизмом формирования исходящих WebSocket-подписок.

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

Это приводило к нескольким ограничениям.

Во-первых, детали протокола Dzengi могли начать проникать в Runtime.

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

В-третьих, будущие Feed были бы вынуждены самостоятельно формировать JSON-документы подписки.

Подобная архитектура противоречила одному из базовых принципов Dzentra — строгому разделению ответственности между слоями системы.

Основная задача Build заключается в создании отдельного уровня Trade Subscription Layer, который полностью инкапсулирует знания о протоколе подписки Dzengi и предоставляет Runtime исключительно универсальные транспортные команды.

После завершения Build система должна уметь:

  • построить стабильный идентификатор подписки;
  • сформировать корректный WebSocket-документ trades.subscribe;
  • преобразовать транспортное сообщение в универсальную SubscribeCommand;
  • полностью скрыть детали протокола Dzengi от Runtime.

При этом Build принципиально не затрагивает:

  • WebSocket Runtime;
  • WebSocket Protocol;
  • Unified Router;
  • Parser;
  • Value Validation;
  • Mapper;
  • Trade Adapter;
  • Trades Feed;
  • Registry подписок;
  • механизм восстановления подписок после reconnect.

Предпосылки

К началу Build архитектура Market Data Acquisition уже содержала полностью реализованный транспортный уровень Runtime.

Он обеспечивал выполнение всех операций, связанных с жизненным циклом WebSocket-соединения.

Конвейер управления соединением выглядел следующим образом.

SubscribeCommand
        │
        ▼
Runtime
        │
        ▼
WebSocket Transport

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

В частности, были реализованы:

ConnectCommand

DisconnectCommand

SubscribeCommand

UnsubscribeCommand

SendTextCommand

SendBinaryCommand

При этом Runtime принципиально не содержал информации о конкретной бирже.

Он не должен был знать:

  • структуру JSON-документов;
  • названия WebSocket destination;
  • формат сообщений подписки;
  • особенности протокола Dzengi.

Одновременно с этим Build 060.15 завершил интеграцию Trade Pipeline в Unified WebSocket Routing.

Таким образом система уже умела получать входящие сообщения:

internal.trade

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

Trade

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

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


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

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

Каждый уровень должен знать исключительно ту информацию, которая относится к его собственной зоне ответственности.

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

Feed отвечает исключительно за организацию потока данных.

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

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

Следовательно, знания о формате WebSocket-подписки также должны быть сосредоточены в отдельном специализированном слое.

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

Trade Symbols
        │
        ▼
Trade Subscription Builder
        │
        ▼
TransportTextMessage
        │
        ▼
SubscribeCommand
        │
        ▼
Runtime
        │
        ▼
WebSocket

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

Builder знает исключительно протокол Dzengi.

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

WebSocket знает исключительно способ передачи сообщения.

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


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

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

Анализ подтвердил наличие полностью сформированного транспортного уровня.

В частности, компонент

runtime/runtime_commands.py

уже содержал универсальную команду

SubscribeCommand

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

Дополнительно был выполнен аудит транспортных сообщений.

Компонент

runtime/transport_messages.py

уже содержал универсальную модель

TransportTextMessage

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

Также был выполнен аудит протокола Runtime.

Интерфейс

WebSocketSubscriptionManagerProtocol

уже предусматривал поддержку восстановления подписок после переподключения посредством методов:

restore_subscriptions()

clear_subscriptions()

Тем самым было подтверждено, что архитектура Runtime уже подготовлена к будущей реализации Registry подписок.

Вмешательство в Runtime в рамках Build 060.16 не требуется.

Единственным отсутствующим уровнем являлся специализированный механизм построения транспортных подписок.

Именно этот уровень и становится предметом настоящего Build.


Исследование протокола Dzengi

Перед реализацией Subscription Layer был выполнен отдельный анализ публичного WebSocket-протокола Dzengi.

Изучение Swagger и существующей производственной интеграции подтвердило использование следующего формата подписки.

{
  "correlationId": "...",
  "destination": "trades.subscribe",
  "payload": {
    "symbols": [
      "BTC/USD_LEVERAGE"
    ]
  }
}

После успешной обработки сервер возвращает подтверждение подписки.

{
  "status": "OK",
  "destination": "trades.subscribe",
  "payload": {
    "subscriptions": {
      "BTC/USD_LEVERAGE": "PROCESSED"
    }
  }
}

После этого сервер начинает передавать сообщения

destination = "internal.trade"

которые поступают в ранее реализованный Trade Pipeline.

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

В Swagger отсутствует описание команды

trades.unsubscribe

что потребовало проведения дополнительного инженерного исследования.


Экспериментальная проверка trades.unsubscribe

В рамках Build был проведён отдельный эксперимент, целью которого являлась проверка существования недокументированной операции выборочной отмены подписки.

Для этого был подготовлен диагностический сценарий, выполняющий следующую последовательность действий.

Открытие WebSocket
        │
        ▼
trades.subscribe
        │
        ▼
Получение ACK
        │
        ▼
trades.unsubscribe
        │
        ▼
Анализ ответа сервера

В ходе эксперимента сервер успешно принял команду

trades.subscribe

и подтвердил регистрацию подписки.

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

destination = "trades.unsubscribe"

Ответ сервера оказался следующим.

{
  "status": "ERROR",
  "payload": {
    "errorCode": "BAD_REQUEST"
  }
}

Таким образом было подтверждено:

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

Полученный результат стал одним из ключевых архитектурных оснований настоящего Build.

Dzentra не реализует неподтверждённые возможности внешнего API.

Subscription Layer поддерживает исключительно подтверждённую операцию

trades.subscribe

а прекращение получения потока данных остаётся частью жизненного цикла самого WebSocket-соединения.


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

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

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

Данный слой полностью изолирует знания о протоколе Dzengi от остальных компонентов системы.

Новая архитектура принимает следующий вид.

Trade Symbols
        │
        ▼
Trade Subscription Layer
        │
        ├────────► build_trade_subscription_key()
        │
        ├────────► build_trade_subscribe_message()
        │
        └────────► build_trade_subscribe_command()
                    │
                    ▼
             SubscribeCommand
                    │
                    ▼
                 Runtime
                    │
                    ▼
               WebSocket

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

Ни один компонент Runtime не знает:

  • название WebSocket destination;
  • структуру JSON-документа;
  • список символов;
  • особенности протокола Dzengi.

Все эти знания полностью сосредоточены внутри нового Subscription Layer.

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


Новый пакет Subscription Layer

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

src/
└── market_data/
    └── acquisition/
        └── subscriptions/
            ├── __init__.py
            └── trades.py

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

Во время проектирования рассматривались несколько альтернатив.

Размещение Builder внутри Runtime было отклонено, поскольку Runtime не должен содержать знания о конкретной бирже.

Размещение Builder внутри Adapter также было признано неудачным.

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

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

В результате был выбран самостоятельный пакет

acquisition/subscriptions

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

Данная архитектура обеспечивает единое место хранения логики построения подписок для всех будущих потоков рыночных данных.

В дальнейшем аналогичным образом могут быть реализованы:

quotes.py

candles.py

orderbook.py

status.py

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


Реализованные Builder-функции

В рамках Build реализованы три чистые функции.

Они полностью покрывают процесс формирования универсальной Runtime-команды.


Построение ключа подписки

Функция

build_trade_subscription_key()

формирует стабильный идентификатор подписки.

При построении ключа выполняется:

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

Например

BTC/USD_LEVERAGE

преобразуется в

trades:BTC/USD_LEVERAGE

а набор

ETH/USD_LEVERAGE
BTC/USD_LEVERAGE
ETH/USD_LEVERAGE

преобразуется в

trades:BTC/USD_LEVERAGE,ETH/USD_LEVERAGE

Использование стабильного идентификатора позволяет в дальнейшем однозначно регистрировать подписки внутри Runtime Registry.


Построение транспортного сообщения

Функция

build_trade_subscribe_message()

формирует полностью готовый WebSocket-документ протокола Dzengi.

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

TransportTextMessage

содержащая сериализованный JSON-документ.

При отсутствии внешнего

correlationId

Builder автоматически создаёт новый UUID.

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

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


Построение Runtime-команды

Функция

build_trade_subscribe_command()

является верхним уровнем Subscription Layer.

Она объединяет результаты двух предыдущих функций.

В результате вызывающая сторона получает полностью сформированную

SubscribeCommand

которая уже содержит:

  • стабильный идентификатор подписки;
  • готовое транспортное сообщение.

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

Runtime получает полностью готовую транспортную команду.


Последовательность формирования SubscribeCommand

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

Symbols
        │
        ▼
Normalization
        │
        ▼
Subscription Key
        │
        ▼
Trade JSON Builder
        │
        ▼
TransportTextMessage
        │
        ▼
SubscribeCommand
        │
        ▼
Runtime
        │
        ▼
WebSocket

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

Нормализация символов не знает о Runtime.

Runtime не знает о JSON.

JSON Builder не знает о транспортном соединении.

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


Использование существующей Runtime-инфраструктуры

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

Subscription Layer не вводит новых транспортных моделей.

Не создаёт новых Runtime-команд.

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

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

Для передачи транспортного документа применяется

TransportTextMessage

Для взаимодействия с Runtime используется

SubscribeCommand

Передача данных продолжает выполняться существующим WebSocket Runtime.

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


Почему Subscription Layer реализован функциями

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

TradeSubscriptionManager

Однако после проведения архитектурного аудита данный вариант был отклонён.

Причина заключается в отсутствии собственного состояния.

Subscription Layer:

  • не хранит активные подписки;
  • не выполняет регистрацию;
  • не взаимодействует с Runtime Registry;
  • не выполняет восстановление после reconnect.

Единственной задачей слоя является построение транспортных объектов.

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

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

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

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

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


Почему Runtime не знает о trades.subscribe

Во время проектирования отдельно рассматривался вариант переноса формирования JSON-документа непосредственно в Runtime.

После анализа архитектуры данный вариант был отклонён.

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

  • Runtime не должен зависеть от конкретной биржи;
  • Runtime не должен знать транспортный протокол;
  • Runtime не должен содержать названия WebSocket destination;
  • Runtime должен работать исключительно с универсальными командами.

После завершения Build Runtime продолжает получать только

SubscribeCommand

которая уже содержит полностью сформированное транспортное сообщение.

Таким образом достигается полная независимость Runtime от конкретной реализации протокола Dzengi.


Почему trades.unsubscribe не реализован

Во время подготовки Build отдельно рассматривалась возможность реализации симметричной операции отмены подписки.

На первый взгляд подобное решение выглядело естественным продолжением механизма

trades.subscribe

Однако архитектура Dzentra строится исключительно на подтверждённых возможностях внешнего API.

Поэтому перед реализацией был проведён отдельный инженерный эксперимент.

В результате сервер вернул ответ

status = ERROR
errorCode = BAD_REQUEST

Тем самым было подтверждено, что используемый формат

trades.unsubscribe

не поддерживается.

Отсутствие документированного контракта означает невозможность гарантировать корректную работу подобной функции.

Поэтому Build сознательно ограничен исключительно подтверждённой возможностью

trades.subscribe

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

Dzentra никогда не реализует функциональность, существование которой не подтверждено документацией либо экспериментально.

Удаление подписки будет реализовано исключительно посредством управления жизненным циклом WebSocket-соединения и будущего Runtime Registry.


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

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

Subscription Layer

src/market_data/acquisition/subscriptions/__init__.py

Создан новый пакет формирования транспортных подписок.

Пакет становится единым местом хранения Builder-функций для различных типов рыночных данных.


Trade Subscription Builder

src/market_data/acquisition/subscriptions/trades.py

Реализованы:

build_trade_subscription_key()

build_trade_subscribe_message()

build_trade_subscribe_command()

Никакие существующие компоненты Runtime изменены не были.


Unit-тесты

Добавлен новый набор тестов.

tests/unit/market_data/acquisition/subscriptions/test_trades.py

Все существующие тесты Runtime сохранены без изменений.


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

В рамках Build реализирован полный набор unit-тестов нового Subscription Layer.

Проверяются следующие сценарии.


Построение ключа подписки

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

trades:BTC/USD_LEVERAGE

для одиночного символа.


Нормализация символов

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

  • удаление дубликатов;
  • удаление пустых строк;
  • удаление пробелов;
  • стабильная сортировка.

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


Проверка пустого списка

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

ValueError

при отсутствии корректных символов.


Построение транспортного сообщения

Подтверждается возврат объекта

TransportTextMessage

с корректным JSON-документом Dzengi.


Генерация UUID

Подтверждается автоматическое создание

correlationId

при отсутствии значения.


Использование внешнего correlationId

Подтверждается сохранение значения,

переданного вызывающей стороной.

Это обеспечивает возможность детерминированного тестирования.


Построение SubscribeCommand

Подтверждается возврат корректной

SubscribeCommand

с правильным:

  • subscription key;
  • TransportTextMessage.

Согласованность Subscription Builder

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

Это гарантирует отсутствие рассогласования между Runtime Registry и транспортным протоколом.


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

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

PYTHONPATH="$PWD" python -m pytest \
tests/unit/market_data/acquisition/subscriptions/test_trades.py -v

Результат:

11 passed

Подтверждена корректная работа всех Builder-функций.


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

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

PYTHONPATH="$PWD" python -m pytest \
tests/unit/market_data/acquisition/runtime

Результат:

30 passed

Подтверждено отсутствие регрессий существующей транспортной инфраструктуры.

Ни один существующий Runtime-компонент не изменился.


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

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

python -m compileall \
src/market_data/acquisition/subscriptions \
tests/unit/market_data/acquisition/subscriptions

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

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

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


Проверка Git diff

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

git diff --check

Результат:

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

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

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

Scope Build 060.16

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

Trade Subscription Layer

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

  • Trades Feed;
  • Runtime Registry;
  • Runtime Integration;
  • Reconnect;
  • восстановление подписок;
  • обработку входящих Trade;
  • сортировку сделок;
  • дедупликацию;
  • REST Backfill.

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

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


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

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

Архитектура приобретает следующий вид.

Trade Symbols
        │
        ▼
Trade Subscription Builder
        │
        ├────────► Subscription Key
        │
        ├────────► TransportTextMessage
        │
        └────────► SubscribeCommand
                    │
                    ▼
                 Runtime
                    │
                    ▼
                WebSocket

Subscription Layer полностью изолирует знания о протоколе Dzengi.

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

Это позволяет в дальнейшем добавлять новые типы подписок без каких-либо изменений транспортной инфраструктуры.


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

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

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

Добавлены только:

  • src/market_data/acquisition/subscriptions/__init__.py;
  • src/market_data/acquisition/subscriptions/trades.py;
  • tests/unit/market_data/acquisition/subscriptions/test_trades.py.

Существующие Runtime-компоненты не изменялись.


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

Subscription Layer полностью использует уже существующие компоненты:

  • TransportTextMessage;
  • SubscribeCommand;
  • WebSocket Runtime.

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


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

Subscription Builder отвечает исключительно за построение транспортных подписок.

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

Feed будет отвечать исключительно за организацию потока данных.

Подобное разделение полностью соответствует архитектуре Market Data Acquisition.


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

Build не вводит нового транспортного уровня.

Не изменяет существующий Runtime.

Не изменяет WebSocket Protocol.

Не изменяет механизм передачи сообщений.

Вместо этого новый уровень полностью использует уже существующую архитектуру Market Data Acquisition.

Фактически Build является логическим продолжением ранее реализованной Runtime-инфраструктуры.

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


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

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

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

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

acquisition/subscriptions

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


Функциональный подход

Все компоненты Subscription Layer реализованы в виде чистых функций.

Каждая функция:

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

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

Stateless-компоненты реализуются функциями. Stateful-компоненты реализуются классами.

Subscription Layer относится к первой категории.


Подготовка к масштабированию

Несмотря на то что Build реализует только Trade Subscription Layer, выбранная архитектура изначально ориентирована на дальнейшее расширение.

В дальнейшем аналогичный механизм может использоваться для:

Quote Subscription Layer

Candles Subscription Layer

Order Book Subscription Layer

Market Status Subscription Layer

Каждый новый Builder будет полностью независимым.

При этом Runtime останется неизменным.

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


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

ADR-060.16-001

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

Runtime не знает:

  • структуру JSON;
  • destination;
  • особенности протокола Dzengi;
  • типы рыночных данных.

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


ADR-060.16-002

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

Все знания о WebSocket-протоколе Dzengi сосредоточены внутри Builder-функций.

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


ADR-060.16-003

Неподтверждённые возможности внешнего API не реализуются.

Во время Build выполнена экспериментальная проверка команды

trades.unsubscribe

Полученный ответ

BAD_REQUEST

подтвердил отсутствие поддерживаемого контракта.

В результате Subscription Layer реализует исключительно документированную операцию

trades.subscribe

ADR-060.16-004

Subscription Builder не хранит собственного состояния.

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

Registry подписок, управление жизненным циклом подписок и механизм восстановления после reconnect относятся к следующим Build и не входят в область ответственности настоящего слоя.


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

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

  • ✔ создан отдельный пакет acquisition/subscriptions;
  • ✔ реализована функция build_trade_subscription_key();
  • ✔ реализована функция build_trade_subscribe_message();
  • ✔ реализована функция build_trade_subscribe_command();
  • ✔ выполнена нормализация списка символов;
  • ✔ реализована генерация стабильного ключа подписки;
  • ✔ реализовано построение TransportTextMessage;
  • ✔ реализовано построение SubscribeCommand;
  • ✔ Runtime не изменён;
  • ✔ подтверждено отсутствие поддержки trades.unsubscribe;
  • ✔ реализованы unit-тесты нового Subscription Layer;
  • ✔ успешно пройдены новые тесты (11 passed);
  • ✔ успешно пройдена регрессия Runtime (30 passed);
  • ✔ проект успешно компилируется;
  • git diff --check не выявил замечаний;
  • ✔ изменения полностью укладываются в согласованный scope Build.

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

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

Build 060.17 — Trades Feed Core

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

  • реализовать специализированный Feed обработки сделок;
  • подключить поток Trade к инфраструктуре Market Data Acquisition;
  • организовать приём канонических моделей Trade;
  • подготовить основу для последующих этапов:
    • упорядочивания сделок;
    • дедупликации;
    • восстановления истории после переподключения;
    • интеграции с Runtime.

Subscription Layer, реализованный в Build 060.16, станет источником формирования подписок для нового Feed.


Итог

Build 060.16 завершил формирование самостоятельного уровня Trade Subscription Layer в подсистеме Market Data Acquisition.

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

Все знания о WebSocket-протоколе Dzengi теперь сосредоточены в одном специализированном пакете, тогда как Runtime продолжает работать исключительно с универсальными транспортными командами.

В ходе Build была не только реализована новая функциональность, но и проведено инженерное исследование публичного WebSocket API Dzengi, подтвердившее отсутствие поддерживаемой операции trades.unsubscribe. Полученные результаты легли в основу принятых архитектурных решений и закреплены в ADR настоящего Build.

Реализация ограничена согласованным scope, успешно прошла целевое и регрессионное тестирование, не потребовала изменений существующей Runtime-инфраструктуры и сформировала единый архитектурный шаблон для будущих Subscription Layer всех типов рыночных данных.

После завершения Build система получила завершённый механизм формирования подписок Trade, который станет фундаментом для реализации Trades Feed Core в следующем этапе дорожной карты.