07.4.3.19.4 — Journal Runtime Standardization & Export Layer
This commit is contained in:
@@ -16,8 +16,8 @@ class TelegramNotificationChannel:
|
||||
|
||||
if bot is None or chat_id is None:
|
||||
JournalService().log_warning(
|
||||
"notification_target_missing",
|
||||
"Telegram notification target is not registered.",
|
||||
"notification_error",
|
||||
"Не удалось отправить Telegram-уведомление: получатель не настроен.",
|
||||
{
|
||||
"title": message.title,
|
||||
"priority": message.priority,
|
||||
@@ -36,8 +36,8 @@ class TelegramNotificationChannel:
|
||||
|
||||
except TelegramRetryAfter as exc:
|
||||
JournalService().log_warning(
|
||||
"notification_telegram_retry_after",
|
||||
"Telegram notification delayed by retry-after.",
|
||||
"notification_error",
|
||||
"Не удалось отправить Telegram-уведомление: Telegram ограничил частоту отправки.",
|
||||
{
|
||||
"title": message.title,
|
||||
"retry_after": exc.retry_after,
|
||||
@@ -49,8 +49,8 @@ class TelegramNotificationChannel:
|
||||
|
||||
except Exception as exc:
|
||||
JournalService().log_error(
|
||||
"notification_telegram_error",
|
||||
"Telegram notification failed.",
|
||||
"notification_error",
|
||||
"Не удалось отправить Telegram-уведомление.",
|
||||
{
|
||||
"title": message.title,
|
||||
"error": str(exc),
|
||||
|
||||
@@ -7,9 +7,7 @@ from src.notifications.dedupe import NotificationDedupe
|
||||
from src.notifications.models import NotificationMessage
|
||||
from src.notifications.templates.execution import build_execution_notification
|
||||
from src.notifications.templates.signal import build_signal_notification
|
||||
from src.runtime_events.event_types import RuntimeEventType
|
||||
from src.runtime_events.models import RuntimeEvent
|
||||
from src.trading.journal.service import JournalService
|
||||
|
||||
|
||||
class NotificationService:
|
||||
@@ -17,112 +15,15 @@ class NotificationService:
|
||||
message = self._build_message(event)
|
||||
|
||||
if message is None:
|
||||
JournalService().log_info(
|
||||
"runtime_event_ignored",
|
||||
"Runtime event has no notification template.",
|
||||
{
|
||||
"event_type": event.event_type.value,
|
||||
"source": event.source,
|
||||
"title": event.title,
|
||||
"priority": event.priority,
|
||||
"dedupe_key": event.dedupe_key,
|
||||
},
|
||||
)
|
||||
return
|
||||
|
||||
if not NotificationDedupe.should_send(message.dedupe_key):
|
||||
self._log_suppressed(event, message)
|
||||
return
|
||||
|
||||
sent = await TelegramNotificationChannel().send(message)
|
||||
|
||||
if sent:
|
||||
self._log_sent(event, message)
|
||||
await TelegramNotificationChannel().send(message)
|
||||
|
||||
def _build_message(self, event: RuntimeEvent) -> NotificationMessage | None:
|
||||
return (
|
||||
build_signal_notification(event)
|
||||
or build_execution_notification(event)
|
||||
)
|
||||
|
||||
def _log_sent(self, event: RuntimeEvent, message: NotificationMessage) -> None:
|
||||
if event.event_type == RuntimeEventType.AUTO_SIGNAL_READY:
|
||||
signal = str(event.payload.get("signal") or "—").upper()
|
||||
|
||||
JournalService().log_ui_info(
|
||||
event_type="auto_strong_signal_alert_sent",
|
||||
message=f"Отправлено уведомление о сильном сигнале {signal}.",
|
||||
screen="auto",
|
||||
action="strong_signal_alert",
|
||||
payload={
|
||||
**event.payload,
|
||||
"runtime_event_type": event.event_type.value,
|
||||
"runtime_source": event.source,
|
||||
"priority": message.priority.upper(),
|
||||
"dedupe_key": message.dedupe_key,
|
||||
},
|
||||
)
|
||||
return
|
||||
|
||||
if event.event_type in {
|
||||
RuntimeEventType.POSITION_OPENED,
|
||||
RuntimeEventType.POSITION_CLOSED,
|
||||
RuntimeEventType.POSITION_FLIPPED,
|
||||
}:
|
||||
JournalService().log_ui_info(
|
||||
event_type="auto_execution_alert_sent",
|
||||
message="Отправлено Telegram-уведомление по paper execution.",
|
||||
screen="auto",
|
||||
action="execution_alert",
|
||||
payload={
|
||||
**event.payload,
|
||||
"runtime_event_type": event.event_type.value,
|
||||
"runtime_source": event.source,
|
||||
"priority": message.priority.upper(),
|
||||
"dedupe_key": message.dedupe_key,
|
||||
},
|
||||
)
|
||||
return
|
||||
|
||||
JournalService().log_info(
|
||||
"notification_sent",
|
||||
"Runtime notification sent.",
|
||||
{
|
||||
"event_type": event.event_type.value,
|
||||
"source": event.source,
|
||||
"title": event.title,
|
||||
"priority": event.priority,
|
||||
"dedupe_key": message.dedupe_key,
|
||||
},
|
||||
)
|
||||
|
||||
def _log_suppressed(self, event: RuntimeEvent, message: NotificationMessage) -> None:
|
||||
if event.event_type == RuntimeEventType.AUTO_SIGNAL_READY:
|
||||
signal = str(event.payload.get("signal") or "—").upper()
|
||||
|
||||
JournalService().log_ui_info(
|
||||
event_type="auto_strong_signal_alert_suppressed",
|
||||
message=f"Повторное уведомление о сильном сигнале {signal} подавлено.",
|
||||
screen="auto",
|
||||
action="strong_signal_alert",
|
||||
payload={
|
||||
**event.payload,
|
||||
"runtime_event_type": event.event_type.value,
|
||||
"runtime_source": event.source,
|
||||
"priority": message.priority.upper(),
|
||||
"dedupe_key": message.dedupe_key,
|
||||
},
|
||||
)
|
||||
return
|
||||
|
||||
JournalService().log_info(
|
||||
"notification_suppressed_duplicate",
|
||||
"Duplicate notification suppressed.",
|
||||
{
|
||||
"event_type": event.event_type.value,
|
||||
"source": event.source,
|
||||
"title": event.title,
|
||||
"priority": event.priority,
|
||||
"dedupe_key": message.dedupe_key,
|
||||
},
|
||||
)
|
||||
Reference in New Issue
Block a user