From 6bcd7b097cd3117068f89e5f4bd00b60f9219883 Mon Sep 17 00:00:00 2001 From: Pigbibi <20649888+Pigbibi@users.noreply.github.com> Date: Thu, 2 Jul 2026 05:02:28 +0800 Subject: [PATCH] simplify compact notifications and margin labels --- constraints.txt | 2 +- notifications/renderers.py | 55 +++++++++++++++++++++++++++++-------- requirements.txt | 2 +- tests/test_notifications.py | 34 ++++++++++++++++++++--- 4 files changed, 75 insertions(+), 18 deletions(-) diff --git a/constraints.txt b/constraints.txt index 2a6081a..80824cb 100644 --- a/constraints.txt +++ b/constraints.txt @@ -4,7 +4,7 @@ # Auto-updated by update-qpk-pin.yml on every push to QPK main. quant-platform-kit @ git+https://github.com/QuantStrategyLab/QuantPlatformKit.git@d786c1140967f0e96e35599d057f0655e5a9ba25 -us-equity-strategies @ git+https://github.com/QuantStrategyLab/UsEquityStrategies.git@c8df5f9659340965bd7f53998892ed1018ed4254 +us-equity-strategies @ git+https://github.com/QuantStrategyLab/UsEquityStrategies.git@c57fb20528d40f363ae149ae6e3f6b1a240ec237 hk-equity-strategies @ git+https://github.com/QuantStrategyLab/HkEquityStrategies.git@700c8b19c46336d3d8fcba687e58553afcf0235f cn-equity-strategies @ git+https://github.com/QuantStrategyLab/CnEquityStrategies.git@e09fd557c2bd9ae5f4d44228915c4e52c4b0dd21 crypto-strategies @ git+https://github.com/QuantStrategyLab/CryptoStrategies.git@565be005e4186fd6d750884e7b0bc59f779f9549 diff --git a/notifications/renderers.py b/notifications/renderers.py index 9b57f10..c064c89 100644 --- a/notifications/renderers.py +++ b/notifications/renderers.py @@ -157,11 +157,26 @@ def _format_inline_segments(line: str, *, translator, holdings_title_emitted: bo def _relabel_dashboard_buying_power(text: str, *, cash_only_execution: bool, translator) -> str: value = str(text or "") if cash_only_execution: + value = value.replace("总资产(策略净值)", "总资产(策略标的+现金,不含融资额度)") + value = value.replace( + "Total assets (strategy net liquidation)", + "Total assets (strategy symbols + cash, ex-margin)", + ) target = translator("buying_power") for source in ("Buying power", "购买力"): if source != target: value = value.replace(source, target) return value + value = value.replace("总资产(策略标的+现金,不含融资额度)", "总资产(策略净值)") + value = value.replace("总资产(策略标的+现金)", "总资产(策略净值)") + value = value.replace( + "Total assets (strategy symbols + cash, ex-margin)", + "Total assets (strategy net liquidation)", + ) + value = value.replace( + "Total assets (strategy symbols + cash)", + "Total assets (strategy net liquidation)", + ) target = translator("buying_power_margin") for source in ("Available cash", "可用现金"): if source != target: @@ -188,6 +203,24 @@ def _format_dashboard_text(text: str, *, translator, cash_only_execution: bool = ) +def _is_compact_dashboard_audit_line(line: str) -> bool: + text = str(line or "").strip() + lowered = text.lower() + return ( + text.startswith(("⏱", "🧾", "🧩 输入状态", "📊", "🎯", "🛡️")) + or lowered.startswith(("signal:", "signal:", "market status:")) + or text.startswith(("信号:", "信号:", "市场状态:", "市场状态:")) + ) + + +def _compact_dashboard_lines(dashboard_text: str) -> list[str]: + return [ + line + for line in str(dashboard_text or "").splitlines() + if line.strip() and not _is_compact_dashboard_audit_line(line) + ] + + def _build_timing_audit_lines(execution, *, translator) -> list[str]: signal_date = str(execution.get("signal_date") or "").strip() effective_date = str(execution.get("effective_date") or "").strip() @@ -439,8 +472,12 @@ def _build_compact_trade_message( lines.extend(line for line in extra_notification_block.splitlines() if line.strip()) dashboard = str(dashboard_text or "").strip() if dashboard: + dashboard_lines = _compact_dashboard_lines(dashboard) + else: + dashboard_lines = [] + if dashboard_lines: lines.append(separator) - lines.extend(line for line in dashboard.splitlines() if line.strip()) + lines.extend(dashboard_lines) lines.append(separator) if trade_logs: lines.extend(str(log).strip() for log in trade_logs if str(log).strip()) @@ -478,18 +515,12 @@ def _build_compact_heartbeat_message( lines.extend(line for line in extra_notification_block.splitlines() if line.strip()) dashboard = str(dashboard_text or "").strip() if dashboard: + dashboard_lines = _compact_dashboard_lines(dashboard) + else: + dashboard_lines = [] + if dashboard_lines: lines.append(separator) - lines.extend(line for line in dashboard.splitlines() if line.strip()) - lines.extend(timing_lines) - if signal_snapshot_line: - lines.append(signal_snapshot_line) - status_summary = _first_detail_line(status_display) - if status_summary: - lines.append(_format_market_status_line(status_summary, translator=translator)) - lines.extend(risk_control_lines) - signal_summary = _first_detail_line(signal_display) - if signal_summary: - lines.append(f"🎯 {translator('signal_label')}: {signal_summary}") + lines.extend(dashboard_lines) lines.append(separator) lines.append(translator("no_trades")) return "\n".join(lines) diff --git a/requirements.txt b/requirements.txt index bde0d81..1b74bf8 100644 --- a/requirements.txt +++ b/requirements.txt @@ -10,4 +10,4 @@ google-cloud-storage google-auth numpy quant-platform-kit @ git+https://github.com/QuantStrategyLab/QuantPlatformKit.git@d786c1140967f0e96e35599d057f0655e5a9ba25 -us-equity-strategies @ git+https://github.com/QuantStrategyLab/UsEquityStrategies.git@c8df5f9659340965bd7f53998892ed1018ed4254 +us-equity-strategies @ git+https://github.com/QuantStrategyLab/UsEquityStrategies.git@c57fb20528d40f363ae149ae6e3f6b1a240ec237 diff --git a/tests/test_notifications.py b/tests/test_notifications.py index 2946d0b..cd741cb 100644 --- a/tests/test_notifications.py +++ b/tests/test_notifications.py @@ -220,9 +220,10 @@ def test_heartbeat_signal_snapshot_localizes_price_source_and_status_label(self) account_label="demo", ) - self.assertIn("数据源 Schwab 日线历史", rendered.compact_text) - self.assertNotIn("报价覆盖", rendered.compact_text) - self.assertIn("📊 市场状态: 🚀 风险开启(SOXX+SOXL)", rendered.compact_text) + self.assertIn("数据源 Schwab 日线历史", rendered.detailed_text) + self.assertIn("📊 市场状态: 🚀 风险开启(SOXX+SOXL)", rendered.detailed_text) + self.assertNotIn("数据源 Schwab 日线历史", rendered.compact_text) + self.assertNotIn("📊 市场状态", rendered.compact_text) self.assertNotIn("schwab_daily_history_with_live_quote_overlay", rendered.compact_text) def test_heartbeat_renders_tqqq_volatility_delever_risk_control(self): @@ -264,8 +265,33 @@ def test_heartbeat_renders_tqqq_volatility_delever_risk_control(self): "🛡️ Risk control: QQQ 5d annualized volatility 31.2% is above effective threshold 30.0% " "(dynamic p90, 252d lookback, bounded 24.0%-36.0%, samples 252); TQQQ redirects to QQQM " "(leveraged sleeve: TQQQ retained 0.0%, QQQM 100.0%)", - rendered.compact_text, + rendered.detailed_text, ) + self.assertNotIn("🛡️ Risk control:", rendered.compact_text) + + def test_dashboard_relabels_total_assets_for_margin_execution(self): + rendered = render_heartbeat_notification( + translator=build_translator("zh"), + strategy_display_name="TQQQ 增长收益", + dry_run_only=False, + extra_notification_lines=(), + execution={ + "dashboard_text": "总资产(策略标的+现金,不含融资额度): $50,000.00\n可用现金: $75,000.00", + "separator": "━━━━━━━━━━━━━━━━━━", + "signal_display": "hold", + "cash_only_execution": False, + }, + portfolio={ + "total_equity": 50000.0, + "portfolio_rows": (("TQQQ",),), + "market_values": {"TQQQ": 8000.0}, + }, + account_label="demo", + ) + + self.assertIn("总资产(策略净值): $50,000.00", rendered.compact_text) + self.assertIn("购买力: $75,000.00", rendered.compact_text) + self.assertNotIn("不含融资额度", rendered.compact_text) def test_dashboard_relabels_buying_power_for_cash_only_execution(self): execution = {