Files
dzentra_bot/docs/migrations/build_060_23.md

36 KiB
Raw Blame History

Build 060.23 — Trade Stream Acquisition Integration

Engineering Migration Report


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

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

Связанные документы

  • build_060_23_architecture.md — архитектурная спецификация Build.
  • build_060_22.md — Engineering Migration Report предыдущего Build.
  • build_060_22_architecture.md — спецификация Acquisition Runtime Service.
  • build_060_20_1.md — Engineering Migration Report корректирующего Build владения состоянием Trade Stream.
  • build_060_19.md — Engineering Migration Report Trade Recovery.
  • build_060_18.md — Engineering Migration Report Trade Stream Consistency.

Цель Build

Build 060.22 завершил создание минимального исполняемого сервисного слоя Acquisition Runtime.

После предыдущего этапа в системе уже существовали:

AcquisitionRuntimeServiceProtocol
AcquisitionRuntimeService
AcquisitionRuntimeCommand
AcquisitionRuntimeEvent

Runtime Service уже умел детерминированно исполнять инфраструктурные команды:

ConnectCommand
DisconnectCommand
SubscribeCommand
UnsubscribeCommand
SendTextCommand
SendBinaryCommand

Однако Runtime по-прежнему оставался изолированным от Trade Stream Acquisition Pipeline.

В системе отсутствовал отдельный компонент, который:

  • формировал команду подписки Trade Stream;
  • передавал её в Acquisition Runtime;
  • принимал один входящий WebSocket-документ;
  • преобразовывал его через Unified Adapter;
  • выделял канонический Trade;
  • передавал Trade в Consistency Layer;
  • возвращал согласованный результат Trade | None.

Главной задачей Build 060.23 стало создание локального интеграционного слоя:

TradeStreamAcquisitionService

и его публичного контракта:

TradeStreamAcquisitionServiceProtocol

После завершения Build система получает:

  • единую сервисную точку подписки Trade Stream;
  • единый путь обработки входящего Trade-сообщения;
  • независимость сервиса от конкретной exchange-specific реализации адаптера;
  • интеграцию с TradeStreamConsistencyProtocol;
  • отдельное unit-покрытие координатора;
  • интеграционные тесты полного локального Dzengi pipeline;
  • подтверждённую регрессионную совместимость Runtime, Consistency, Recovery, Feeds и Dzengi Adapters.

При этом Build сознательно не реализует production WebSocket transport, receive-loop, reconnect и Runtime Recovery.


Предпосылки

К началу настоящего Build были доступны следующие подсистемы.

Runtime Layer

AcquisitionRuntimeServiceProtocol
AcquisitionRuntimeService
AcquisitionRuntimeCommandDispatcherProtocol
AcquisitionRuntimeEventPublisherProtocol

Trade Subscription Layer

build_trade_subscribe_command()

WebSocket Adapter Layer

DzengiUnifiedWebSocketAdapter
DzengiWebSocketTradeAdapter

Consistency Layer

TradeStreamConsistencyProtocol
TradeStreamConsistencyController
TradeStreamStateStore

Canonical Model

Trade

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

Однако их взаимодействие не было оформлено в единый Acquisition Service.

Архитектура до Build выглядела следующим образом:

Subscription Builder
        │
        ▼
SubscribeCommand
        │
        ▼
AcquisitionRuntimeService

и отдельно:

WebSocket Document
        │
        ▼
DzengiUnifiedWebSocketAdapter
        │
        ▼
Trade

и отдельно:

Trade
        │
        ▼
TradeStreamConsistencyController
        │
        ▼
Trade | None

Build 060.23 должен был соединить эти независимые части без изменения их существующего поведения.


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

Перед реализацией были проанализированы:

