8.3 KiB
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 уже существует независимая предметная модель:
Instrument
Следующим архитектурным слоем является транспортная модель адаптера.
До начала Build 002 существующая реализация выглядела следующим образом:
REST
↓
dict
↓
ExchangeService
↓
ExchangeSymbol
Parser и mapper были объединены внутри ExchangeService.
Это нарушало принцип разделения ответственности.
После Build 002 появилась отдельная транспортная модель:
REST
↓
Raw Models
которая станет входом для parser в следующем Build.
Проанализированные материалы
Перед реализацией были полностью проанализированы:
app/tools/dzengi_probe/runtime_samples/rest/exchangeInfo/all.json
docs/market_intelligence/information/dzengi_openapi.json
Также были повторно использованы результаты анализа:
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
status
correlationId
payload
и
Unwrapped
timezone
serverTime
symbols
Parser следующего Build сможет привести оба формата к единому контракту.
Классификация:
Улучшение надёжности.
3. Decimal сознательно не используется
Raw Models сохраняют транспортный тип.
Например:
"stepSize": "0.001"
остаётся строкой.
Преобразование в Decimal является обязанностью mapper.
4. Filters представлены отдельной иерархией
Созданы:
DzengiLotSizeFilter
DzengiMinNotionalFilter
DzengiUnknownFilter
Неизвестные фильтры не приводят к ошибке.
Они сохраняются для дальнейшего анализа.
Классификация:
Улучшение надёжности.
5. Все коллекции являются immutable
Используются:
tuple
вместо
list
Причина:
Raw Models являются снимком транспортного ответа.
Их нельзя изменять после создания.
6. Все Raw Models являются immutable
Все dataclass объявлены как:
@dataclass(frozen=True, slots=True)
Это гарантирует неизменяемость транспортного контракта.
Созданные файлы
Создан:
app/src/market_data/acquisition/adapters/dzengi/models.py
Создан:
app/tests/unit/market_data/acquisition/adapters/dzengi/test_models.py
Другие production-файлы не изменялись.
Проверки
Выполнены все проверки Build.
Unit Test
Статус:
✅ Passed
6 passed
Импорт полной транспортной модели
Проверено:
- импортируются все классы;
- создаётся полная иерархия объектов;
- вложенные dataclass работают корректно.
Статус:
✅ Passed
Компиляция
Проверено:
python -m py_compile
Статус:
✅ Passed
Проверка отсутствия использования в production
Подтверждено:
Raw Models используются только:
src/market_data/acquisition/adapters/dzengi/models.py
tests/unit/market_data/acquisition/adapters/dzengi/test_models.py
ExchangeService их не использует.
Parser их ещё не использует.
Mapper их ещё не использует.
Статус:
✅ Passed
Полный набор тестов
Выполнено:
python -m pytest -q
Результат:
11 passed
Статус:
✅ Passed
Архитектурный результат
После Build 002 структура подсистемы стала выглядеть следующим образом:
Dzengi REST API
│
▼
Raw Models
Следующие слои пока отсутствуют:
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 останется полностью независимым от бизнес-логики.