Build 060.30: finalize Market Data Acquisition documentation
This commit is contained in:
@@ -6,8 +6,8 @@
|
||||
|---|---|
|
||||
| Тип | Target Architecture |
|
||||
| Статус | Active Baseline |
|
||||
| Версия | 1.0 |
|
||||
| Дата | 2026-07-31 |
|
||||
| Версия | 1.1 |
|
||||
| Дата | 2026-08-03 |
|
||||
| Проект | Dzentra |
|
||||
|
||||
---
|
||||
@@ -51,6 +51,12 @@ Dzentra является работающим modular monolith, который
|
||||
Любое изменение ownership или направления зависимостей выполняется
|
||||
отдельным Build после анализа фактических consumers.
|
||||
|
||||
Вертикаль Trades Feed принята от Production Runtime до persistent
|
||||
Storage, Startup Recovery, Historical Access и deterministic Replay в
|
||||
Builds 060.25–060.29. Build 060.30 актуализировал документацию этого
|
||||
состояния. Завершение одной вертикали не означает готовность остальных
|
||||
Market Data feeds или всей торговой платформы.
|
||||
|
||||
---
|
||||
|
||||
## 3. Верхнеуровневая карта
|
||||
@@ -150,7 +156,8 @@ app/src/market_data/acquisition/
|
||||
```
|
||||
|
||||
**Текущий активный результат:** Production Runtime для Trades Feed
|
||||
завершён в Build 060.25.
|
||||
завершён в Build 060.25, а network/fault/stress/soak/live verification —
|
||||
в Build 060.26.
|
||||
|
||||
### 4.2. Validation, Canonicalization and Data Quality
|
||||
|
||||
@@ -195,6 +202,10 @@ Missing Data Recovery не должны смешиваться в один ун
|
||||
`TradeStreamState` принадлежит Consistency Layer, а не общему Market
|
||||
Data Storage и не WebSocket Transport.
|
||||
|
||||
Подтверждённая durable точка восстановления хранится отдельно как
|
||||
Persistent Checkpoint. Она восстанавливает operational state после
|
||||
перезапуска, но не заменяет долговременную историю рынка.
|
||||
|
||||
### 4.4. Persistent Market Data Storage
|
||||
|
||||
**Назначение:** долговременно хранить Canonical Market Data для:
|
||||
@@ -206,31 +217,106 @@ Data Storage и не WebSocket Transport.
|
||||
- backtesting;
|
||||
- аудита качества данных.
|
||||
|
||||
Хранилище должно определить:
|
||||
Build 060.27 реализовал два явно разных слоя:
|
||||
|
||||
- raw и canonical retention policy;
|
||||
- ключи идемпотентности;
|
||||
- порядок и уникальность событий;
|
||||
- партиционирование по типу данных, символу и времени;
|
||||
- правила исправления и повторной загрузки;
|
||||
- provenance и версию Canonical schema.
|
||||
```text
|
||||
app/src/storage/
|
||||
общий/исторический PostgreSQL foundation, pool и migrations
|
||||
|
||||
Существующий `app/src/storage/` нельзя автоматически считать готовым
|
||||
Market Data Storage. Его фактические контракты проверяются в
|
||||
Build 060.27.
|
||||
app/src/market_data/storage/
|
||||
канонические contracts и repositories Market Data
|
||||
```
|
||||
|
||||
### 4.5. Historical Access and Replay
|
||||
Канонический слой содержит idempotent PostgreSQL repositories для
|
||||
Trades, Quotes и Candle revisions, provenance, schema versions,
|
||||
write-only `MarketDataStorage`, Partition Manager и Retention Service.
|
||||
Production writer wiring подключён только для Trades. Существующие REST
|
||||
Quotes/Candles обслуживают Trading/UI, но не записываются этими
|
||||
persistent repositories автоматически.
|
||||
|
||||
**Назначение:**
|
||||
Физическое partitioning реализовано отдельным parent/default family для
|
||||
каждого типа данных:
|
||||
|
||||
- исторические запросы;
|
||||
- последовательное воспроизведение Canonical Market Data;
|
||||
- управляемые виртуальные часы;
|
||||
- одинаковые контракты данных для production и replay consumers;
|
||||
- основа backtesting и воспроизводимой диагностики.
|
||||
```text
|
||||
market_data.trades
|
||||
RANGE (executed_at)
|
||||
├── trades_default
|
||||
└── trades_YYYY_MM
|
||||
|
||||
Replay должен воспроизводить порядок событий и не обходить Canonical
|
||||
Models или validation guarantees.
|
||||
market_data.quotes
|
||||
RANGE (received_at)
|
||||
├── quotes_default
|
||||
└── quotes_YYYY_MM
|
||||
|
||||
market_data.candle_revisions
|
||||
RANGE (open_time)
|
||||
├── candle_revisions_default
|
||||
└── candle_revisions_YYYY_MM
|
||||
```
|
||||
|
||||
`venue` и `symbol` участвуют в identity и queries, но не являются
|
||||
уровнями физического partitioning. Месячный child имеет UTC-границы для
|
||||
всех venue/symbol соответствующего parent. Partition Manager вызывается
|
||||
явно, сериализует создание advisory lock, переносит подходящие строки из
|
||||
default partition и регистрирует управляемый child в
|
||||
`market_data.partition_registry` в одной транзакции.
|
||||
|
||||
Retention также запускается только явно. Он не является Scheduler-задачей
|
||||
Production Runtime. Raw storage, automatic partition creation,
|
||||
historical backfill и гарантия полноты истории пока не реализованы.
|
||||
|
||||
### 4.5. Persistent Checkpoint and Startup Recovery
|
||||
|
||||
Build 060.28 реализовал постоянный operational checkpoint Trades:
|
||||
|
||||
- identity checkpoint — `(venue, symbol)`;
|
||||
- checkpoint ссылается на точную durable Trade;
|
||||
- Trade и checkpoint продвигаются в одной PostgreSQL-транзакции;
|
||||
- optimistic CAS revision защищает конкурентное продвижение;
|
||||
- in-memory state изменяется только после durable commit;
|
||||
- Hydration восстанавливает checkpoint и bounded deduplication tail;
|
||||
- Startup Recovery заполняет разрыв при закрытом Live gate;
|
||||
- buffered live data выпускаются только после успешного Recovery.
|
||||
|
||||
Checkpoint существует только для Trades. Он не является второй копией
|
||||
истории, не доказывает полноту Storage и не имеет отдельного feature
|
||||
flag: persistent checkpoint включается вместе с Market Data Storage.
|
||||
|
||||
### 4.6. Historical Access
|
||||
|
||||
Build 060.29 создал отдельный synchronous read-side:
|
||||
|
||||
```text
|
||||
app/src/market_data/access/
|
||||
```
|
||||
|
||||
Trade, Quote и Candle revision history читаются forward keyset pages.
|
||||
Каждый вызов Historical query читает одну текущую committed page;
|
||||
единый snapshot между последовательными страницами не гарантируется.
|
||||
Access не изменяет durable data или operational checkpoint, вызывается
|
||||
явным consumer и не запускается из Bootstrap автоматически.
|
||||
|
||||
### 4.7. Deterministic Replay
|
||||
|
||||
Replay использует те же Canonical Models, что live processing, и не
|
||||
обходит validation guarantees. Migration 9 добавила общий immutable
|
||||
`replay_sequence` для Trades, Quotes и Candle revisions. Миграция
|
||||
блокирующая и перед большой production-базой требует maintenance window,
|
||||
backup и предварительного замера длительности.
|
||||
|
||||
Replay Plan Builder материализует bounded snapshot в транзакции
|
||||
`READ ONLY REPEATABLE READ`. Превышение `max_records` завершается явной
|
||||
ошибкой. Смешанный порядок событий равен
|
||||
`(replay_at, replay_sequence)`.
|
||||
|
||||
`DeterministicReplayClock` принимает timezone-aware `datetime`,
|
||||
канонизирует его в UTC, допускает равное время и запрещает движение
|
||||
назад; naive `datetime` запрещён. `ReplaySession` — caller-owned one-shot
|
||||
lifecycle с новым графом зависимостей для каждого запуска.
|
||||
|
||||
Автоматический Replay startup, default consumer, отдельный Replay
|
||||
endpoint, hidden task и historical backfill не реализованы. Backtesting
|
||||
может использовать этот фундамент, но сам не входит в Build 060.29.
|
||||
|
||||
---
|
||||
|
||||
@@ -436,6 +522,11 @@ Backtesting является отдельной capability, но переисп
|
||||
|
||||
Отдельная копия торговой логики только для backtest не допускается.
|
||||
|
||||
Persistent Storage, Historical Access, Replay Plan, deterministic clock
|
||||
и Replay Session уже создают необходимые data/time prerequisites.
|
||||
Backtesting engine, exchange/OMS simulator и автоматическая composition
|
||||
этой capability пока не реализованы.
|
||||
|
||||
---
|
||||
|
||||
## 8. Правила зависимостей
|
||||
@@ -485,7 +576,10 @@ order, account и runtime events, а не через обратные импор
|
||||
| Market Data Acquisition | `app/src/market_data/acquisition/` |
|
||||
| Application Runtime Composition | `app/src/bootstrap/` |
|
||||
| Runtime Events | `app/src/runtime_events/` и локальные runtime events |
|
||||
| Storage foundation | `app/src/storage/` |
|
||||
| Общий/исторический Storage foundation | `app/src/storage/` |
|
||||
| Canonical Market Data Storage | `app/src/market_data/storage/` |
|
||||
| Historical Market Data Access | `app/src/market_data/access/` |
|
||||
| Deterministic Replay | `app/src/market_data/replay/` |
|
||||
| Market Intelligence | `app/src/trading/market_intelligence/` |
|
||||
| Trading Decision | `app/src/trading/decision/` |
|
||||
| Execution | `app/src/trading/execution/` |
|
||||
@@ -501,9 +595,11 @@ order, account и runtime events, а не через обратные импор
|
||||
4. подготовлен отдельный migration plan;
|
||||
5. проверено направление импортов.
|
||||
|
||||
Предложенные имена вроде `analytics/features`,
|
||||
`market_data/normalization` или `market_data/storage` являются
|
||||
логическими ориентирами, а не заранее утверждённой файловой структурой.
|
||||
Предложенные имена вроде `analytics/features` или
|
||||
`market_data/normalization` являются логическими ориентирами, а не
|
||||
заранее утверждённой файловой структурой. Каталоги
|
||||
`market_data/storage`, `market_data/access` и `market_data/replay` уже
|
||||
являются принятыми фактическими boundaries.
|
||||
|
||||
---
|
||||
|
||||
@@ -511,18 +607,19 @@ order, account и runtime events, а не через обратные импор
|
||||
|
||||
| Область | Состояние |
|
||||
|---|---|
|
||||
| Market Data Acquisition foundation | Реализуется Build-by-Build |
|
||||
| Market Data Acquisition foundation | Trades vertical slice завершён; остальные feeds развиваются Build-by-Build |
|
||||
| Trades Feed production runtime | Completed — Build 060.25 |
|
||||
| Runtime integration/stress verification | Next — Build 060.26 |
|
||||
| Persistent Market Data Storage | Planned — Build 060.27 |
|
||||
| Persistent Checkpoint / Startup Recovery | Planned — Build 060.28 |
|
||||
| Historical Access / Replay | Planned — Build 060.29 |
|
||||
| Runtime integration/stress/live verification | Completed — Build 060.26 |
|
||||
| Persistent Market Data Storage | Completed — Build 060.27 |
|
||||
| Persistent Checkpoint / Startup Recovery | Completed — Build 060.28 |
|
||||
| Historical Access / Replay | Completed — Build 060.29 |
|
||||
| Market Data Acquisition Final Documentation | Completed — Build 060.30 |
|
||||
| Validation ownership audit/refactoring | Planned — Build 061.00 |
|
||||
| Market Intelligence | Существующая активная подсистема |
|
||||
| Decision / Execution / Position | Существующие подсистемы, требуют будущих boundary audits |
|
||||
| OMS / Reconciliation | Целевая ответственность, отдельный план не утверждён |
|
||||
| Backtesting | Целевая capability после Storage и Replay |
|
||||
| Operations / Deployment | Целевая cross-cutting программа |
|
||||
| Backtesting | Storage/Replay prerequisites готовы; capability не реализована |
|
||||
| Operations / Deployment | Docker hardening принят; deployment остаётся отдельной cross-cutting программой |
|
||||
|
||||
`Completed` означает завершение утверждённого Build, а не окончательную
|
||||
сертификацию всей подсистемы для любой production-нагрузки.
|
||||
|
||||
@@ -1,11 +1,117 @@
|
||||
# Architecture Overview
|
||||
# Обзор архитектуры Dzentra
|
||||
|
||||
Проект строится как modular monolith с разделением по слоям:
|
||||
**Статус:** Current; Build 060.30.3
|
||||
|
||||
- `telegram` — меню, handlers, routers
|
||||
- `bootstrap` — сборка приложения
|
||||
- `core` — конфигурация и базовые сущности
|
||||
- `trading` — бизнес-логика торговли
|
||||
- `storage` — доступ к данным
|
||||
- `integrations` — внешние API
|
||||
- `shared` — общие утилиты
|
||||
Dzentra развивается как модульный монолит: приложение собирается одним
|
||||
Composition Root, но ответственность разделена между пакетами и
|
||||
связывается через явные контракты.
|
||||
|
||||
Каноническое подробное описание готовой Market Data вертикали находится
|
||||
в [архитектуре Trades Feed](trades_feed.md). Эта страница служит
|
||||
верхнеуровневой картой всего приложения и не дублирует lifecycle и
|
||||
recovery-сценарии.
|
||||
|
||||
## Composition Root и текущие связи
|
||||
|
||||
`src.bootstrap` загружает настройки, выполняет базовый `init_schema()` с
|
||||
PostgreSQL I/O, собирает опциональный Market Data pool/repository graph
|
||||
без I/O и управляет общим lifecycle Telegram, Trade Runtime и Market
|
||||
Data Storage.
|
||||
|
||||
Схема запуска и основных взаимодействий:
|
||||
|
||||
```text
|
||||
main.py → bootstrap
|
||||
├→ init_schema() → src.storage → PostgreSQL
|
||||
├→ Telegram polling → trading / integrations
|
||||
└→ optional Trade Runtime
|
||||
├→ market_data/acquisition → Consistency / Recovery
|
||||
└→ optional market_data/storage → PostgreSQL
|
||||
|
||||
trading / integrations / notifications / runtime_events
|
||||
→ существующие связи модульного монолита
|
||||
```
|
||||
|
||||
Это карта исполнения, а не утверждение о полностью однонаправленном
|
||||
import graph. В исторических пакетах сохраняются перекрёстные связи между
|
||||
`trading`, `integrations` и `notifications`. Новая Market Data вертикаль
|
||||
имеет более строгие protocol/composition boundaries. Пакеты не должны
|
||||
самостоятельно запускать общий Application lifecycle.
|
||||
|
||||
## Основные пакеты `app/src`
|
||||
|
||||
| Пакет | Ответственность |
|
||||
|---|---|
|
||||
| `bootstrap` | Composition Root, startup, graceful shutdown и feature-flag wiring |
|
||||
| `core` | Settings, logging и общие базовые компоненты приложения |
|
||||
| `telegram` | Routers, handlers, keyboards и Telegram UI |
|
||||
| `trading` | Торговая бизнес-логика, журнал и существующие runtime-компоненты |
|
||||
| `integrations` | Клиенты и адаптеры внешних API вне канонической Market Data вертикали |
|
||||
| `market_data` | Acquisition, persistent Storage, Historical Access и deterministic Replay |
|
||||
| `runtime_events` | Внутренние runtime-события и их публикация |
|
||||
| `notifications` | Доставка и маршрутизация уведомлений |
|
||||
| `storage` | Смешанный общий/исторический PostgreSQL foundation, migrations и in-memory caches |
|
||||
| `shared` | Общие вспомогательные компоненты без владения lifecycle |
|
||||
|
||||
## Market Data
|
||||
|
||||
Пакет `market_data` разделён на четыре независимые области:
|
||||
|
||||
| Область | Назначение |
|
||||
|---|---|
|
||||
| `acquisition` | WebSocket/REST ingestion, validation, Consistency, Recovery и Production Runtime Trades |
|
||||
| `storage` | Канонические Trade/Quote/Candle repositories, persistent Trade checkpoint, partitions и Retention |
|
||||
| `access` | Read-only Historical Access к сохранённым данным |
|
||||
| `replay` | Ограниченный deterministic Replay через явно создаваемую one-shot session |
|
||||
|
||||
WebSocket Runtime, Consistency/Recovery и persistence wiring завершены
|
||||
только для Trades. Существующие REST-потоки Quotes/Candles продолжают
|
||||
обслуживать Trading/UI. Quote и Candle repositories/readers реализованы,
|
||||
но persistent writer consumers к ним пока не подключены.
|
||||
|
||||
Historical Access, Replay, Retention и создание месячных партиций не
|
||||
являются фоновыми задачами приложения и выполняются только явным
|
||||
вызывающим кодом.
|
||||
|
||||
## Две Storage-границы
|
||||
|
||||
Историческое имя `src/storage` охватывает несколько разных обязанностей:
|
||||
|
||||
- `session.py`, `schema.py` и repositories журнала/balance snapshots
|
||||
обслуживают базовую схему приложения;
|
||||
- `instrument_store.py` и `quote_store.py` предоставляют in-memory caches;
|
||||
- `postgres_pool.py` и `migrations.py` являются общей
|
||||
PostgreSQL-инфраструктурой, которую использует новая Market Data
|
||||
вертикаль.
|
||||
|
||||
`src/market_data/storage` владеет каноническими persistent Market Data
|
||||
contracts и repositories. Поэтому `src/storage` нельзя считать целиком
|
||||
устаревшим или неиспользуемым. Подробная карта ownership приведена в
|
||||
[Storage README](../../app/src/storage/README.md).
|
||||
|
||||
## Runtime и данные
|
||||
|
||||
Краткая цепочка принятой Trades-вертикали:
|
||||
|
||||
```text
|
||||
Dzengi WebSocket + REST Recovery
|
||||
↓
|
||||
Canonical Trade → Consistency
|
||||
↓
|
||||
optional atomic Trade + checkpoint write
|
||||
↓
|
||||
next startup: Hydration → Startup Recovery → buffered live processing
|
||||
|
||||
explicit caller → Historical Access / Replay
|
||||
```
|
||||
|
||||
PostgreSQL доступен обычному Bootstrap даже при выключенных Trade Stream
|
||||
и Market Data Storage, поскольку базовые таблицы журнала и balance
|
||||
snapshots инициализируются всегда.
|
||||
|
||||
## Связанные документы
|
||||
|
||||
- [Структура проекта](project_structure.md)
|
||||
- [Текущая архитектура Trades Feed](trades_feed.md)
|
||||
- [Эксплуатация Trade Stream Runtime](../operations/trades_feed_runtime.md)
|
||||
- [Архитектура Build 060.30](../migrations/build_060_30_architecture.md)
|
||||
|
||||
@@ -1,15 +1,108 @@
|
||||
# Project Structure
|
||||
# Структура проекта Dzentra
|
||||
|
||||
## Корневые папки
|
||||
- `app/` — код приложения
|
||||
- `docs/` — документация
|
||||
- `infra/` — Docker и compose
|
||||
**Статус:** Current; Build 060.30.3
|
||||
|
||||
## Внутри `app/src`
|
||||
- `bootstrap/`
|
||||
- `core/`
|
||||
- `telegram/`
|
||||
- `trading/`
|
||||
- `storage/`
|
||||
- `integrations/`
|
||||
- `shared/`
|
||||
Документ показывает назначение верхних уровней текущего checkout. Это
|
||||
навигационная карта, а не полный перечень файлов.
|
||||
|
||||
## Корень репозитория
|
||||
|
||||
```text
|
||||
dzentra_bot/
|
||||
├── app/ Python-приложение, зависимости и тесты
|
||||
├── docs/ архитектура, runbook, roadmap и история Builds
|
||||
├── infra/ Dockerfile и Docker Compose
|
||||
├── scripts/ общие quality-gate и вспомогательные scripts
|
||||
├── pyrightconfig.json единая конфигурация статической проверки
|
||||
├── README.md входная страница существующего checkout
|
||||
└── bootstrap_project.py исторический генератор первоначального каркаса
|
||||
```
|
||||
|
||||
`bootstrap_project.py` не является командой установки или запуска
|
||||
текущего проекта.
|
||||
|
||||
## Каталог `app`
|
||||
|
||||
| Путь | Назначение |
|
||||
|---|---|
|
||||
| `src/` | Production-код модульного монолита |
|
||||
| `tests/unit/` | Unit-тесты default offline regression |
|
||||
| `tests/static/` | Обязательный Pyright gate внутри default pytest |
|
||||
| `tests/integration/` | Opt-in локальные network/PostgreSQL сценарии |
|
||||
| `tests/stress/` | Fixed stress и opt-in soak проверки |
|
||||
| `tests/live/` | Только явно разрешённые проверки внешних endpoints |
|
||||
| `tests/support/` | Общие test harness и безопасные opt-in helpers |
|
||||
| `scripts/` | Ручные диагностические scripts |
|
||||
| `tools/` | Исследовательские Dzengi probes и сохранённые samples |
|
||||
| `.env.example` | Полный безопасный пример поддерживаемых настроек |
|
||||
| `requirements.txt` | Прямые Production dependencies |
|
||||
| `requirements.lock` | Полный hash-locked набор Production image |
|
||||
| `requirements-dev.txt` | Production dependencies плюс pytest и Pyright |
|
||||
|
||||
Диагностические `app/scripts` и `app/tools` не запускаются автоматически
|
||||
вместе с Production Runtime.
|
||||
|
||||
## Пакеты `app/src`
|
||||
|
||||
```text
|
||||
src/
|
||||
├── bootstrap/ Composition Root и общий lifecycle
|
||||
├── core/ settings, logging и общие компоненты
|
||||
├── integrations/ внешние API вне Market Data vertical slice
|
||||
├── market_data/ acquisition, storage, access и replay
|
||||
├── notifications/ доставка и маршрутизация уведомлений
|
||||
├── runtime_events/ внутренняя Runtime Event система
|
||||
├── shared/ общие вспомогательные компоненты
|
||||
├── storage/ общий/исторический Storage foundation
|
||||
├── telegram/ Telegram UI и handlers
|
||||
├── trading/ торговая бизнес-логика и runtime-компоненты
|
||||
└── main.py async entry point приложения
|
||||
```
|
||||
|
||||
## Пакет `market_data`
|
||||
|
||||
```text
|
||||
market_data/
|
||||
├── acquisition/ Canonical models, protocols, validation, Recovery и Runtime
|
||||
├── storage/ persistent repositories, checkpoint, partitions и Retention
|
||||
├── access/ Historical Access read-side
|
||||
└── replay/ Replay plan, deterministic clock и one-shot session
|
||||
```
|
||||
|
||||
Фактические WebSocket Runtime, Consistency/Recovery и persistent writer
|
||||
consumer существуют только для Trades. REST-потоки Quotes/Candles
|
||||
продолжают использоваться Trading/UI; их persistence/read-side API
|
||||
реализованы отдельно.
|
||||
|
||||
## Storage ownership
|
||||
|
||||
`src/storage` и `src/market_data/storage` не являются взаимозаменяемыми:
|
||||
|
||||
| Путь | Фактическая роль |
|
||||
|---|---|
|
||||
| `src/storage/session.py`, `schema.py`, `repositories/` | Базовая PostgreSQL-схема журнала и balance snapshots |
|
||||
| `src/storage/instrument_store.py`, `quote_store.py` | In-memory caches существующих consumers |
|
||||
| `src/storage/postgres_pool.py`, `migrations.py` | Общая инфраструктура pool/migrations, используемая Market Data Storage |
|
||||
| `src/market_data/storage/` | Канонические persistent Market Data contracts и repositories |
|
||||
| `src/market_data/access/` | Отдельный read-side сохранённых данных |
|
||||
| `src/market_data/replay/` | Отдельная deterministic Replay-вертикаль |
|
||||
|
||||
Подробности приведены в [README пакета Storage](../../app/src/storage/README.md).
|
||||
|
||||
## Документация
|
||||
|
||||
| Каталог | Назначение |
|
||||
|---|---|
|
||||
| `docs/architecture/` | Current и target architecture |
|
||||
| `docs/operations/` | Актуальные эксплуатационные руководства |
|
||||
| `docs/migrations/` | Architecture/report документов отдельных Builds |
|
||||
| `docs/roadmap/` | План развития и исторические stage roadmaps |
|
||||
| `docs/stages/`, `docs/decisions/` | Исторические этапы и решения |
|
||||
| `docs/market_intelligence/` | Отдельная развиваемая Market Intelligence область |
|
||||
|
||||
## Связанные документы
|
||||
|
||||
- [Обзор архитектуры](overview.md)
|
||||
- [Текущая архитектура Trades Feed](trades_feed.md)
|
||||
- [Эксплуатация Trade Stream Runtime](../operations/trades_feed_runtime.md)
|
||||
- [Инструкция приложения](../../app/README.md)
|
||||
|
||||
585
docs/architecture/trades_feed.md
Normal file
585
docs/architecture/trades_feed.md
Normal file
@@ -0,0 +1,585 @@
|
||||
# Trades Feed (Time & Sales) — текущая архитектура
|
||||
|
||||
**Статус:** Current; accepted in Build 060.30.1
|
||||
|
||||
**Область:** Production vertical slice Canonical Trades
|
||||
|
||||
**Версия документа:** 1.0
|
||||
|
||||
---
|
||||
|
||||
## Связанные документы
|
||||
|
||||
- [Архитектура Build 060.30](../migrations/build_060_30_architecture.md)
|
||||
- [Эксплуатация Trade Stream Runtime](../operations/trades_feed_runtime.md)
|
||||
- [Build 060.27 — Persistent Market Data Storage](../migrations/build_060_27.md)
|
||||
- [Build 060.28 — Persistent Checkpoint](../migrations/build_060_28.md)
|
||||
- [Build 060.29 — Market Data Access and Replay](../migrations/build_060_29.md)
|
||||
|
||||
---
|
||||
|
||||
## 1. Назначение и фактический scope
|
||||
|
||||
Trades Feed получает сделки Dzengi, преобразует их в Canonical `Trade`,
|
||||
проверяет порядок и дубликаты, восстанавливает разрывы через REST и при
|
||||
включённом Storage атомарно сохраняет сделку вместе с persistent
|
||||
checkpoint.
|
||||
|
||||
После перезапуска Runtime восстанавливает Consistency state из
|
||||
PostgreSQL, выполняет Startup Recovery и только затем пропускает
|
||||
накопленные live-сообщения. Сохранённые Canonical Market Data доступны
|
||||
через отдельные Historical Access и deterministic Replay API.
|
||||
|
||||
Краткая итоговая цепочка:
|
||||
|
||||
```text
|
||||
Dzengi WebSocket → Transport → validation/mapping → Canonical Trade ─┐
|
||||
├→ Consistency
|
||||
Dzengi REST Recovery → validation/mapping → Canonical Trade ─────────┘
|
||||
↓
|
||||
optional PostgreSQL Trade + checkpoint
|
||||
├→ next persistent startup
|
||||
│ → Hydration
|
||||
│ → Consistency state
|
||||
│ → Startup Recovery
|
||||
├→ explicit caller
|
||||
│ → Historical Access
|
||||
└→ explicit caller
|
||||
→ Replay Plan
|
||||
→ Replay Session → consumer
|
||||
```
|
||||
|
||||
Production ingestion и persistence в этой цепочке реализованы только
|
||||
для Trades. Наличие Quote/Candle моделей и repositories не означает,
|
||||
что Quotes и Candles уже подключены как Production feeds.
|
||||
|
||||
---
|
||||
|
||||
## 2. Матрица готовности Market Data
|
||||
|
||||
| Возможность | Trades | Quotes | Candle revisions |
|
||||
|---|---:|---:|---:|
|
||||
| Canonical model и Dzengi adapters | Да | Да | Да |
|
||||
| Production WebSocket Runtime consumer | Да | Нет | Нет |
|
||||
| Live/Recovery Consistency | Да | Нет | Нет |
|
||||
| Production persistence wiring | Да | Нет | Нет |
|
||||
| PostgreSQL repository и schema | Да | Да | Да |
|
||||
| Persistent operational checkpoint | Да | Нет | Нет |
|
||||
| Historical reader | Да | Да | Да |
|
||||
| Bounded deterministic Replay | Да | Да | Да |
|
||||
|
||||
Другие acquisition feeds проекта не входят в завершённую production
|
||||
вертикаль Trades Feed.
|
||||
|
||||
---
|
||||
|
||||
## 3. Режимы по feature flags
|
||||
|
||||
| Trade Stream | Market Data Storage | Фактическое поведение |
|
||||
|---|---|---|
|
||||
| выключен | выключен | Trade Runtime и Market Data pool не создаются |
|
||||
| включён | выключен | Live, in-memory Consistency и reconnect Recovery без restart persistence |
|
||||
| включён | включён | Durable Trades, checkpoint, Hydration и Startup Recovery |
|
||||
| выключен | включён | Недопустимая конфигурация; settings завершаются ошибкой |
|
||||
|
||||
Оба флага по умолчанию выключены. При включённом Trade Stream требуются
|
||||
явные WebSocket URL, REST base URL и symbols. Скрытых URL или symbol
|
||||
fallback нет.
|
||||
|
||||
Без Storage первоначальный startup подписывается без persistent
|
||||
Hydration, ожидания startup ACK и Startup REST Recovery. Reconnect
|
||||
Recovery во время уже работающего процесса остаётся доступным.
|
||||
|
||||
---
|
||||
|
||||
## 4. Карта компонентов
|
||||
|
||||
| Граница | Ответственность | Основные компоненты |
|
||||
|---|---|---|
|
||||
| Transport | WebSocket lifecycle, send/receive, Ping/Pong probe | `DzengiWebSocketTransport`, `WebSocketSession` |
|
||||
| Protocol | Команды, события, subscription и control routing | `AcquisitionRuntimeService`, `WebSocketSubscriptionManager` |
|
||||
| Adapter | JSON/schema/value validation и Canonical mapping | `DzengiUnifiedWebSocketAdapter`, REST adapter |
|
||||
| Runtime | Startup, receive loop, buffering, tasks и shutdown | `TradeStreamProductionRuntime` |
|
||||
| Consistency | Порядок, deduplication и per-symbol state | `TradeStreamConsistencyController`, `TradeStreamStateStore` |
|
||||
| Recovery | REST windows и повторная подача в Consistency | `RuntimeRecoveryCoordinator`, `TradeRecoveryController` |
|
||||
| Persistence | Canonical write, provenance и checkpoint | `TradeStorageObservationSink`, `PostgresTradeRepository` |
|
||||
| Startup | Hydration durable tail и Startup Recovery | `TradeStreamStateHydrator`, `RuntimeStartupRecoveryCoordinator` |
|
||||
| Read-side | Historical pages | `MarketDataHistoricalAccess`, PostgreSQL readers |
|
||||
| Replay | Snapshot, virtual clock и one-shot playback | `PostgresReplayPlanBuilder`, `ReplaySessionFactory`, `ReplaySession` |
|
||||
| Composition | Concrete dependency graph и root lifecycle | `bootstrap`, `ApplicationComposition` |
|
||||
|
||||
Transport не знает Canonical models, Recovery или PostgreSQL. Bootstrap
|
||||
является внешним composition root и создаёт concrete adapters.
|
||||
|
||||
---
|
||||
|
||||
## 5. Canonical Trade и Consistency
|
||||
|
||||
Один `TradeStreamState` принадлежит одному нормализованному symbol.
|
||||
Состояние хранит:
|
||||
|
||||
- последнюю принятую сделку;
|
||||
- in-memory checkpoint;
|
||||
- ограниченное окно Trade ID для deduplication;
|
||||
- Canonical payload уже наблюдавшихся сделок.
|
||||
|
||||
Размер deduplication tail по умолчанию равен 10 000 Trades.
|
||||
|
||||
Trade ID соответствует signed 32-bit контракту. Сравнение учитывает
|
||||
rollover:
|
||||
|
||||
- `INT32_MAX → INT32_MIN` является продвижением;
|
||||
- `-1 → 0` является продвижением;
|
||||
- расстояние ровно в половину 32-битного цикла неоднозначно и
|
||||
отклоняется.
|
||||
|
||||
Две доставки считаются одним биржевым фактом, если совпадают symbol,
|
||||
Trade ID, цена, количество, execution time и aggressor side. Поле
|
||||
`source` описывает путь доставки WebSocket/REST и не участвует в этом
|
||||
сравнении. При этом `source` сохраняется как часть Canonical payload и
|
||||
provenance.
|
||||
|
||||
Конфликтующий дубликат и нарушение rollover-aware порядка являются
|
||||
ошибками, а не молча отбрасываемыми данными.
|
||||
|
||||
Исходники:
|
||||
|
||||
- [TradeStreamState](../../app/src/market_data/acquisition/consistency/trade_stream_state.py)
|
||||
- [Consistency Controller](../../app/src/market_data/acquisition/consistency/trade_stream_consistency_controller.py)
|
||||
- [Trade ID sequence](../../app/src/market_data/acquisition/trade_id_sequence.py)
|
||||
|
||||
---
|
||||
|
||||
## 6. Live processing
|
||||
|
||||
Точная последовательность одного live-документа:
|
||||
|
||||
```text
|
||||
WebSocket receive
|
||||
→ зафиксировать transport activity
|
||||
→ опубликовать Runtime Event
|
||||
→ JSON decode
|
||||
→ войти в LiveProcessingGate
|
||||
→ разделить control и market document
|
||||
→ Dzengi adapter
|
||||
→ Canonical Trade
|
||||
→ общий Consistency Controller
|
||||
→ optional durable sink
|
||||
→ продвинуть in-memory state
|
||||
```
|
||||
|
||||
Blocking adapter/Consistency/Persistence path выполняется через
|
||||
`asyncio.to_thread`. Runtime владеет worker-задачей и при cancellation
|
||||
дожидается уже начатой обработки, чтобы не оставить неизвестный
|
||||
результат записи.
|
||||
|
||||
При выключенном Storage Consistency продвигает только память процесса.
|
||||
При включённом Storage durable callback завершается до изменения
|
||||
in-memory checkpoint.
|
||||
|
||||
Runtime events доставляются in-process последовательно. Publisher не
|
||||
имеет фоновой очереди или отдельной root task; production composition
|
||||
регистрирует logging consumer.
|
||||
|
||||
Исходники:
|
||||
|
||||
- [Production Runtime](../../app/src/market_data/acquisition/runtime/trade_stream_production_runtime.py)
|
||||
- [Acquisition Service](../../app/src/market_data/acquisition/trade_stream_acquisition_service.py)
|
||||
- [Runtime Event Publisher](../../app/src/market_data/acquisition/runtime/acquisition_runtime_event_publisher.py)
|
||||
|
||||
---
|
||||
|
||||
## 7. Durable write и persistent checkpoint
|
||||
|
||||
Для новой принятой сделки гарантия имеет следующий порядок:
|
||||
|
||||
```text
|
||||
BEGIN
|
||||
→ insert либо validate identical Trade
|
||||
→ compare-and-set persistent checkpoint
|
||||
→ COMMIT
|
||||
→ advance in-memory state
|
||||
```
|
||||
|
||||
Trade и checkpoint записываются одним `PostgresTradeRepository` и одной
|
||||
транзакцией. Ошибка вставки, payload conflict или checkpoint conflict
|
||||
откатывает операцию и не продвигает in-memory state.
|
||||
|
||||
Полный дубликат обрабатывается отдельно:
|
||||
|
||||
```text
|
||||
validate stored Trade
|
||||
→ optional provenance update
|
||||
→ persistent checkpoint не двигается
|
||||
→ in-memory checkpoint не двигается
|
||||
```
|
||||
|
||||
Идентичность строки Trade:
|
||||
|
||||
```text
|
||||
venue + symbol + trade_id + executed_at
|
||||
```
|
||||
|
||||
Persistent checkpoint имеет один ключ `venue + symbol` и ссылается на
|
||||
точную durable Trade identity через `DEFERRABLE INITIALLY DEFERRED`
|
||||
foreign key с `NO ACTION`.
|
||||
|
||||
Parent table Trades partitioned по диапазону `executed_at`; Quotes — по
|
||||
`received_at`, Candle revisions — по `open_time`. Миграции всегда
|
||||
создают default partition. Конкретная месячная UTC-partition появляется
|
||||
только после явного вызова Partition Manager. Symbol и venue являются
|
||||
identity/query scope, но не отдельными физическими уровнями
|
||||
partitioning.
|
||||
|
||||
Исходники:
|
||||
|
||||
- [Trade Storage Sink](../../app/src/market_data/storage/trade_storage_observation_sink.py)
|
||||
- [PostgreSQL Trade Repository](../../app/src/market_data/storage/postgres_trade_repository.py)
|
||||
- [Storage migrations](../../app/src/storage/migrations.py)
|
||||
|
||||
---
|
||||
|
||||
## 8. Startup с persistent state
|
||||
|
||||
Application сначала открывает Market Data pool и применяет migrations.
|
||||
Только после успешного Storage startup запускаются Telegram polling и
|
||||
Trade Runtime tasks.
|
||||
|
||||
Persistent Trade Runtime выполняет:
|
||||
|
||||
```text
|
||||
load checkpoint и bounded durable tail
|
||||
→ либо атомарно принять последнюю durable Trade при первом запуске
|
||||
→ опубликовать восстановленный StateStore целиком
|
||||
→ WebSocket connect
|
||||
→ отправить subscriptions
|
||||
→ дождаться соответствующего ACK
|
||||
→ сохранить ранние market documents в bounded FIFO
|
||||
→ REST Recovery до одной зафиксированной границы времени
|
||||
→ обработать FIFO в исходном порядке
|
||||
→ запустить Supervisor, receive loop и Scheduler
|
||||
```
|
||||
|
||||
Если для symbol нет checkpoint и durable Trades, state создаётся пустым;
|
||||
исторический backfill с биржи до начала доступного REST-окна не
|
||||
выполняется.
|
||||
|
||||
Если durable Trades есть, а checkpoint отсутствует, Hydrator может
|
||||
атомарно принять последнюю durable Trade как начальную точку. Corrupt,
|
||||
orphan или несовместимый checkpoint является фатальной ошибкой. Тихого
|
||||
сброса checkpoint нет.
|
||||
|
||||
Startup buffer по умолчанию ограничен 10 000 documents. Negative ACK,
|
||||
ACK timeout, overflow, Hydration error и Recovery error не открывают
|
||||
Live gate.
|
||||
|
||||
Исходники:
|
||||
|
||||
- [State Hydrator](../../app/src/market_data/acquisition/checkpoint/trade_stream_state_hydrator.py)
|
||||
- [Startup Recovery Coordinator](../../app/src/market_data/acquisition/runtime/runtime_startup_recovery_coordinator.py)
|
||||
- [Application lifecycle](../../app/src/bootstrap/application.py)
|
||||
|
||||
---
|
||||
|
||||
## 9. Reconnect и Recovery
|
||||
|
||||
Transport receive error и Heartbeat timeout используют одну
|
||||
generation-aware single-flight операцию:
|
||||
|
||||
```text
|
||||
закрыть общий Live gate
|
||||
→ Disconnect
|
||||
→ Connect
|
||||
→ переотправить desired subscriptions
|
||||
→ зафиксировать recovery_end_time
|
||||
→ последовательно выполнить REST Recovery для symbols
|
||||
→ тот же Consistency Controller и durable sink
|
||||
→ открыть Live gate
|
||||
```
|
||||
|
||||
Вторая причина reconnect для того же connection generation
|
||||
присоединяется к уже выполняющейся операции. Старое transport error не
|
||||
запускает новый reconnect после смены generation.
|
||||
|
||||
Важные границы:
|
||||
|
||||
- Reconnect выполняет одну попытку; retry loop и backoff отсутствуют.
|
||||
- Restore subscriptions означает успешную повторную отправку; отдельное
|
||||
ожидание ACK перед reconnect Recovery не реализовано.
|
||||
- Recovery использует REST `/api/v1/aggTrades` через настроенный base URL.
|
||||
- Окна ограничены `TRADE_STREAM_RECOVERY_WINDOW_MS`, по умолчанию
|
||||
3 599 999 ms.
|
||||
- Возможный повтор на границе окон удаляет общий Consistency layer.
|
||||
- Если state/checkpoint отсутствует, Recovery не придумывает начальную
|
||||
историю и возвращает пустой результат.
|
||||
- Ошибка reconnect или Recovery переводит gate в terminal failure и
|
||||
распространяется в Application.
|
||||
|
||||
Recovery гарантирует упорядоченную обработку фактически полученных REST
|
||||
данных, но не может гарантировать полноту данных, которых нет в ответе
|
||||
биржи.
|
||||
|
||||
Исходники:
|
||||
|
||||
- [Reconnect Coordinator](../../app/src/market_data/acquisition/runtime/reconnect.py)
|
||||
- [Reconnect Recovery Coordinator](../../app/src/market_data/acquisition/runtime/runtime_reconnect_recovery_coordinator.py)
|
||||
- [Runtime Recovery Coordinator](../../app/src/market_data/acquisition/runtime/runtime_recovery_coordinator.py)
|
||||
- [Trade Recovery Controller](../../app/src/market_data/acquisition/recovery/trade_recovery_controller.py)
|
||||
|
||||
---
|
||||
|
||||
## 10. Liveness, Heartbeat и Scheduler
|
||||
|
||||
Встроенный WebSocket keepalive библиотеки отключён. Источником
|
||||
transport liveness является явный Ping/Pong probe.
|
||||
|
||||
Scheduler периодически:
|
||||
|
||||
1. вызывает transport probe;
|
||||
2. при положительном ответе обновляет Heartbeat activity;
|
||||
3. проверяет Heartbeat timeout;
|
||||
4. передаёт подтверждённый timeout Supervisor.
|
||||
|
||||
Любое успешно полученное WebSocket-сообщение также считается activity.
|
||||
Отрицательный probe сам по себе не запускает reconnect немедленно:
|
||||
решение принимается по Heartbeat timeout. Supervisor не допускает
|
||||
параллельный второй timeout reconnect.
|
||||
|
||||
Scheduler не владеет своей asyncio task. Task принадлежит Production
|
||||
Runtime, который предварительно `claim()`-ит Scheduler и освобождает его
|
||||
после остановки.
|
||||
|
||||
Исходники:
|
||||
|
||||
- [Heartbeat](../../app/src/market_data/acquisition/runtime/heartbeat.py)
|
||||
- [Scheduler](../../app/src/market_data/acquisition/runtime/scheduler.py)
|
||||
- [Supervisor](../../app/src/market_data/acquisition/runtime/supervisor.py)
|
||||
|
||||
---
|
||||
|
||||
## 11. Historical Access
|
||||
|
||||
Historical Access является отдельной synchronous read-side границей и
|
||||
не расширяет write-only Storage facade.
|
||||
|
||||
Поддерживаются:
|
||||
|
||||
- Trade History;
|
||||
- Quote History;
|
||||
- Candle Revision History.
|
||||
|
||||
Общие свойства:
|
||||
|
||||
- timezone-aware полуоткрытый диапазон `[start_time, end_time)`;
|
||||
- forward-only keyset pagination;
|
||||
- строгий cursor scope;
|
||||
- Canonical validation прочитанных PostgreSQL rows;
|
||||
- limit по умолчанию 500, максимум 1 000.
|
||||
|
||||
Порядок страниц:
|
||||
|
||||
| Тип | Порядок |
|
||||
|---|---|
|
||||
| Trade | `executed_at`, затем `replay_sequence` |
|
||||
| Quote | `received_at`, затем `replay_sequence` |
|
||||
| Candle revision | `open_time`, затем `replay_sequence` |
|
||||
|
||||
Каждая страница выполняет отдельный запрос. Между страницами не
|
||||
удерживается одна `REPEATABLE READ` транзакция, поэтому concurrent writes
|
||||
или Retention могут изменить dataset следующего запроса.
|
||||
|
||||
Исходники:
|
||||
|
||||
- [Historical Access facade](../../app/src/market_data/access/market_data_historical_access.py)
|
||||
- [Historical models](../../app/src/market_data/access/models.py)
|
||||
|
||||
---
|
||||
|
||||
## 12. Deterministic Replay
|
||||
|
||||
Replay отделён от live Runtime:
|
||||
|
||||
```text
|
||||
caller
|
||||
→ ReplaySessionFactory.prepare_session()
|
||||
→ PostgresReplayPlanBuilder
|
||||
→ READ ONLY REPEATABLE READ snapshot
|
||||
→ bounded immutable ReplayPlan
|
||||
→ закрыть transaction и connection
|
||||
→ fresh Clock + fresh consumer + fresh ReplaySession
|
||||
→ caller await session.run()
|
||||
```
|
||||
|
||||
ReplayPlan ограничен максимум 100 000 events. Превышение limit приводит
|
||||
к явной ошибке без частичного плана.
|
||||
|
||||
Глобальный порядок задаётся парой:
|
||||
|
||||
```text
|
||||
replay_at + replay_sequence
|
||||
```
|
||||
|
||||
| Тип | `replay_at` |
|
||||
|---|---|
|
||||
| Trade | `executed_at` |
|
||||
| Quote | `received_at` |
|
||||
| Candle revision | `observed_at` |
|
||||
|
||||
`replay_sequence` выдаётся одним PostgreSQL sequence для всех трёх
|
||||
семейств и остаётся неизменяемым.
|
||||
|
||||
Clock начинается в `request.time_range.start_time`, разрешает равное
|
||||
время и запрещает движение назад. Session является one-shot:
|
||||
|
||||
```text
|
||||
CREATED → RUNNING → COMPLETED | FAILED | CANCELLED
|
||||
```
|
||||
|
||||
Повторный `run()` запрещён. Отдельного `ReplayEngine`, default consumer,
|
||||
background task, automatic startup и wall-clock pacing нет. Вызвавший
|
||||
код предоставляет `ReplayConsumerFactoryProtocol`. Затем
|
||||
`ReplaySessionFactory.prepare_session()` создаёт fresh consumer, Clock и
|
||||
Session; caller владеет полученной Session и её `run()`.
|
||||
|
||||
Исходники:
|
||||
|
||||
- [Replay Plan Builder](../../app/src/market_data/replay/postgres_replay_plan_builder.py)
|
||||
- [Replay Session Factory](../../app/src/market_data/replay/replay_session_factory.py)
|
||||
- [Replay Session](../../app/src/market_data/replay/replay_session.py)
|
||||
|
||||
---
|
||||
|
||||
## 13. Ownership и lifecycle
|
||||
|
||||
| Ресурс | Владелец |
|
||||
|---|---|
|
||||
| PostgreSQL pool и migrations | Application через `MarketDataStorageLifecycle` |
|
||||
| Telegram polling и root Runtime task | `run_application()` |
|
||||
| startup, receive, scheduler и market-processing tasks | `TradeStreamProductionRuntime` |
|
||||
| Heartbeat state | `RuntimeSupervisor` |
|
||||
| reconnect/recovery single-flight | `RuntimeReconnectRecoveryCoordinator` |
|
||||
| Hydration/Startup Recovery worker | Runtime через `RuntimeStartupRecoveryCoordinator` |
|
||||
| WebSocket connection | `DzengiWebSocketTransport` через Session |
|
||||
| Runtime Event delivery | caller `publish()`; фонового owner нет |
|
||||
| Historical connection/cursor | один repository call |
|
||||
| Replay snapshot transaction | `PostgresReplayPlanBuilder.create_plan()` |
|
||||
| Replay execution | caller `session.run()` |
|
||||
|
||||
Application shutdown:
|
||||
|
||||
```text
|
||||
отменить Telegram polling
|
||||
→ runtime.stop()
|
||||
→ завершить startup worker, если он выполняется
|
||||
→ остановить и дождаться Scheduler
|
||||
→ остановить Supervisor
|
||||
→ отменить и дождаться receive loop
|
||||
→ остановить WebSocket Session
|
||||
→ очистить subscriptions
|
||||
→ дождаться root Runtime task
|
||||
→ закрыть PostgreSQL pool
|
||||
→ закрыть bot HTTP session
|
||||
```
|
||||
|
||||
Ошибка включённого Runtime или persistent write считается фатальной для
|
||||
всего приложения. Degraded fallback к in-memory режиму не выполняется.
|
||||
|
||||
---
|
||||
|
||||
## 14. Направление зависимостей
|
||||
|
||||
```text
|
||||
bootstrap
|
||||
↓
|
||||
concrete Dzengi adapters + Runtime composition + PostgreSQL adapters
|
||||
|
||||
acquisition → Canonical models + own Protocol boundaries
|
||||
→ narrow Storage checkpoint contracts/exceptions
|
||||
Dzengi REST adapter → integrations.exchange REST client
|
||||
storage → Canonical models
|
||||
access → Canonical models + read contracts
|
||||
replay → Canonical models + access row materialization
|
||||
```
|
||||
|
||||
Подтверждённые границы:
|
||||
|
||||
- `market_data` не импортирует Telegram, Trading или Bootstrap;
|
||||
- Bootstrap импортирует concrete adapters как composition root;
|
||||
- Acquisition не зависит от Historical Access или Replay;
|
||||
- Production Runtime не импортирует concrete PostgreSQL repository;
|
||||
- Replay не зависит от Live Runtime и не вызывает Consistency;
|
||||
- Dzengi-specific код преимущественно находится в
|
||||
`acquisition/adapters/dzengi`, но provider subscription document и
|
||||
часть validation/handlers физически размещены в соседних acquisition
|
||||
пакетах.
|
||||
|
||||
Canonical models сейчас физически находятся в
|
||||
`market_data/acquisition/models`. Это фактическое расположение, а не
|
||||
утверждение, что общая Domain package уже выделена.
|
||||
|
||||
---
|
||||
|
||||
## 15. Failure policy
|
||||
|
||||
| Ошибка | Поведение |
|
||||
|---|---|
|
||||
| Неверные settings | Fail fast до запуска Runtime |
|
||||
| Storage pool или migration | Application startup завершается ошибкой |
|
||||
| Corrupt/orphan checkpoint | Startup завершается ошибкой |
|
||||
| Subscription ACK timeout/negative ACK при persistent startup | Live gate остаётся закрытым, Runtime завершается |
|
||||
| Startup buffer overflow | Runtime завершается |
|
||||
| WebSocket receive failure | Одна generation-aware reconnect/recovery попытка |
|
||||
| Reconnect или REST Recovery failure | Terminal gate failure и завершение Application |
|
||||
| Canonical conflict/order error | Не принимается и распространяется как ошибка |
|
||||
| Persistent write/checkpoint conflict | Transaction rollback, in-memory state не двигается |
|
||||
| Replay consumer failure | Session переходит в `FAILED` |
|
||||
| Replay cancellation | Session переходит в `CANCELLED` |
|
||||
|
||||
Ошибки не превращаются в молчаливое продолжение с потенциально
|
||||
несогласованным состоянием.
|
||||
|
||||
---
|
||||
|
||||
## 16. Доступный период и ограничения
|
||||
|
||||
Доступная история начинается не с момента существования инструмента на
|
||||
бирже, а с наиболее ранней Canonical записи, которая фактически
|
||||
находится в PostgreSQL. Обычно это момент успешного включения Storage,
|
||||
но история может также включать ранее импортированные durable rows.
|
||||
|
||||
Граница может сдвигаться из-за явно применённой Retention Policy.
|
||||
|
||||
Система не предоставляет:
|
||||
|
||||
- initial exchange historical backfill;
|
||||
- completeness metadata и доказательство полной биржевой истории;
|
||||
- storage raw exchange documents;
|
||||
- automatic monthly partition creation;
|
||||
- automatic Retention Scheduler;
|
||||
- Production persistence Quotes/Candles;
|
||||
- общий snapshot между Historical pages;
|
||||
- восстановление исходного порядка сетевых пакетов;
|
||||
- Replay HTTP/CLI/UI endpoint;
|
||||
- automatic Replay startup;
|
||||
- infinite reconnect retry/backoff;
|
||||
- HA, leader election, distributed lease или multi-instance ownership;
|
||||
- автоматические backup, metrics и alerting.
|
||||
|
||||
Default PostgreSQL partitions принимают строки без заранее созданной
|
||||
месячной partition. Явный Partition Manager позднее может атомарно
|
||||
перенести соответствующие строки.
|
||||
|
||||
Migration 9 выполняет блокирующий backfill `replay_sequence`. Для
|
||||
крупной базы нужны backup, измерение на сопоставимом объёме и отдельное
|
||||
maintenance window.
|
||||
|
||||
---
|
||||
|
||||
## 17. Безопасная итоговая формулировка
|
||||
|
||||
Trades Feed реализует единый Canonical Trade pipeline с live-получением,
|
||||
in-process consistency, generation-aware reconnect, REST gap recovery,
|
||||
опциональной durable-записью и persistent startup recovery. Historical
|
||||
Access и deterministic Replay работают над фактически сохранёнными
|
||||
Canonical Market Data. Полнота истории ограничена моментом включения
|
||||
persistence, доступностью REST Recovery и применяемой Retention Policy.
|
||||
Reference in New Issue
Block a user