src/market_data/acquisition/protocol.py
src/market_data/acquisition/service.py
src/market_data/acquisition/registry.py
src/market_data/acquisition/feeds/trades_feed.py
src/market_data/acquisition/subscriptions/trades.py
src/market_data/acquisition/adapters/dzengi/websocket.py
src/market_data/acquisition/runtime/acquisition_runtime_service.py
src/market_data/acquisition/runtime/acquisition_runtime_service_protocol.py
src/market_data/acquisition/consistency/trade_stream_protocol.py
src/market_data/acquisition/consistency/trade_stream_consistency_controller.py
src/market_data/acquisition/consistency/trade_stream_state_store.py

Дополнительно были изучены legacy-компоненты:

src/integrations/exchange/market_stream.py
src/integrations/exchange/market_data_runner.py
src/integrations/exchange/ws_client.py
src/integrations/exchange/service.py

и соответствующие unit-тесты.

Аудит подтвердил следующие выводы.


Существующий TradesFeed остаётся синхронным REST Feed

Текущий TradesFeed работает по модели:

TradeDocumentSource
        │
        ▼
TradeDocumentHandler
        │
        ▼
Trade

Он не владеет:

  • WebSocket lifecycle;
  • Runtime Commands;
  • активными подписками;
  • receive-loop;
  • reconnect;
  • Consistency State.

Поэтому внедрение Runtime в существующий TradesFeed было признано нарушением Single Responsibility.

Build 060.23 не изменяет TradesFeed.


Legacy MarketDataRunner не является точкой интеграции

MarketDataRunner уже содержит собственные:

  • task lifecycle;
  • reconnect-циклы;
  • REST fallback;
  • quote-specific runtime state;
  • журналирование;
  • status events.

Подключение нового Trade Stream Acquisition Service внутрь него смешало бы новую Acquisition Architecture с существующим legacy runtime и преждевременно затронуло бы Scope Build 060.24.

Поэтому MarketDataRunner не изменяется.


Legacy market_stream.py не является Composition Root

market_stream.py представляет отдельный quote-specific WebSocket-контур.

Его запуск в main.py не является активной точкой новой Trade Stream Architecture.

Файл не изменяется и не используется как Composition Root Build 060.23.


ExchangeWebSocketClient не реализует новые Runtime Protocol

ExchangeWebSocketClient является специализированным legacy-клиентом для depth stream.

Он:

  • самостоятельно открывает соединение;
  • самостоятельно отправляет depth request;
  • самостоятельно выполняет ping;
  • содержит внутренний цикл;
  • возвращает raw document;
  • жёстко связан со стаканом.

Следовательно он не является реализацией:

WebSocketTransportProtocol
WebSocketSessionProtocol
WebSocketSubscriptionManagerProtocol

и не адаптируется в рамках Build 060.23.


Trade consumer и Trade store отсутствуют

Repository-wide поиск не выявил утверждённых компонентов:

TradeStore
TradeConsumer
publish_trade()
on_trade()
consume_trade()

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

Его результатом остаётся:

Trade | None

trades.unsubscribe не поддерживается биржей

Предыдущий инженерный аудит Dzengi WebSocket API подтвердил отсутствие поддерживаемой операции:

trades.unsubscribe

Поэтому Build 060.23 не создаёт фиктивный exchange-specific unsubscribe builder.

Завершение Trade Stream в будущем должно выполняться через lifecycle соединения либо иной подтверждённый механизм.


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

По результатам аудита утверждена следующая схема.

symbols
    │
    ▼
TradeStreamAcquisitionService.subscribe()
    │
    ▼
build_trade_subscribe_command()
    │
    ▼
SubscribeCommand
    │
    ▼
AcquisitionRuntimeServiceProtocol.dispatch()

Входящий поток:

raw WebSocket document
        │
        ▼
TradeStreamMessageAdapterProtocol.map_message()
        │
        ▼
Quote | CandleCloseEvent | Trade
        │
        ▼
isinstance(result, Trade)
        │
        ├── нет ──► None
        │
        ▼
