# Build 044 — Canonical Candles Feed Foundation

**Документ миграции**

---

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

| Свойство | Значение |
|---|---|
| Документ | Build 044 — Canonical Candles Feed Foundation |
| Тип документа | Migration Build Record |
| Проект | Dzentra |
| Подсистема | Market Data Acquisition |
| Направление | OHLCV Feed / Candles Feed |
| Статус | **Complete** |
| Язык | Русский |
| Дата | 2026-07-15 |

---

## 1. Назначение Build

Build 044 создаёт автономную каноническую основу **Candles Feed** в утверждённой подсистеме:

```text
src/market_data/acquisition/
```

Build реализует новую read-only цепочку получения и обработки свечей рядом с действующим legacy-потоком.

Рабочий бот после Build 044 продолжает использовать существующий метод:

```text
ExchangeService.get_klines()
```

Переключение рабочего runtime на новый Candles Feed в данный Build не входит.

---

## 2. Причина выполнения Build

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

```text
Instrument Reference Data
Quotes Feed
```

следующим активным legacy-потоком Market Data Acquisition остаётся получение OHLCV-свечей.

До Build 044 рабочая цепочка свечей находилась в legacy exchange layer:

```text
ExchangeService.get_klines()
    ↓
ExchangeRestClient
    ↓
GET /api/v1/klines
    ↓
ExchangeService._extract_klines_items()
    ↓
ExchangeService._parse_kline_item()
    ↓
Kline
    ↓
KlineBatch
    ↓
trading/market_analysis
```

В результате:

- endpoint `/api/v1/klines` находился в `ExchangeService`;
- transport parsing выполнялся в `ExchangeService`;
- модель `Kline` находилась в `src/integrations/exchange/models.py`;
- Market Analysis зависел от legacy-моделей;
- новая структура `Candles Feed` существовала только как набор пустых файлов.

Build 044 создаёт новую каноническую цепочку без изменения рабочего legacy-контракта.

---

## 3. Границы Build

### 3.1. В Build входит

Реализована цепочка:

```text
Dzengi REST /api/v1/klines
    ↓
schema validation
    ↓
parser
    ↓
value validation
    ↓
mapper
    ↓
Candle
    ↓
DzengiCandlesDocumentHandler
    ↓
CandlesFeed
```

Также добавлены:

- candle-specific исключения;
- transport-модели Dzengi;
- контракты source, handler и feed;
- специализированные unit-тесты;
- архитектурные проверки.

### 3.2. В Build не входит

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

```text
src/integrations/exchange/service.py
src/integrations/exchange/models.py
src/trading/market_analysis/
```

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

- переключение `ExchangeService.get_klines()`;
- замену `Kline`;
- замену `KlineBatch`;
- миграцию consumers;
- добавление CandleStore;
- добавление candle cache;
- регистрацию Candles Feed в registry;
- публикацию через MarketDataAcquisitionService;
- WebSocket-поток свечей;
- sequence gap detection;
- дедупликацию свечей;
- resampling;
- определение закрытости свечи;
- удаление legacy parsing.

---

## 4. Реализованная архитектура

### 4.1. Каноническая модель

Создана модель:

```text
src/market_data/acquisition/models/candle.py
```

Контракт:

```python
@dataclass(frozen=True, slots=True)
class Candle:
    symbol: str
    interval: str
    open_time: datetime
    open_price: Decimal
    high_price: Decimal
    low_price: Decimal
    close_price: Decimal
    volume: Decimal
    source: str
```

Свойства модели:

- immutable;
- `slots=True`;
- цены и объём представлены `Decimal`;
- время открытия представлено timezone-aware UTC `datetime`;
- модель не зависит от Dzengi;
- модель не зависит от legacy exchange layer.

В модель намеренно не добавлены:

```text
close_time
is_closed
CandleBatch
```

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

---

### 4.2. Transport-модели Dzengi

В файл:

```text
src/market_data/acquisition/adapters/dzengi/models.py
```

добавлены:

