From 44b4c7813f39869cc2b52c32f8da10bebcd2e28b Mon Sep 17 00:00:00 2001 From: Pigbibi <20649888+Pigbibi@users.noreply.github.com> Date: Mon, 25 May 2026 20:42:36 +0800 Subject: [PATCH] Use shared strategy plugin alert dispatcher --- main.py | 58 +++++++--------------------------- requirements.txt | 4 +-- tests/test_request_handling.py | 44 ++++++-------------------- 3 files changed, 24 insertions(+), 82 deletions(-) diff --git a/main.py b/main.py index 3bba163..ad02338 100644 --- a/main.py +++ b/main.py @@ -25,14 +25,10 @@ from decision_mapper import map_strategy_decision from entrypoints.cloud_run import is_market_open_today from notifications.telegram import build_strategy_display_name, build_translator, send_telegram_message -from quant_platform_kit.notifications.strategy_plugin_email import ( - StrategyPluginEmailAlertMarkerStore, - build_strategy_plugin_alert_context_label as build_email_alert_context_label, - publish_strategy_plugin_email_alerts, -) -from quant_platform_kit.notifications.strategy_plugin_sms import ( - StrategyPluginSmsAlertMarkerStore, - publish_strategy_plugin_sms_alerts, +from quant_platform_kit.notifications.strategy_plugin_alerts import ( + StrategyPluginAlertStateSettings, + build_strategy_plugin_alert_context_label as build_alert_context_label, + publish_strategy_plugin_alerts as dispatch_strategy_plugin_alerts, ) from quant_platform_kit.common.runtime_assembly import build_runtime_assembly from quant_platform_kit.common.runtime_reports import ( @@ -481,24 +477,14 @@ def build_strategy_plugin_alert_messages(signals): return build_strategy_adapters().build_strategy_plugin_alert_messages(signals) -def build_strategy_plugin_alert_store(): - return StrategyPluginEmailAlertMarkerStore( - local_dir=os.getenv("STRATEGY_PLUGIN_ALERT_STATE_DIR") or "/tmp/quant_strategy_plugin_alerts", - gcs_prefix_uri=os.getenv("STRATEGY_PLUGIN_ALERT_STATE_GCS_URI") or os.getenv("EXECUTION_REPORT_GCS_URI"), - gcp_project_id=PROJECT_ID, - ) - - -def build_strategy_plugin_sms_alert_store(): - return StrategyPluginSmsAlertMarkerStore( - local_dir=os.getenv("STRATEGY_PLUGIN_ALERT_STATE_DIR") or "/tmp/quant_strategy_plugin_alerts", - gcs_prefix_uri=os.getenv("STRATEGY_PLUGIN_ALERT_STATE_GCS_URI") or os.getenv("EXECUTION_REPORT_GCS_URI"), +def build_strategy_plugin_alert_state_settings(): + return StrategyPluginAlertStateSettings.from_env( gcp_project_id=PROJECT_ID, ) def build_strategy_plugin_alert_context_label() -> str: - return build_email_alert_context_label( + return build_alert_context_label( platform_id="ibkr", strategy_profile=STRATEGY_PROFILE, account_scope=ACCOUNT_GROUP, @@ -507,39 +493,19 @@ def build_strategy_plugin_alert_context_label() -> str: ) -def attach_strategy_plugin_alert_email_result(report, result) -> None: - report.setdefault("summary", {})["strategy_plugin_alert_email_sent_count"] = result.sent_count - report.setdefault("diagnostics", {}).update(result.to_report_fields()) - - -def attach_strategy_plugin_alert_sms_result(report, result) -> None: - report.setdefault("summary", {})["strategy_plugin_alert_sms_sent_count"] = result.sent_count - report.setdefault("diagnostics", {}).update(result.to_report_fields()) - - def publish_strategy_plugin_alerts(signals, *, report=None): - email_result = publish_strategy_plugin_email_alerts( - signals, - email_settings=RUNTIME_SETTINGS, - translator=t, - strategy_label=STRATEGY_PROFILE, - context_label=build_strategy_plugin_alert_context_label(), - alert_store=build_strategy_plugin_alert_store(), - log_message=print, - ) - sms_result = publish_strategy_plugin_sms_alerts( + result = dispatch_strategy_plugin_alerts( signals, - sms_settings=RUNTIME_SETTINGS, + notification_settings=RUNTIME_SETTINGS, translator=t, strategy_label=STRATEGY_PROFILE, context_label=build_strategy_plugin_alert_context_label(), - alert_store=build_strategy_plugin_sms_alert_store(), + state_settings=build_strategy_plugin_alert_state_settings(), log_message=print, ) if report is not None: - attach_strategy_plugin_alert_email_result(report, email_result) - attach_strategy_plugin_alert_sms_result(report, sms_result) - return email_result + result.attach_to_report(report) + return result def build_account_notification_lines() -> tuple[str, ...]: diff --git a/requirements.txt b/requirements.txt index 4236414..bb6348a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ flask gunicorn -quant-platform-kit @ git+https://github.com/QuantStrategyLab/QuantPlatformKit.git@d43800180aae1c7fe7051496a6af5d76f2c65879 -us-equity-strategies @ git+https://github.com/QuantStrategyLab/UsEquityStrategies.git@9661d8bb74e33466fa0ec1efef168b1d1bae8875 +quant-platform-kit @ git+https://github.com/QuantStrategyLab/QuantPlatformKit.git@532346b6e22d9f9c0a25c5e859f29084d7b27f6c +us-equity-strategies @ git+https://github.com/QuantStrategyLab/UsEquityStrategies.git@7ccc46038e6f0fe84a6910a6fa0515252bf15b79 pandas numpy requests diff --git a/tests/test_request_handling.py b/tests/test_request_handling.py index 82a965d..7b3a892 100644 --- a/tests/test_request_handling.py +++ b/tests/test_request_handling.py @@ -43,40 +43,17 @@ def test_handle_request_sends_escalated_strategy_plugin_alert(strategy_module, m would_trade_if_enabled=True, as_of="2026-05-24", ) - observed = {"email_alerts": [], "sms_alerts": []} + observed = {"alerts": []} monkeypatch.setattr(strategy_module, "is_market_open_today", lambda: True) monkeypatch.setattr(strategy_module, "load_strategy_plugin_signals", lambda: ((signal,), None)) monkeypatch.setattr(strategy_module, "attach_strategy_plugin_report", lambda *args, **kwargs: None) - def fake_email_publish(signals, **kwargs): - observed["email_alerts"].append((tuple(signals), kwargs)) - return types.SimpleNamespace( - sent_count=1, - to_report_fields=lambda: { - "strategy_plugin_alert_email_attempted_count": 1, - "strategy_plugin_alert_email_sent_count": 1, - "strategy_plugin_alert_email_skipped_count": 0, - "strategy_plugin_alert_email_failed_count": 0, - "strategy_plugin_alert_email_deliveries": [], - }, - ) - - def fake_sms_publish(signals, **kwargs): - observed["sms_alerts"].append((tuple(signals), kwargs)) - return types.SimpleNamespace( - sent_count=1, - to_report_fields=lambda: { - "strategy_plugin_alert_sms_attempted_count": 1, - "strategy_plugin_alert_sms_sent_count": 1, - "strategy_plugin_alert_sms_skipped_count": 0, - "strategy_plugin_alert_sms_failed_count": 0, - "strategy_plugin_alert_sms_deliveries": [], - }, - ) + def fake_dispatch(signals, **kwargs): + observed["alerts"].append((tuple(signals), kwargs)) + return types.SimpleNamespace(attach_to_report=lambda _report: None) - monkeypatch.setattr(strategy_module, "publish_strategy_plugin_email_alerts", fake_email_publish) - monkeypatch.setattr(strategy_module, "publish_strategy_plugin_sms_alerts", fake_sms_publish) + monkeypatch.setattr(strategy_module, "dispatch_strategy_plugin_alerts", fake_dispatch) monkeypatch.setattr(strategy_module, "run_strategy_core", lambda **_kwargs: "OK - executed") with strategy_module.app.test_request_context("/", method="POST"): @@ -84,12 +61,11 @@ def fake_sms_publish(signals, **kwargs): assert status == 200 assert body == "OK - executed" - assert len(observed["email_alerts"]) == 1 - assert len(observed["sms_alerts"]) == 1 - assert observed["email_alerts"][0][0] == (signal,) - assert observed["sms_alerts"][0][0] == (signal,) - assert "ibkr" in observed["email_alerts"][0][1]["context_label"] - assert "ibkr" in observed["sms_alerts"][0][1]["context_label"] + assert len(observed["alerts"]) == 1 + assert observed["alerts"][0][0] == (signal,) + assert "ibkr" in observed["alerts"][0][1]["context_label"] + assert observed["alerts"][0][1]["notification_settings"] is strategy_module.RUNTIME_SETTINGS + assert observed["alerts"][0][1]["state_settings"] is not None def test_handle_precheck_post_uses_dry_run_override(strategy_module, monkeypatch):