TradeStreamConsistencyProtocol.accept()
        │
        ▼
Trade | None

Новый сервис является stateless-координатором.

Он не создаёт транспорт, не запускает фоновые задачи и не хранит состояние Trade Stream.


Правило уникальности имён файлов

Build 060.23 сохраняет обязательное правило проекта Dzentra:

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

Build не создаёт новые общие файлы:

service.py
protocol.py
test_service.py

Вместо них добавлены уникальные имена:

trade_stream_acquisition_protocol.py
trade_stream_acquisition_service.py
trade_stream_message_adapter_protocol.py
test_trade_stream_acquisition_service.py
test_dzengi_trade_stream_acquisition_integration.py

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


TradeStreamAcquisitionServiceProtocol

В рамках Build создан новый публичный контракт:

TradeStreamAcquisitionServiceProtocol

Файл:

src/market_data/acquisition/
trade_stream_acquisition_protocol.py

Protocol определяет две операции.

subscribe()

async def subscribe(
    symbols: tuple[str, ...],
    *,
    correlation_id: str | None = None,
) -> None

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

handle_message()

def handle_message(
    document: object,
) -> Trade | None

Метод отвечает только за обработку одного входящего документа.

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

В частности отсутствуют:

start()
stop()
run()
receive()
reconnect()
recover()
publish()

TradeStreamMessageAdapterProtocol

Во время реализации было выявлено, что первоначальная зависимость сервиса от конкретного:

DzengiUnifiedWebSocketAdapter

создавала прямую exchange-specific связь внутри координационного слоя.

Для устранения этой связи введён отдельный контракт:

TradeStreamMessageAdapterProtocol

Файл:

src/market_data/acquisition/
trade_stream_message_adapter_protocol.py

Protocol определяет одну операцию:

def map_message(
    document: object,
) -> TradeStreamMappedMessage

Тип результата:

TradeStreamMappedMessage

объединяет:

Quote
CandleCloseEvent
Trade

DzengiUnifiedWebSocketAdapter структурно удовлетворяет этому Protocol и не требует изменения.

Благодаря этому TradeStreamAcquisitionService зависит от абстракции, а конкретный Dzengi Adapter подключается только при композиции и в интеграционных тестах.


TradeStreamAcquisitionService

Главным production-компонентом Build является:

TradeStreamAcquisitionService

Файл:

src/market_data/acquisition/
trade_stream_acquisition_service.py

Сервис реализует:

TradeStreamAcquisitionServiceProtocol

и координирует три зависимости:

AcquisitionRuntimeServiceProtocol
TradeStreamMessageAdapterProtocol
TradeStreamConsistencyProtocol

Сервис не создаёт зависимости самостоятельно.


Зависимости сервиса

Конструктор принимает:

runtime_service
adapter
consistency_controller

Полная схема:

TradeStreamAcquisitionService
        │
        ├── AcquisitionRuntimeServiceProtocol
        ├── TradeStreamMessageAdapterProtocol
        └── TradeStreamConsistencyProtocol

Это обеспечивает:

  • независимость от конкретного Runtime implementation;
  • независимость от конкретной биржи;
  • независимость от конкретной Consistency implementation;
  • возможность изолированного unit-тестирования.

subscribe()

Метод subscribe() использует существующий builder:

build_trade_subscribe_command()

Последовательность:

symbols
    │
    ▼
build_trade_subscribe_command(
    symbols,
    correlation_id=...
)
    │
    ▼
SubscribeCommand
    │
    ▼
runtime_service.dispatch(command)

Сервис не:

  • сериализует JSON;
  • создаёт TransportTextMessage вручную;
  • строит subscription key самостоятельно;
  • нормализует символы;
  • хранит активные подписки;
  • выполняет connect;
  • выполняет retry.

correlation_id

Параметр:

correlation_id

передаётся без изменения существующему Subscription Builder.