```text
DzengiKline
DzengiKlinesResponse
```

Transport-модель хранит данные после parser, но до канонического mapping.

Допустимые transport numeric-типы:

```text
str | int | float
```

---

### 4.3. REST source

В файл:

```text
src/market_data/acquisition/adapters/dzengi/rest.py
```

добавлен endpoint:

```text
/api/v1/klines
```

и источник:

```text
DzengiCandlesDocumentSource
```

Источник выполняет только transport-вызов и не выполняет:

- schema validation;
- parsing;
- value validation;
- mapping;
- сортировку;
- кэширование;
- нормализацию запроса.

Transport-ошибки преобразуются в:

```text
CandleTransportError
```

---

### 4.4. Schema validation

В файл:

```text
src/market_data/acquisition/validation/schema.py
```

добавлены:

```text
ValidatedCandlesDocument
validate_candles_schema()
```

Поддерживаются legacy-compatible envelope-форматы:

```text
root list
root.klines
root.candles
root.data
root.result
root.payload list
root.payload.klines
root.payload.candles
root.payload.data
```

Поддерживаются два формата одной свечи:

```text
JSON object
JSON array
```

После schema validation:

```text
dict → MappingProxyType
list → tuple
```

---

### 4.5. Parser

В файл:

```text
src/market_data/acquisition/adapters/dzengi/parser.py
```

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

```text
parse_candles()
```

Поддерживаются object-поля:

```text
openTime
open_time
time
timestamp
open
high
low
close
volume
```

Поддерживается array-формат:

```text
[
    open_time,
    open,
    high,
    low,
    close,
    volume,
    ...
]
```

Дополнительные поля массива игнорируются.

Parser:

- проверяет transport-типы;
- не создаёт `Decimal`;
- не проверяет OHLC-инварианты;
- не создаёт canonical `Candle`.

---

### 4.6. Value validation

В файл:

```text
src/market_data/acquisition/validation/values.py
```

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

```text
validate_candles_values()
```

Проверяются:

```text
open_time > 0
open_price > 0
high_price > 0
low_price > 0
close_price > 0
volume >= 0
```

Также проверяются:

- конечность числовых значений;
- запрет `bool`;
- OHLC-инварианты;
- `high >= low`;
- `high >= open`;
- `high >= close`;
- `low <= open`;
- `low <= close`.

В Build 044 не выполняются:

- проверка последовательности timestamp;
- проверка gaps;
- проверка соответствия интервалу;
- дедупликация;
- проверка равномерности шага.

---

### 4.7. Mapper

В файл:

```text
src/market_data/acquisition/adapters/dzengi/mapper.py
```

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

```text
map_dzengi_klines_to_candles()
```

Mapper выполняет:

```text
raw numeric → Decimal
milliseconds timestamp → UTC datetime
DzengiKline → Candle
sorting by open_time
list → tuple
```

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

- исправление некорректных значений;
- удаление свечей;
- обрезку по `limit`;
- дедупликацию;
- определение закрытости свечи.

---

### 4.8. Handler

Реализован:

```text
src/market_data/acquisition/handlers/candles_handler.py
```

Основной класс:

```text
DzengiCandlesDocumentHandler
```

Последовательность обработки:

```text
validate_candles_schema()
    ↓
parse_candles()
    ↓
validate_candles_values()
    ↓
map_dzengi_klines_to_candles()
```

---

### 4.9. Feed

Реализован:

```text
src/market_data/acquisition/feeds/candles_feed.py
```

Основной класс:

```text
CandlesFeed
```

Feed координирует:

```text
CandlesDocumentSource
    ↓
CandlesDocumentHandler
```

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

- transport parsing;
- value validation;
- mapping;
- кэширование;
- повторную обрезку результата по `limit`.

---

### 4.10. Protocols

В файл:

```text
src/market_data/acquisition/protocol.py
```

добавлены:

```text
CandlesDocumentSource
CandlesDocumentHandler
CandlesFeedProtocol
```

Runtime-проверка протоколов выполнена успешно:

