Stage 07.4.3.2 — price polling, event bus and UI throttling
This commit is contained in:
@@ -0,0 +1,328 @@
|
||||
# Stage 07.4.3.2 — Price Polling + EventBus + UI Throttling
|
||||
|
||||
## 🎯 Цель этапа
|
||||
|
||||
Разделить три независимых процесса автоторговли:
|
||||
|
||||
- частое получение рыночной цены;
|
||||
- анализ стратегии;
|
||||
- обновление Telegram UI.
|
||||
|
||||
Главная цель — убрать постоянное обновление Telegram на каждом цикле анализа и подготовить архитектуру к реальному execution.
|
||||
|
||||
---
|
||||
|
||||
## 🧱 Что было до этапа
|
||||
|
||||
Ранее один runner фактически связывал всё вместе:
|
||||
|
||||
```text
|
||||
run_cycle()
|
||||
↓
|
||||
strategy.analyze()
|
||||
↓
|
||||
update state
|
||||
↓
|
||||
edit Telegram message
|
||||
```
|
||||
|
||||
Из-за этого:
|
||||
|
||||
- Telegram мог получать слишком частые `edit_message_text`;
|
||||
- появлялся риск `Flood control exceeded`;
|
||||
- частота анализа зависела от UI;
|
||||
- цена не была выделена в отдельный polling-процесс.
|
||||
|
||||
---
|
||||
|
||||
## ✅ Что реализовано
|
||||
|
||||
## 1. MarketDataRunner
|
||||
|
||||
Добавлен отдельный runner для быстрого обновления рыночной цены.
|
||||
|
||||
Файл:
|
||||
|
||||
```text
|
||||
app/src/integrations/exchange/market_data_runner.py
|
||||
```
|
||||
|
||||
Задача:
|
||||
|
||||
```text
|
||||
каждую 1 секунду:
|
||||
получить актуальную цену
|
||||
сохранить её в MarketPriceCache
|
||||
```
|
||||
|
||||
Runner работает отдельно от Telegram UI и отдельно от анализа стратегии.
|
||||
|
||||
---
|
||||
|
||||
## 2. MarketPriceCache
|
||||
|
||||
Обновлён кэш рыночных цен.
|
||||
|
||||
Файл:
|
||||
|
||||
```text
|
||||
app/src/integrations/exchange/market_cache.py
|
||||
```
|
||||
|
||||
Теперь cache хранит:
|
||||
|
||||
- symbol;
|
||||
- price;
|
||||
- bid_price;
|
||||
- ask_price;
|
||||
- updated_at;
|
||||
- source.
|
||||
|
||||
Кэш становится единым источником актуальной цены для:
|
||||
|
||||
- экрана автоторговли;
|
||||
- стратегии;
|
||||
- будущего execution engine.
|
||||
|
||||
---
|
||||
|
||||
## 3. ExchangeService.refresh_price_cache()
|
||||
|
||||
В `ExchangeService` добавлен метод:
|
||||
|
||||
```python
|
||||
refresh_price_cache(symbol)
|
||||
```
|
||||
|
||||
Назначение:
|
||||
|
||||
- получить цену через REST;
|
||||
- записать цену в `MarketPriceCache`;
|
||||
- вернуть `TickerPrice`.
|
||||
|
||||
Это позволяет отдельно обновлять цену без прямого обновления Telegram UI.
|
||||
|
||||
---
|
||||
|
||||
## 4. Кэширование exchangeInfo
|
||||
|
||||
В `ExchangeService` добавлен class-level cache:
|
||||
|
||||
```python
|
||||
_exchange_symbols_cache
|
||||
```
|
||||
|
||||
Это нужно, чтобы быстрый price polling не вызывал `exchangeInfo` слишком часто.
|
||||
|
||||
Используется class-level доступ:
|
||||
|
||||
```python
|
||||
type(self)._exchange_symbols_cache
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. EventBus
|
||||
|
||||
Добавлен простой in-memory EventBus.
|
||||
|
||||
Файл:
|
||||
|
||||
```text
|
||||
app/src/core/event_bus.py
|
||||
```
|
||||
|
||||
EventBus хранит:
|
||||
|
||||
- текущую версию событий;
|
||||
- последний тип события;
|
||||
- последний payload.
|
||||
|
||||
Используется для важных изменений:
|
||||
|
||||
```text
|
||||
auto_status_changed
|
||||
auto_signal_changed
|
||||
auto_decision_changed
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. AutoTradeService emits events
|
||||
|
||||
`AutoTradeService` теперь отправляет события при изменениях:
|
||||
|
||||
### Смена статуса автоторговли
|
||||
|
||||
```text
|
||||
OFF → OBSERVING
|
||||
OBSERVING → RUNNING
|
||||
RUNNING → OFF
|
||||
```
|
||||
|
||||
Событие:
|
||||
|
||||
```text
|
||||
auto_status_changed
|
||||
```
|
||||
|
||||
### Смена сигнала
|
||||
|
||||
```text
|
||||
HOLD → BUY
|
||||
BUY → SELL
|
||||
SELL → HOLD
|
||||
```
|
||||
|
||||
Событие:
|
||||
|
||||
```text
|
||||
auto_signal_changed
|
||||
```
|
||||
|
||||
### Смена decision state
|
||||
|
||||
```text
|
||||
WAITING → CONFIRMING
|
||||
CONFIRMING → READY
|
||||
READY → BLOCKED
|
||||
```
|
||||
|
||||
Событие:
|
||||
|
||||
```text
|
||||
auto_decision_changed
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. AutoTradeRunner decoupling
|
||||
|
||||
`AutoTradeRunner` теперь разделяет процессы:
|
||||
|
||||
```text
|
||||
MarketDataRunner: 1 сек
|
||||
Strategy analysis: 5 сек
|
||||
Telegram UI: 60 сек или событие
|
||||
```
|
||||
|
||||
### Telegram обновляется:
|
||||
|
||||
- сразу при важном событии;
|
||||
- либо раз в 60 секунд;
|
||||
- только если текст реально изменился;
|
||||
- с учётом `TelegramRetryAfter`.
|
||||
|
||||
---
|
||||
|
||||
## 8. UI throttling
|
||||
|
||||
Добавлена защита от Telegram flood control:
|
||||
|
||||
- не отправлять update, если текст не изменился;
|
||||
- не обновлять UI чаще заданного интервала;
|
||||
- учитывать `TelegramRetryAfter`;
|
||||
- снимать регистрацию, если сообщение удалено.
|
||||
|
||||
---
|
||||
|
||||
## 🧠 Итоговая архитектура
|
||||
|
||||
```text
|
||||
MarketDataRunner
|
||||
↓
|
||||
ExchangeService.refresh_price_cache()
|
||||
↓
|
||||
MarketPriceCache
|
||||
↓
|
||||
TrendStrategy / Auto UI
|
||||
↓
|
||||
AutoTradeService
|
||||
↓
|
||||
EventBus
|
||||
↓
|
||||
AutoTradeRunner
|
||||
↓
|
||||
Telegram UI
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📂 Изменённые / добавленные файлы
|
||||
|
||||
### Добавлены
|
||||
|
||||
```text
|
||||
app/src/core/event_bus.py
|
||||
app/src/integrations/exchange/market_data_runner.py
|
||||
```
|
||||
|
||||
### Изменены
|
||||
|
||||
```text
|
||||
app/src/trading/auto/runner.py
|
||||
app/src/trading/auto/service.py
|
||||
app/src/integrations/exchange/service.py
|
||||
app/src/integrations/exchange/market_cache.py
|
||||
app/src/telegram/handlers/auto.py
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ✅ Проверка
|
||||
|
||||
Проверено:
|
||||
|
||||
- бот запускается без ошибок;
|
||||
- цена отображается на экране автоторговли;
|
||||
- `MarketDataRunner` обновляет цену отдельно;
|
||||
- Telegram UI не обновляется каждую секунду;
|
||||
- кнопки не ловят flood control;
|
||||
- сигнал и decision state обновляются через EventBus;
|
||||
- экран обновляется сразу при важных изменениях;
|
||||
- `exchangeInfo` не дергается на каждом price polling.
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ Ограничения текущего этапа
|
||||
|
||||
EventBus пока:
|
||||
|
||||
- in-memory;
|
||||
- без подписчиков;
|
||||
- без persistence;
|
||||
- без приоритетов событий.
|
||||
|
||||
Это нормально для текущего этапа. Для будущего execution можно расширить EventBus или заменить на более полноценную event-модель.
|
||||
|
||||
---
|
||||
|
||||
## 🔜 Следующий этап
|
||||
|
||||
Рекомендуемый следующий этап:
|
||||
|
||||
```text
|
||||
Stage 07.4.3.3 — Position / Execution Skeleton
|
||||
```
|
||||
|
||||
Возможные задачи:
|
||||
|
||||
- модель позиции;
|
||||
- entry price;
|
||||
- position size;
|
||||
- unrealized PnL;
|
||||
- execution readiness;
|
||||
- безопасный skeleton исполнения ордеров без реальной отправки.
|
||||
|
||||
---
|
||||
|
||||
## ✅ Итог
|
||||
|
||||
Stage 07.4.3.2 завершает важный архитектурный переход:
|
||||
|
||||
```text
|
||||
от UI-driven автоторговли
|
||||
к event-driven trading engine
|
||||
```
|
||||
|
||||
Теперь система готова к дальнейшему развитию execution layer.
|
||||
Reference in New Issue
Block a user