Stage 07.4.3.4 — Telegram strong signal alerts via EventBus

This commit is contained in:
2026-05-03 09:15:34 +03:00
parent 24c910fade
commit af2d27761f
6 changed files with 280 additions and 1 deletions

View File

View File

@@ -12,6 +12,7 @@ from aiogram.exceptions import TelegramBadRequest, TelegramRetryAfter
from src.core.event_bus import EventBus from src.core.event_bus import EventBus
from src.integrations.exchange.market_data_runner import MarketDataRunner from src.integrations.exchange.market_data_runner import MarketDataRunner
from src.trading.auto.service import AutoTradeService from src.trading.auto.service import AutoTradeService
from src.trading.journal.service import JournalService
class AutoTradeRunner: class AutoTradeRunner:
@@ -33,6 +34,7 @@ class AutoTradeRunner:
_last_ui_refresh_at: float = 0.0 _last_ui_refresh_at: float = 0.0
_last_event_version: int = 0 _last_event_version: int = 0
_retry_after_until: float = 0.0 _retry_after_until: float = 0.0
_last_strong_alert_key: str | None = None
@classmethod @classmethod
def register_screen( def register_screen(
@@ -139,11 +141,94 @@ class AutoTradeRunner:
if has_important_event: if has_important_event:
cls._last_event_version = current_event_version cls._last_event_version = current_event_version
await cls._handle_important_event(state)
await cls._refresh_screen(force=has_important_event) await cls._refresh_screen(force=has_important_event)
await asyncio.sleep(cls._analysis_interval_seconds) await asyncio.sleep(cls._analysis_interval_seconds)
@classmethod
async def _handle_important_event(cls, state) -> None:
event_type, payload = EventBus.last_event()
if event_type != "auto_decision_changed":
return
if payload.get("decision_status") != "READY":
return
signal = str(payload.get("signal", "")).upper()
if signal not in {"BUY", "SELL"}:
return
await cls._send_strong_signal_alert(state=state, payload=payload)
@classmethod
async def _send_strong_signal_alert(cls, *, state, payload: dict) -> None:
if cls._bot is None or cls._chat_id is None:
return
signal = str(payload.get("signal", "")).upper()
symbol = str(payload.get("symbol") or state.symbol or "")
strategy = str(payload.get("strategy") or state.strategy or "")
repeat_count = int(payload.get("repeat_count") or state.last_signal_repeat_count or 0)
confidence = float(payload.get("confidence") or state.last_signal_confidence or 0.0)
leverage = payload.get("leverage") if payload.get("leverage") is not None else state.leverage
reason = str(payload.get("reason") or state.last_signal_reason or "")
alert_key = (
f"{symbol}:{strategy}:{signal}:"
f"{repeat_count}:{confidence:.2f}:{state.decision_status}"
)
if alert_key == cls._last_strong_alert_key:
return
cls._last_strong_alert_key = alert_key
signal_icon = {
"BUY": "🟢",
"SELL": "🔴",
}.get(signal, "🚨")
leverage_text = f"x{leverage:g}" if isinstance(leverage, (int, float)) else ""
text = (
f"<b>🚨 Сильный сигнал {signal_icon} {signal}</b>\n\n"
f"{symbol} · {strategy} · {leverage_text}\n"
f"Confidence: {confidence:.2f}\n"
f"Repeats: {repeat_count}\n\n"
f"Причина: {reason}"
)
try:
await cls._bot.send_message(
chat_id=cls._chat_id,
text=text,
)
JournalService().log_ui_info(
event_type="auto_strong_signal_alert_sent",
message=f"Отправлено уведомление о сильном сигнале {signal}.",
screen="auto",
action="strong_signal_alert",
payload={
"symbol": symbol,
"strategy": strategy,
"signal": signal,
"repeat_count": repeat_count,
"confidence": confidence,
"leverage": leverage,
"reason": reason,
},
)
except TelegramRetryAfter as exc:
cls._retry_after_until = time.monotonic() + exc.retry_after + 5
except Exception:
pass
@classmethod @classmethod
async def _refresh_screen(cls, *, force: bool = False) -> None: async def _refresh_screen(cls, *, force: bool = False) -> None:
now = time.monotonic() now = time.monotonic()

View File

@@ -349,6 +349,10 @@ class AutoTradeService:
"signal": state.last_signal, "signal": state.last_signal,
"repeat_count": state.last_signal_repeat_count, "repeat_count": state.last_signal_repeat_count,
"confidence": state.last_signal_confidence, "confidence": state.last_signal_confidence,
"symbol": state.symbol,
"strategy": state.strategy,
"leverage": state.leverage,
"reason": state.last_signal_reason,
}, },
) )

View File

