fix: V3动态阈值两处根因修复

根因1: _check_rebalance重复代码计分Bug
- 问题: "CL=F,931862.CSI,931862.CSI"中短债只计一次得分
- 修复: 直接遍历持仓列表计算得分,而非遍历factor_cols做in判断
- 影响: 278天应防御时继续持有风险资产

根因2: 短债填充依赖阈值过滤
- 问题: 短债动量为负时(钱荒等)不填充防御仓位
- 修复: 无条件填充短债(防御机制不应依赖动量阈值)
- 影响: 17天仓位不满(1/3或2/3空置)

修复后结果:
- 净值: 292.56 → 334.46 (+14.4%)
- 夏普: 1.33 → 1.41 (+0.08)
- 持仓3只: 92.3% → 99.4% (满仓率提升)
- 短债填充更积极: 28.7%时间持有短债
This commit is contained in:
2026-05-19 00:38:04 +08:00
parent 957769b501
commit be8ca023f7

View File

@@ -205,8 +205,9 @@ class TopNSelector(SignalGenerator):
return False # 组合完全相同,不调仓 return False # 组合完全相同,不调仓
# 计算新旧组合的总得分 # 计算新旧组合的总得分
old_total = sum(float(row.get(col, 0)) for col in factor_cols if col in old_codes) # 修复: 按实际份数计算得分(支持重复代码如"931862.CSI,931862.CSI"
new_total = sum(float(row.get(col, 0)) for col in factor_cols if col in new_codes) old_total = sum(float(row.get(c, 0)) for c in old_codes)
new_total = sum(float(row.get(c, 0)) for c in new_codes)
# 新组合得分需超过当前组合一定比例才调仓 # 新组合得分需超过当前组合一定比例才调仓
# 即使 threshold=0也要确保 new_total >= old_total # 即使 threshold=0也要确保 new_total >= old_total
@@ -247,13 +248,11 @@ class TopNSelector(SignalGenerator):
selected = [code for code, score in sorted_champions[:self.select_num]] selected = [code for code, score in sorted_champions[:self.select_num]]
# V3: 空余仓位填充短债 # V3: 空余仓位填充短债
# 短债填充是防御机制,不应受阈值过滤影响
if cfg.get('fill_bond', False) and bond_code: if cfg.get('fill_bond', False) and bond_code:
n_bond_slots = self.select_num - len(selected) n_bond_slots = self.select_num - len(selected)
if n_bond_slots > 0: if n_bond_slots > 0:
# 检查短债是否满足阈值条件需在原始scores中存在 # 修复: 无条件填充短债(防御仓位不应依赖动量阈值
bond_score = scores.get(bond_code, None)
if bond_score is not None:
# 用短债代码填充空余仓位(可能重复填充多次)
for _ in range(n_bond_slots): for _ in range(n_bond_slots):
selected.append(bond_code) selected.append(bond_code)