|
24 | 24 | localize_notification_text as _base_localize_notification_text, |
25 | 25 | translator_uses_zh as _base_translator_uses_zh, |
26 | 26 | ) |
| 27 | +from quant_platform_kit.strategy_lifecycle.performance_monitor import try_record_platform_execution |
27 | 28 | from quant_platform_kit.common.port_adapters import CallableNotificationPort, CallablePortfolioPort |
28 | 29 |
|
29 | 30 |
|
|
37 | 38 | _DETAIL_FIELD_SPLIT_RE = re.compile(r"\s+(?=[^\s=::]+[=::])") |
38 | 39 |
|
39 | 40 |
|
| 41 | +def _record_platform_execution_telemetry( |
| 42 | + signal_metadata: Mapping[str, object] | None, |
| 43 | + execution_summary: Mapping[str, object] | None, |
| 44 | +) -> None: |
| 45 | + metadata = signal_metadata if isinstance(signal_metadata, Mapping) else {} |
| 46 | + profile = str(metadata.get("strategy_profile") or "").strip() |
| 47 | + if not profile: |
| 48 | + return |
| 49 | + summary = dict(execution_summary or {}) |
| 50 | + try_record_platform_execution( |
| 51 | + profile, |
| 52 | + { |
| 53 | + "platform": "ibkr", |
| 54 | + "mode": summary.get("mode"), |
| 55 | + "execution_status": summary.get("execution_status"), |
| 56 | + "no_op_reason": summary.get("no_op_reason") or metadata.get("no_op_reason"), |
| 57 | + "orders_submitted": list(summary.get("orders_submitted") or ()), |
| 58 | + "orders_filled": list(summary.get("orders_filled") or ()), |
| 59 | + "orders_skipped": list(summary.get("orders_skipped") or ()), |
| 60 | + "trade_date": summary.get("trade_date") or metadata.get("trade_date"), |
| 61 | + }, |
| 62 | + domain=str(metadata.get("domain") or ""), |
| 63 | + ) |
| 64 | + |
| 65 | + |
40 | 66 | def _format_text(value, *, fallback: str) -> str: |
41 | 67 | text = str(value).strip() if value is not None else "" |
42 | 68 | return text or fallback |
@@ -885,6 +911,7 @@ def run_strategy_core( |
885 | 911 | extra_notification_lines=config.extra_notification_lines, |
886 | 912 | ) |
887 | 913 | ) |
| 914 | + _record_platform_execution_telemetry(signal_metadata, {}) |
888 | 915 | return StrategyCycleResult( |
889 | 916 | result="OK - no-op" if notification_suppressed else "OK - heartbeat", |
890 | 917 | signal_metadata=dict(signal_metadata or {}), |
@@ -969,6 +996,10 @@ def run_strategy_core( |
969 | 996 | extra_notification_lines=config.extra_notification_lines, |
970 | 997 | ) |
971 | 998 | ) |
| 999 | + _record_platform_execution_telemetry( |
| 1000 | + signal_metadata, |
| 1001 | + {"action_done": False, "no_op_reason": "execution_already_recorded"}, |
| 1002 | + ) |
972 | 1003 | return StrategyCycleResult( |
973 | 1004 | result="OK - no-op" if notification_suppressed else "OK - heartbeat", |
974 | 1005 | signal_metadata=dict(signal_metadata or {}), |
@@ -1063,6 +1094,7 @@ def run_strategy_core( |
1063 | 1094 | ), |
1064 | 1095 | flush=True, |
1065 | 1096 | ) |
| 1097 | + _record_platform_execution_telemetry(signal_metadata, dict(execution_summary or {})) |
1066 | 1098 | return StrategyCycleResult( |
1067 | 1099 | result="OK - executed", |
1068 | 1100 | signal_metadata=dict(signal_metadata or {}), |
|
0 commit comments