Если он не задан, его создание остаётся ответственностью builder.

Сервис не генерирует correlation id самостоятельно.


handle_message()

Метод handle_message() обрабатывает один входящий документ.

Последовательность:

document
    │
    ▼
adapter.map_message(document)
    │
    ▼
mapped result
    │
    ▼
isinstance(mapped result, Trade)

Если результат не является Trade, сервис возвращает:

None

Если результат является Trade, сервис вызывает:

consistency_controller.accept(trade)

и возвращает результат без изменения.


Поведение для Quote

Если Adapter возвращает:

Quote

сервис:

  • не вызывает Consistency;
  • не преобразует Quote;
  • не публикует Quote;
  • возвращает None.

Поведение для CandleCloseEvent

Если Adapter возвращает:

CandleCloseEvent

сервис:

  • не вызывает Consistency;
  • не преобразует CandleCloseEvent;
  • не публикует событие;
  • возвращает None.

Поведение для Trade

Если Adapter возвращает:

Trade

сервис передаёт тот же экземпляр в:

TradeStreamConsistencyProtocol.accept()

Сервис не копирует и не изменяет модель.


Поведение для дубликата

Если Consistency Layer возвращает:

None

это означает корректный дубликат.

Сервис сохраняет результат и также возвращает:

None

Дополнительная логика не выполняется.


Сохранение идентичности результата Consistency

Если TradeStreamConsistencyProtocol.accept() возвращает отдельный экземпляр Trade, сервис возвращает именно этот объект.

Сервис не заменяет его исходным результатом Adapter и не создаёт копию.

Данный инвариант подтверждён unit-тестом.


Обработка исключений

Build не вводит отдельную иерархию ошибок Trade Stream Acquisition Service.

Исключения распространяются без обёртки.

Ошибка Subscription Builder

Ошибка формирования SubscribeCommand передаётся вызывающей стороне.

Ошибка Runtime dispatch

Ошибка runtime_service.dispatch() передаётся вызывающей стороне.

Ошибка Adapter

Schema, parser, value validation или mapper error распространяется без изменения.

Ошибка Consistency

TradeConsistencyError, TradeOrderingError и иные исключения Consistency Layer распространяются без изменения.

Сервис не создаёт общий TradeStreamAcquisitionError.


Stateless-архитектура

TradeStreamAcquisitionService не хранит операционное состояние.

В объекте сохраняются только внедрённые зависимости.

Сервис не хранит:

  • symbols;
  • correlation id;
  • active subscriptions;
  • last trade;
  • duplicate window;
  • reconnect attempts;
  • recovery state;
  • runtime status;
  • received documents.

Состояние Consistency принадлежит TradeStreamStateStore.

Состояние Runtime будет принадлежать будущим Session и Subscription Manager.


Изменённые и добавленные файлы

Новый Acquisition Service Protocol

src/market_data/acquisition/
trade_stream_acquisition_protocol.py

Добавлен:

TradeStreamAcquisitionServiceProtocol

Новый Trade Stream Message Adapter Protocol

src/market_data/acquisition/
trade_stream_message_adapter_protocol.py

Добавлены:

TradeStreamMappedMessage
TradeStreamMessageAdapterProtocol

Новый Trade Stream Acquisition Service

src/market_data/acquisition/
trade_stream_acquisition_service.py

Добавлен:

TradeStreamAcquisitionService

Unit-тест Acquisition Service

tests/unit/market_data/acquisition/
test_trade_stream_acquisition_service.py

Добавлены Fake-реализации:

  • FakeRuntimeService;
  • FakeMessageAdapter;
  • FakeConsistencyController.

Проверены subscribe и handle_message без привязки к Dzengi.


Интеграционный тест Dzengi pipeline

tests/unit/market_data/acquisition/
test_dzengi_trade_stream_acquisition_integration.py

Проверен реальный локальный pipeline:

Dzengi WebSocket document
        │
        ▼