@@ -149,6 +149,14 @@
- логирование paper execution - логирование paper execution
- EventBus события (paper_position_opened) - EventBus события (paper_position_opened)
### Stage 07.4.3.4 — Telegram Strong Signal Alerts
- EventBus-driven уведомления
- Фильтрация READY сигналов
- Поддержка BUY / SELL
- Анти-спам (deduplication)
- Интеграция с Journal
- Runner полностью управляет Telegram-уведомлениями
### 07.4.4 ### 07.4.4
⏳ Grid Strategy ⏳ Grid Strategy

View File

@@ -119,7 +119,7 @@
--- ---
### Stage 07.4.3.3 — Paper Position & Execution Engine ### Stage 07.4.3.3 — Paper Position & Execution Engine
- добавлен ExecutionEngine - добавлен ExecutionEngine
- реализованы paper-позиции (LONG / SHORT) - реализованы paper-позиции (LONG / SHORT)
- интеграция с AutoTradeService - интеграция с AutoTradeService
@@ -129,6 +129,21 @@
--- ---
## Stage 07.4.3.4 — Telegram Strong Signal Alerts
- EventBus-driven уведомления
- Фильтрация READY сигналов
- Поддержка BUY / SELL
- Анти-спам (deduplication)
- Интеграция с Journal
- Runner полностью управляет Telegram-уведомлениями
➡️ Подготовка к:
- Debug tools
- Execution lifecycle
- Real trading notifications
---
### 07.4.4 ### 07.4.4
⏳ Grid strategy ⏳ Grid strategy

View File

@@ -0,0 +1,167 @@
# Stage 07.4.3.4 — Telegram Strong Signal Alerts
## 📌 Цель этапа
Добавить систему уведомлений в Telegram при появлении **сильного торгового сигнала**:
- Только при `BUY / SELL`
- Только при `decision_status = READY`
- Без спама (дедупликация)
- Через EventBus (без прямой связи UI ↔ стратегия)
---
## 🧠 Архитектурная идея
Strategy → AutoTradeService → EventBus → AutoTradeRunner → Telegram
- Strategy генерирует сигнал
- Service обновляет decision state
- EventBus фиксирует изменение
- Runner реагирует и отправляет сообщение
---
## ⚙️ Реализация
### 1. EventBus расширен
Добавлены дополнительные поля в событие:
```python
EventBus.emit("auto_decision_changed", {
"decision_status": state.decision_status,
"signal": state.last_signal,
"repeat_count": state.last_signal_repeat_count,
"confidence": state.last_signal_confidence,
"symbol": state.symbol,
"strategy": state.strategy,
"leverage": state.leverage,
"reason": state.last_signal_reason,
})
```
### 2. AutoTradeRunner — обработка событий
Добавлены методы:
_handle_important_event()
_send_strong_signal_alert()
Логика:
* слушаем EventBus.version()
* проверяем last_event()
* фильтруем только READY + BUY/SELL
* отправляем уведомление
### 3. Анти-спам защита
Добавлено поле:
_last_strong_alert_key
Ключ:
symbol + strategy + signal + repeat + confidence + decision_status
👉 Если ключ совпадает — сообщение не отправляется
### 4. Telegram уведомление
Формат сообщения:
🚨 Сильный сигнал 🟢 BUY
BTC/USD · TREND · x2
Confidence: 0.82
Repeats: 3
Причина: Пробой уровня сопротивления
### 5. Логирование
Добавлено событие:
auto_strong_signal_alert_sent
С payload:
* symbol
* strategy
* signal
* confidence
* repeat_count
* leverage
* reason
## ✅ Критерии готовности
✔ Уведомление приходит только при:
* BUY или SELL
* decision_status = READY
Не приходит при:
* HOLD
* CONFIRMING
* BLOCKED
Не спамит при каждом цикле
✔ Логируется в Journal
Не ломает UI
## 🧪 Тестирование
Рекомендуемый способ
Форсирование события:
```
EventBus.emit("auto_decision_changed", {
"decision_status": "READY",
"signal": "BUY",
"repeat_count": 2,
"confidence": 0.9,
"symbol": state.symbol,
"strategy": state.strategy,
"leverage": state.leverage,
"reason": "TEST SIGNAL",
})
```
## ⚠️ Ограничения
* Нет cooldown между сигналами
* Нет разных уровней сигналов (weak/strong)
* Нет user-level подписок
* Нет отключения уведомлений
## 🚀 Следующий этап
Stage 07.4.3.5 — Debug Commands & Test Mode
Добавим:
* /debug signal BUY
* /debug ready
* test_mode=True
* override стратегии
## 📦 Итог
Этап завершает переход к event-driven архитектуре автоторговли:
* UI отвязан от логики
* Runner управляет Telegram
* Service управляет сигналами
* EventBus связывает всё
Это фундамент для:
* Execution Engine
* Risk Engine
* Real trading
## 💾 Коммит
git add .
git commit -m "Stage 07.4.3.4 — Telegram strong signal alerts via EventBus"