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
2 changes: 1 addition & 1 deletion constraints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
55 changes: 43 additions & 12 deletions notifications/renderers.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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(("信号:", "信号:", "市场状态:", "市场状态:"))
Comment on lines +210 to +212

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Exclude remaining audit rows from compact dashboards

When dashboard_text contains strategy audit rows that do not start with these prefixes—for example TQQQ dashboard rows like QQQ: ... | MA200 Exit: ... or Vol Delever: ..._compact_dashboard_lines() keeps them, so compact trade/heartbeat Telegram messages still include benchmark and risk diagnostics instead of only account/position/outcome information. Please either positively allow the account/holding/cash rows or add the remaining audit prefixes before using this helper for compact notifications.

Useful? React with 👍 / 👎.

)


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()
Expand Down Expand Up @@ -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())
Expand Down Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
34 changes: 30 additions & 4 deletions tests/test_notifications.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down Expand Up @@ -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 = {
Expand Down
Loading