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
25 changes: 13 additions & 12 deletions application/rebalance_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,14 @@ def _build_benchmark_line(execution):
)


def _format_holdings_lines(portfolio_rows, market_values, *, translator) -> list[str]:
lines = [translator("holdings_title")]
for row in portfolio_rows:
for symbol in row:
lines.append(f" - {symbol}: ${market_values[symbol]:,.2f}")
return lines


def _append_status_lines(lines, *, execution, translator, signal_key):
status_display = _localize_notification_text(execution.get("status_display"), translator=translator)
if status_display:
Expand Down Expand Up @@ -501,7 +509,7 @@ def record_dry_run(symbol, side, quantity, price, *, order_type):
available=f"{available_cash:.2f}",
investable=f"{investable_cash:.2f}",
)
formatted_logs = "\n".join(f" {log}" for log in [*logs, *skip_logs, *note_logs])
formatted_logs = "\n".join(f" - {log}" for log in [*logs, *skip_logs, *note_logs])
tg_lines = [translator("rebalance_title")]
_append_strategy_line(
tg_lines,
Expand All @@ -517,7 +525,7 @@ def record_dry_run(symbol, side, quantity, price, *, order_type):
translator=translator,
signal_key="signal",
)
tg_lines.extend([separator, formatted_logs])
tg_lines.extend([separator, translator("order_logs_title"), formatted_logs])
tg_message = "\n".join(tg_lines)
print(with_prefix(tg_message), flush=True)
send_tg_message(tg_message)
Expand All @@ -528,14 +536,7 @@ def record_dry_run(symbol, side, quantity, price, *, order_type):
available=f"{available_cash:.2f}",
investable=f"{investable_cash:.2f}",
)
holdings_lines = []
for row in portfolio_rows:
holdings_lines.append(
" ".join(
f"{symbol}: ${market_values[symbol]:,.2f}"
for symbol in row
)
)
holdings_lines = _format_holdings_lines(portfolio_rows, market_values, translator=translator)
no_trade_lines = [
translator("heartbeat_title"),
]
Expand Down Expand Up @@ -572,13 +573,13 @@ def record_dry_run(symbol, side, quantity, price, *, order_type):
no_trade_message += (
f"\n{separator}\n"
f"{translator('skipped_actions')}\n"
+ "\n".join(f" {log}" for log in skip_logs)
+ "\n".join(f" - {log}" for log in skip_logs)
)
if note_logs:
no_trade_message += (
f"\n{separator}\n"
f"{translator('notes_title')}\n"
+ "\n".join(f" {log}" for log in note_logs)
+ "\n".join(f" - {log}" for log in note_logs)
)
print(with_prefix(no_trade_message), flush=True)
send_tg_message(no_trade_message)
Expand Down
4 changes: 4 additions & 0 deletions notifications/telegram.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
"equity": "💰 净值: ${value}",
"cash_summary": "💵 账户现金: ${available} | 可投资现金: ${investable}",
"cash_label": "现金",
"holdings_title": "💼 持仓",
"order_logs_title": "🧾 执行明细",
"heartbeat_signal": "🎯 信号: {msg}",
"no_trades": "✅ 无需调仓",
"no_executable_orders": "⚠️ 本轮没有可执行订单",
Expand Down Expand Up @@ -95,6 +97,8 @@
"equity": "💰 Equity: ${value}",
"cash_summary": "💵 Cash: ${available} | Investable cash: ${investable}",
"cash_label": "Cash",
"holdings_title": "💼 Holdings",
"order_logs_title": "🧾 Execution details",
"heartbeat_signal": "🎯 Signal: {msg}",
"no_trades": "✅ No trades needed",
"no_executable_orders": "⚠️ No executable orders this cycle",
Expand Down
2 changes: 2 additions & 0 deletions tests/test_notifications.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ class NotificationTests(unittest.TestCase):
def test_build_translator_supports_chinese(self):
translate = build_translator("zh")
self.assertEqual(translate("equity", value="123.45"), "💰 净值: $123.45")
self.assertEqual(translate("holdings_title"), "💼 持仓")
self.assertEqual(translate("order_logs_title"), "🧾 执行明细")
self.assertEqual(translate("market_status_blend_gate_risk_on", asset="SOXX+SOXL"), "🚀 风险开启(SOXX+SOXL)")
self.assertEqual(
translate(
Expand Down
8 changes: 7 additions & 1 deletion tests/test_rebalance_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -609,7 +609,8 @@ def test_heartbeat_accepts_normalized_portfolio_and_execution_sections(self):
self.assertEqual(len(sent_messages), 1)
self.assertIn("💓 【心跳检测】", sent_messages[0])
self.assertIn("可投资现金", sent_messages[0])
self.assertIn("SOXX", sent_messages[0])
self.assertIn("💼 持仓", sent_messages[0])
self.assertIn(" - SOXX:", sent_messages[0])

def test_hybrid_heartbeat_hides_empty_semiconductor_fields_and_shows_benchmark_line(self):
plan = _build_plan(
Expand Down Expand Up @@ -650,8 +651,13 @@ def test_hybrid_heartbeat_hides_empty_semiconductor_fields_and_shows_benchmark_l
self.assertIn("💓 【心跳检测】", sent_messages[0])
self.assertIn("🧭 策略: TQQQ 增长收益", sent_messages[0])
self.assertIn("🧪 模拟运行模式", sent_messages[0])
self.assertIn("💼 持仓", sent_messages[0])
self.assertIn(" - TQQQ: $0.00", sent_messages[0])
self.assertIn(" - BOXX: $0.00", sent_messages[0])
self.assertIn(" - QQQI: $0.00", sent_messages[0])
self.assertIn("QQQ: 588.50 | MA200: 595.25 | Exit: 573.00", sent_messages[0])
self.assertIn("🎯 信号: 💤 等待信号", sent_messages[0])
self.assertNotIn("TQQQ: $0.00 BOXX", sent_messages[0])
self.assertNotIn("📊 市场状态: ", sent_messages[0])
self.assertNotIn("💼 交易层风险仓位: ", sent_messages[0])
self.assertNotIn("🏦 收入层锁定占比: ", sent_messages[0])
Expand Down