策略评估报告:Doubles
来源: Obsidian Vault
总体评估
这是一份生产就绪程度较高的量化策略文档。逻辑链条完整(翻倍股内部动量延续 → LightGBM 排序 → 月度调仓),迭代过程透明(v1→v7 + walk‑forward),绩效数据诚实(含生存者偏差警示、成本、horizon mismatch 反思)。主要亮点与待改进点如下。
优点
1. 问题定义清晰,对标明确
-
明确区分与 B‑Line 的 alpha 来源(动量延续 vs 反转),避免了常见策略组合中的冗余。
-
承认 生存者偏差 并将基准定为 660 只已翻倍股的等权组合(
Alpha = Top - Bench),这是正确的相对评估方法。
2. 实验迭代严谨
-
从 v1 OHLCV 基线到 v5 加入
r_spread_60dregime indicator 及交互项,每一步都有 OOS 验证和归因。 -
K‑day holding 扫描 是亮点:发现 K=1 负 alpha 并正确归因为 horizon mismatch,而非模型失效。
-
walk‑forward 4 窗口全部正收益(最小 +0.76 Sharpe),过拟合风险较低。
3. 生产约束务实
-
soft sector cap(每组最多 4 只)优于 strict neutral(强制均分导致 alpha 变负),保留了模型对板块的偏斜能力。
-
停牌处理
fillna(0)经验证等同于dropna,无画图偏差。 -
交易成本(0.10%买+0.15%卖)符合 A 股真实水平。
4. 文档与工程分离良好
doubles(数据+模型)与RD-Agent(LLM 实验)职责清晰,信号输出为标准化 HDF5([datetime, instrument, weight]),可直接对接 OMS。
风险与待改进项
1. 数据源单一依赖(ELTDX F10)
-
当前翻倍股筛选、估值因子均来自 ELTDX。若该数据源出现延迟或错误(如复权、除息处理不一致),整个信号链会受冲击。
-
建议:增加备选数据源(如 Wind、聚宽)做交叉验证,至少对关键估值字段(PE、PB)进行一致性校验。
2. 翻倍股 Universe 的稳定性存疑
-
660 只股票是 历史已翻倍 的集合(2024‑06 至 2026‑01)。未来新进入的翻倍股可能携带不同特征(例如 2026 年小微盘翻倍股与 2024 年赛道股不同)。模型是否能在分布漂移下保持预测力?
-
当前缓解措施:每月 expanding window 重训,且 walk‑forward 覆盖到 2026‑01 表现稳定。但需要持续监控 特征分布漂移(PSI 统计)和 模型 AUC 衰减。
3. 实盘执行细节仍缺失
| 缺失项 | 潜在问题 |
|---|---|
| ST/*ST 剔除的数据接入 | 文中仅写“需接入标记数据源”,若实盘未实现,则可能买入 ST 导致跌停无法卖出。 |
| ADV 容量约束的具体实现 | 单股仓位 ≤ 20% 的 20 日 ADV,需要盘中实时计算 ADV 并调整权重。文档未说明计算频率(日频?)和 fail‑over 逻辑。 |
| T+1 开盘执行 vs 持仓重叠 | 每日 T 收盘后选出的 top‑10 将在 T+1 开盘执行,但已有 20 个 sub‑portfolio 滚动。文中未解释 订单执行优先级(例如若 T+1 开盘涨停买不进,如何处理?)。 |
| 跌停强平的具体触发条件 | “跌停封死 → T+1 集合竞价无条件强平” – 集合竞价的申报时间(9:15‑9:25)可能仍无法成交(封单过大)。没有备选方案(如连续竞价继续挂单)。 |
4. 绩效指标中缺少几个关键度量
-
信息比率 (IR) 已给出(ICIR +1.09),但缺少 Calmar 比率(return / max drawdown)和 月度胜率。对于月度调仓策略,月度正收益占比非常重要。
-
换手率 仅定性说“K=20 自然约束 ≤ 5%”,没有实际 backtest 的平均双边换手率数字。高换手会侵蚀净收益,尤其 top‑10 可能频繁更替。
-
不同市场环境下的分解:建议按大盘上涨/下跌/震荡期分别展示 alpha。当前 walk‑forward 按时间窗口,但未区分 regime(如 2025‑07 至 08 的高 Sharpe 是否对应大盘强 beta)。
5. 模型解释性不足
-
LightGBM 提供 feature importance,但文档未报告 哪些因子贡献最大。对于风控(如是否隐含市值、行业暴露)需更透明。建议输出 SHAP 值或部分依赖图,至少列出 top‑5 因子。
-
交互项
d_tradable_mv × r_spread_60d的引入理由合理(大小盘在不同动量环境下表现不同),但未验证其增量 IC 是否显著。
6. “禁止优化清单” 部分固化过快
-
例如 v6(scale_pos_weight + 5‑fold CV)失败可能因为 fold 1 数据不足,但 数据不足 是可解决的问题(例如改用时间序列交叉验证,或减少 fold 数)。永久禁止可能过早关闭了一条可行路径。
-
建议改为“当前版本不采用”而非“已证伪永久禁止”,留出未来数据积累后的重试空间。
实施建议优先级
| 优先级 | 行动项 | 负责人/时间 |
|---|---|---|
| P0 (上线前必须) | 实现 ST/*ST 实时剔除接口 | 数据工程 |
| P0 | 落地 ADV 容量计算与动态权重调整逻辑 | 执行层 |
| P0 | 跌停强平的分步处理(集合竞价失败后连续竞价继续挂单,并设置止损时限) | 风控模块 |
| P1 (模拟盘验证期) | 接入备选数据源对 PE/PB 做交叉校验,监控偏差 | 数据质量 |
| P1 | 计算并报告月度胜率、Calmar、换手率,按市场 regime 分解绩效 | 回测增强 |
| P1 | 输出 top‑5 因子重要性,验证交互项贡献 | 模型分析 |
| P2 (后续迭代) | 定期(每月)监控特征分布漂移(PSI)和 AUC 衰减,设置预警阈值 | 监控系统 |
| P2 | 重审 v6 路线(时间序列 CV + 更宽训练窗),作为 v8 候选 | 研究 |
结论
该策略在方法论、实验验证、生产约束三方面均达到较高成熟度,主要风险集中在实盘执行细节(ST 剔除、ADV 容量、跌停处理)和单一数据源依赖。建议先完成 P0 项,随后进行 1‑2 个月模拟盘(纸面跟踪) 以暴露执行偏差,再逐步进实盘。当前文档可作为正式策略规范(SOP)使用,但需补充上述缺失的执行细则后,方可通过最终评审。
项目方核实情况(2026-06-14)
针对"风险与待改进项"章节逐条核实,标注 ✅ 已覆盖 / 🔧 待补 / 🚧 需工程。核实方法:grep 代码 + 读报告。
一、已覆盖项(评估文档判断准确)
| 评估点 | 核实位置 | 状态 |
|---|---|---|
| 生存者偏差识别 | Doubles 策略总览.md §四 显式警告 "Alpha = Top - Bench 才是真实信号" |
✅ |
| Horizon mismatch 诊断 | K=1/5/10/20 全扫描, K-day 扫描表已锁定 K=20 | ✅ |
| Walk-forward 稳定性 | 4 窗口 expanding retrain, 全正 (Min +0.76, Max +4.11) | ✅ |
| Soft vs strict sector cap | 6 配置对比已固化, strict 杀 alpha -1.01 | ✅ |
| RD-Agent 仓库分离 | doubles (数据+模型) / RD-Agent (prompt+实验) HDF5 状态隔离 | ✅ |
二、待补项(已确认代码缺失,可立即修复)
2026-06-14 更新:5 条待补项 全部已修复 ✅,结果如下。修复脚本:
backtest_enhanced_metrics.py,输出:factor_output_enhanced/enhanced_metrics.json。
| # | 评估项 | 状态 | 修复后结果 |
|---|---|---|---|
| 1 | Calmar 比率 + 月度胜率 | ✅ 已修复 | Calmar = +3.71 (Alpha: 年化 +29.43% / MaxDD -7.94%), 月度胜率 = 80.0% (10 月中 8 月正收益) |
| 2 | 实际换手率数字 | ✅ 已修复 | K=20 blended weights avg 4.03%/day 双边, max 100% (首日建仓), avg 28.5 只活跃 |
| 3 | Regime 分解 Sharpe | ✅ 已修复 | High regime (>median -0.099) Sharpe +2.22 vs Low regime +1.67, Δ +0.55 — alpha 在 spread 高时更强(符合 v5 设计假设,非纯 beta) |
| 4 | v5 Top-5 feature importance | ✅ 已修复 | d_pe (18.1%), d_peg (17.1%), d_tradable_mv (11.7%), d_pb (8.5%), d_pcf (8.4%); 交互项 r_spread_60d #8 (4.1%) + x_mv_x_spread #10 (3.2%) |
| 5 | v6/v7 措辞软化 | ✅ 已修复 | Doubles 策略总览.md §六 改为"不采用清单(当前版本)",v6/v7 标 ⏸ 待重审 |
判定:3 ✅ + 1 ⚠️(regime delta 偏大但与 v5 设计一致,交互项贡献实证 +7.3% gain,证明 alpha 非纯 beta 暴露)。
三、需 P0 工程项(超出 factor_mining 范畴)
| 评估项 | 阻塞原因 | 责任方 |
|---|---|---|
| 🚧 ST/*ST 实时剔除接口 | 需要外部标记数据源(Wind/聚宽/Tushare) | 数据工程 |
| 🚧 ADV 容量约束盘中计算 | 需要实时 OHLCV 行情接入 | 执行层 |
| 🚧 跌停强平分步逻辑(集合竞价 → 连续竞价) | 需要 OMS 配合 + 风控规则 | 风控模块 |
四、中期可探索
- PSI 月度监控(Population Stability Index)— 接 walk-forward 框架, 每月特征漂移预警, ~1 小时
- v6 时间序列 CV 重审 — 用
TimeSeriesSplit替代 K-fold, fold 1 数据不足问题可解, 作为 v8 候选, ~半天
五、立即执行优先级
| 优先级 | 任务 | 工作量 | 价值 | 状态 |
|---|---|---|---|---|
| P0 (本周) | #1 + #2 + #3 + #4 合并到一个增强 backtest 脚本 | ~45 min | 月度调仓策略必备指标补齐 | ✅ 已完成 (2026-06-14) |
| P0 (本周) | #5 改 Doubles 策略总览.md 措辞 |
~5 min | 不永久关闭 v6/v7 重审路径 | ✅ 已完成 (2026-06-14) |
| P1 (模拟盘期) | PSI 月度监控接入 walk-forward | ~1 h | 实盘漂移预警 | ✅ 已完成 (2026-06-14) |
| P2 (后续迭代) | v6 时间序列 CV 重审 (v8 候选) | ~半天 | 数据积累后重试 | ⏳ 待办 |
六、核实结论
评估文档(§风险与待改进项)的 6 条判断 全部成立,无高估或误判。其中:
- 5 条已覆盖 —
Doubles 策略总览.md已显式记录或代码已实现 - 5 条待补 → 全部已修复 ✅ — 见 §二 表格 (2026-06-14 完成)
- 3 条 P0 工程 — 数据源/执行层/风控模块的接口问题,需跨团队协调
当前状态:doubles 项目已从"研究阶段"过渡到"准实盘 SOP"。配合 Doubles 策略总览.md,可作为正式策略规范使用,待 P0 工程三项接入后通过最终评审。下一步建议:执行 P1 PSI 月度监控,然后进入 1-2 个月模拟盘验证期。
七、Alpha 真实性核查(2026-06-14,关键发现)
2026-06-14 跑真实 benchmark 对比 + 白噪测试,颠覆性修正策略定位。
真实 benchmark 对比(5 个基准)
| Benchmark | Bench Sharpe | Bench Total | Alpha Sharpe | 判定 |
|---|---|---|---|---|
| 660等权(生存者偏差) | +3.98 | +26.10% | +1.94 | ❌ 虚假基准(生存者偏差) |
| 沪深300 | +1.86 | +51.78% | -0.11 | ❌ 跑输大盘 |
| 中证500(最公平) | +1.91 | +57.58% | -0.25 | ❌ 跑输 |
| 创业板指 | +2.65 | +64.32% | -0.44 | ❌ 跑输 |
| 国证2000(中小盘) | +2.22 | +33.18% | +0.96 | ✅ 真实 alpha |
白噪测试(100 次随机 pred, 同一 backtest pipeline)
| 指标 | v5 | Random mean | p-value | 判定 |
|---|---|---|---|---|
| Top Sharpe | +4.03 | +3.23 | 4.0% | ✅ 框架无 bug |
| Alpha vs 660等权 | +1.94 | -1.09 | 0.0% | ✅ 极显著 |
| Alpha vs 国证2000 | +0.96 | -1.04 | 0.0% | ✅ 真实 stock selection alpha |
核心发现
- v5 alpha 真实存在(白噪测试 p < 5%,框架无 look-ahead bias)
- v5 alpha 主要来自 universe 选择:660 翻倍股池本身在 2025-05~2026-01 是大风口(A 股上涨期)
- 真实 stock selection alpha ≈ +0.96 Sharpe(vs 国证2000 中小盘宽基),不是 +1.94
- Random Top Sharpe 平均 +3.23:660 universe 在该期间就是 high-beta 风口,任何选股都有 alpha vs 大盘
策略定位修正
❌ 不能宣称 "Alpha Sharpe +1.94" 作为实盘 alpha(相对生存者偏差 bench) ✅ 策略真实定位是 两阶段 stock picker: - ① universe 选择:从全市场筛 660 只翻倍股(universe alpha vs 大盘) - ② universe 内 selection:v5 LightGBM 选 top-10(stock selection alpha vs 国证2000 ≈ +0.96)
实盘含义
- 不要用 v5 替代大盘配置——直接买 CSI500 更好(Bench Sharpe +1.91)
- 当前
production_signals_v5/daily_target_weights.h5是"660 universe 内的相对权重",不能直接对接大盘 OMS - 真实可期待 alpha ≈ +0.96 Sharpe(vs 中小盘宽基),不是 +1.94
下一步
- A1 重定位(✅ 已完成 2026-06-15,假设证伪):在国证2000 universe 上重训 v5 → Alpha −0.60 ❌。核心发现:v5 的 +0.96 alpha 不来自国证2000 内部选股,而来自 389 只 660∖国证2000 的小盘翻倍股(未进指数)。详见 §八
- A2 简化版(已完成):当前 v5 信号定位为"660 universe 内的相对权重",benchmark 改为国证2000
- D 文档同步(已完成):
Doubles 策略总览.md§四 加真实 alpha 定位子章节
八、A1 国证2000 Overlay 结果(2026-06-15)
假设证伪:stock selection alpha 不能脱离 660 universe 在国证2000 上直接复现。但揭示了 alpha 真正来源。
执行限制
v5 factors 只覆盖 660 翻倍股,无法在完整 2000 只国证2000 上重训。实际测试 = 271 只(660 ∩ 国证2000)子集,不是完整 A1。
结果
| Config | Universe | n_inst | TRAIN AUC | OOS AUC | OOS IC | Alpha vs 399303 |
|---|---|---|---|---|---|---|
| v5 原版 | 660 | 660 | 0.91 | 0.74 | +0.044 | +0.96 ✅ |
| v5 GZH2000 子集 | 271 | 271 | 0.91 | 0.56 | −0.002 | −0.60 ❌ |
关键发现 — alpha 真正来源
660 universe = 271 大盘翻倍股(已进国证2000) → 内部 ranking alpha ≈ -0.60
+ 389 小盘翻倍股(未进国证2000) → 隐含 alpha ≈ +2.0+ (vs 国证2000)
= +0.96 blended alpha
v5 的 +0.96 alpha 不来自国证2000 内部选股,而来自 389 只未进国证2000 的小盘翻倍股(规模太小或刚翻倍未被指数纳入)。
实盘含义
- ❌ 不能把 v5 移植到国证2000 — alpha 源头在 index 之外
- ✅ 保留 660 universe — alpha 主要来自 universe selection 步骤 + 389 子集 stock selection
- ⚠️ 实盘容量警告 — 389 小盘股流动性差,必须接入 ADV 容量约束(P0 工程项)
- ⚠️ 生存者偏差仍在 — 每月 expanding retrain + PSI 监控是必需的
A1 任务关闭 — 转向实盘工程
| 下一步 | 优先级 | 工作量 |
|---|---|---|
| ST/*ST 实时剔除接口 | P0 | 数据工程 |
| ADV 容量约束盘中计算 | P0 | 执行层 |
| 跌停强平分步逻辑 | P0 | 风控模块 |
| 模拟盘 1-2 个月验证 | P1 | 跟踪 |
| v6 时间序列 CV 重审(v8 候选) | P2 | ~半天 |
九、P0 实盘工程三项落地结果(2026-06-15)
脚本:
backtest_production_constrained.py,输出:factor_output_constrained/constrained_backtest.json
6 配置对比
| Config | Top Sharpe | Alpha vs 国证2000 | MaxDD | 判定 |
|---|---|---|---|---|
| C1 baseline (无约束) | +4.03 | +0.96 | −12.0% | 理论 alpha |
| C2 +ST/*ST 剔除 | +4.25 | +1.11 | −9.3% | ✅ +0.15 改善 |
| C3 +ADV cap (AUM=1亿) | +2.11 | −1.77 | −32.2% | ❌ 翻负 |
| C4 +ST +ADV cap | +1.96 | −1.80 | −32.2% | ❌ |
| C5 +ADV filter (≥100万) | +1.69 | −0.72 | −21.2% | ❌ |
| C6 +ST +ADV filter | +1.60 | −0.88 | −19.9% | ❌ |
P0-1 ST/*ST 剔除 ✅ 通过
- 数据源:MySQL
stock_fundamentals.name(snapshot,含 ST/*ST 标记) - 实现:日级 universe 过滤,从 660 中剔除 30 只 ST/*ST
- ⚠️ Look-ahead bias:snapshot 是 2026-06 当前状态,backtest 期实际 ST 状态可能不同
- 效果:Alpha +0.15 Sharpe,MaxDD 改善 -2.8%
- 生产接入(2026-06-15):
production_signal_generator.py已加APPLY_ST_FILTER=True开关,输出到production_signals_v5_st/。原版 selections 含 9 只 ST,新版 0 只,Alpha Sharpe +1.94 → +2.13(vs 660 等权 bench)。
P0-2 ADV 容量约束 ❌ 1 亿 AUM 不可行
- 数据源:qlib
$volume × $close→ 20d 滚动 ADV(金额) - 容量评估:单股极低 ADV 6.3 万元(异常),中位 ADV 184 万元
- 关键发现:AUM=1 亿时单股仓位 500 万元,多数股票 ADV×20% < 500 万,cap 触发后权重错配,Alpha 从 +0.96 翻负到 -1.77
- 真实容量上限:v5 660 universe 实盘容量 ≈ 2000-3000 万元(中位 ADV 假设理论值 7400 万,安全边界实际 3000 万)
- 印证 A1 发现:v5 alpha 主要来自 389 小盘翻倍股,流动性约束是硬瓶颈
P0-3 跌停强平 ⏳ 写 spec(OMS 范畴)
详见 §十。
实盘可行性结论
| 场景 | 可行性 | 说明 |
|---|---|---|
| 个人投资者 < 3000 万 | ✅ 可行 | ST 剔除后 Alpha +1.11,ADV 不构成瓶颈 |
| 个人投资者 3000 万-1 亿 | ⚠️ 部分可行 | 需降 K(如 K=10)或加 ADV universe filter(alpha 衰减到 -0.72) |
| 机构 > 1 亿 | ❌ 不可行 | ADV cap 让 alpha 翻负,需重新设计策略 |
十、P0-3 跌停强平 Spec(OMS 工程规范)
触发场景
持仓股在 T 日 09:25 集合竞价显示跌停封单(卖一档挂单量 > 流通盘 0.5% 或 > 5 万手)。
数据契约
| 数据源 | 字段 | 频率 | 用途 |
|---|---|---|---|
| 实时行情 | ask1_price, ask1_volume, bid1_price, bid1_volume | Tick | 跌停封单检测 |
| 持仓表 | instrument, shares, avg_cost, K_entry_date | 日度 | 识别需强平的 K-portfolio |
| ST 标记 | is_st (来自 stock_fundamentals.name snapshot) | 日度 | ST 跌停阈值 ±5% vs 普通 ±10% |
分步处理流程
T 日 09:25 集合竞价:
Step 1: 扫描持仓股, 检测跌停封单 (ask1_price ≤ pre_close × (1 - limit_pct))
limit_pct = 0.05 (ST) / 0.10 (普通) / 0.20 (科创板/创业板)
Step 2: 若封单量 > 流通盘 0.5%:
→ 标记为 "强平候选"
→ 申报卖出 (与开盘价 100% 撮合)
Step 3: 09:25-09:30 集合竞价结果:
→ 成交: 释放 K-portfolio 槽位
→ 未成交 (封单过大): 进入连续竞价
Step 4: 09:30-11:30/13:00-15:00 连续竞价:
→ 挂单价格 = 当前买一价 + 0.01 (确保成交)
→ 重新挂单频率: 每 30 秒检查一次
→ 14:57 仍未成交: 进入收盘集合竞价
Step 5: 14:57-15:00 收盘集合竞价:
→ 申报卖出 (与收盘价 100% 撮合)
→ 15:00 仍未成交: T+1 日重复 Step 1
Step 6 (T+1 日): 同 Step 1-5, 直到全部强平完成
风控约束
- 强平不撤单:一旦标记强平,禁止转回持有(避免情绪化决策)
- 跌停封单监控:09:25 封单量 > 5 万手且 > 流通盘 0.5% → 自动触发
- K-portfolio 占位:强平期间该 K 槽位禁用,不重复选股(避免重复建仓)
- 告警机制:连续 3 日跌停未成交 → 邮件/短信告警,转人工
接口规范
| 接口 | 方法 | 输入 | 输出 |
|---|---|---|---|
check_limit_down(instrument, pre_close, ask1) |
同步 | 跌停状态 + 封单量 | bool (是否需强平) |
submit_force_close(instrument, shares, reason) |
异步 | 卖出订单 | order_id |
get_force_close_status(order_id) |
同步 | order_id | status (filled/partial/cancelled) |
责任分工
| 模块 | 责任方 | 工作量 |
|---|---|---|
| 实时行情接入 | 数据工程 | 1 周 |
| 跌停封单检测 | 数据工程 | 3 天 |
| 强平订单管理 | 执行层 | 1 周 |
| K-portfolio 槽位管理 | 因子工程 | 3 天 |
| 告警 + 人工 fallback | 风控模块 | 3 天 |
| 合计 | ~3 周 |
测试要求
- 历史回放:用 2015 股灾 + 2024-01 雪球 + 2025-04 关税战数据回放跌停场景
- 模拟盘:1-2 个月观察真实跌停频率与强平成功率
- 上线前必过:连续 5 个真实跌停案例全部成功强平