```text
candles protocols: OK
```

---

### 4.11. Exceptions

В файл:

```text
src/market_data/acquisition/exceptions.py
```

добавлены:

```text
CandleTransportError
CandleSchemaError
CandleParseError
CandleValueError
CandleMappingError
```

Registry-specific исключение не добавлялось, поскольку регистрация Candles Feed не входит в Build 044.

---

## 5. Изменённые production-файлы

```text
src/market_data/acquisition/exceptions.py
src/market_data/acquisition/protocol.py
src/market_data/acquisition/models/candle.py
src/market_data/acquisition/adapters/dzengi/models.py
src/market_data/acquisition/adapters/dzengi/rest.py
src/market_data/acquisition/adapters/dzengi/parser.py
src/market_data/acquisition/adapters/dzengi/mapper.py
src/market_data/acquisition/validation/schema.py
src/market_data/acquisition/validation/values.py
src/market_data/acquisition/handlers/candles_handler.py
src/market_data/acquisition/feeds/candles_feed.py
```

---

## 6. Добавленные unit-тесты

```text
tests/unit/market_data/acquisition/models/test_candle.py
tests/unit/market_data/acquisition/adapters/dzengi/test_candle_rest.py
tests/unit/market_data/acquisition/validation/test_candle_schema.py
tests/unit/market_data/acquisition/adapters/dzengi/test_candle_parser.py
tests/unit/market_data/acquisition/validation/test_candle_values.py
tests/unit/market_data/acquisition/adapters/dzengi/test_candle_mapper.py
tests/unit/market_data/acquisition/handlers/test_candles_handler.py
tests/unit/market_data/acquisition/feeds/test_candles_feed.py
```

Покрыты:

- immutable-модель Candle;
- REST source;
- поддерживаемые envelope-форматы;
- object- и array-parsing;
- aliases времени;
- проверки transport-типов;
- проверки значений;
- OHLC-инварианты;
- Decimal mapping;
- UTC datetime mapping;
- сортировка;
- handler pipeline;
- feed orchestration;
- propagation исключений.

---

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

### 7.1. Специализированные тесты Build 044

```text
70 passed
```

### 7.2. Полный unit-test suite проекта

```text
683 passed in 3.29s
```

### 7.3. Проверка форматирования diff

```text
git diff --check
```

Результат:

```text
пустой вывод
```

---

## 8. Архитектурные проверки

### 8.1. Endpoint `/api/v1/klines`

Команда:

```bash
grep -RIn \
  --exclude-dir="__pycache__" \
  --exclude="*.pyc" \
  '"/api/v1/klines"' \
  src
```

Результат:

```text
src/market_data/acquisition/adapters/dzengi/rest.py
src/integrations/exchange/service.py
```

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

- новая canonical acquisition-цепочка;
- действующий legacy-путь.

---

### 8.2. Импорты canonical Candle

Команда:

```bash
grep -RIn \
  --exclude-dir="__pycache__" \
  --exclude="*.pyc" \
  "models.candle import Candle" \
  src tests
```

Canonical `Candle` используется только в новой acquisition-цепочке и её тестах.

---

### 8.3. Обратная зависимость Market Data → Trading

Команда:

```bash
grep -RIn \
  --exclude-dir="__pycache__" \
  --exclude="*.pyc" \
  "from src.trading\|import src.trading" \
  src/market_data
```

Результат:

```text
пусто
```

---

### 8.4. Зависимость Candle Feed от ExchangeService

Команда:

```bash
grep -RIn \
  --exclude-dir="__pycache__" \
  --exclude="*.pyc" \
  "ExchangeService" \
  src/market_data/acquisition/models/candle.py \
  src/market_data/acquisition/feeds/candles_feed.py \
  src/market_data/acquisition/handlers/candles_handler.py
```

Результат:

```text
пусто
```

---

## 9. Сопутствующая очистка документации

Вместе с Build 044 намеренно удалены устаревшие временные grep-файлы:

```text
docs/migrations/greps.txt
docs/migrations/Вывод grep по дополнительным полям.txt
```

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

