build 039: complete Quotes Feed migration foundation
This commit is contained in:
864
docs/migrations/build_033.md
Normal file
864
docs/migrations/build_033.md
Normal file
@@ -0,0 +1,864 @@
|
||||
# Build 033 — Перенос MarketPriceCache на Quote Store
|
||||
|
||||
**Engineering Build Record**
|
||||
|
||||
---
|
||||
|
||||
## Контроль документа
|
||||
|
||||
| Свойство | Значение |
|
||||
|---|---|
|
||||
| Документ | Build 033 — Перенос MarketPriceCache на Quote Store |
|
||||
| Тип документа | Engineering Build Record |
|
||||
| Статус | **Completed** |
|
||||
| Подсистема | Market Data / Storage / Legacy Exchange Integration |
|
||||
| Проект | Dzentra |
|
||||
| Язык | Русский |
|
||||
| Предыдущий этап | Build 032 — Канонический Quote Store |
|
||||
| Следующий этап | Build 034 — Dzengi WebSocket quote parsing и адаптер |
|
||||
|
||||
---
|
||||
|
||||
## 1. Назначение Build
|
||||
|
||||
Цель Build 033 — перевести legacy-компонент `MarketPriceCache` с собственного внутреннего хранилища котировок на канонический `Quote Store`, сохранив полную обратную совместимость с существующими потребителями.
|
||||
|
||||
До Build 033 `MarketPriceCache` самостоятельно владел runtime-состоянием котировок:
|
||||
|
||||
```python
|
||||
_prices: dict[tuple[str, str], MarketPriceSnapshot] = {}
|
||||
```
|
||||
|
||||
Это создавало отдельный контур хранения рыночных цен параллельно с введённым в Build 032 каноническим `Quote Store`.
|
||||
|
||||
После Build 033 единственным владельцем состояния котировок, доступных через `MarketPriceCache`, становится канонический `Quote Store`.
|
||||
|
||||
Целевая переходная архитектура:
|
||||
|
||||
```text
|
||||
Legacy consumers
|
||||
│
|
||||
▼
|
||||
MarketPriceCache
|
||||
compatibility facade
|
||||
│
|
||||
▼
|
||||
Canonical Quote
|
||||
│
|
||||
▼
|
||||
InMemoryQuoteStore
|
||||
```
|
||||
|
||||
Сам `MarketPriceCache` сохраняется временно как compatibility facade до его окончательного удаления на Build 039.
|
||||
|
||||
---
|
||||
|
||||
## 2. Архитектурный контекст
|
||||
|
||||
Build 033 является частью последовательного перехода Quotes Feed на новую архитектуру Market Data Acquisition:
|
||||
|
||||
```text
|
||||
Build 026 — Аудит текущего контура Quotes Feed
|
||||
Build 027 — Каноническая модель Quote и специализированные контракты
|
||||
Build 028 — Dzengi REST quote models, parser и validation
|
||||
Build 029 — Dzengi mapper и Quotes Handler
|
||||
Build 030 — Quotes Feed и регистрация в Acquisition Service
|
||||
Build 031 — Подключение нового REST Quotes Feed под legacy ExchangeService facade
|
||||
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 033 не переводит непосредственных потребителей `MarketPriceCache` на новые API. Эта миграция выполняется последующими Build.
|
||||
|
||||
Задача текущего этапа — устранить независимое legacy-хранилище котировок без нарушения работы существующего бота.
|
||||
|
||||
---
|
||||
|
||||
## 3. Исходное состояние
|
||||
|
||||
До Build 033 класс:
|
||||
|
||||
```text
|
||||
src/integrations/exchange/market_cache.py
|
||||
```
|
||||
|
||||
содержал собственное class-level хранилище:
|
||||
|
||||
```python
|
||||
class MarketPriceCache:
|
||||
_prices: dict[tuple[str, str], MarketPriceSnapshot] = {}
|
||||
```
|
||||
|
||||
Ключ записи формировался из:
|
||||
|
||||
```text
|
||||
(runtime_key, symbol)
|
||||
```
|
||||
|
||||
`MarketPriceCache` самостоятельно выполнял:
|
||||
|
||||
- запись текущей цены;
|
||||
- хранение `bid_price`;
|
||||
- хранение `ask_price`;
|
||||
- хранение `updated_at`;
|
||||
- хранение фактического источника данных;
|
||||
- изоляцию по `runtime_key`;
|
||||
- вычисление возраста snapshot;
|
||||
- очистку записей по символу и runtime.
|
||||
|
||||
При этом после Build 032 уже существовал канонический:
|
||||
|
||||
```text
|
||||
InMemoryQuoteStore
|
||||
```
|
||||
|
||||
работающий с моделью:
|
||||
|
||||
```text
|
||||
Quote
|
||||
```
|
||||
|
||||
Таким образом, существовали два отдельных механизма хранения котировок:
|
||||
|
||||
```text
|
||||
MarketPriceCache
|
||||
│
|
||||
└── собственный dict[tuple[str, str], MarketPriceSnapshot]
|
||||
|
||||
Quote Store
|
||||
│
|
||||
└── каноническое хранилище Quote
|
||||
```
|
||||
|
||||
Build 033 устранил это дублирование для контура `MarketPriceCache`.
|
||||
|
||||
---
|
||||
|
||||
## 4. Выполненные изменения
|
||||
|
||||
### 4.1. Изменённый исходный файл
|
||||
|
||||
Изменён:
|
||||
|
||||
```text
|
||||
src/integrations/exchange/market_cache.py
|
||||
```
|
||||
|
||||
### 4.2. Добавленный тестовый файл
|
||||
|
||||
Добавлен:
|
||||
|
||||
```text
|
||||
tests/unit/integrations/exchange/test_market_cache.py
|
||||
```
|
||||
|
||||
### 4.3. Файлы, не потребовавшие изменений
|
||||
|
||||
В рамках Build 033 не изменялись:
|
||||
|
||||
```text
|
||||
src/storage/quote_store.py
|
||||
src/storage/exceptions.py
|
||||
src/market_data/acquisition/models/quote.py
|
||||
tests/unit/storage/test_quote_store.py
|
||||
src/integrations/exchange/service.py
|
||||
src/integrations/exchange/market_stream.py
|
||||
src/integrations/exchange/market_data_runner.py
|
||||
```
|
||||
|
||||
Это подтверждает сохранение существующих публичных контрактов и минимальный scope миграции.
|
||||
|
||||
---
|
||||
|
||||
## 5. Новая роль MarketPriceCache
|
||||
|
||||
После Build 033 `MarketPriceCache` больше не является самостоятельным владельцем runtime-состояния котировок.
|
||||
|
||||
Его новая роль:
|
||||
|
||||
```text
|
||||
Legacy compatibility facade
|
||||
```
|
||||
|
||||
Он обеспечивает совместимость между существующими legacy-потребителями и канонической моделью хранения котировок.
|
||||
|
||||
Логика записи:
|
||||
|
||||
```text
|
||||
Legacy caller
|
||||
│
|
||||
▼
|
||||
MarketPriceCache.set_price(...)
|
||||
│
|
||||
▼
|
||||
Canonical Quote
|
||||
│
|
||||
▼
|
||||
QuoteStoreProtocol.set(...)
|
||||
```
|
||||
|
||||
Логика чтения:
|
||||
|
||||
```text
|
||||
Legacy caller
|
||||
│
|
||||
▼
|
||||
MarketPriceCache.get_price(...)
|
||||
│
|
||||
▼
|
||||
QuoteStoreProtocol.get(...)
|
||||
│
|
||||
▼
|
||||
Canonical Quote
|
||||
│
|
||||
▼
|
||||
MarketPriceSnapshot
|
||||
│
|
||||
▼
|
||||
Legacy caller
|
||||
```
|
||||
|
||||
Таким образом, `MarketPriceSnapshot` остаётся только временной compatibility model.
|
||||
|
||||
---
|
||||
|
||||
## 6. Устранение собственного хранилища MarketPriceCache
|
||||
|
||||
До Build 033:
|
||||
|
||||
```python
|
||||
_prices: dict[tuple[str, str], MarketPriceSnapshot] = {}
|
||||
```
|
||||
|
||||
После Build 033 `MarketPriceCache` использует канонический контракт:
|
||||
|
||||
```text
|
||||
QuoteStoreProtocol
|
||||
```
|
||||
|
||||
и реализацию:
|
||||
|
||||
```text
|
||||
InMemoryQuoteStore
|
||||
```
|
||||
|
||||
Собственное независимое хранилище `_prices` устранено.
|
||||
|
||||
Это является главным архитектурным результатом Build 033.
|
||||
|
||||
---
|
||||
|
||||
## 7. Преобразование legacy-входа в канонический Quote
|
||||
|
||||
Публичный legacy-контракт записи сохранён:
|
||||
|
||||
```python
|
||||
MarketPriceCache.set_price(
|
||||
symbol=...,
|
||||
price=...,
|
||||
bid_price=...,
|
||||
ask_price=...,
|
||||
updated_at=...,
|
||||
source=...,
|
||||
runtime_key=...,
|
||||
)
|
||||
```
|
||||
|
||||
Внутри compatibility facade эти данные преобразуются в каноническую модель:
|
||||
|
||||
```text
|
||||
Quote
|
||||
```
|
||||
|
||||
Основное соответствие полей:
|
||||
|
||||
| Legacy `MarketPriceCache` | Канонический `Quote` |
|
||||
|---|---|
|
||||
| `symbol` | `symbol` |
|
||||
| `price` | `last_price` |
|
||||
| `bid_price` | `bid_price` |
|
||||
| `ask_price` | `ask_price` |
|
||||
| `updated_at` | каноническое timestamp-представление |
|
||||
| `source` | `source` |
|
||||
| время получения | `received_at` |
|
||||
|
||||
На legacy-границе сохраняется использование `float`.
|
||||
|
||||
Внутри канонической модели используются точные числовые значения `Decimal`.
|
||||
|
||||
Таким образом, преобразование имеет вид:
|
||||
|
||||
```text
|
||||
Legacy float values
|
||||
│
|
||||
▼
|
||||
MarketPriceCache
|
||||
│
|
||||
▼
|
||||
Decimal values
|
||||
│
|
||||
▼
|
||||
Canonical Quote
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. Чтение через MarketPriceSnapshot
|
||||
|
||||
Существующие потребители ожидают от:
|
||||
|
||||
```python
|
||||
MarketPriceCache.get_price(...)
|
||||
```
|
||||
|
||||
объект:
|
||||
|
||||
```text
|
||||
MarketPriceSnapshot
|
||||
```
|
||||
|
||||
Поэтому Build 033 не удаляет эту модель.
|
||||
|
||||
При чтении выполняется обратное compatibility-преобразование:
|
||||
|
||||
```text
|
||||
QuoteStore
|
||||
│
|
||||
▼
|
||||
Quote
|
||||
│
|
||||
▼
|
||||
MarketPriceSnapshot
|
||||
```
|
||||
|
||||
Сохраняются legacy-поля:
|
||||
|
||||
```text
|
||||
symbol
|
||||
price
|
||||
bid_price
|
||||
ask_price
|
||||
updated_at
|
||||
source
|
||||
runtime_key
|
||||
```
|
||||
|
||||
Также сохранены методы:
|
||||
|
||||
```python
|
||||
age_seconds()
|
||||
has_bid_ask()
|
||||
```
|
||||
|
||||
Благодаря этому существующие потребители не потребовали изменений.
|
||||
|
||||
---
|
||||
|
||||
## 9. Сохранение семантики свежести
|
||||
|
||||
Legacy-потребители используют:
|
||||
|
||||
```python
|
||||
cached_price.age_seconds()
|
||||
```
|
||||
|
||||
для определения возраста котировки.
|
||||
|
||||
Build 033 сохраняет этот публичный контракт.
|
||||
|
||||
Возраст snapshot определяется на основе канонической информации о времени получения котировки.
|
||||
|
||||
Таким образом, freshness-семантика больше не требует отдельного независимого хранилища состояния внутри `MarketPriceCache`.
|
||||
|
||||
Существующие вызовы:
|
||||
|
||||
```python
|
||||
cached_price.age_seconds()
|
||||
```
|
||||
|
||||
продолжают работать без изменений.
|
||||
|
||||
---
|
||||
|
||||
## 10. Сохранение семантики bid/ask
|
||||
|
||||
Legacy-модель предоставляет:
|
||||
|
||||
```python
|
||||
has_bid_ask()
|
||||
```
|
||||
|
||||
Этот контракт сохранён.
|
||||
|
||||
Он продолжает использоваться существующими execution-потребителями для проверки наличия корректных положительных значений:
|
||||
|
||||
```text
|
||||
bid_price
|
||||
ask_price
|
||||
```
|
||||
|
||||
Build 033 не требует изменения существующих потребителей этой проверки.
|
||||
|
||||
---
|
||||
|
||||
## 11. Изоляция runtime_key
|
||||
|
||||
Сохранена существующая изоляция котировок по:
|
||||
|
||||
```text
|
||||
runtime_key
|
||||
```
|
||||
|
||||
Например:
|
||||
|
||||
```text
|
||||
auto
|
||||
debug_auto
|
||||
default
|
||||
```
|
||||
|
||||
Котировки одного инструмента в разных runtime остаются независимыми.
|
||||
|
||||
Концептуальный ключ хранения:
|
||||
|
||||
```text
|
||||
source_name
|
||||
+
|
||||
runtime_key
|
||||
+
|
||||
symbol
|
||||
```
|
||||
|
||||
Это позволяет одновременно хранить:
|
||||
|
||||
```text
|
||||
BTC/USD_LEVERAGE + auto
|
||||
BTC/USD_LEVERAGE + debug_auto
|
||||
BTC/USD_LEVERAGE + default
|
||||
```
|
||||
|
||||
как независимые runtime-записи.
|
||||
|
||||
---
|
||||
|
||||
## 12. Нормализация runtime_key и symbol
|
||||
|
||||
Сохранено существующее поведение нормализации.
|
||||
|
||||
Символ нормализуется в uppercase:
|
||||
|
||||
```text
|
||||
btc/usd_leverage
|
||||
↓
|
||||
BTC/USD_LEVERAGE
|
||||
```
|
||||
|
||||
`runtime_key` нормализуется в lowercase:
|
||||
|
||||
```text
|
||||
AUTO
|
||||
↓
|
||||
auto
|
||||
```
|
||||
|
||||
Это сохраняет прежнюю семантику `MarketPriceCache`.
|
||||
|
||||
---
|
||||
|
||||
## 13. Разделение source_name и Quote.source
|
||||
|
||||
Build 033 сохраняет архитектурное различие между:
|
||||
|
||||
```text
|
||||
source_name
|
||||
```
|
||||
|
||||
и:
|
||||
|
||||
```text
|
||||
Quote.source
|
||||
```
|
||||
|
||||
`source_name` определяет namespace хранения.
|
||||
|
||||
`Quote.source` определяет фактическое происхождение котировки.
|
||||
|
||||
Например:
|
||||
|
||||
```text
|
||||
Storage namespace:
|
||||
legacy-market-price-cache
|
||||
|
||||
Actual quote source:
|
||||
ws_depth:auto
|
||||
```
|
||||
|
||||
или:
|
||||
|
||||
```text
|
||||
Storage namespace:
|
||||
legacy-market-price-cache
|
||||
|
||||
Actual quote source:
|
||||
market-polling
|
||||
```
|
||||
|
||||
Это предотвращает смешивание:
|
||||
|
||||
- идентичности storage namespace;
|
||||
- provenance рыночных данных.
|
||||
|
||||
---
|
||||
|
||||
## 14. Сохранение семантики clear()
|
||||
|
||||
Полностью сохранены существующие варианты очистки.
|
||||
|
||||
### Полная очистка facade namespace
|
||||
|
||||
```python
|
||||
MarketPriceCache.clear()
|
||||
```
|
||||
|
||||
Очищает все записи, принадлежащие `MarketPriceCache`.
|
||||
|
||||
### Очистка символа во всех runtime
|
||||
|
||||
```python
|
||||
MarketPriceCache.clear("BTC/USD_LEVERAGE")
|
||||
```
|
||||
|
||||
Очищает указанный символ во всех runtime внутри namespace facade.
|
||||
|
||||
### Очистка runtime по всем символам
|
||||
|
||||
```python
|
||||
MarketPriceCache.clear(runtime_key="auto")
|
||||
```
|
||||
|
||||
Очищает все символы указанного runtime.
|
||||
|
||||
### Точечная очистка
|
||||
|
||||
```python
|
||||
MarketPriceCache.clear(
|
||||
"BTC/USD_LEVERAGE",
|
||||
runtime_key="auto",
|
||||
)
|
||||
```
|
||||
|
||||
Очищает только конкретную запись.
|
||||
|
||||
---
|
||||
|
||||
## 15. Изоляция от других владельцев Quote Store
|
||||
|
||||
Критически важное требование Build 033:
|
||||
|
||||
```text
|
||||
MarketPriceCache.clear()
|
||||
```
|
||||
|
||||
не должен удалять котировки, записанные другими владельцами или источниками в канонический `Quote Store`.
|
||||
|
||||
Поэтому операции facade ограничиваются собственным storage namespace.
|
||||
|
||||
Архитектурно:
|
||||
|
||||
```text
|
||||
Quote Store
|
||||
├── legacy-market-price-cache
|
||||
│ ├── auto
|
||||
│ ├── debug_auto
|
||||
│ └── default
|
||||
│
|
||||
└── other-source
|
||||
└── ...
|
||||
```
|
||||
|
||||
Очистка:
|
||||
|
||||
```python
|
||||
MarketPriceCache.clear()
|
||||
```
|
||||
|
||||
затрагивает только:
|
||||
|
||||
```text
|
||||
legacy-market-price-cache
|
||||
```
|
||||
|
||||
и не изменяет данные других namespace.
|
||||
|
||||
---
|
||||
|
||||
## 16. Обратная совместимость
|
||||
|
||||
Build 033 не изменил публичные вызовы:
|
||||
|
||||
```python
|
||||
MarketPriceCache.set_price(...)
|
||||
MarketPriceCache.get_price(...)
|
||||
MarketPriceCache.clear(...)
|
||||
```
|
||||
|
||||
Не изменены существующие production-потребители:
|
||||
|
||||
```text
|
||||
src/integrations/exchange/service.py
|
||||
src/integrations/exchange/market_stream.py
|
||||
src/integrations/exchange/market_data_runner.py
|
||||
```
|
||||
|
||||
Также сохранены legacy-контракты:
|
||||
|
||||
```python
|
||||
MarketPriceSnapshot.age_seconds()
|
||||
MarketPriceSnapshot.has_bid_ask()
|
||||
```
|
||||
|
||||
Это позволило выполнить архитектурную миграцию без изменения поведения работающего бота.
|
||||
|
||||
---
|
||||
|
||||
## 17. Тестовое покрытие
|
||||
|
||||
Добавлен специализированный тестовый файл:
|
||||
|
||||
```text
|
||||
tests/unit/integrations/exchange/test_market_cache.py
|
||||
```
|
||||
|
||||
Тестами проверяются:
|
||||
|
||||
- соответствие `MarketPriceCache` каноническому `QuoteStoreProtocol`;
|
||||
- запись канонического `Quote`;
|
||||
- чтение через legacy `MarketPriceSnapshot`;
|
||||
- сохранение `symbol`;
|
||||
- сохранение `price`;
|
||||
- сохранение `bid_price`;
|
||||
- сохранение `ask_price`;
|
||||
- сохранение `source`;
|
||||
- сохранение `runtime_key`;
|
||||
- нормализация символа;
|
||||
- нормализация `runtime_key`;
|
||||
- изоляция разных runtime;
|
||||
- изоляция разных символов;
|
||||
- замена предыдущей котировки новой;
|
||||
- полная очистка facade namespace;
|
||||
- очистка по символу;
|
||||
- очистка по runtime;
|
||||
- точечная очистка;
|
||||
- вычисление возраста snapshot;
|
||||
- legacy-проверка `has_bid_ask()`;
|
||||
- преобразование timestamp;
|
||||
- защита внешних записей другого `source_name` от очистки через `MarketPriceCache`.
|
||||
|
||||
---
|
||||
|
||||
## 18. Проверка компиляции
|
||||
|
||||
Выполнена команда:
|
||||
|
||||
```bash
|
||||
python -m py_compile \
|
||||
src/integrations/exchange/market_cache.py \
|
||||
tests/unit/integrations/exchange/test_market_cache.py
|
||||
```
|
||||
|
||||
Результат:
|
||||
|
||||
```text
|
||||
SUCCESS
|
||||
```
|
||||
|
||||
Ошибок компиляции нет.
|
||||
|
||||
---
|
||||
|
||||
## 19. Специализированные тесты
|
||||
|
||||
Выполнена команда:
|
||||
|
||||
```bash
|
||||
python -m pytest \
|
||||
tests/unit/integrations/exchange/test_market_cache.py \
|
||||
tests/unit/storage/test_quote_store.py \
|
||||
-q
|
||||
```
|
||||
|
||||
Результат:
|
||||
|
||||
```text
|
||||
76 passed in 0.04s
|
||||
```
|
||||
|
||||
Все специализированные тесты успешно пройдены.
|
||||
|
||||
---
|
||||
|
||||
## 20. Регрессионная проверка потребителей
|
||||
|
||||
Выполнена команда:
|
||||
|
||||
```bash
|
||||
python -m pytest \
|
||||
tests/unit/integrations/exchange/test_service_quotes_facade.py \
|
||||
tests/unit/integrations/exchange/test_service_symbol_runtime_status.py \
|
||||
tests/unit/integrations/exchange/test_market_stream.py \
|
||||
tests/unit/integrations/exchange/test_market_data_runner.py \
|
||||
-q
|
||||
```
|
||||
|
||||
Результат:
|
||||
|
||||
```text
|
||||
47 passed in 0.13s
|
||||
```
|
||||
|
||||
Регрессионный контур существующих потребителей полностью сохранён.
|
||||
|
||||
---
|
||||
|
||||
## 21. Полная регрессионная проверка проекта
|
||||
|
||||
Выполнена команда:
|
||||
|
||||
```bash
|
||||
python -m pytest -q
|
||||
```
|
||||
|
||||
Результат:
|
||||
|
||||
```text
|
||||
578 passed in 0.28s
|
||||
```
|
||||
|
||||
Все тесты проекта успешно пройдены.
|
||||
|
||||
Регрессий не обнаружено.
|
||||
|
||||
---
|
||||
|
||||
## 22. Архитектурный результат
|
||||
|
||||
До Build 033:
|
||||
|
||||
```text
|
||||
Legacy consumers
|
||||
│
|
||||
▼
|
||||
MarketPriceCache
|
||||
│
|
||||
▼
|
||||
Private _prices dict
|
||||
│
|
||||
▼
|
||||
MarketPriceSnapshot
|
||||
```
|
||||
|
||||
Параллельно существовал:
|
||||
|
||||
```text
|
||||
Canonical Quote
|
||||
│
|
||||
▼
|
||||
Quote Store
|
||||
```
|
||||
|
||||
После Build 033:
|
||||
|
||||
```text
|
||||
Legacy consumers
|
||||
│
|
||||
▼
|
||||
MarketPriceCache
|
||||
compatibility facade
|
||||
│
|
||||
▼
|
||||
Canonical Quote
|
||||
│
|
||||
▼
|
||||
Quote Store
|
||||
```
|
||||
|
||||
При чтении:
|
||||
|
||||
```text
|
||||
Quote Store
|
||||
│
|
||||
▼
|
||||
Canonical Quote
|
||||
│
|
||||
▼
|
||||
MarketPriceSnapshot
|
||||
compatibility model
|
||||
│
|
||||
▼
|
||||
Legacy consumer
|
||||
```
|
||||
|
||||
Таким образом, независимое legacy-хранилище котировок устранено.
|
||||
|
||||
---
|
||||
|
||||
## 23. Что намеренно не входит в Build 033
|
||||
|
||||
Build 033 не выполняет:
|
||||
|
||||
- удаление `MarketPriceCache`;
|
||||
- удаление `MarketPriceSnapshot`;
|
||||
- перевод WebSocket parsing на новый Dzengi quote adapter;
|
||||
- перевод `MarketDataRunner` на `Quotes Feed`;
|
||||
- перевод UI-потребителей на канонический `Quote`;
|
||||
- перевод execution-потребителей на канонический `Quote`;
|
||||
- удаление `TickerPrice`;
|
||||
- удаление legacy market snapshot dict layer;
|
||||
- удаление legacy quote parsing.
|
||||
|
||||
Эти изменения выполняются последующими этапами утверждённого плана.
|
||||
|
||||
---
|
||||
|
||||
## 24. Условия завершения
|
||||
|
||||
Build 033 считается завершённым, поскольку выполнены все обязательные условия:
|
||||
|
||||
- [x] `MarketPriceCache` больше не владеет собственным `_prices` dict.
|
||||
- [x] Канонический `Quote Store` используется для хранения котировок facade.
|
||||
- [x] `set_price()` преобразует legacy-вход в канонический `Quote`.
|
||||
- [x] `get_price()` возвращает совместимый `MarketPriceSnapshot`.
|
||||
- [x] Сохранён контракт `age_seconds()`.
|
||||
- [x] Сохранён контракт `has_bid_ask()`.
|
||||
- [x] Сохранена изоляция по `runtime_key`.
|
||||
- [x] Сохранена нормализация символа.
|
||||
- [x] Сохранена семантика `clear()`.
|
||||
- [x] Очистка facade не затрагивает другие storage namespace.
|
||||
- [x] Production-потребители не потребовали изменений.
|
||||
- [x] Специализированные тесты успешно пройдены.
|
||||
- [x] Регрессионные тесты потребителей успешно пройдены.
|
||||
- [x] Полный набор тестов проекта успешно пройден.
|
||||
- [x] Обратная совместимость работающего бота сохранена.
|
||||
|
||||
---
|
||||
|
||||
## 25. Статус Build
|
||||
|
||||
**Build 033 — Completed.**
|
||||
|
||||
Канонический `Quote Store` теперь является владельцем состояния котировок, доступных через legacy `MarketPriceCache`.
|
||||
|
||||
`MarketPriceCache` сохранён только как временный compatibility facade для существующих потребителей.
|
||||
|
||||
Следующий этап:
|
||||
|
||||
```text
|
||||
Build 034 — Dzengi WebSocket quote parsing и адаптер
|
||||
```
|
||||
Reference in New Issue
Block a user