Skip to content

Commit 82efccd

Browse files
committed
feat(notif): expand suppress logic — skip idle/waiting runs
1 parent 1fb979f commit 82efccd

1 file changed

Lines changed: 27 additions & 11 deletions

File tree

application/rebalance_service.py

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -65,21 +65,33 @@ def _localize_notification_text(text: str, *, translator) -> str:
6565
)
6666

6767

68-
def _should_suppress_noop_notification(signal_metadata: Mapping[str, object] | None) -> bool:
68+
def _should_suppress_noop_notification(signal_metadata: Mapping[str, object] | None, *, order_count: int = -1, has_error: bool = False) -> bool:
69+
"""Return True when we should skip sending a Telegram notification.
70+
71+
Suppress when:
72+
- Outside execution window (monthly/weekly cadence)
73+
- No orders placed, no errors, and signal is idle/waiting
74+
- Purely informational 'waiting for signal' runs
75+
"""
6976
metadata = signal_metadata if isinstance(signal_metadata, Mapping) else {}
7077
no_op_reason = str(metadata.get("no_op_reason") or "").strip()
7178
if no_op_reason.startswith(("outside_execution_window", "outside_monthly_execution_window")):
7279
return True
7380
notification_context = metadata.get("notification_context")
74-
if not isinstance(notification_context, Mapping):
75-
return False
76-
status_context = notification_context.get("status")
77-
if not isinstance(status_context, Mapping):
78-
return False
79-
return str(status_context.get("code") or "").strip() in {
80-
"status_monthly_snapshot_waiting_window",
81-
"status_no_execution_window_after_snapshot",
82-
}
81+
if isinstance(notification_context, Mapping):
82+
status_context = notification_context.get("status")
83+
if isinstance(status_context, Mapping) and str(status_context.get("code") or "").strip() in {
84+
"status_monthly_snapshot_waiting_window",
85+
"status_no_execution_window_after_snapshot",
86+
}:
87+
return True
88+
# New: skip if nothing happened (no trades, no errors, idle signal)
89+
if order_count == 0 and not has_error:
90+
actionable = bool(metadata.get("actionable", True))
91+
risk_flags = metadata.get("risk_flags") or ()
92+
if not actionable and not risk_flags:
93+
return True
94+
return False
8395

8496

8597
def _normalize_reconciliation_mode(value: object, *, fallback: str = "") -> str:
@@ -781,7 +793,11 @@ def run_strategy_core(
781793
+ json.dumps({"path": str(record_path), "status": record.get("execution_status"), "no_op_reason": record.get("no_op_reason")}, ensure_ascii=False),
782794
flush=True,
783795
)
784-
notification_suppressed = _should_suppress_noop_notification(signal_metadata)
796+
order_count = len(orders) if 'orders' in dir() and orders else 0
797+
has_error = bool(no_op_reason or fail_reason)
798+
notification_suppressed = _should_suppress_noop_notification(
799+
signal_metadata, order_count=order_count, has_error=has_error
800+
)
785801
if notification_suppressed:
786802
print(
787803
"notification_suppressed "

0 commit comments

Comments
 (0)