---

## 10. Совместимость

После Build 044:

- рабочий бот продолжает использовать legacy `ExchangeService.get_klines()`;
- `Kline` и `KlineBatch` сохранены;
- Market Analysis не изменён;
- runtime не переключён;
- существующее поведение торгового бота сохранено;
- новая Candles Feed foundation работает параллельно legacy-потоку.

---

## 11. Критерии завершения

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

- создана canonical модель `Candle`;
- реализован REST source `/api/v1/klines`;
- реализована schema validation;
- реализован parser object/list форматов;
- реализована value validation;
- реализован canonical mapper;
- реализован handler;
- реализован standalone Candles Feed;
- добавлены runtime-checkable protocols;
- добавлены специализированные исключения;
- добавлено полное unit-покрытие foundation-цепочки;
- targeted-тесты проходят;
- полный suite проходит;
- архитектурные grep соответствуют ожидаемому переходному состоянию;
- legacy runtime не изменён.

---

# 12. Ориентировочный дальнейший план миграции

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

Главный принцип остаётся неизменным:

```text
foundation
    ↓
service/registry integration
    ↓
compatibility facade
    ↓
consumer migration
    ↓
legacy removal
    ↓
architecture verification
```

---

## 12.1. Завершение OHLCV Feed

### Build 045 — register canonical Candles Feed

Цель:

- добавить Candles Feed в `registry.py`;
- добавить candle-specific registry contract;
- добавить registry tests;
- не менять `ExchangeService`;
- не менять Market Analysis.

Ожидаемый результат:

```text
CandlesFeed
    ↓
Candles registry
```

---

### Build 046 — expose Candles Feed through Acquisition Service

Цель:

- добавить read-only метод загрузки свечей в `service.py`;
- сохранить точные параметры:
  - symbol;
  - interval;
  - limit;
  - price_type;
- добавить service tests;
- не переключать legacy runtime.

Ожидаемый результат:

```text
MarketDataAcquisitionService.load_candles()
    ↓
CandlesFeed
```

---

### Build 047 — switch ExchangeService klines facade

Цель:

- сохранить публичный контракт `ExchangeService.get_klines()`;
- внутри переключить получение данных на canonical Acquisition Service;
- временно преобразовывать `Candle` в legacy `Kline`;
- сохранить `KlineBatch`;
- добавить compatibility tests;
- удалить прямой REST-вызов `/api/v1/klines` из `ExchangeService`;
- удалить legacy parsing из `ExchangeService`.

Ожидаемый результат:

```text
ExchangeService.get_klines()
    ↓
MarketDataAcquisitionService.load_candles()
    ↓
Candle
    ↓
temporary compatibility mapping
    ↓
KlineBatch
```

---

### Build 048 — migrate Market Analysis to Candle

Цель:

- перевести `trading/market_analysis` с `Kline` на canonical `Candle`;
- сохранить расчётную семантику;
- локально адаптировать timestamp и numeric-типы;
- не изменять сами торговые алгоритмы;
- добавить/обновить тесты consumers.

Ожидаемый результат:

```text
Market Analysis
    ↓
Candle
```

---

### Build 049 — remove legacy Kline compatibility

Цель:

- удалить `Kline`;
- удалить `KlineBatch`, если он больше не нужен;
- удалить compatibility mapping;
- удалить legacy candle parsing;
- очистить импорты `src.integrations.exchange.models.Kline`.

---

### Build 050 — finalize OHLCV Feed architecture verification

Цель:

- полный архитектурный аудит Candles Feed;
- контроль endpoint;
- контроль raw transport keys;
- контроль legacy imports;
- контроль consumer contracts;
- документация итогового состояния;
- полный suite.

---

## 12.2. Trades Feed — Time & Sales

После завершения OHLCV Feed выполнить отдельный аудит:

```text
REST trades endpoints
WebSocket trade messages
journal trade events
execution trade records
market trade data
```

Важно не смешивать:

```text
Market Trades Feed
```

с:

