diff --git a/backend/app/quant/combo_engine.py b/backend/app/quant/combo_engine.py index 6f02555..10eeb4d 100644 --- a/backend/app/quant/combo_engine.py +++ b/backend/app/quant/combo_engine.py @@ -173,6 +173,11 @@ _UNIMPLEMENTED_BASE = [ "多策略打分采用 Borda 秩和(各策略 1/名次 求和):不假设不同策略的因子分值可比," "但极端情况下某策略覆盖极少股票会使其秩和贡献偏大" ), + ( + "买卖说明覆盖 signal_history 里的每个买卖点(含涨停/停牌/现金不足等未成交情形);" + "但「当日排名在 TopN 之外、策略本来就无意买入」的候选不计为买卖点," + "要看完整候选与名次请查选股明细(selection_history)" + ), ] diff --git a/backend/app/quant/local_engine.py b/backend/app/quant/local_engine.py index 76a5bd0..29d8636 100644 --- a/backend/app/quant/local_engine.py +++ b/backend/app/quant/local_engine.py @@ -927,6 +927,13 @@ class TopKBacktestRunner: def _unimplemented(self, curve_note: str | None = None) -> list[str]: notes = list(_DEFAULT_UNIMPLEMENTED) + unimplemented_notes(self.spec.portfolio) + # 如实说明买卖理由的覆盖边界:每个买卖点(含涨停/停牌/现金不足等未成交)都有理由, + # 但「排名在 TopN 之外、策略本来就无意买入」的候选不算买卖点(看选股明细即可)。 + notes.append( + "买卖说明覆盖 signal_history 里的每个买卖点(含涨停/停牌/现金不足等未成交情形);" + "「当日排名在 TopN 之外、策略本来就无意买入」的候选不计为买卖点," + "要看完整候选与名次请查选股明细(selection_history)" + ) if self._no_prev_close_symbols: notes.append( f"有 {len(self._no_prev_close_symbols)} 只标的成交时缺少上一有效收盘价," diff --git a/frontend/web/components/TradeReasons.tsx b/frontend/web/components/TradeReasons.tsx index 104e7dc..73c82a2 100644 --- a/frontend/web/components/TradeReasons.tsx +++ b/frontend/web/components/TradeReasons.tsx @@ -302,6 +302,9 @@ export function TradeReasonsCard({ {withReason < signals.length ? ` 有 ${signals.length - withReason} 条来自 2026-10 之前的旧归档,当时还没有结构化理由。` : ""} + {" "}覆盖边界:「当日排名在 TopN 之外、策略本来就无意买入」的候选不算买卖点 + (要看完整候选与名次,请看选股明细);每个真正的买卖点 —— 包括涨停、停牌、 + 跌停、现金不足这类没成交的 —— 都在上表里。 );