Files
dzentra_bot/docs/migrations/build_002.md

421 lines
8.3 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 002 — Raw Models Dzengi exchangeInfo
**Проект:** Dzentra
**Подсистема:** Market Data Acquisition
**Миграция:** Instrument Reference Data
**Статус:** ✅ Завершён
**Дата:** 2026-07-10
---
# Цель Build
Создать транспортные модели (Raw Models), полностью описывающие ответ REST API Dzengi `exchangeInfo`.
На данном этапе запрещалось:
- изменять ExchangeService;
- изменять ExchangeSymbol;
- изменять SymbolValidationResult;
- изменять runtime;
- изменять Telegram UI;
- выполнять parser JSON;
- выполнять mapper в предметную модель Instrument.
Build создаёт исключительно транспортный контракт между REST API и будущим parser.
---
# Причина выполнения Build
После Build 001 уже существует независимая предметная модель:
```text
Instrument
```
Следующим архитектурным слоем является транспортная модель адаптера.
До начала Build 002 существующая реализация выглядела следующим образом:
```text
REST
dict
ExchangeService
ExchangeSymbol
```
Parser и mapper были объединены внутри `ExchangeService`.
Это нарушало принцип разделения ответственности.
После Build 002 появилась отдельная транспортная модель:
```text
REST
Raw Models
```
которая станет входом для parser в следующем Build.
---
# Проанализированные материалы
Перед реализацией были полностью проанализированы:
```text
app/tools/dzengi_probe/runtime_samples/rest/exchangeInfo/all.json
docs/market_intelligence/information/dzengi_openapi.json
```
Также были повторно использованы результаты анализа:
```text
app/src/integrations/exchange/service.py
app/src/integrations/exchange/models.py
```
и результаты grep по использованию ExchangeSymbol.
---
# Основные выводы анализа
Подтверждено:
реальный ответ API значительно богаче текущей модели ExchangeSymbol.
В ответе присутствуют:
- symbol
- name
- status
- assetType
- baseAsset
- baseAssetPrecision
- quoteAsset
- quoteAssetId
- quotePrecision
- orderTypes
- marketModes
- marketType
- country
- sector
- industry
- tradingHours
- tickSize
- tickValue
- tradingFee
- exchangeFee
- longRate
- shortRate
- swapChargeInterval
- minSLGap
- maxSLGap
- minTPGap
- maxTPGap
- filters
- rateLimits
- exchangeFilters
Часть этих данных ранее полностью терялась.
---
# Принятые архитектурные решения
## 1. Raw Models полностью отделены от предметной модели
Созданы транспортные модели.
Они:
- ничего не вычисляют;
- ничего не нормализуют;
- ничего не валидируют.
Они только описывают транспортный контракт.
---
## 2. Поддержка двух форматов ответа API
Поддерживаются оба варианта:
### Wrapped
```text
status
correlationId
payload
```
и
### Unwrapped
```text
timezone
serverTime
symbols
```
Parser следующего Build сможет привести оба формата к единому контракту.
Классификация:
**Улучшение надёжности.**
---
## 3. Decimal сознательно не используется
Raw Models сохраняют транспортный тип.
Например:
```json
"stepSize": "0.001"
```
остаётся строкой.
Преобразование в Decimal является обязанностью mapper.
---
## 4. Filters представлены отдельной иерархией
Созданы:
```text
DzengiLotSizeFilter
DzengiMinNotionalFilter
DzengiUnknownFilter
```
Неизвестные фильтры не приводят к ошибке.
Они сохраняются для дальнейшего анализа.
Классификация:
**Улучшение надёжности.**
---
## 5. Все коллекции являются immutable
Используются:
```python
tuple
```
вместо
```python
list
```
Причина:
Raw Models являются снимком транспортного ответа.
Их нельзя изменять после создания.
---
## 6. Все Raw Models являются immutable
Все dataclass объявлены как:
```python
@dataclass(frozen=True, slots=True)
```
Это гарантирует неизменяемость транспортного контракта.
---
# Созданные файлы
Создан:
```text
app/src/market_data/acquisition/adapters/dzengi/models.py
```
Создан:
```text
app/tests/unit/market_data/acquisition/adapters/dzengi/test_models.py
```
Другие production-файлы не изменялись.
---
# Проверки
Выполнены все проверки Build.
---
## Unit Test
Статус:
✅ Passed
```
6 passed
```
---
## Импорт полной транспортной модели
Проверено:
- импортируются все классы;
- создаётся полная иерархия объектов;
- вложенные dataclass работают корректно.
Статус:
✅ Passed
---
## Компиляция
Проверено:
```text
python -m py_compile
```
Статус:
✅ Passed
---
## Проверка отсутствия использования в production
Подтверждено:
Raw Models используются только:
```text
src/market_data/acquisition/adapters/dzengi/models.py
tests/unit/market_data/acquisition/adapters/dzengi/test_models.py
```
ExchangeService их не использует.
Parser их ещё не использует.
Mapper их ещё не использует.
Статус:
✅ Passed
---
## Полный набор тестов
Выполнено:
```text
python -m pytest -q
```
Результат:
```text
11 passed
```
Статус:
✅ Passed
---
# Архитектурный результат
После Build 002 структура подсистемы стала выглядеть следующим образом:
```text
Dzengi REST API
Raw Models
```
Следующие слои пока отсутствуют:
```text
Parser
Mapper
Instrument
Handler
Feed
Service
```
Именно это соответствует утверждённому плану миграции.
---
# Обратная совместимость
Полностью сохранена.
Не изменены:
- ExchangeService
- ExchangeSymbol
- SymbolValidationResult
- validate_symbol()
- normalize_symbol()
- symbol_candidates()
- Runtime
- Telegram UI
Новые Raw Models пока не подключены к работающему боту.
---
# Итог Build
Build 002 завершён успешно.
Получен полноценный транспортный контракт REST API Dzengi.
Создан фундамент для следующих этапов миграции.
Работающий бот не изменил своего поведения.
---
# Следующий Build
## Build 003 — Структурная валидация exchangeInfo
Следующий этап реализует parser, который будет преобразовывать сырой JSON REST API в созданные транспортные модели.
На Build 003 по-прежнему:
- ExchangeService изменяться не будет;
- предметная модель Instrument использоваться не будет;
- parser останется полностью независимым от бизнес-логики.