```text
сделками самого торгового бота
execution events
journal events
```

Ориентировочная последовательность:

### Build 051 — audit Trades Feed sources and consumers

- определить фактические Dzengi endpoints/messages;
- отделить рыночные сделки от execution-событий;
- определить текущие consumers;
- зафиксировать минимальный scope.

### Build 052 — establish canonical Trades Feed foundation

- `Trade`;
- transport model;
- REST/WebSocket source;
- schema;
- parser;
- values;
- mapper;
- handler;
- feed;
- tests.

### Build 053 — register and expose Trades Feed

- registry;
- acquisition service;
- tests.

### Build 054 — integrate first read-only consumer

- подключить один фактический consumer;
- не менять торговую семантику.

### Build 055 — remove legacy trade market-data path

- удалить legacy parsing;
- удалить старые transport-модели;
- очистить imports.

### Build 056 — finalize Trades Feed verification

- полный suite;
- grep;
- документация.

---

## 12.3. Order Book Feed

Текущий `/api/v1/depth` используется для получения best bid / best ask и построения Quote.

Поэтому перед миграцией Order Book Feed обязательно разделить:

```text
Quote use case
```

и:

```text
canonical Order Book use case
```

Нельзя удалять WebSocket depth-путь, пока Quotes Feed использует его как источник котировки.

Ориентировочная последовательность:

### Build 057 — audit Order Book and depth contracts

- определить фактический формат Dzengi depth;
- определить уровни доступной глубины;
- определить sequence identifiers;
- определить snapshot/delta семантику;
- определить consumers;
- зафиксировать зависимость Quotes Feed.

### Build 058 — establish Order Book model foundation

- `OrderBook`;
- `OrderBookLevel`;
- snapshot model;
- transport model;
- schema;
- parser;
- values;
- mapper;
- tests.

### Build 059 — establish Order Book snapshot feed

- REST snapshot source;
- handler;
- feed;
- registry;
- service.

### Build 060 — establish Order Book WebSocket updates

- delta/update parsing;
- sequence validation;
- snapshot reconciliation;
- tests.

### Build 061 — add Order Book runtime storage

Только если подтверждено фактическими consumers:

- OrderBookStore;
- atomic update;
- source/runtime keys;
- freshness policy.

### Build 062 — integrate execution-quality consumers

- spread/depth/slippage consumers;
- сохранить fallback на Quote;
- не менять торговые решения одним Build.

### Build 063 — separate Quotes Feed from legacy depth runtime

- оставить Quotes Feed на canonical WebSocket adapter;
- удалить старый depth parsing из legacy runtime.

### Build 064 — finalize Order Book verification

---

## 12.4. Derivatives Market Feed

Перед foundation Build требуется аудит фактических данных:

```text
funding rate
overnight fee
mark price
open interest
contract metadata
leverage limits
liquidation-related fields
```

Нужно отделить:

```text
Instrument Reference Data
Trading Conditions
Derivatives Market Data
Account-specific data
```

Ориентировочная последовательность:

### Build 065 — audit derivatives data contracts

### Build 066 — establish canonical Derivatives Feed foundation

### Build 067 — register and expose Derivatives Feed

### Build 068 — migrate funding / overnight consumers

### Build 069 — migrate mark-price / open-interest consumers

### Build 070 — remove legacy derivatives parsing

### Build 071 — finalize Derivatives Feed verification

---

## 12.5. Market Index Feed

Перед началом требуется подтвердить, какие индексы реально предоставляет Dzengi:

```text
index price
reference price
composite index
underlying index
```

Ориентировочная последовательность:

### Build 072 — audit index data sources

### Build 073 — establish Market Index Feed foundation

### Build 074 — register and expose Index Feed

### Build 075 — integrate confirmed consumers

### Build 076 — remove legacy index path

### Build 077 — finalize Index Feed verification

---

## 12.6. Exchange Time Feed

Текущий endpoint:

```text
/api/v1/time
```

находится в:

```text
ExchangeService.get_exchange_server_time_ms()
```