DzengiUnifiedWebSocketAdapter
        │
        ▼
Canonical Trade
        │
        ▼
TradeStreamConsistencyController
        │
        ▼
Trade | None

Архитектурная документация

docs/migrations/
build_060_23_architecture.md

Документ фиксирует:

  • границы Build;
  • ответственность сервиса;
  • dependency direction;
  • ADR;
  • Definition of Done;
  • связь с последующими этапами.

Файлы, которые не изменялись

Build не изменяет:

src/market_data/acquisition/feeds/trades_feed.py
src/market_data/acquisition/subscriptions/trades.py
src/market_data/acquisition/adapters/dzengi/websocket.py
src/market_data/acquisition/runtime/acquisition_runtime_service.py
src/market_data/acquisition/runtime/acquisition_runtime_service_protocol.py
src/market_data/acquisition/consistency/trade_stream_protocol.py
src/market_data/acquisition/consistency/trade_stream_consistency_controller.py
src/market_data/acquisition/consistency/trade_stream_state_store.py
src/market_data/acquisition/recovery/trade_recovery_controller.py

Также не изменяются:

src/integrations/exchange/market_stream.py
src/integrations/exchange/market_data_runner.py
src/integrations/exchange/ws_client.py
src/integrations/exchange/service.py

Build не затрагивает legacy quote runtime.


Unit-тестирование TradeStreamAcquisitionService

Новый сервис покрыт отдельным набором unit-тестов.

Проверены следующие сценарии:

  • сервис соответствует TradeStreamAcquisitionServiceProtocol;
  • subscribe() передаёт одну команду Runtime;
  • передаётся именно SubscribeCommand;
  • symbols сохраняются в сформированной команде;
  • correlation_id сохраняется в payload;
  • Adapter вызывается один раз;
  • Trade передаётся в Consistency;
  • возвращается тот же объект, который вернула Consistency;
  • None для корректного дубликата сохраняется;
  • Quote игнорируется;
  • CandleCloseEvent игнорируется;
  • Consistency не вызывается для не-Trade;
  • ошибка Adapter распространяется без изменения;
  • ошибка Consistency распространяется без изменения.

Результат совместного локального прогона unit и integration тестов:

14 passed

Интеграционное тестирование Dzengi pipeline

Интеграционный тест использует настоящий:

DzengiUnifiedWebSocketAdapter

и документ реального WebSocket Trade-контракта:

status
destination
payload

Проверяется полный путь:

schema validation
        │
        ▼
parser
        │
        ▼
value validation
        │
        ▼
mapper
        │
        ▼
Trade
        │
        ▼
Consistency

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

symbol
trade_id
price
quantity
executed_at
aggressor_side
source

Для WebSocket Trade подтверждён источник:

dzengi_websocket_trade

Также реальный TradeStreamConsistencyController подтвердил, что повторная обработка идентичного Trade возвращает:

None

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

После завершения реализации выполнен совместный прогон:

Runtime
Consistency
Recovery
Feeds
Dzengi Adapters
Trade Stream Acquisition Unit Tests
Dzengi Trade Stream Acquisition Integration Tests

Охвачены каталоги:

tests/unit/market_data/acquisition/runtime
tests/unit/market_data/acquisition/consistency
tests/unit/market_data/acquisition/recovery
tests/unit/market_data/acquisition/feeds
tests/unit/market_data/acquisition/adapters/dzengi

и новые файлы:

tests/unit/market_data/acquisition/
test_trade_stream_acquisition_service.py

tests/unit/market_data/acquisition/
test_dzengi_trade_stream_acquisition_integration.py

Результат:

496 passed

