build 039: complete Quotes Feed migration foundation
This commit is contained in:
894
docs/migrations/build_031.md
Normal file
894
docs/migrations/build_031.md
Normal file
@@ -0,0 +1,894 @@
|
||||
# Build 031 — Подключение нового REST Quotes Feed под legacy ExchangeService facade
|
||||
|
||||
## Статус
|
||||
|
||||
**Завершён.**
|
||||
|
||||
---
|
||||
|
||||
## Цель
|
||||
|
||||
Подключить новый канонический контур **Quotes Feed** как внутренний источник свежих REST-котировок для существующего `ExchangeService`, сохранив без изменений его публичные legacy-контракты и поведение существующих потребителей.
|
||||
|
||||
Основная архитектурная цель Build 031:
|
||||
|
||||
```text
|
||||
Dzengi GET /api/v1/ticker/24hr
|
||||
↓
|
||||
DzengiQuoteDocumentSource
|
||||
↓
|
||||
DzengiQuoteDocumentHandler
|
||||
↓
|
||||
QuotesFeed
|
||||
↓
|
||||
QuoteAcquisitionService
|
||||
↓
|
||||
Quote
|
||||
↓
|
||||
ExchangeService legacy facade
|
||||
↓
|
||||
существующие потребители
|
||||
```
|
||||
|
||||
После Build 031 `ExchangeService` больше не должен самостоятельно:
|
||||
|
||||
- выполнять прямой REST-запрос к `/api/v1/ticker/24hr`;
|
||||
- знать транспортные поля `lastPrice`, `bidPrice`, `askPrice`, `closeTime`;
|
||||
- разбирать сырой ответ ticker endpoint;
|
||||
- выполнять собственный parsing котировки Dzengi.
|
||||
|
||||
Эти обязанности переданы специализированной подсистеме `market_data/acquisition`.
|
||||
|
||||
---
|
||||
|
||||
## Исходное состояние
|
||||
|
||||
До Build 031 метод:
|
||||
|
||||
```python
|
||||
ExchangeService.get_fresh_market_snapshot()
|
||||
```
|
||||
|
||||
самостоятельно выполнял полный legacy-процесс:
|
||||
|
||||
```text
|
||||
ExchangeService
|
||||
↓
|
||||
ExchangeRestClient
|
||||
↓
|
||||
GET /api/v1/ticker/24hr
|
||||
↓
|
||||
ручное чтение lastPrice / bidPrice / askPrice / closeTime
|
||||
↓
|
||||
legacy dict snapshot
|
||||
```
|
||||
|
||||
В результате `ExchangeService` одновременно отвечал за:
|
||||
|
||||
- транспорт;
|
||||
- знание конкретного endpoint Dzengi;
|
||||
- знание транспортной схемы Dzengi;
|
||||
- parsing значений;
|
||||
- формирование внутреннего представления котировки;
|
||||
- формирование legacy snapshot;
|
||||
- обработку freshness.
|
||||
|
||||
Это нарушало архитектурное разделение ответственности.
|
||||
|
||||
К моменту начала Build 031 новый канонический Quotes Feed уже был реализован:
|
||||
|
||||
```text
|
||||
DzengiQuoteDocumentSource
|
||||
↓
|
||||
DzengiQuoteDocumentHandler
|
||||
↓
|
||||
QuotesFeed
|
||||
↓
|
||||
QuoteFeedRegistry
|
||||
↓
|
||||
QuoteAcquisitionService
|
||||
↓
|
||||
Quote
|
||||
```
|
||||
|
||||
Задачей Build 031 стало подключение этого контура под существующий `ExchangeService` facade.
|
||||
|
||||
---
|
||||
|
||||
## Объём изменений
|
||||
|
||||
### Изменён production-файл
|
||||
|
||||
```text
|
||||
src/integrations/exchange/service.py
|
||||
```
|
||||
|
||||
### Добавлен тестовый файл
|
||||
|
||||
```text
|
||||
tests/unit/integrations/exchange/test_service_quotes_facade.py
|
||||
```
|
||||
|
||||
### Не изменялись
|
||||
|
||||
```text
|
||||
src/integrations/exchange/models.py
|
||||
src/integrations/exchange/market_cache.py
|
||||
src/integrations/exchange/mock_data.py
|
||||
|
||||
src/market_data/acquisition/adapters/dzengi/rest.py
|
||||
src/market_data/acquisition/feeds/quotes_feed.py
|
||||
src/market_data/acquisition/handlers/quotes_handler.py
|
||||
src/market_data/acquisition/models/quote.py
|
||||
src/market_data/acquisition/registry.py
|
||||
src/market_data/acquisition/service.py
|
||||
src/market_data/acquisition/exceptions.py
|
||||
```
|
||||
|
||||
Новый Acquisition-контур уже содержал всю необходимую функциональность и не потребовал дополнительных изменений.
|
||||
|
||||
---
|
||||
|
||||
## Реализованная архитектура
|
||||
|
||||
После Build 031 получение свежей REST-котировки выполняется по следующей цепочке:
|
||||
|
||||
```text
|
||||
ExchangeService.get_fresh_market_snapshot()
|
||||
↓
|
||||
QuoteAcquisitionService
|
||||
↓
|
||||
QuoteFeedRegistry
|
||||
↓
|
||||
QuotesFeed
|
||||
↓
|
||||
DzengiQuoteDocumentSource
|
||||
↓
|
||||
GET /api/v1/ticker/24hr
|
||||
↓
|
||||
DzengiQuoteDocumentHandler
|
||||
↓
|
||||
schema validation
|
||||
↓
|
||||
parser
|
||||
↓
|
||||
value validation
|
||||
↓
|
||||
mapper
|
||||
↓
|
||||
canonical Quote
|
||||
↓
|
||||
legacy-compatible snapshot dict
|
||||
```
|
||||
|
||||
Таким образом, граница ответственности теперь выглядит следующим образом:
|
||||
|
||||
```text
|
||||
market_data/acquisition
|
||||
│
|
||||
│ отвечает за получение, проверку,
|
||||
│ parsing и mapping котировки
|
||||
↓
|
||||
canonical Quote
|
||||
│
|
||||
│ временная compatibility boundary
|
||||
↓
|
||||
ExchangeService facade
|
||||
│
|
||||
│ сохраняет старые публичные контракты
|
||||
↓
|
||||
legacy consumers
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Подключение Quote Acquisition pipeline
|
||||
|
||||
В `ExchangeService` добавлен внутренний путь получения канонической котировки через уже реализованные компоненты Quotes Feed.
|
||||
|
||||
Используемая цепочка:
|
||||
|
||||
```text
|
||||
DzengiQuoteDocumentSource
|
||||
↓
|
||||
DzengiQuoteDocumentHandler
|
||||
↓
|
||||
QuotesFeed
|
||||
↓
|
||||
QuoteFeedRegistry
|
||||
↓
|
||||
QuoteAcquisitionService
|
||||
↓
|
||||
Quote
|
||||
```
|
||||
|
||||
`ExchangeService` теперь получает готовую каноническую модель:
|
||||
|
||||
```python
|
||||
Quote
|
||||
```
|
||||
|
||||
вместо сырого ответа Dzengi:
|
||||
|
||||
```python
|
||||
dict[str, object]
|
||||
```
|
||||
|
||||
Это устраняет зависимость facade от транспортной схемы `ticker/24hr`.
|
||||
|
||||
---
|
||||
|
||||
## Изменение get_fresh_market_snapshot()
|
||||
|
||||
До Build 031 метод самостоятельно выполнял:
|
||||
|
||||
```text
|
||||
создание ExchangeRestClient
|
||||
↓
|
||||
вызов /api/v1/ticker/24hr
|
||||
↓
|
||||
чтение lastPrice
|
||||
↓
|
||||
чтение bidPrice
|
||||
↓
|
||||
чтение askPrice
|
||||
↓
|
||||
чтение closeTime / eventTime
|
||||
↓
|
||||
преобразование значений
|
||||
↓
|
||||
формирование snapshot
|
||||
```
|
||||
|
||||
После Build 031 метод получает:
|
||||
|
||||
```python
|
||||
quote = self._load_quote_via_acquisition(
|
||||
validation.normalized_symbol,
|
||||
)
|
||||
```
|
||||
|
||||
После чего выполняет только временную legacy-проекцию:
|
||||
|
||||
```text
|
||||
Quote
|
||||
↓
|
||||
legacy-compatible dict snapshot
|
||||
```
|
||||
|
||||
Таким образом, `get_fresh_market_snapshot()` больше не является parser транспортного ответа Dzengi.
|
||||
|
||||
---
|
||||
|
||||
## Удалённый legacy parsing
|
||||
|
||||
Из REST quote-пути `ExchangeService` удалено прямое знание следующих транспортных полей:
|
||||
|
||||
```text
|
||||
lastPrice
|
||||
bidPrice
|
||||
askPrice
|
||||
closeTime
|
||||
eventTime
|
||||
```
|
||||
|
||||
Также удалён прямой вызов:
|
||||
|
||||
```text
|
||||
GET /api/v1/ticker/24hr
|
||||
```
|
||||
|
||||
из `ExchangeService`.
|
||||
|
||||
Теперь endpoint и его транспортная схема принадлежат исключительно адаптеру:
|
||||
|
||||
```text
|
||||
src/market_data/acquisition/adapters/dzengi/
|
||||
```
|
||||
|
||||
Это соответствует утверждённой архитектуре Acquisition.
|
||||
|
||||
---
|
||||
|
||||
## Legacy-compatible projection
|
||||
|
||||
Build 031 намеренно не удаляет legacy snapshot layer.
|
||||
|
||||
Каноническая модель:
|
||||
|
||||
```python
|
||||
Quote
|
||||
```
|
||||
|
||||
временно преобразуется обратно в:
|
||||
|
||||
```python
|
||||
dict[str, object]
|
||||
```
|
||||
|
||||
с сохранением прежней структуры:
|
||||
|
||||
```python
|
||||
{
|
||||
"symbol": ...,
|
||||
"last_price": ...,
|
||||
"bid_price": ...,
|
||||
"ask_price": ...,
|
||||
"updated_at": ...,
|
||||
"source": "fresh_rest",
|
||||
"age_seconds": ...,
|
||||
"is_fresh": ...,
|
||||
}
|
||||
```
|
||||
|
||||
Это необходимо для безопасной поэтапной миграции существующего работающего бота.
|
||||
|
||||
Удаление этого compatibility layer запланировано на:
|
||||
|
||||
```text
|
||||
Build 038 — Удаление legacy TickerPrice и market snapshot dict layer
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Сохранение числового контракта
|
||||
|
||||
Каноническая модель `Quote` использует точные числовые значения, представленные через `Decimal`.
|
||||
|
||||
Legacy-потребители ожидают `float`.
|
||||
|
||||
Поэтому на временной границе совместимости выполняется преобразование:
|
||||
|
||||
```text
|
||||
Quote Decimal
|
||||
↓
|
||||
ExchangeService compatibility boundary
|
||||
↓
|
||||
legacy float
|
||||
```
|
||||
|
||||
То есть точность сохраняется внутри новой канонической подсистемы, а преобразование выполняется только при передаче данных старым потребителям.
|
||||
|
||||
Это временное решение до полного перевода потребителей на канонический `Quote`.
|
||||
|
||||
---
|
||||
|
||||
## Сохранение symbol contract
|
||||
|
||||
Перед получением котировки сохраняется существующая проверка символа:
|
||||
|
||||
```python
|
||||
validation = self.validate_symbol(symbol_to_use)
|
||||
```
|
||||
|
||||
В новый Acquisition pipeline передаётся:
|
||||
|
||||
```python
|
||||
validation.normalized_symbol
|
||||
```
|
||||
|
||||
Таким образом:
|
||||
|
||||
- невалидный символ не передаётся в Quotes Feed;
|
||||
- используется канонически нормализованный символ;
|
||||
- существующее поведение `ExchangeService` сохраняется.
|
||||
|
||||
---
|
||||
|
||||
## Сохранение source contract
|
||||
|
||||
Канонический `Quote` содержит источник Acquisition:
|
||||
|
||||
```text
|
||||
dzengi
|
||||
```
|
||||
|
||||
Однако существующий legacy snapshot использует:
|
||||
|
||||
```text
|
||||
fresh_rest
|
||||
```
|
||||
|
||||
В Build 031 сохранено прежнее значение:
|
||||
|
||||
```python
|
||||
"source": "fresh_rest"
|
||||
```
|
||||
|
||||
Это исключает непреднамеренное изменение поведения:
|
||||
|
||||
- UI;
|
||||
- журналирования;
|
||||
- диагностики;
|
||||
- runtime;
|
||||
- существующих потребителей, потенциально зависящих от значения `source`.
|
||||
|
||||
Переход на каноническую семантику источника должен выполняться отдельно при удалении legacy snapshot layer.
|
||||
|
||||
---
|
||||
|
||||
## Сохранение timestamp contract
|
||||
|
||||
Канонический `Quote` содержит timezone-aware timestamp.
|
||||
|
||||
На legacy-границе сохраняется прежнее представление:
|
||||
|
||||
```text
|
||||
Quote.exchange_timestamp
|
||||
↓
|
||||
timestamp в миллисекундах
|
||||
↓
|
||||
существующие ExchangeService helpers
|
||||
↓
|
||||
updated_at
|
||||
age_seconds
|
||||
is_fresh
|
||||
```
|
||||
|
||||
Благодаря этому существующие потребители не получают изменения временной семантики.
|
||||
|
||||
---
|
||||
|
||||
## Сохранение freshness contract
|
||||
|
||||
Сохранена существующая логика определения свежести REST-котировки.
|
||||
|
||||
Порог:
|
||||
|
||||
```text
|
||||
60 секунд
|
||||
```
|
||||
|
||||
Результат продолжает содержать:
|
||||
|
||||
```python
|
||||
"age_seconds": ...
|
||||
"is_fresh": ...
|
||||
```
|
||||
|
||||
Условие остаётся эквивалентным прежнему:
|
||||
|
||||
```python
|
||||
is_fresh = (
|
||||
age_seconds is not None
|
||||
and age_seconds <= 60
|
||||
)
|
||||
```
|
||||
|
||||
Build 031 не меняет политику freshness.
|
||||
|
||||
---
|
||||
|
||||
## Сохранение публичных контрактов ExchangeService
|
||||
|
||||
После Build 031 сохранены без изменения следующие публичные методы:
|
||||
|
||||
```text
|
||||
get_price() -> TickerPrice
|
||||
|
||||
get_fresh_market_snapshot() -> dict[str, object]
|
||||
|
||||
refresh_price_cache() -> TickerPrice
|
||||
|
||||
refresh_market_snapshot_cache() -> dict[str, object]
|
||||
|
||||
get_market_snapshot() -> dict[str, object]
|
||||
|
||||
get_execution_snapshot() -> ExecutionPriceSnapshot
|
||||
```
|
||||
|
||||
Это позволяет существующим потребителям продолжать работу без изменений.
|
||||
|
||||
В частности, не потребовалось изменять:
|
||||
|
||||
```text
|
||||
src/telegram/ui/currency_ui.py
|
||||
src/telegram/handlers/auto/ui.py
|
||||
src/telegram/handlers/debug_auto/ui.py
|
||||
|
||||
src/trading/auto/signal_runtime.py
|
||||
src/trading/auto/execution_quality.py
|
||||
|
||||
src/trading/strategies/trend.py
|
||||
src/trading/strategies/scalp.py
|
||||
|
||||
src/trading/execution/pricing.py
|
||||
src/trading/diagnostics/snapshot.py
|
||||
src/trading/debug/execution.py
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Влияние на существующие методы ExchangeService
|
||||
|
||||
Методы:
|
||||
|
||||
```text
|
||||
get_price()
|
||||
get_market_snapshot()
|
||||
get_execution_snapshot()
|
||||
refresh_market_snapshot_cache()
|
||||
refresh_price_cache()
|
||||
_get_real_price()
|
||||
get_symbol_runtime_status()
|
||||
```
|
||||
|
||||
продолжают работать через существующие публичные и внутренние контракты.
|
||||
|
||||
Поскольку свежая REST-котировка теперь поступает через:
|
||||
|
||||
```text
|
||||
get_fresh_market_snapshot()
|
||||
↓
|
||||
Quote Acquisition pipeline
|
||||
```
|
||||
|
||||
существующие методы автоматически используют новый канонический REST Quotes Feed без прямого перевода каждого потребителя.
|
||||
|
||||
---
|
||||
|
||||
## Обработка ошибок
|
||||
|
||||
Новый Acquisition-контур использует специализированные ошибки quote-подсистемы.
|
||||
|
||||
Внешний контракт `ExchangeService` продолжает использовать:
|
||||
|
||||
```python
|
||||
ExchangeError
|
||||
```
|
||||
|
||||
Поэтому на границе facade сохраняется адаптация:
|
||||
|
||||
```text
|
||||
Acquisition error
|
||||
↓
|
||||
ExchangeService compatibility boundary
|
||||
↓
|
||||
ExchangeError
|
||||
```
|
||||
|
||||
При этом исходная ошибка сохраняется как:
|
||||
|
||||
```python
|
||||
__cause__
|
||||
```
|
||||
|
||||
Это обеспечивает одновременно:
|
||||
|
||||
- совместимость существующих потребителей;
|
||||
- сохранение исходного контекста ошибки;
|
||||
- возможность диагностики первопричины;
|
||||
- отсутствие утечки новой модели исключений в legacy-код раньше запланированного этапа миграции.
|
||||
|
||||
---
|
||||
|
||||
## Сохранение mock-режима
|
||||
|
||||
При отключённой реальной биржевой интеграции:
|
||||
|
||||
```python
|
||||
exchange_enabled = False
|
||||
```
|
||||
|
||||
новый Acquisition pipeline не вызывается.
|
||||
|
||||
Сохраняется прежний mock-контур:
|
||||
|
||||
```text
|
||||
ExchangeService
|
||||
↓
|
||||
mock_ticker_price()
|
||||
↓
|
||||
legacy snapshot
|
||||
```
|
||||
|
||||
Build 031 не изменяет поведение mock-режима.
|
||||
|
||||
---
|
||||
|
||||
## Тестовое покрытие
|
||||
|
||||
Добавлен специализированный тестовый файл:
|
||||
|
||||
```text
|
||||
tests/unit/integrations/exchange/test_service_quotes_facade.py
|
||||
```
|
||||
|
||||
Тесты проверяют границу между:
|
||||
|
||||
```text
|
||||
canonical Quote Acquisition
|
||||
```
|
||||
|
||||
и:
|
||||
|
||||
```text
|
||||
legacy ExchangeService facade
|
||||
```
|
||||
|
||||
Проверяемые свойства включают:
|
||||
|
||||
- использование нового Acquisition pipeline;
|
||||
- передачу нормализованного символа;
|
||||
- сохранение legacy snapshot contract;
|
||||
- преобразование канонических числовых значений в legacy-compatible значения;
|
||||
- сохранение `source="fresh_rest"`;
|
||||
- сохранение timestamp contract;
|
||||
- сохранение freshness contract;
|
||||
- адаптацию ошибок в `ExchangeError`;
|
||||
- сохранение исходной ошибки в `__cause__`;
|
||||
- отсутствие вызова нового Acquisition pipeline в mock-режиме;
|
||||
- отсутствие прямого ticker REST parsing в новом facade-пути.
|
||||
|
||||
---
|
||||
|
||||
## Регрессионная проверка runtime status
|
||||
|
||||
Дополнительно выполнен существующий набор тестов:
|
||||
|
||||
```text
|
||||
tests/unit/integrations/exchange/test_service_symbol_runtime_status.py
|
||||
```
|
||||
|
||||
Он подтверждает сохранение внешнего runtime-контракта после переключения внутреннего источника REST-котировки.
|
||||
|
||||
---
|
||||
|
||||
## Выполненные проверки
|
||||
|
||||
### Проверка синтаксиса
|
||||
|
||||
```bash
|
||||
python -m py_compile \
|
||||
src/integrations/exchange/service.py \
|
||||
tests/unit/integrations/exchange/test_service_quotes_facade.py
|
||||
```
|
||||
|
||||
Результат:
|
||||
|
||||
```text
|
||||
успешно
|
||||
```
|
||||
|
||||
### Специализированные и регрессионные тесты
|
||||
|
||||
```bash
|
||||
python -m pytest \
|
||||
tests/unit/integrations/exchange/test_service_quotes_facade.py \
|
||||
tests/unit/integrations/exchange/test_service_symbol_runtime_status.py \
|
||||
-q
|
||||
```
|
||||
|
||||
Результат:
|
||||
|
||||
```text
|
||||
38 passed in 0.08s
|
||||
```
|
||||
|
||||
### Полная регрессия проекта
|
||||
|
||||
```bash
|
||||
python -m pytest -q
|
||||
```
|
||||
|
||||
Результат:
|
||||
|
||||
```text
|
||||
502 passed in 0.25s
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Рост тестового покрытия
|
||||
|
||||
После предыдущего этапа:
|
||||
|
||||
```text
|
||||
Build 030
|
||||
498 passed
|
||||
```
|
||||
|
||||
После завершения Build 031:
|
||||
|
||||
```text
|
||||
Build 031
|
||||
502 passed
|
||||
```
|
||||
|
||||
Добавлено:
|
||||
|
||||
```text
|
||||
4 новых теста
|
||||
```
|
||||
|
||||
Полная регрессия остаётся зелёной.
|
||||
|
||||
---
|
||||
|
||||
## Архитектурный результат
|
||||
|
||||
### До Build 031
|
||||
|
||||
```text
|
||||
ExchangeService
|
||||
↓
|
||||
ExchangeRestClient
|
||||
↓
|
||||
GET /api/v1/ticker/24hr
|
||||
↓
|
||||
ручной parsing полей Dzengi
|
||||
↓
|
||||
legacy dict snapshot
|
||||
↓
|
||||
потребители
|
||||
```
|
||||
|
||||
### После Build 031
|
||||
|
||||
```text
|
||||
ExchangeService legacy facade
|
||||
↓
|
||||
QuoteAcquisitionService
|
||||
↓
|
||||
QuoteFeedRegistry
|
||||
↓
|
||||
QuotesFeed
|
||||
↓
|
||||
DzengiQuoteDocumentSource
|
||||
↓
|
||||
DzengiQuoteDocumentHandler
|
||||
↓
|
||||
schema validation
|
||||
↓
|
||||
parser
|
||||
↓
|
||||
value validation
|
||||
↓
|
||||
mapper
|
||||
↓
|
||||
canonical Quote
|
||||
↓
|
||||
legacy-compatible dict projection
|
||||
↓
|
||||
существующие потребители
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Архитектурные гарантии после Build 031
|
||||
|
||||
После завершения этапа выполняются следующие гарантии:
|
||||
|
||||
1. `ExchangeService` больше не выполняет прямой REST-запрос к `/api/v1/ticker/24hr`.
|
||||
|
||||
2. `ExchangeService` больше не знает транспортные поля:
|
||||
|
||||
```text
|
||||
lastPrice
|
||||
bidPrice
|
||||
askPrice
|
||||
closeTime
|
||||
eventTime
|
||||
```
|
||||
|
||||
3. REST-котировка проходит через канонический Quotes Feed.
|
||||
|
||||
4. Внутренним результатом Acquisition является:
|
||||
|
||||
```python
|
||||
Quote
|
||||
```
|
||||
|
||||
5. Legacy snapshot создаётся только как временная compatibility projection.
|
||||
|
||||
6. Существующие публичные контракты `ExchangeService` сохранены.
|
||||
|
||||
7. `MarketPriceCache` пока не изменён.
|
||||
|
||||
8. WebSocket-контур пока не изменён.
|
||||
|
||||
9. UI-потребители пока не переведены напрямую на `Quote`.
|
||||
|
||||
10. Execution-потребители пока не переведены напрямую на `Quote`.
|
||||
|
||||
11. Полная регрессия проекта проходит успешно:
|
||||
|
||||
```text
|
||||
502 passed
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Что намеренно не входит в Build 031
|
||||
|
||||
Build 031 не реализует:
|
||||
|
||||
```text
|
||||
Quote Store
|
||||
перенос MarketPriceCache
|
||||
удаление MarketPriceCache
|
||||
изменение MarketPriceSnapshot
|
||||
WebSocket quote parsing
|
||||
WebSocket quote adapter
|
||||
перевод market runtime на Quotes Feed
|
||||
прямой перевод UI на Quote
|
||||
прямой перевод execution на Quote
|
||||
удаление TickerPrice
|
||||
удаление ExecutionPriceSnapshot
|
||||
удаление legacy market snapshot dict layer
|
||||
удаление legacy quote compatibility layer
|
||||
```
|
||||
|
||||
Эти изменения выполняются последующими Build по утверждённому плану.
|
||||
|
||||
---
|
||||
|
||||
## Следующий этап
|
||||
|
||||
```text
|
||||
Build 032 — Канонический Quote Store
|
||||
```
|
||||
|
||||
Его задача — создать канонический слой хранения текущих котировок, который станет основой для последующего переноса существующего:
|
||||
|
||||
```text
|
||||
MarketPriceCache
|
||||
```
|
||||
|
||||
на новую архитектуру.
|
||||
|
||||
Последовательность дальнейшей миграции:
|
||||
|
||||
```text
|
||||
Build 032 — Канонический Quote Store
|
||||
Build 033 — Перенос MarketPriceCache на Quote Store
|
||||
Build 034 — Dzengi WebSocket quote parsing и адаптер
|
||||
Build 035 — Перевод market runtime на Quotes Feed
|
||||
Build 036 — Перевод read-only и UI-потребителей
|
||||
Build 037 — Перевод execution-потребителей
|
||||
Build 038 — Удаление legacy TickerPrice и market snapshot dict layer
|
||||
Build 039 — Удаление legacy quote parsing и MarketPriceCache
|
||||
Build 040 — Финальная архитектурная проверка Quotes Feed
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Итог
|
||||
|
||||
**Build 031 завершён полностью.**
|
||||
|
||||
Новый канонический REST Quotes Feed стал внутренним источником свежих котировок для `ExchangeService`, при этом существующий работающий бот сохранил прежние публичные контракты.
|
||||
|
||||
Ключевой результат:
|
||||
|
||||
```text
|
||||
Было:
|
||||
|
||||
ExchangeService
|
||||
↓
|
||||
прямой REST ticker/24hr
|
||||
↓
|
||||
ручной parsing
|
||||
↓
|
||||
legacy snapshot
|
||||
```
|
||||
|
||||
```text
|
||||
Стало:
|
||||
|
||||
ExchangeService facade
|
||||
↓
|
||||
canonical Quotes Feed
|
||||
↓
|
||||
Quote
|
||||
↓
|
||||
временная legacy projection
|
||||
↓
|
||||
существующие потребители
|
||||
```
|
||||
|
||||
Это создаёт безопасную архитектурную основу для следующего этапа:
|
||||
|
||||
```text
|
||||
Build 032 — Канонический Quote Store
|
||||
```
|
||||
Reference in New Issue
Block a user