907 lines
21 KiB
Markdown
907 lines
21 KiB
Markdown
# Build 048 — Переключение вычислительных потребителей Market Analysis на каноническую модель Candle
|
||
|
||
**Статус:** Completed
|
||
|
||
**Дата:** 2026-07-15
|
||
|
||
**Подсистема:** Market Data Acquisition / OHLCV Feed / Market Analysis
|
||
|
||
---
|
||
|
||
## 1. Назначение Build
|
||
|
||
Build 048 переводит активные вычислительные компоненты подсистемы `Market Analysis`, непосредственно работающие с последовательностями рыночных свечей, с legacy-модели:
|
||
|
||
```text
|
||
src.integrations.exchange.models.Kline
|
||
```
|
||
|
||
на каноническую модель рыночной свечи:
|
||
|
||
```text
|
||
src.market_data.acquisition.models.candle.Candle
|
||
```
|
||
|
||
Build является очередным этапом поэтапной миграции получения и использования OHLCV-данных в канонический слой:
|
||
|
||
```text
|
||
Market Data Acquisition
|
||
```
|
||
|
||
Основная цель Build — устранить прямую зависимость активных вычислительных функций анализа рынка от legacy-модели `Kline`, сохранив существующую торговую семантику и поведение системы.
|
||
|
||
---
|
||
|
||
## 2. Контекст миграции
|
||
|
||
До Build 048 канонический OHLCV pipeline уже был создан и интегрирован поэтапно.
|
||
|
||
### Build 044
|
||
|
||
Создан фундамент канонического Candles Feed:
|
||
|
||
```text
|
||
REST transport
|
||
↓
|
||
schema validation
|
||
↓
|
||
parser
|
||
↓
|
||
value validation
|
||
↓
|
||
mapper
|
||
↓
|
||
Candle
|
||
↓
|
||
handler
|
||
↓
|
||
CandlesFeed
|
||
```
|
||
|
||
Каноническая модель:
|
||
|
||
```text
|
||
src/market_data/acquisition/models/candle.py
|
||
```
|
||
|
||
### Build 045
|
||
|
||
Создан и протестирован:
|
||
|
||
```text
|
||
CandlesFeedRegistry
|
||
```
|
||
|
||
### Build 046
|
||
|
||
Создан и интегрирован:
|
||
|
||
```text
|
||
CandlesAcquisitionService
|
||
```
|
||
|
||
### Build 047
|
||
|
||
Legacy-метод:
|
||
|
||
```text
|
||
ExchangeService.get_klines()
|
||
```
|
||
|
||
переключён на канонический Candles Feed.
|
||
|
||
После Build 047 транспортный запрос:
|
||
|
||
```text
|
||
/api/v1/klines
|
||
```
|
||
|
||
выполняется только внутри:
|
||
|
||
```text
|
||
src/market_data/acquisition/adapters/dzengi/rest.py
|
||
```
|
||
|
||
При этом `ExchangeService.get_klines()` временно сохраняет обратную совместимость и преобразует канонические `Candle` обратно в legacy-модели `Kline`.
|
||
|
||
Build 048 начинает устранять эту обратную legacy-зависимость непосредственно внутри вычислительных потребителей `Market Analysis`.
|
||
|
||
---
|
||
|
||
## 3. Границы Build
|
||
|
||
В Build 048 изменены только активные вычислительные компоненты `Market Analysis`, которые непосредственно принимают последовательности свечей и используют поля OHLCV.
|
||
|
||
Изменены:
|
||
|
||
```text
|
||
src/trading/market_analysis/indicators/volatility.py
|
||
src/trading/market_analysis/quality.py
|
||
src/trading/market_analysis/structure.py
|
||
```
|
||
|
||
Добавлены специализированные unit-тесты:
|
||
|
||
```text
|
||
tests/unit/trading/market_analysis/indicators/test_volatility_candle.py
|
||
tests/unit/trading/market_analysis/test_quality_candle.py
|
||
tests/unit/trading/market_analysis/test_structure_candle.py
|
||
```
|
||
|
||
Build 048 не изменяет:
|
||
|
||
```text
|
||
src/trading/market_analysis/service.py
|
||
src/trading/market_analysis/htf.py
|
||
src/trading/market_analysis/indicators_legacy.py
|
||
src/integrations/exchange/service.py
|
||
src/integrations/exchange/models.py
|
||
```
|
||
|
||
Build также не удаляет:
|
||
|
||
```text
|
||
Kline
|
||
KlineBatch
|
||
ExchangeService.get_klines()
|
||
```
|
||
|
||
Их дальнейшая судьба определяется отдельными последующими этапами миграции.
|
||
|
||
---
|
||
|
||
## 4. Основное архитектурное изменение
|
||
|
||
До Build 048 активные вычислительные функции использовали legacy-модель:
|
||
|
||
```python
|
||
from src.integrations.exchange.models import Kline
|
||
```
|
||
|
||
После Build 048 они используют каноническую модель:
|
||
|
||
```python
|
||
from src.market_data.acquisition.models.candle import Candle
|
||
```
|
||
|
||
Изменение выполнено в:
|
||
|
||
```text
|
||
src/trading/market_analysis/indicators/volatility.py
|
||
src/trading/market_analysis/quality.py
|
||
src/trading/market_analysis/structure.py
|
||
```
|
||
|
||
Таким образом, активные вычислительные функции:
|
||
|
||
```text
|
||
atr()
|
||
atr_percent_baseline()
|
||
candle_noise_score()
|
||
market_structure()
|
||
```
|
||
|
||
больше не зависят от:
|
||
|
||
```text
|
||
src.integrations.exchange.models.Kline
|
||
```
|
||
|
||
и работают непосредственно с:
|
||
|
||
```text
|
||
src.market_data.acquisition.models.candle.Candle
|
||
```
|
||
|
||
---
|
||
|
||
## 5. Адаптация к канонической модели Candle
|
||
|
||
Каноническая модель `Candle` использует точные числовые значения:
|
||
|
||
```text
|
||
Decimal
|
||
```
|
||
|
||
для полей:
|
||
|
||
```text
|
||
open_price
|
||
high_price
|
||
low_price
|
||
close_price
|
||
volume
|
||
```
|
||
|
||
Legacy-модель `Kline` использовала:
|
||
|
||
```text
|
||
float
|
||
```
|
||
|
||
Поэтому Build 048 выполняет явную адаптацию вычислительного слоя к `Decimal`.
|
||
|
||
Для безопасного преобразования используется существующий helper:
|
||
|
||
```text
|
||
src.core.numbers.safe_float
|
||
```
|
||
|
||
Числовые значения преобразуются непосредственно на границе вычислений.
|
||
|
||
Принцип:
|
||
|
||
```text
|
||
Candle
|
||
↓
|
||
Decimal OHLCV
|
||
↓
|
||
safe_float(...)
|
||
↓
|
||
float
|
||
↓
|
||
существующая вычислительная логика Market Analysis
|
||
```
|
||
|
||
Это позволяет:
|
||
|
||
- сохранить точность канонической модели данных;
|
||
- не переносить `float` в слой Market Data Acquisition;
|
||
- сохранить существующие вычислительные алгоритмы;
|
||
- минимизировать область изменений;
|
||
- не изменять торговую семантику в рамках миграционного Build.
|
||
|
||
---
|
||
|
||
## 6. Изменения volatility.py
|
||
|
||
Файл:
|
||
|
||
```text
|
||
src/trading/market_analysis/indicators/volatility.py
|
||
```
|
||
|
||
переведён с:
|
||
|
||
```text
|
||
Sequence[Kline]
|
||
```
|
||
|
||
на:
|
||
|
||
```text
|
||
Sequence[Candle]
|
||
```
|
||
|
||
Адаптированы функции:
|
||
|
||
```text
|
||
atr()
|
||
atr_percent_baseline()
|
||
```
|
||
|
||
Поля канонической модели:
|
||
|
||
```text
|
||
previous.close_price
|
||
current.high_price
|
||
current.low_price
|
||
```
|
||
|
||
преобразуются через:
|
||
|
||
```text
|
||
safe_float(...)
|
||
```
|
||
|
||
Дополнительно выполняется проверка:
|
||
|
||
```text
|
||
math.isfinite(...)
|
||
```
|
||
|
||
для исключения нечисловых конечных значений:
|
||
|
||
```text
|
||
NaN
|
||
Infinity
|
||
-Infinity
|
||
```
|
||
|
||
Это необходимо, поскольку преобразование:
|
||
|
||
```text
|
||
Decimal("NaN")
|
||
```
|
||
|
||
в `float` само по себе не возвращает `None`, а создаёт:
|
||
|
||
```text
|
||
float("nan")
|
||
```
|
||
|
||
Без проверки `isfinite()` такое значение могло проникнуть в вычисление ATR.
|
||
|
||
---
|
||
|
||
## 7. Изменения quality.py
|
||
|
||
Файл:
|
||
|
||
```text
|
||
src/trading/market_analysis/quality.py
|
||
```
|
||
|
||
переведён с:
|
||
|
||
```text
|
||
Sequence[Kline]
|
||
```
|
||
|
||
на:
|
||
|
||
```text
|
||
Sequence[Candle]
|
||
```
|
||
|
||
Адаптирована функция:
|
||
|
||
```text
|
||
candle_noise_score()
|
||
```
|
||
|
||
Поля:
|
||
|
||
```text
|
||
high_price
|
||
low_price
|
||
open_price
|
||
close_price
|
||
```
|
||
|
||
преобразуются через:
|
||
|
||
```text
|
||
safe_float(...)
|
||
```
|
||
|
||
и проверяются через:
|
||
|
||
```text
|
||
isfinite(...)
|
||
```
|
||
|
||
Невалидные свечи не участвуют в расчёте.
|
||
|
||
Если после фильтрации отсутствуют допустимые свечи, функция возвращает:
|
||
|
||
```text
|
||
None
|
||
```
|
||
|
||
Существующая функция:
|
||
|
||
```text
|
||
price_position_score()
|
||
```
|
||
|
||
сохранена.
|
||
|
||
Build 048 не изменяет её назначение и вычислительную семантику.
|
||
|
||
---
|
||
|
||
## 8. Изменения structure.py
|
||
|
||
Файл:
|
||
|
||
```text
|
||
src/trading/market_analysis/structure.py
|
||
```
|
||
|
||
переведён с:
|
||
|
||
```text
|
||
Sequence[Kline]
|
||
```
|
||
|
||
на:
|
||
|
||
```text
|
||
Sequence[Candle]
|
||
```
|
||
|
||
Адаптирована функция:
|
||
|
||
```text
|
||
market_structure()
|
||
```
|
||
|
||
Для построения последовательностей максимумов и минимумов используются значения:
|
||
|
||
```text
|
||
candle.high_price
|
||
candle.low_price
|
||
```
|
||
|
||
с безопасным преобразованием к вычислительному типу.
|
||
|
||
Существующая логика определения структуры рынка сохранена:
|
||
|
||
```text
|
||
HH_HL
|
||
LH_LL
|
||
MIXED
|
||
UNKNOWN
|
||
```
|
||
|
||
Build 048 не изменяет:
|
||
|
||
- правила определения swing high;
|
||
- правила определения swing low;
|
||
- правила сравнения последних swing-точек;
|
||
- adaptive structure parameters;
|
||
- существующие причины результата;
|
||
- существующую классификацию `MarketStructure`.
|
||
|
||
---
|
||
|
||
## 9. Защита от невалидных числовых значений
|
||
|
||
В ходе специализированного тестирования была выявлена необходимость явной проверки конечности числовых значений.
|
||
|
||
Для вычислительных функций используется:
|
||
|
||
```python
|
||
from math import isfinite
|
||
```
|
||
|
||
После:
|
||
|
||
```text
|
||
safe_float(...)
|
||
```
|
||
|
||
значения дополнительно проверяются на:
|
||
|
||
```text
|
||
NaN
|
||
Infinity
|
||
-Infinity
|
||
```
|
||
|
||
Это предотвращает распространение невалидных числовых значений внутри:
|
||
|
||
```text
|
||
ATR
|
||
ATR baseline
|
||
candle noise score
|
||
```
|
||
|
||
В частности, предотвращается ситуация:
|
||
|
||
```text
|
||
Decimal("NaN")
|
||
↓
|
||
float("nan")
|
||
↓
|
||
результат вычисления nan
|
||
```
|
||
|
||
Вместо этого невалидное значение исключается из вычисления согласно локальной логике соответствующей функции.
|
||
|
||
---
|
||
|
||
## 10. Специализированные unit-тесты
|
||
|
||
Добавлены три специализированных тестовых файла.
|
||
|
||
### 10.1. Volatility
|
||
|
||
Файл:
|
||
|
||
```text
|
||
tests/unit/trading/market_analysis/indicators/test_volatility_candle.py
|
||
```
|
||
|
||
Проверяет:
|
||
|
||
- работу `atr()` с каноническими `Candle`;
|
||
- поддержку `Decimal`;
|
||
- недостаточное количество свечей;
|
||
- невалидный период;
|
||
- обработку не конечных числовых значений;
|
||
- работу `atr_percent_baseline()`;
|
||
- невалидную цену закрытия.
|
||
|
||
### 10.2. Quality
|
||
|
||
Файл:
|
||
|
||
```text
|
||
tests/unit/trading/market_analysis/test_quality_candle.py
|
||
```
|
||
|
||
Проверяет:
|
||
|
||
- работу `candle_noise_score()` с `Candle`;
|
||
- поддержку `Decimal`;
|
||
- пустую последовательность;
|
||
- свечу с нулевым диапазоном;
|
||
- не конечные числовые значения;
|
||
- применение указанного tail window.
|
||
|
||
### 10.3. Structure
|
||
|
||
Файл:
|
||
|
||
```text
|
||
tests/unit/trading/market_analysis/test_structure_candle.py
|
||
```
|
||
|
||
Проверяет:
|
||
|
||
- структуру `HH_HL`;
|
||
- структуру `LH_LL`;
|
||
- структуру `MIXED`;
|
||
- недостаточное количество свечей;
|
||
- непосредственную работу с `Decimal`-значениями `Candle`.
|
||
|
||
---
|
||
|
||
## 11. Результаты специализированных тестов
|
||
|
||
Команда:
|
||
|
||
```bash
|
||
python -m pytest -q \
|
||
tests/unit/trading/market_analysis/indicators/test_volatility_candle.py \
|
||
tests/unit/trading/market_analysis/test_quality_candle.py \
|
||
tests/unit/trading/market_analysis/test_structure_candle.py
|
||
```
|
||
|
||
Результат:
|
||
|
||
```text
|
||
16 passed in 0.02s
|
||
```
|
||
|
||
---
|
||
|
||
## 12. Regression-проверка стратегий
|
||
|
||
Дополнительно выполнена проверка стратегий:
|
||
|
||
```bash
|
||
python -m pytest -q \
|
||
tests/unit/trading/strategies/test_scalp_quote.py \
|
||
tests/unit/trading/strategies/test_trend_quote.py
|
||
```
|
||
|
||
Результат:
|
||
|
||
```text
|
||
6 passed in 0.14s
|
||
```
|
||
|
||
Эта проверка подтверждает сохранение импортов и существующей интеграции `Market Analysis` с торговыми стратегиями.
|
||
|
||
---
|
||
|
||
## 13. Полный regression suite
|
||
|
||
Выполнена команда:
|
||
|
||
```bash
|
||
python -m pytest -q
|
||
```
|
||
|
||
Результат:
|
||
|
||
```text
|
||
766 passed in 2.53s
|
||
```
|
||
|
||
Полный unit test suite проекта проходит успешно.
|
||
|
||
---
|
||
|
||
## 14. Контроль legacy-зависимости Kline
|
||
|
||
Выполнена команда:
|
||
|
||
```bash
|
||
grep -RIn \
|
||
--exclude-dir="__pycache__" \
|
||
--exclude="*.pyc" \
|
||
"integrations.exchange.models import Kline" \
|
||
src/trading/market_analysis
|
||
```
|
||
|
||
Результат:
|
||
|
||
```text
|
||
src/trading/market_analysis/indicators_legacy.py:5:from src.integrations.exchange.models import Kline
|
||
```
|
||
|
||
Следовательно, после Build 048 активные вычислительные компоненты:
|
||
|
||
```text
|
||
volatility.py
|
||
quality.py
|
||
structure.py
|
||
```
|
||
|
||
больше не импортируют legacy-модель `Kline`.
|
||
|
||
Оставшийся импорт находится только в:
|
||
|
||
```text
|
||
indicators_legacy.py
|
||
```
|
||
|
||
который не изменяется в рамках Build 048.
|
||
|
||
---
|
||
|
||
## 15. Контроль использования канонической модели Candle
|
||
|
||
Выполнена команда:
|
||
|
||
```bash
|
||
grep -RIn \
|
||
--exclude-dir="__pycache__" \
|
||
--exclude="*.pyc" \
|
||
"models.candle import Candle" \
|
||
src/trading/market_analysis
|
||
```
|
||
|
||
Результат:
|
||
|
||
```text
|
||
src/trading/market_analysis/indicators/volatility.py:10:from src.market_data.acquisition.models.candle import Candle
|
||
src/trading/market_analysis/structure.py:9:from src.market_data.acquisition.models.candle import Candle
|
||
src/trading/market_analysis/quality.py:9:from src.market_data.acquisition.models.candle import Candle
|
||
```
|
||
|
||
Это подтверждает прямую зависимость трёх активных вычислительных потребителей от канонической модели `Candle`.
|
||
|
||
---
|
||
|
||
## 16. Контроль оставшихся вызовов ExchangeService.get_klines()
|
||
|
||
Выполнена команда:
|
||
|
||
```bash
|
||
grep -RIn \
|
||
--exclude-dir="__pycache__" \
|
||
--exclude="*.pyc" \
|
||
"\.get_klines(" \
|
||
src/trading/market_analysis
|
||
```
|
||
|
||
Результат:
|
||
|
||
```text
|
||
src/trading/market_analysis/service.py:243: batch = ExchangeService().get_klines(
|
||
src/trading/market_analysis/htf.py:55: batch = ExchangeService().get_klines(
|
||
src/trading/market_analysis/htf.py:153: batch = ExchangeService().get_klines(
|
||
```
|
||
|
||
Эти три вызова являются ожидаемыми и не удаляются в Build 048.
|
||
|
||
Они показывают следующую границу дальнейшей миграции:
|
||
|
||
```text
|
||
Market Analysis orchestration
|
||
↓
|
||
прямое получение Candle
|
||
↓
|
||
устранение зависимости от ExchangeService.get_klines()
|
||
```
|
||
|
||
Такое переключение должно выполняться отдельным Build после анализа контрактов:
|
||
|
||
```text
|
||
service.py
|
||
htf.py
|
||
```
|
||
|
||
---
|
||
|
||
## 17. Проверка форматирования diff
|
||
|
||
Выполнена команда:
|
||
|
||
```bash
|
||
git diff --check
|
||
```
|
||
|
||
Вывод отсутствует.
|
||
|
||
Следовательно:
|
||
|
||
```text
|
||
trailing whitespace отсутствует
|
||
ошибки whitespace отсутствуют
|
||
```
|
||
|
||
---
|
||
|
||
## 18. Архитектурный результат
|
||
|
||
После Build 048 активный вычислительный путь выглядит следующим образом:
|
||
|
||
```text
|
||
Dzengi REST API
|
||
↓
|
||
DzengiCandlesDocumentSource
|
||
↓
|
||
validate_candles_schema()
|
||
↓
|
||
parse_candles()
|
||
↓
|
||
validate_candles_values()
|
||
↓
|
||
map_candles()
|
||
↓
|
||
Candle
|
||
↓
|
||
CandlesDocumentHandler
|
||
↓
|
||
CandlesFeed
|
||
↓
|
||
CandlesFeedRegistry
|
||
↓
|
||
CandlesAcquisitionService
|
||
↓
|
||
ExchangeService.get_klines()
|
||
↓
|
||
legacy compatibility conversion
|
||
↓
|
||
Market Analysis orchestration
|
||
↓
|
||
active computational consumers typed for Candle
|
||
```
|
||
|
||
При этом три активных вычислительных компонента уже используют канонический контракт:
|
||
|
||
```text
|
||
volatility.py → Candle
|
||
quality.py → Candle
|
||
structure.py → Candle
|
||
```
|
||
|
||
Однако orchestration-слой `Market Analysis` пока продолжает получать данные через:
|
||
|
||
```text
|
||
ExchangeService.get_klines()
|
||
```
|
||
|
||
Поэтому полное устранение legacy-преобразования `Candle → Kline` ещё не завершено.
|
||
|
||
---
|
||
|
||
## 19. Что сознательно не сделано
|
||
|
||
В Build 048 сознательно не выполнялось:
|
||
|
||
- удаление `Kline`;
|
||
- удаление `KlineBatch`;
|
||
- удаление `ExchangeService.get_klines()`;
|
||
- изменение `MarketAnalysisService`;
|
||
- изменение HTF orchestration;
|
||
- изменение `indicators_legacy.py`;
|
||
- изменение торговых стратегий;
|
||
- изменение scoring;
|
||
- изменение signal logic;
|
||
- изменение торговых порогов;
|
||
- изменение определения market structure;
|
||
- изменение правил ATR;
|
||
- изменение существующей архитектуры каталогов;
|
||
- удаление рабочего legacy-кода.
|
||
|
||
Это соответствует принципу поэтапной миграции:
|
||
|
||
```text
|
||
сначала новый канонический путь
|
||
↓
|
||
затем переключение потребителей
|
||
↓
|
||
затем подтверждение отсутствия legacy-потребителей
|
||
↓
|
||
только после этого отдельное удаление legacy-кода
|
||
```
|
||
|
||
---
|
||
|
||
## 20. Соблюдение правил миграции
|
||
|
||
Build 048 соответствует утверждённым правилам проекта Dzentra:
|
||
|
||
1. Рабочий код не удаляется без отдельного согласования.
|
||
2. Изменения ограничены согласованными границами Build.
|
||
3. Канонический слой Market Data не зависит от `src.trading`.
|
||
4. Миграция выполняется поэтапно.
|
||
5. Обратная совместимость сохраняется там, где она ещё необходима.
|
||
6. Legacy-код не удаляется до подтверждённого переключения всех его потребителей.
|
||
7. Существующая торговая семантика не изменяется в рамках инфраструктурной миграции.
|
||
8. Каждый Build подтверждается специализированными тестами, полным regression suite и контрольными grep.
|
||
|
||
---
|
||
|
||
## 21. Итог Build 048
|
||
|
||
Build 048 завершён успешно.
|
||
|
||
В результате:
|
||
|
||
```text
|
||
volatility.py
|
||
quality.py
|
||
structure.py
|
||
```
|
||
|
||
переведены с:
|
||
|
||
```text
|
||
Kline
|
||
```
|
||
|
||
на:
|
||
|
||
```text
|
||
Candle
|
||
```
|
||
|
||
Канонические `Decimal`-значения адаптированы к существующему вычислительному слою через:
|
||
|
||
```text
|
||
safe_float(...)
|
||
```
|
||
|
||
с дополнительной защитой от:
|
||
|
||
```text
|
||
NaN
|
||
Infinity
|
||
-Infinity
|
||
```
|
||
|
||
Подтверждено:
|
||
|
||
```text
|
||
16 специализированных тестов passed
|
||
6 regression-тестов стратегий passed
|
||
766 тестов полного suite passed
|
||
git diff --check — чисто
|
||
```
|
||
|
||
Build 048 завершает переключение выбранных активных вычислительных потребителей `Market Analysis` на каноническую модель `Candle`.
|
||
|
||
Следующая архитектурная граница миграции — прямое переключение orchestration-компонентов:
|
||
|
||
```text
|
||
src/trading/market_analysis/service.py
|
||
src/trading/market_analysis/htf.py
|
||
```
|
||
|
||
с:
|
||
|
||
```text
|
||
ExchangeService.get_klines()
|
||
```
|
||
|
||
на получение канонических:
|
||
|
||
```text
|
||
Candle
|
||
```
|
||
|
||
через слой:
|
||
|
||
```text
|
||
Market Data Acquisition
|
||
```
|
||
|
||
Такое переключение должно выполняться отдельным Build с сохранением существующего поведения системы. |