Тем самым подтверждено:

  • Runtime Service не нарушен;
  • Runtime Protocol Layer не нарушен;
  • Trade Stream Consistency не нарушена;
  • TradeStreamStateStore не нарушен;
  • Trade Recovery не нарушена;
  • существующие Feeds не нарушены;
  • REST Trade Adapter не нарушен;
  • WebSocket Quote Adapter не нарушен;
  • WebSocket OHLC Adapter не нарушен;
  • WebSocket Trade Adapter не нарушен;
  • Unified WebSocket Adapter не нарушен;
  • новый Acquisition Service корректно интегрируется с реальным Dzengi Adapter;
  • duplicate filtering работает через реальный Consistency Controller.

Проверка качества Git diff

После реализации выполнены:

git diff --stat
git diff --check

git diff --check не выявил ошибок форматирования в отслеживаемых изменениях.

Новые production и test-файлы на момент проверки оставались untracked, поэтому не отображались в git diff --stat.

Изменение:

.gitignore

не относится к Scope Build 060.23 и не должно включаться в коммит этапа.


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

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

Не изменились:

  • TradesFeedProtocol;
  • TradesFeed;
  • TradeDocumentSource;
  • TradeDocumentHandler;
  • Trade model;
  • Runtime Commands;
  • Runtime Events;
  • Acquisition Runtime Service;
  • Trade Subscription Builder;
  • Unified Dzengi Adapter;
  • Trade Stream Consistency API;
  • Trade Recovery API;
  • Feed Registry;
  • legacy Exchange Runtime.

Новый сервис добавляется как отдельный слой и не заменяет существующие REST Feed.


Производительность

subscribe()

Метод выполняет:

  • один вызов Subscription Builder;
  • один асинхронный вызов Runtime dispatch.

Алгоритмическая сложность зависит от существующего builder и количества symbols.

Сервис не создаёт дополнительных копий команд и payload.

handle_message()

Метод выполняет:

  • один вызов Adapter;
  • одну isinstance-проверку;
  • не более одного вызова Consistency.

Координационные накладные расходы постоянны:

O(1)

без учёта внутренней стоимости Adapter и Consistency Layer.

Сервис не вводит:

  • очереди;
  • блокировки;
  • фоновые задачи;
  • retries;
  • дополнительную сериализацию;
  • storage writes.

Подтверждённые архитектурные инварианты

Runtime не знает о Trade

Новые зависимости направлены из Acquisition Service в Runtime Protocol, а не обратно.


TradeStreamAcquisitionService не зависит от Dzengi

Production-сервис зависит от:

TradeStreamMessageAdapterProtocol

а не от конкретного DzengiUnifiedWebSocketAdapter.


Dzengi Adapter проверяется отдельно

Exchange-specific корректность подтверждена интеграционным тестом.


Consistency остаётся единственной точкой проверки последовательности

Сервис не реализует duplicate detection или ordering logic самостоятельно.


TradeStreamStateStore остаётся единственным владельцем Consistency State

Новый сервис не хранит состояния по symbols.


Существующий TradesFeed не изменяется

REST Feed и WebSocket Acquisition Integration остаются отдельными путями.


Сервис не публикует Trade

До появления утверждённого Trade Consumer результат возвращается вызывающей стороне.


Сервис не владеет WebSocket lifecycle

Он не реализует connect, disconnect, receive-loop или reconnect.


trades.unsubscribe не создаётся

Build не вводит неподдерживаемую exchange-команду.


Уникальность новых имён файлов соблюдена

Все новые production и test-файлы имеют уникальные имена.


Что не входит в Scope Build

Build сознательно не реализует:

  • production WebSocketTransportProtocol;
  • production WebSocketSessionProtocol;
  • production WebSocketSubscriptionManagerProtocol;
  • Runtime Event Publisher implementation;
  • Runtime Supervisor;
  • receive-loop;
  • reconnect;
  • heartbeat;
  • scheduler;
  • resubscribe orchestration;
  • автоматический вызов Trade Recovery;
  • восстановление Trade Stream после разрыва;
  • Trade Store;
  • Trade Consumer;
  • публикацию Trade;
  • root Composition;
  • изменение MarketDataRunner;
  • изменение market_stream.py;
  • изменение ExchangeWebSocketClient;
  • изменение существующего TradesFeed;
  • биржевую команду trades.unsubscribe.

