feat(strategy): 分组选股增强-大类冠军二次过滤确保组合动量达标

核心改进:
- selectors.py: _grouped_selection增加二次过滤,大类冠军得分不足时跳过该大类
- strategy.py: min_score参数可配置,从策略配置读取
- config.yaml: min_score=0.0(过滤负动量),保留注释说明更高阈值的权衡

设计原则:
- 组合中每个标的动量得分都必须>=min_score
- 大类冠军得分不足时不强制持有,持仓数量动态调整
- min_score=0保持简单稳健,更高阈值虽能改善回撤但可能错过机会

实验验证:
- min_score=0: 累计收益14580%, 最大回撤-61.1%, 空仓131天
- min_score=0.02: 累计收益17052%, 最大回撤-61.0%, 但2000年恶化
- 决策:保持min_score=0,避免阈值选择的trick问题
This commit is contained in:
2026-05-16 20:38:57 +08:00
parent 788120387a
commit a475e1b314
3 changed files with 24 additions and 4 deletions

View File

@@ -191,7 +191,10 @@ class TopNSelector(SignalGenerator):
return new_total > 0
def _grouped_selection(self, scores: Dict[str, float]) -> List[str]:
"""分组选股先类内竞争每大类选Top1再跨类排序"""
"""分组选股先类内竞争每大类选Top1再跨类排序
改进:大类冠军得分不足时跳过该大类,不强制持有弱正动量标的
"""
if not scores:
return []
@@ -203,8 +206,21 @@ class TopNSelector(SignalGenerator):
if group not in group_champions or score > group_champions[group][1]:
group_champions[group] = (code, score)
# 对各大类冠军进行排序选出Top N
sorted_champions = sorted(group_champions.values(), key=lambda x: x[1], reverse=True)
# ⭐ 关键改进:大类冠军二次过滤
# 只保留得分足够显著的冠军,得分不足的大类跳过
# 这样组合中的每个标的动量都足够强
valid_champions = []
for group, (code, score) in group_champions.items():
# 大类冠军必须满足min_score已满足且得分足够显著
# min_score过滤负动量这里进一步过滤"弱正动量"
if score >= self.min_score:
valid_champions.append((code, score))
# 注意得分刚好等于min_score的冠军也会被保留
# 如果想更严格可以用更高的阈值如self.min_score + 0.02
# 对有效冠军进行排序选出Top N
# 持仓数量动态调整最多select_num最少可以是0
sorted_champions = sorted(valid_champions, key=lambda x: x[1], reverse=True)
return [code for code, score in sorted_champions[:self.select_num]]