Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 12 additions & 46 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand Down Expand Up @@ -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,
Expand All @@ -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, ...]:
Expand Down
4 changes: 2 additions & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -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
Expand Down
44 changes: 10 additions & 34 deletions tests/test_request_handling.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,53 +43,29 @@ 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"):
body, status = strategy_module.handle_request()

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):
Expand Down