Отсутствие перечисленных компонентов является осознанной границей этапа.


Архитектурное значение Build

Build 060.23 впервые соединяет ранее независимые части Trades Acquisition Architecture:

Subscription Builder
Runtime Service
Unified Adapter
Canonical Trade
Consistency Controller

До Build каждый компонент существовал отдельно.

После завершения Build появляется единая сервисная граница:

TradeStreamAcquisitionService

которая поддерживает оба направления интеграции:

outbound subscription command

и:

inbound Trade message processing

При этом сервис остаётся stateless, exchange-independent и не вмешивается в lifecycle Runtime.


Связь с последующими Build

Build 060.24 — Reconnect & Runtime Recovery

На основе текущего сервиса должны быть построены:

  • Runtime reconnect orchestration;
  • автоматическое восстановление подписок;
  • восстановление Trade Stream continuity;
  • координация Consistency и Recovery после разрыва;
  • lifecycle соединения.

Build 060.25 — Integration & Regression

Будет выполнена полная проверка production graph:

Runtime
Trade Stream Acquisition
Consistency
Recovery
Trades Feed

после появления реальных Runtime implementations.


Build 060.26 — Final Documentation

Будет подготовлена итоговая документация всей ветки Trades Feed Runtime.


Заключение

Build 060.23 завершает service-level интеграцию Trade Stream с Acquisition Runtime.

В рамках этапа реализованы:

TradeStreamAcquisitionServiceProtocol
TradeStreamMessageAdapterProtocol
TradeStreamAcquisitionService

Новый сервис:

  • формирует Trade SubscribeCommand через существующий builder;
  • передаёт команду в AcquisitionRuntimeServiceProtocol;
  • обрабатывает один WebSocket-документ через Adapter Protocol;
  • пропускает только канонический Trade;
  • делегирует проверку последовательности Consistency Layer;
  • возвращает Trade | None;
  • не хранит состояние;
  • не содержит exchange-specific логики;
  • не реализует reconnect и Recovery.

Unit-тесты подтверждают поведение координатора независимо от биржи.

Интеграционные тесты подтверждают полный локальный Dzengi pipeline и duplicate filtering через реальный Consistency Controller.

Расширенная регрессия завершена результатом:

496 passed

Итог Build

После завершения Build 060.23 система обладает следующими возможностями.

✓ Создан TradeStreamAcquisitionServiceProtocol.

✓ Создан TradeStreamMessageAdapterProtocol.

✓ Реализован TradeStreamAcquisitionService.

✓ Подписка Trade Stream проходит через существующий Subscription Builder.

✓ SubscribeCommand передаётся через AcquisitionRuntimeServiceProtocol.

✓ Входящие сообщения проходят через Adapter Protocol.

DzengiUnifiedWebSocketAdapter структурно совместим с новым Protocol.

✓ Только Trade передаётся в Consistency.

✓ Quote и CandleCloseEvent игнорируются без побочных эффектов.

✓ Дубликат возвращается как None.

✓ Исключения Adapter и Consistency распространяются без изменения.

✓ Проверена идентичность результата Consistency.

✓ Реальный Dzengi WebSocket Trade document проходит полный pipeline.

✓ Реальный Consistency Controller отклоняет идентичный дубликат.

✓ Существующий TradesFeed не изменён.

✓ Legacy Exchange Runtime не изменён.

Все новые файлы имеют уникальные имена.

✓ Локальный функциональный прогон завершён результатом 14 passed.

✓ Расширенный regression завершён результатом 496 passed.

Build 060.23 — Trade Stream Acquisition Integration считается полностью завершённым и готовым к фиксации в Git.