1616 ("pending_orders_detected" , "检测到未完成订单" ),
1717 ("same_day_execution_locked" , "当日执行锁已存在" ),
1818 ("same_day_fills_detected" , "检测到当日成交" ),
19+ ("target_diff_below_threshold" , "调仓差异低于阈值" ),
20+ ("min_notional" , "低于最小订单金额" ),
21+ ("quantity_zero" , "整数股数量为0" ),
1922 ("fail_reason=" , "失败原因=" ),
2023 ("decision=" , "决策=" ),
2124)
@@ -186,6 +189,13 @@ def _build_notification_trade_lines(
186189 snapshot_date = _format_text (execution_summary .get ("snapshot_as_of" ), fallback = "<none>" ),
187190 )
188191 )
192+ elif no_op_reason :
193+ lines .append (
194+ translator (
195+ "no_order_plan_reason" ,
196+ reason = _localize_notification_text (f"reason={ no_op_reason } " , translator = translator ),
197+ )
198+ )
189199
190200 fallback_symbols = tuple (execution_summary .get ("snapshot_price_fallback_symbols" ) or ())
191201 if execution_summary .get ("snapshot_price_fallback_used" ) and fallback_symbols :
@@ -215,7 +225,7 @@ def _build_notification_trade_lines(
215225 continue
216226 if "execution_lock_acquired" in text or "已获取执行锁" in text :
217227 continue
218- if text .startswith (("profile=" , "strategy_profile=" , "策略 =" )):
228+ if text .startswith (("profile=" , "strategy_profile=" , "execution_profile=" , "策略=" , "执行配置 =" )):
219229 continue
220230 if "same_day_execution_locked" in text or "当日执行锁已存在" in text :
221231 continue
@@ -225,6 +235,16 @@ def _build_notification_trade_lines(
225235 return lines
226236
227237
238+ def _build_detailed_trade_lines (trade_logs , * , translator ) -> list [str ]:
239+ lines : list [str ] = []
240+ for raw_line in trade_logs or ():
241+ text = _localize_notification_text (str (raw_line ).strip (), translator = translator )
242+ if not text :
243+ continue
244+ lines .extend (_split_labeled_text (text ))
245+ return lines
246+
247+
228248def _resolve_weight_allocation (signal_metadata , * , required : bool ) -> dict :
229249 metadata = dict (signal_metadata or {})
230250 allocation = dict (metadata .get ("allocation" ) or {})
@@ -384,10 +404,27 @@ def build_dashboard(
384404 )
385405
386406
387- def _first_prefixed_line ( prefix : str , text : str , * , translator ) -> str | None :
407+ def _first_summary_text ( text : str , * , translator ) -> str :
388408 localized = _localize_notification_text (text , translator = translator )
389- lines = _format_prefixed_text (prefix , localized )
390- return lines [0 ] if lines else None
409+ lines = _split_labeled_text (localized )
410+ return lines [0 ] if lines else ""
411+
412+
413+ def _localize_signal_state (text : str , * , translator ) -> str :
414+ value = str (text or "" ).strip ()
415+ if value .lower () not in {"hold" , "entry" , "reduce" , "exit" , "idle" }:
416+ return value
417+ key = f"signal_state_{ value .lower ()} "
418+ translated = translator (key )
419+ return value if translated == key else str (translated )
420+
421+
422+ def _extract_timing_lines (text : str ) -> list [str ]:
423+ return [
424+ line .strip ()
425+ for line in _format_dashboard_text (text ).splitlines ()
426+ if line .strip ().startswith ("⏱" )
427+ ]
391428
392429
393430def _build_compact_message (
@@ -402,19 +439,26 @@ def _build_compact_message(
402439 body_lines ,
403440 dashboard_text : str = "" ,
404441 extra_notification_lines = (),
442+ include_dashboard : bool = False ,
405443) -> str :
406444 lines = [title ]
407445 strategy_name = _format_text (strategy_display_name , fallback = "<unknown>" )
408446 lines .append (translator ("strategy_label" , name = strategy_name ))
409447 lines .extend (_extra_notification_lines (extra_notification_lines ))
410448 dashboard = _format_dashboard_text (dashboard_text )
411- if dashboard :
449+ if include_dashboard and dashboard :
412450 lines .append (separator )
413451 lines .extend (dashboard .splitlines ())
414- status_line = _first_prefixed_line (status_icon , status_desc , translator = translator )
415- if status_line :
452+ elif dashboard :
453+ lines .extend (_extract_timing_lines (dashboard ))
454+ status_summary = _first_summary_text (status_desc , translator = translator )
455+ signal_summary = _first_summary_text (signal_desc , translator = translator )
456+ status_summary = _localize_signal_state (status_summary , translator = translator )
457+ signal_summary = _localize_signal_state (signal_summary , translator = translator )
458+ status_line = f"{ status_icon } { status_summary } " .strip () if status_summary else None
459+ if status_line and status_summary != signal_summary :
416460 lines .append (status_line )
417- signal_line = _first_prefixed_line ( "🎯" , signal_desc , translator = translator )
461+ signal_line = f"🎯 { signal_summary } " . strip () if signal_summary else None
418462 if signal_line :
419463 lines .append (signal_line )
420464 compact_body = [str (line ).strip () for line in body_lines or () if str (line ).strip ()]
@@ -451,6 +495,7 @@ def render_heartbeat_notification(
451495 body_lines = [no_op_text ],
452496 dashboard_text = strategy_dashboard ,
453497 extra_notification_lines = extra_lines ,
498+ include_dashboard = True ,
454499 )
455500 return RenderedNotification (detailed_text = detailed_text , compact_text = compact_text )
456501
@@ -476,12 +521,16 @@ def render_trade_notification(
476521 execution_summary = execution_summary ,
477522 translator = translator ,
478523 )
524+ detailed_trade_lines = _build_detailed_trade_lines (
525+ trade_logs ,
526+ translator = translator ,
527+ )
479528 detailed_text = (
480529 f"{ translator ('rebalance_title' )} \n "
481530 f"{ chr (10 ).join (extra_lines ) + chr (10 ) if extra_lines else '' } "
482531 f"{ dashboard } \n "
483532 f"{ separator } \n "
484- f"{ chr (10 ).join (notification_trade_lines )} "
533+ f"{ chr (10 ).join (detailed_trade_lines )} "
485534 )
486535 compact_text = _build_compact_message (
487536 title = translator ("rebalance_title" ),
@@ -494,6 +543,7 @@ def render_trade_notification(
494543 body_lines = notification_trade_lines ,
495544 dashboard_text = strategy_dashboard ,
496545 extra_notification_lines = extra_lines ,
546+ include_dashboard = True ,
497547 )
498548 return RenderedNotification (detailed_text = detailed_text , compact_text = compact_text )
499549
@@ -510,5 +560,6 @@ def render_trade_notification(
510560 body_lines = [translator ("no_trades" )],
511561 dashboard_text = strategy_dashboard ,
512562 extra_notification_lines = extra_lines ,
563+ include_dashboard = True ,
513564 )
514565 return RenderedNotification (detailed_text = detailed_text , compact_text = compact_text )
0 commit comments