Skip to content

Commit 330bd19

Browse files
committed
Split dense notification details
1 parent c326b61 commit 330bd19

2 files changed

Lines changed: 49 additions & 9 deletions

File tree

application/rebalance_service.py

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from __future__ import annotations
44

55
import json
6+
import re
67

78
from application.reconciliation_service import (
89
build_reconciliation_record,
@@ -88,6 +89,7 @@
8889
("fail_reason=", "失败原因="),
8990
("decision=", "决策="),
9091
)
92+
_DETAIL_FIELD_SPLIT_RE = re.compile(r"\s+(?=[^\s=::]+[=::])")
9193

9294

9395
def _format_text(value, *, fallback: str) -> str:
@@ -121,6 +123,34 @@ def _localize_notification_text(text: str, *, translator) -> str:
121123
return localized
122124

123125

126+
def _split_detail_segment(text: str) -> list[str]:
127+
value = str(text or "").strip()
128+
if not value:
129+
return []
130+
if "=" not in value and ":" not in value and ":" not in value:
131+
return [value]
132+
return [part.strip() for part in _DETAIL_FIELD_SPLIT_RE.split(value) if part.strip()]
133+
134+
135+
def _split_labeled_text(text: str) -> list[str]:
136+
segments = [segment.strip() for segment in str(text or "").split(" | ") if segment.strip()]
137+
if not segments:
138+
return []
139+
lines = [segments[0]]
140+
for segment in segments[1:]:
141+
lines.extend(_split_detail_segment(segment))
142+
return lines
143+
144+
145+
def _format_prefixed_text(prefix: str, text: str) -> list[str]:
146+
parts = _split_labeled_text(text)
147+
if not parts:
148+
return []
149+
lines = [f"{prefix} {parts[0]}".strip()]
150+
lines.extend(f" - {part}" for part in parts[1:])
151+
return lines
152+
153+
124154
def _summarize_target_changes(target_vs_current, *, limit: int = 5) -> str | None:
125155
rows = []
126156
for row in target_vs_current or ():
@@ -240,7 +270,7 @@ def _build_notification_trade_lines(
240270
if "same_day_execution_locked" in text or "当日执行锁已存在" in text:
241271
continue
242272
if text not in lines:
243-
lines.append(text)
273+
lines.extend(_split_labeled_text(text))
244274

245275
return lines
246276

@@ -327,6 +357,10 @@ def build_dashboard(
327357
diagnostics_text = "\n".join(diagnostics_lines)
328358
localized_status_desc = _localize_notification_text(status_desc, translator=translator)
329359
localized_signal_desc = _localize_notification_text(signal_desc, translator=translator)
360+
status_lines = _format_prefixed_text(status_icon, localized_status_desc)
361+
signal_lines = _format_prefixed_text("🎯", localized_signal_desc)
362+
status_text = "\n".join(status_lines)
363+
signal_text = "\n".join(signal_lines)
330364
return (
331365
f"{translator('account_summary_title')}\n"
332366
f" - {translator('equity')}: ${equity:,.2f}\n"
@@ -338,8 +372,8 @@ def build_dashboard(
338372
f"{translator('execution_summary_title')}\n"
339373
f"{diagnostics_text}\n"
340374
f"{separator}\n"
341-
f"{status_icon} {localized_status_desc}\n"
342-
f"🎯 {localized_signal_desc}\n"
375+
f"{status_text}\n"
376+
f"{signal_text}\n"
343377
f"{separator}\n"
344378
f"{translator('target_weights_title')}:\n{target_text}"
345379
)
@@ -397,6 +431,7 @@ def run_strategy_core(
397431
no_op_text = f"{no_op_text} | {_localize_notification_text(f'reason={no_op_reason}', translator=translator)}"
398432
if fail_reason:
399433
no_op_text = f"{no_op_text} | {_localize_notification_text(f'fail_reason={fail_reason}', translator=translator)}"
434+
no_op_text = "\n".join(_split_labeled_text(no_op_text))
400435
record = build_reconciliation_record(
401436
strategy_profile=signal_metadata.get("strategy_profile"),
402437
mode="dry_run" if signal_metadata.get("dry_run_only") else "paper",

tests/test_rebalance_service.py

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ def test_build_dashboard_localizes_snapshot_guard_text_for_zh():
115115
status_icon="🛑",
116116
)
117117

118-
assert "🛑 关闭执行 | 原因=缺少特征快照路径" in dashboard
118+
assert "🛑 关闭执行\n - 原因=缺少特征快照路径" in dashboard
119119
assert "🎯 特征快照校验阻止执行" in dashboard
120120

121121

@@ -138,7 +138,9 @@ def test_build_dashboard_localizes_qqq_tech_diagnostics_for_zh():
138138
strategy_display_name="科技通信回调增强",
139139
)
140140

141-
assert "市场阶段=软防御 | 市场宽度=41.2% | 目标股票仓位=60.0% | 实际股票仓位=60.0%" in dashboard
141+
assert "🐤 市场阶段=软防御\n - 市场宽度=41.2%" in dashboard
142+
assert " - 目标股票仓位=60.0%" in dashboard
143+
assert " - 实际股票仓位=60.0%" in dashboard
142144
assert "基准趋势=向下" in dashboard
143145
assert "入选标的数=8 前排标的=CIEN(0.92)" in dashboard
144146

@@ -156,10 +158,13 @@ def test_notification_trade_lines_localize_runtime_diagnostic_tail_for_zh():
156158
)
157159

158160
assert lines == [
159-
(
160-
"执行配置=SOXL/SOXX 半导体趋势收益 | 市场阶段=无 | 宽度=0.0% | "
161-
"目标股票仓位=0.0% | 实际股票仓位=0.0% | 快照日期=无 | 交易日=无"
162-
)
161+
"执行配置=SOXL/SOXX 半导体趋势收益",
162+
"市场阶段=无",
163+
"宽度=0.0%",
164+
"目标股票仓位=0.0%",
165+
"实际股票仓位=0.0%",
166+
"快照日期=无",
167+
"交易日=无",
163168
]
164169

165170

0 commit comments

Comments
 (0)