и используется логикой time synchronization.

Ориентировочная последовательность:

### Build 078 — establish Exchange Time Feed foundation

- canonical time model;
- REST source;
- schema;
- parser;
- values;
- mapper;
- handler;
- feed;
- tests.

### Build 079 — register and expose Time Feed

### Build 080 — switch ExchangeService time facade

- сохранить текущий публичный контракт;
- переключить внутренний источник;
- сохранить time-sync поведение.

### Build 081 — remove legacy time REST path

### Build 082 — finalize Exchange Time Feed verification

---

## 12.7. Exchange Status Feed

Перед началом требуется разделить:

```text
exchange availability
market availability
instrument status
runtime freshness
authentication status
account availability
```

Не все перечисленные состояния относятся к Market Data Acquisition.

Ориентировочная последовательность:

### Build 083 — audit status semantics

### Build 084 — establish Exchange Status Feed foundation

### Build 085 — register and expose Status Feed

### Build 086 — migrate public exchange-status consumers

### Build 087 — remove legacy public-status acquisition

### Build 088 — finalize Exchange Status Feed verification

---

## 12.8. Runtime подсистемы Acquisition

Файлы:

```text
runtime/heartbeat.py
runtime/reconnect.py
runtime/scheduler.py
runtime/supervisor.py
```

не должны наполняться заранее.

Они должны мигрироваться только после появления реальных потоков, которым необходим общий lifecycle.

Ориентировочная последовательность после стабилизации Quotes, Trades и Order Book:

### Build 089 — audit acquisition runtime ownership

- определить существующие runner/stream responsibilities;
- определить lifecycle ownership;
- определить реальные retry/reconnect policies.

### Build 090 — establish common reconnect policy

### Build 091 — establish heartbeat contract

### Build 092 — establish acquisition scheduler

### Build 093 — establish acquisition supervisor

### Build 094 — migrate MarketDataRunner responsibilities

### Build 095 — remove legacy market runtime orchestration

### Build 096 — finalize Acquisition runtime verification

---

## 12.9. Финальная консолидация Market Data Acquisition

После миграции всех фактически используемых Feed:

### Build 097 — remove unused acquisition placeholders

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

- удалить неиспользуемые placeholders;
- не удалять утверждённые модули, если их реализация отложена;
- зафиксировать статус каждого Feed.

### Build 098 — finalize Acquisition service surface

- единый публичный read-only API;
- отсутствие transport details;
- отсутствие consumer-specific логики;
- стабильные protocols.

### Build 099 — finalize Dzengi adapter isolation

- endpoint strings только в adapter;
- raw keys только в adapter/validation;
- отсутствие Dzengi transport-моделей вне adapter.

### Build 100 — complete Market Data Acquisition migration

- итоговый полный suite;
- итоговый архитектурный grep;
- удаление подтверждённого legacy Market Data кода;
- итоговая документация;
- release checkpoint.

---

## 13. Правила применения дальнейшего плана

Этот план является ориентировочным и не разрешает автоматическое выполнение всех перечисленных Build.

Перед каждым Build обязательно:

1. выполнить аудит фактического текущего кода;
2. определить реальные sources и consumers;
3. проверить, используется ли placeholder;
4. выбрать минимальный безопасный scope;
5. подготовить пошаговый план;
6. согласовать план;
7. только после согласования изменять код;
8. выполнить targeted tests;
9. выполнить полный unit-test suite;
10. выполнить архитектурные grep;
11. оформить `docs/migrations/build_XXX.md`;
12. создать отдельный git commit.

Запрещено:

- объединять несколько Feed в один Build;
- создавать store без подтверждённой runtime-потребности;
- добавлять поля моделей «на будущее»;
- удалять legacy до переключения consumers;
- менять торговую семантику внутри Market Data migration;
- пересматривать утверждённую структуру каталогов без отдельного обсуждения.

---

## 14. Git commit

Рекомендуемое сообщение:

```bash
git commit -m "build 044: establish canonical candles feed foundation"
```
