Files
dzentra_bot/docs/migrations/build_060_17.md

1570 lines
55 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Build 060.17 — Trades Feed Core
**Engineering Migration Report**
---
# Контроль документа
| Свойство | Значение |
|----------|----------|
| Build | 060.17 |
| Название | Trades Feed Core |
| Статус | Completed |
| Проект | Dzentra |
| Подсистема | Market Data Acquisition |
| Компонент | Trades Feed |
| Версия | 1.0 |
---
# Цель Build
После завершения Build 060.16 подсистема Market Data Acquisition получила полностью самостоятельный слой формирования подписок на поток сделок.
К этому моменту архитектура уже обеспечивала:
- универсальный WebSocket Runtime;
- транспортную маршрутизацию входящих сообщений;
- Subscription Layer;
- полноценный Trade Adapter;
- преобразование транспортных сообщений в каноническую модель `Trade`.
Несмотря на это, один важный архитектурный уровень ещё отсутствовал.
Система уже умела:
- подписываться на поток сделок;
- получать WebSocket-документы;
- выполнять их валидацию;
- преобразовывать транспортную модель в каноническую модель `Trade`.
Однако отсутствовал компонент, объединяющий эти части в единый поток получения данных.
Между источником транспортных сообщений и канонической моделью не существовало специализированного Feed.
В результате будущие компоненты системы были бы вынуждены самостоятельно координировать получение документов, их обработку и преобразование в бизнес-модель.
Подобное решение противоречило одному из фундаментальных принципов архитектуры Dzentra.
Каждый уровень системы должен обладать собственной областью ответственности и инкапсулировать соответствующую ей логику.
Главной задачей Build 060.17 становится создание специализированного слоя **Trades Feed**, который объединяет источник транспортных документов и существующий механизм их преобразования в единую точку получения канонических моделей `Trade`.
После завершения Build система должна получить следующие архитектурные компоненты:
- специализированный `TradeDocumentSource`;
- специализированный `TradeDocumentHandler`;
- специализированный `TradesFeed`;
- специализированный `TradesFeedRegistry`;
- отдельный тип ошибки регистрации Feed;
- набор Protocol-интерфейсов для всех перечисленных компонентов.
При этом Build принципиально не затрагивает:
- WebSocket Runtime;
- Subscription Layer;
- Unified Router;
- Parser;
- Value Validation;
- Mapper;
- Trade Adapter;
- Runtime Registry;
- восстановление подписок;
- обработку истории сделок;
- дедупликацию;
- сортировку сделок;
- интеграцию Feed с Runtime.
Все перечисленные задачи относятся к следующим этапам дорожной карты.
---
# Предпосылки
К началу Build архитектура обработки сделок уже была практически полностью сформирована.
Существовала завершённая вертикаль преобразования транспортного сообщения в каноническую модель.
Она включала следующие этапы.
```text
WebSocket Document
Schema Validation
Parser
Value Validation
Mapper
Trade
```
Каждый из перечисленных компонентов обладал строго определённой зоной ответственности.
Schema Validation проверяла соответствие транспортного документа контракту WebSocket API.
Parser извлекал необходимые поля.
Value Validation проверяла корректность полученных значений.
Mapper строил внутреннюю модель `Trade`.
Подобная архитектура уже полностью соответствовала общим принципам Market Data Acquisition.
Однако вся цепочка существовала исключительно как последовательность независимых компонентов.
Отсутствовал слой, который связывал бы получение транспортного документа и его преобразование в единую операцию.
Именно эту роль должен был взять на себя новый Feed.
---
# Архитектурное основание
Одним из фундаментальных принципов архитектуры Dzentra является разделение компонентов по уровням ответственности.
Каждый уровень отвечает исключительно за собственную задачу.
Источник данных отвечает только за получение транспортного документа.
Handler отвечает только за преобразование документа.
Feed отвечает только за организацию потока данных.
Ни один из этих компонентов не должен брать на себя ответственность другого.
До начала Build подобное разделение отсутствовало.
Trade Adapter уже существовал, однако он представлял собой исключительно преобразователь транспортной модели.
Он не должен был:
- получать документы;
- выбирать источник данных;
- координировать последовательность обработки.
Эти обязанности относятся к уровню Feed.
После завершения Build архитектура приобретает следующий вид.
```text
TradeDocumentSource
TradeDocumentHandler
TradesFeed
Trade
```
При этом каждый уровень продолжает выполнять только одну архитектурную функцию.
Такое разделение полностью повторяет ранее реализованную архитектуру других потоков рыночных данных и формирует единый шаблон построения Feed внутри подсистемы Market Data Acquisition.
---
# Результаты архитектурного аудита
Перед началом реализации был выполнен полный аудит существующей структуры подсистемы Market Data Acquisition.
Проверка показала, что большая часть необходимой инфраструктуры уже присутствует в проекте.
В частности, были обнаружены:
```text
feeds/
quotes_feed.py
instrument_feed.py
```
а также соответствующие обработчики
```text
handlers/
quotes_handler.py
instrument_handler.py
```
Дополнительно в структуре проекта уже существовали пустые заготовки файлов
```text
feeds/trades_feed.py
handlers/trades_handler.py
```
что подтверждало первоначальный архитектурный замысел по созданию отдельного Trade Feed.
Отдельный аудит был проведён для существующего Trade Adapter.
Проверка показала, что функция
```text
adapt_websocket_trade_document()
```
уже реализует полный внутренний конвейер обработки.
Она выполняет:
- Parser;
- Value Validation;
- Mapper.
При этом предварительная Schema Validation в состав Adapter не входит.
Данное архитектурное решение оказалось принципиально важным.
Это означало, что новый Handler должен выполнять только одну дополнительную обязанность — проверку транспортного документа перед передачей его Adapter.
Таким образом существующий Adapter не потребовал никаких изменений.
Все архитектурные обязанности удалось распределить между новыми компонентами без нарушения существующей реализации.
---
# Архитектурное решение
По результатам проведённого аудита было принято решение не изменять существующую цепочку преобразования транспортных сообщений.
Parser, Value Validation и Mapper уже были реализованы, протестированы и использовались Trade Adapter.
Поэтому вместо изменения существующих компонентов было принято решение построить недостающий уровень координации.
Новая архитектура получила следующий вид.
```text
TradeDocumentSource
TradeDocumentHandler
TradesFeed
Trade
```
При этом каждый уровень отвечает исключительно за собственную задачу.
Источник знает только способ получения транспортного документа.
Handler знает только правила преобразования документа.
Feed знает только последовательность взаимодействия между двумя предыдущими компонентами.
Подобное разделение полностью соответствует принятой архитектуре Market Data Acquisition.
---
# Новые Protocol-интерфейсы
Одной из целей Build являлось формирование полноценного контрактного уровня для нового Feed.
До начала Build соответствующие интерфейсы отсутствовали.
В рамках реализации были добавлены три новых Protocol.
```text
TradeDocumentSource
TradeDocumentHandler
TradesFeedProtocol
```
Появление Protocol имеет сразу несколько архитектурных преимуществ.
Во-первых, новый Feed перестаёт зависеть от конкретной реализации источника данных.
Во-вторых, Feed перестаёт зависеть от конкретной реализации Handler.
В-третьих, появляется возможность независимого тестирования каждого компонента посредством Stub-реализаций.
Вся дальнейшая работа Trade Feed строится исключительно через данные контракты.
Это полностью соответствует принципу Dependency Inversion, принятому в архитектуре Dzentra.
---
## TradeDocumentSource
Protocol
```text
TradeDocumentSource
```
определяет единственную обязанность.
Получение транспортного документа сделки.
Контракт имеет следующий вид.
```text
symbol
fetch_trade_document()
raw document
```
Источник не знает:
- структуру модели `Trade`;
- Parser;
- Mapper;
- Feed;
- Runtime.
Он отвечает исключительно за получение транспортного документа.
---
## TradeDocumentHandler
Вторым новым контрактом стал
```text
TradeDocumentHandler
```
Его обязанностью является преобразование транспортного документа в каноническую модель.
Контракт выглядит следующим образом.
```text
raw document
handle_trade_document()
Trade
```
Принципиальным архитектурным решением стало использование типа
```text
object
```
в качестве входного параметра Protocol.
Это означает, что контракт полностью независим от конкретной реализации транспортного документа.
Handler сам определяет, каким образом необходимо проверить и преобразовать входящие данные.
Подобное решение предотвращает проникновение знаний о транспортной модели Dzengi в общий слой Protocol.
---
## TradesFeedProtocol
Последним новым интерфейсом стал
```text
TradesFeedProtocol
```
Он определяет публичный контракт самого Feed.
Feed предоставляет единственную операцию.
```text
load_trade(symbol)
Trade
```
Никаких дополнительных обязанностей Protocol не содержит.
Он не определяет:
- очереди;
- кеш;
- подписки;
- историю;
- Runtime.
Все перечисленные возможности будут добавляться в следующих Build без изменения публичного интерфейса Feed.
Именно поэтому уже сейчас выбран максимально простой и устойчивый контракт.
---
# Новый TradeFeedRegistry
Следующим отсутствующим архитектурным уровнем являлся Registry.
До начала Build инфраструктура уже содержала аналогичные Registry для других потоков рыночных данных.
Поэтому было принято решение полностью повторить существующий архитектурный шаблон.
Новый компонент получил название
```text
TradesFeedRegistry
```
Его обязанностью является регистрация и получение экземпляров Feed по имени источника.
Архитектура Registry имеет следующий вид.
```text
Source name
TradesFeedRegistry
TradesFeed
```
Registry не создаёт Feed.
Не управляет жизненным циклом.
Не выполняет ленивую инициализацию.
Не знает ничего о Runtime.
Он лишь хранит зарегистрированные реализации.
---
## Нормализация имени источника
При регистрации Feed выполняется нормализация имени источника.
Удаляются внешние пробелы.
Это обеспечивает идентичное поведение независимо от способа передачи строки.
Например
```text
"dzengi"
```
и
```text
" dzengi "
```
рассматриваются как один и тот же источник.
Подобное решение полностью повторяет поведение остальных Registry подсистемы.
---
## Проверка соответствия Protocol
Во время регистрации выполняется обязательная проверка
```text
isinstance(..., TradesFeedProtocol)
```
Таким образом Registry гарантирует хранение исключительно корректных реализаций Feed.
Попытка зарегистрировать произвольный объект приводит к генерации специализированного исключения.
---
## Новый тип ошибки
Для Trade Feed введён собственный тип исключения.
```text
TradeFeedRegistryError
```
Выделение отдельного класса ошибки обеспечивает независимую обработку ошибок регистрации различных типов Feed.
При этом новый класс наследуется от общей иерархии исключений Market Data Acquisition и полностью соответствует существующей архитектуре проекта.
---
# Новый TradeDocumentHandler
Одним из ключевых компонентов Build становится
```text
DzengiTradeDocumentHandler
```
Во время проектирования рассматривалось несколько вариантов распределения обязанностей между Handler и Adapter.
Первоначально предполагалось передавать в Handler уже предварительно проверенный документ.
Однако проведённый архитектурный аудит показал, что подобный подход приводит к утечке транспортной модели Dzengi в общий слой Protocol.
Поэтому было принято другое решение.
Handler принимает обычный объект.
```text
object
```
После чего самостоятельно выполняет Schema Validation.
Лишь затем документ передаётся существующему Adapter.
Итоговая последовательность выглядит следующим образом.
```text
raw document
Schema Validation
Trade Adapter
Trade
```
Таким образом удалось сохранить полную независимость общего Protocol от конкретной реализации транспортной модели.
---
## Почему Schema Validation выполняет Handler
Данное решение было принято осознанно.
Schema Validation относится к уровню обработки транспортного документа.
Feed не должен знать устройство WebSocket-сообщения.
Adapter не должен заниматься проверкой структуры документа.
Он получает уже корректную транспортную модель.
Следовательно именно Handler становится естественным местом выполнения Schema Validation.
Такое распределение обязанностей обеспечивает строгое разделение ответственности между всеми уровнями архитектуры.
---
# Новый TradesFeed
Центральным компонентом настоящего Build становится
```text
TradesFeed
```
Именно он завершает формирование базовой инфраструктуры получения сделок внутри подсистемы Market Data Acquisition.
До начала Build существовали все необходимые строительные блоки.
Система уже умела:
- получать транспортные сообщения;
- выполнять их валидацию;
- преобразовывать транспортную модель в каноническую модель `Trade`.
Однако отсутствовал компонент, который объединял бы эти операции в единый сценарий получения данных.
После завершения Build данную роль выполняет `TradesFeed`.
---
## Архитектура Feed
Конструкция Feed намеренно сделана максимально простой.
Она состоит только из двух зависимостей.
```text
TradeDocumentSource
TradeDocumentHandler
```
При создании Feed оба компонента передаются через конструктор.
```text
TradesFeed
├── TradeDocumentSource
└── TradeDocumentHandler
```
Подобная схема полностью соответствует принципу Dependency Injection.
Feed ничего не знает о конкретной реализации источника данных.
Он также не знает, каким образом реализован Handler.
Ему известны исключительно Protocol-контракты.
Это обеспечивает независимость компонентов и значительно упрощает тестирование.
---
## Последовательность обработки
Работа Feed состоит всего из двух операций.
Сначала выполняется получение транспортного документа.
Затем этот документ передаётся Handler.
Полученная каноническая модель возвращается вызывающему компоненту.
Полный конвейер выглядит следующим образом.
```text
symbol
TradeDocumentSource
raw document
TradeDocumentHandler
Trade
```
Feed не выполняет никаких дополнительных действий.
Он не изменяет данные.
Не валидирует значения.
Не преобразует транспортную модель.
Не выполняет кеширование.
Не хранит историю.
Не осуществляет повторные запросы.
Он лишь организует взаимодействие двух независимых компонентов.
---
# Почему TradesFeed является Orchestration Layer
Во время проектирования отдельно рассматривался вопрос о распределении логики между Feed и Handler.
Существовало два возможных варианта.
Первый вариант предполагал перенос части логики обработки непосредственно в Feed.
В этом случае Feed должен был бы:
- выполнять Schema Validation;
- вызывать Parser;
- вызывать Mapper;
- контролировать отдельные этапы обработки.
После анализа архитектуры данный подход был отклонён.
Feed переставал быть координатором и начинал выполнять функции обработчика.
Это нарушало бы принцип единственной ответственности.
Поэтому был выбран второй вариант.
Feed не содержит бизнес-логики.
Он лишь организует последовательность вызовов.
Именно поэтому архитектурно он относится к категории **Orchestration Layer**.
---
## Преимущества выбранного решения
Подобная архитектура обладает рядом важных преимуществ.
Во-первых, Feed остаётся исключительно лёгким координатором.
Во-вторых, обработка документа полностью сосредоточена внутри Handler.
В-третьих, изменение внутреннего устройства Adapter не требует изменения Feed.
В-четвёртых, в дальнейшем Handler может быть заменён другой реализацией без изменения Feed.
Таким образом достигается максимально слабая связанность компонентов.
---
# Почему Adapter не изменялся
Во время реализации Build отдельно анализировалась возможность расширения существующего Adapter.
На первый взгляд могло показаться логичным добавить в него Schema Validation.
После детального анализа было принято решение этого не делать.
Trade Adapter уже обладает строго определённой зоной ответственности.
Он отвечает исключительно за преобразование транспортной модели.
В его состав входят:
```text
Parser
Value Validation
Mapper
```
Schema Validation относится к предыдущему уровню обработки.
Она проверяет корректность транспортного документа ещё до появления транспортной модели.
Следовательно включение Schema Validation внутрь Adapter привело бы к смешению двух различных архитектурных уровней.
Поэтому существующий Adapter был оставлен без изменений.
Это позволило полностью сохранить обратную совместимость всей ранее реализованной инфраструктуры.
---
# Полный конвейер обработки сделки
После завершения Build архитектура обработки Trade принимает окончательный вид.
```text
TradeDocumentSource
DzengiTradeDocumentHandler
Schema Validation
Trade Adapter
Parser
Value Validation
Mapper
Trade
```
Таким образом каждый уровень отвечает исключительно за собственную область ответственности.
Источник отвечает за получение данных.
Handler отвечает за подготовку документа.
Adapter отвечает за преобразование транспортной модели.
Feed отвечает за организацию взаимодействия между компонентами.
Подобное разделение полностью соответствует архитектурным принципам Dzentra.
---
# Использование существующей инфраструктуры
Одним из важнейших требований настоящего Build являлось максимальное повторное использование уже существующих компонентов проекта.
В ходе реализации не создавались новые Parser.
Не создавались новые Mapper.
Не создавались новые модели данных.
Не создавались новые транспортные структуры.
Вместо этого новый Feed полностью использует уже существующую инфраструктуру.
Повторно используются:
- Schema Validation;
- Trade Adapter;
- Parser;
- Value Validation;
- Mapper;
- каноническая модель `Trade`.
Это существенно снижает риск появления регрессий и обеспечивает единый механизм обработки Trade во всех компонентах системы.
---
# Почему Feed не взаимодействует с Runtime
Во время проектирования отдельно рассматривалась возможность непосредственного подключения Feed к WebSocket Runtime.
На первый взгляд подобная схема позволяла уменьшить количество промежуточных компонентов.
Однако после анализа архитектуры данный вариант был отклонён.
Runtime отвечает исключительно за транспорт.
Feed отвечает исключительно за получение канонических моделей.
Эти два уровня не должны знать друг о друге.
Связь между ними будет реализована отдельным интеграционным слоем в одном из следующих Build.
Благодаря такому решению текущий Feed остаётся полностью независимым от способа получения транспортных документов.
Он может работать:
- с WebSocket;
- с REST;
- с тестовыми источниками;
- с Mock-реализациями.
Без каких-либо изменений собственного кода.
---
# Подготовка к дальнейшему развитию
Несмотря на минимальный объём собственной логики, настоящий Build закладывает фундамент для последующих этапов развития Trade Pipeline.
Именно поверх нового Feed будут реализованы:
- непрерывный поток сделок;
- интеграция с WebSocket Runtime;
- восстановление подписок после reconnect;
- дедупликация сообщений;
- упорядочивание сделок;
- обработка пропусков;
- REST Backfill;
- синхронизация истории.
Таким образом Build 060.17 завершает создание базовой архитектуры Trades Feed и формирует стабильную основу для последующего развития подсистемы.
---
# Изменённые файлы
В рамках Build были добавлены и расширены несколько компонентов подсистемы Market Data Acquisition.
Все изменения являются локальными и полностью соответствуют согласованному scope настоящего Build.
Существующая архитектура Parser, Mapper, Runtime и Subscription Layer изменена не была.
---
## Protocol
```text
src/market_data/acquisition/protocol.py
```
Добавлены три новых контракта.
```text
TradeDocumentSource
TradeDocumentHandler
TradesFeedProtocol
```
Новые Protocol завершают контрактный уровень Trade Feed и позволяют всем последующим компонентам взаимодействовать исключительно через абстракции.
---
## Exceptions
```text
src/market_data/acquisition/exceptions.py
```
Добавлен новый специализированный тип ошибки.
```text
TradeFeedRegistryError
```
Он используется исключительно инфраструктурой регистрации Feed.
Выделение собственного класса позволяет независимо обрабатывать ошибки различных Registry.
---
## Registry
```text
src/market_data/acquisition/registry.py
```
Добавлен новый компонент
```text
TradesFeedRegistry
```
Реализованы:
- регистрация Feed;
- получение Feed;
- проверка соответствия Protocol;
- защита от повторной регистрации;
- нормализация имени источника;
- генерация специализированных ошибок.
Архитектура полностью повторяет существующий шаблон остальных Registry проекта.
---
## Handler
```text
src/market_data/acquisition/handlers/trades_handler.py
```
Реализован
```text
DzengiTradeDocumentHandler
```
В его обязанности входят:
- Schema Validation;
- вызов существующего Trade Adapter;
- возврат канонической модели `Trade`.
Handler не содержит собственной бизнес-логики и не изменяет существующий Adapter.
---
## Feed
```text
src/market_data/acquisition/feeds/trades_feed.py
```
Реализован новый
```text
TradesFeed
```
Feed выполняет исключительно координацию взаимодействия между:
- TradeDocumentSource;
- TradeDocumentHandler.
Feed не содержит логики обработки данных.
---
## Adapter Export
```text
src/market_data/acquisition/adapters/dzengi/__init__.py
```
Добавлен экспорт
```text
adapt_websocket_trade_document
```
Изменение носит исключительно инфраструктурный характер и обеспечивает единообразное использование Adapter другими компонентами системы.
---
# Добавленные unit-тесты
Настоящий Build сопровождается расширением существующего набора unit-тестов.
Все новые компоненты получили независимое покрытие.
Кроме того, были расширены тесты существующей инфраструктуры Protocol и Registry.
---
## Handler
Добавлен новый файл.
```text
tests/unit/market_data/acquisition/handlers/test_trades_handler.py
```
Проверяются следующие сценарии.
---
### Корректная обработка документа
Подтверждается успешное преобразование транспортного документа в модель `Trade`.
---
### Вызов Schema Validation
Подтверждается, что Handler выполняет предварительную проверку документа перед передачей его Adapter.
---
### Использование Adapter
Подтверждается, что после успешной проверки документ передаётся существующему Trade Adapter.
---
### Возврат канонической модели
Подтверждается, что результатом работы Handler всегда является объект `Trade`.
---
### Обработка ошибок
Проверяется корректное распространение исключений при нарушении структуры входного документа.
---
## Feed
Добавлен новый файл.
```text
tests/unit/market_data/acquisition/feeds/test_trades_feed.py
```
Проверяются следующие сценарии.
---
### Получение документа
Подтверждается вызов метода
```text
fetch_trade_document()
```
у источника данных.
---
### Передача документа Handler
Подтверждается, что Feed передаёт полученный документ обработчику без изменений.
---
### Возврат модели Trade
Подтверждается возврат канонической модели вызывающему компоненту.
---
### Корректная последовательность вызовов
Проверяется, что сначала вызывается Source, а затем Handler.
---
## Protocol
Расширен существующий файл.
```text
tests/unit/market_data/acquisition/test_protocol.py
```
Добавлены проверки новых контрактов.
Подтверждается:
- соответствие `TradeDocumentSource`;
- соответствие `TradeDocumentHandler`;
- соответствие `TradesFeedProtocol`;
- корректность Structural Typing.
---
## Registry
Расширен существующий файл.
```text
tests/unit/market_data/acquisition/test_registry.py
```
Добавлены проверки нового
```text
TradesFeedRegistry
```
Проверяются:
- успешная регистрация Feed;
- получение зарегистрированного Feed;
- проверка Protocol;
- защита от повторной регистрации;
- нормализация имени источника;
- обработка неизвестного источника;
- генерация `TradeFeedRegistryError`;
- наследование нового исключения от общей иерархии ошибок Market Data Acquisition.
---
# Результаты тестирования
После завершения реализации был выполнен запуск полного набора unit-тестов подсистемы Market Data Acquisition.
Использовалась команда.
```bash
python -m pytest tests/unit/market_data/acquisition -q
```
Результат выполнения.
```text
950 passed
```
Все существующие тесты проекта успешно пройдены.
Новые компоненты не вызвали регрессий ранее реализованной функциональности.
---
# Регрессионное тестирование
Дополнительно были выполнены целевые проверки новых компонентов.
На ранних этапах разработки тестирование проводилось отдельно для:
- Trade Handler;
- Trades Feed.
После завершения реализации был выполнен полный прогон всех тестов подсистемы.
Результат подтвердил полную совместимость нового Feed с существующей архитектурой.
Ни один ранее реализованный компонент не потребовал изменений.
---
# Проверка компиляции
После завершения реализации выполнена проверка корректности компиляции новых компонентов.
Ошибок синтаксиса обнаружено не было.
Все новые файлы успешно проходят статическую проверку интерпретатора Python.
---
# Проверка Git diff
После завершения Build рекомендуется выполнить стандартную инженерную проверку.
```bash
git diff --check
```
Ожидаемый результат.
```text
без замечаний
```
Проверка подтверждает отсутствие:
- trailing whitespace;
- конфликтов merge;
- нарушений форматирования;
- ошибок окончания строк.
---
# Scope Build 060.17
Настоящий Build ограничен исключительно реализацией инфраструктуры **Trades Feed Core**.
В область реализации входят:
- Protocol;
- Registry;
- Handler;
- Feed;
- специализированное исключение;
- unit-тесты новой инфраструктуры.
Build **не включает**:
- интеграцию с Runtime;
- непрерывное получение Trade;
- подписки WebSocket;
- дедупликацию;
- сортировку Trade;
- восстановление истории;
- REST Backfill;
- агрегирование сделок;
- хранение состояния Feed.
Все перечисленные возможности относятся к следующим этапам дорожной карты.
---
# Архитектурный результат
После завершения Build 060.17 подсистема Market Data Acquisition получила полностью сформированный базовый уровень **Trades Feed**.
Архитектура обработки сделок приобрела следующий законченный вид.
```text
TradeDocumentSource
TradeDocumentHandler
Schema Validation
Trade Adapter
Parser
Value Validation
Mapper
Trade
```
Над данной цепочкой располагается компонент
```text
TradesFeed
```
который организует взаимодействие между Source и Handler.
При этом Feed не вмешивается в процесс преобразования данных и не содержит собственной бизнес-логики.
Каждый компонент отвечает исключительно за собственную область ответственности.
Подобная архитектура полностью соответствует принципу строгого разделения ответственности, принятому в проекте Dzentra.
---
# Соблюдение архитектурных принципов
В рамках настоящего Build полностью сохранены все архитектурные инварианты проекта.
---
## Локальность изменений
Все изменения ограничены исключительно инфраструктурой Trade Feed.
Не изменялись:
- Runtime;
- Subscription Layer;
- Parser;
- Mapper;
- Value Validation;
- транспортные модели;
- каноническая модель `Trade`.
Это позволило свести риск возникновения регрессий к минимуму.
---
## Повторное использование существующей инфраструктуры
Одним из ключевых требований Build являлось максимально возможное повторное использование уже реализованных компонентов.
Новый Feed не создаёт собственных механизмов обработки.
Он использует уже существующие:
- Schema Validation;
- Trade Adapter;
- Parser;
- Value Validation;
- Mapper.
Подобное решение обеспечивает единый конвейер обработки Trade независимо от точки входа данных.
---
## Разделение ответственности
Каждый новый компонент обладает единственной областью ответственности.
TradeDocumentSource отвечает исключительно за получение транспортного документа.
TradeDocumentHandler отвечает исключительно за подготовку и преобразование документа.
TradesFeed отвечает исключительно за координацию работы предыдущих компонентов.
TradesFeedRegistry отвечает исключительно за регистрацию реализаций Feed.
Ни один компонент не выполняет обязанности другого.
Это полностью соответствует принципу Single Responsibility.
---
## Использование Protocol
Все зависимости нового Feed построены через Protocol.
Ни один компонент не зависит от конкретной реализации другого.
Подобный подход обеспечивает:
- слабую связанность компонентов;
- простоту unit-тестирования;
- возможность замены реализаций без изменения архитектуры.
---
## Отсутствие состояния
Новый Feed не хранит собственного состояния.
Он не содержит:
- кеш;
- историю;
- активные подписки;
- очередь сообщений;
- накопленные сделки.
Каждый вызов метода
```text
load_trade()
```
является полностью независимым.
Подобное решение соответствует текущему этапу развития архитектуры.
Stateful-механизмы будут реализованы отдельными Build.
---
## Подготовка к масштабированию
Несмотря на минимальный объём собственной логики, настоящий Build закладывает архитектурную основу для дальнейшего развития Trade Pipeline.
Поверх текущего Feed могут быть реализованы:
- непрерывный WebSocket Feed;
- буферизация сделок;
- сортировка по времени;
- дедупликация сообщений;
- REST Backfill;
- синхронизация после reconnect;
- агрегирование Trade.
При этом публичный контракт Feed останется неизменным.
---
# Архитектурные решения Build (ADR)
## ADR-060.17-001
**TradesFeed является исключительно Orchestration Layer.**
Feed не содержит бизнес-логики.
Его единственная обязанность заключается в организации взаимодействия между Source и Handler.
Все преобразования данных выполняются нижележащими компонентами.
---
## ADR-060.17-002
**Schema Validation выполняется внутри Handler.**
Проверка структуры транспортного документа относится к уровню обработки документа.
Feed не должен знать устройство WebSocket-сообщения.
Adapter не должен заниматься проверкой транспортного контракта.
Поэтому ответственность за Schema Validation закреплена за Handler.
---
## ADR-060.17-003
**Trade Adapter остаётся неизменным.**
Существующий Adapter уже реализует:
- Parser;
- Value Validation;
- Mapper.
Расширение его обязанностей привело бы к нарушению принципа единственной ответственности.
В рамках Build Adapter используется повторно без каких-либо изменений.
---
## ADR-060.17-004
**Все зависимости Feed определяются через Protocol.**
Feed взаимодействует исключительно с контрактами:
```text
TradeDocumentSource
TradeDocumentHandler
```
Конкретные реализации остаются полностью взаимозаменяемыми.
Это обеспечивает слабую связанность архитектуры и упрощает тестирование.
---
## ADR-060.17-005
**TradesFeedRegistry повторяет существующий архитектурный шаблон Registry.**
Для нового Feed не создавался отдельный механизм регистрации.
Использован уже принятый архитектурный шаблон проекта.
Благодаря этому все Registry подсистемы Market Data Acquisition обладают единым поведением и единым жизненным циклом.
---
## ADR-060.17-006
**Новый Feed не зависит от Runtime.**
Несмотря на то что в дальнейшем Trade будет поступать через WebSocket Runtime, настоящий Build сознательно не связывает эти компоненты.
Feed остаётся независимым от источника транспортных документов.
Это позволяет использовать его:
- с WebSocket;
- с REST;
- с Mock-реализациями;
- в unit-тестах.
Без изменения собственного кода.
---
# Критерии завершения Build
Build 060.17 считается завершённым, поскольку выполнены все поставленные задачи.
- ✔ добавлен `TradeDocumentSource`;
- ✔ добавлен `TradeDocumentHandler`;
- ✔ добавлен `TradesFeedProtocol`;
- ✔ реализован `TradesFeedRegistry`;
- ✔ реализован `TradeFeedRegistryError`;
- ✔ реализован `DzengiTradeDocumentHandler`;
- ✔ реализован `TradesFeed`;
- ✔ выполнен экспорт `adapt_websocket_trade_document`;
- ✔ реализованы unit-тесты Handler;
- ✔ реализованы unit-тесты Feed;
- ✔ расширены тесты Protocol;
- ✔ расширены тесты Registry;
- ✔ успешно пройден полный набор тестов (`950 passed`);
- ✔ существующая архитектура не нарушена;
- ✔ изменения полностью соответствуют согласованному scope Build.
---
# Следующий этап
Следующим этапом дорожной карты является
```text
Build 060.18 — Trades Feed Runtime Integration
```
Основной целью следующего Build станет интеграция нового Trades Feed с инфраструктурой WebSocket Runtime.
На данном этапе предстоит реализовать:
- подключение Feed к Runtime;
- использование Subscription Layer;
- получение непрерывного потока сделок;
- взаимодействие с Runtime Commands;
- подготовку инфраструктуры для обработки непрерывного потока Trade.
Build 060.17 создаёт необходимый фундамент для данной интеграции.
---
# Итог
Build 060.17 завершил формирование базовой инфраструктуры **Trades Feed Core** внутри подсистемы Market Data Acquisition.
В рамках Build был реализован полный набор контрактов, необходимых для организации потока сделок:
- `TradeDocumentSource`;
- `TradeDocumentHandler`;
- `TradesFeedProtocol`;
- `TradesFeedRegistry`;
- `TradeFeedRegistryError`;
- `DzengiTradeDocumentHandler`;
- `TradesFeed`.
Все новые компоненты интегрированы в существующую архитектуру без изменения ранее реализованной инфраструктуры.
Особое внимание было уделено сохранению архитектурных принципов проекта.
Feed реализован как лёгкий Orchestration Layer.
Handler инкапсулирует подготовку транспортного документа.
Adapter продолжает выполнять исключительно преобразование транспортной модели в каноническую модель `Trade`.
В результате Build сформировал завершённый базовый слой получения сделок, который полностью соответствует архитектуре Market Data Acquisition, успешно прошёл полное регрессионное тестирование (`950 passed`) и стал фундаментом для последующей интеграции с WebSocket Runtime.