框架

回测审核清单 · Backtest Pitfalls(研究层)

**结论:engine_v1 全项符合(尾部指标列为存疑)。

回测 · 资产·机制 · 回测/回测审核清单_backtest_pitfalls.md · 18027 B

回测审核清单 · Backtest Pitfalls(研究层)

这是什么:把 ML4T 教材(machine-learning-for-trading-main)「回测陷阱」相关章节的操作性要求,

转成本库可执行的审核清单——每条都给「可追溯出处 / 表现 / 本库自查命令或字段 / 三态判定」。

第 15/16 条适用范围(2026-10-02 补):第 15 条仅对使用状态空间/卡尔曼类滤波器的新产出生效;

第 16 条仅对新增/修改阈值闸、状态闸的新产出生效(现有闸门为文档定义、门槛明确,不在此列)。

本库 engine_v1(ADX/ER/Hurst 势态)、engine_multi(矩估计)、portfolio.py(60 周样本 std)均不使用此类滤波器,故 §二 的三处机械自查不受第 15 条影响(维持原判:1 违背 + 3 存疑)。

怎么用:任何回测产出(新引擎、新表、新图)对外引用前过一遍主表。判定为"违背"的不许在审核中就地修改被审对象,只登记(修复另立任务)。

口径:本清单只描述审核动作,不定义数字口径——数字口径以 框架/数据口径定义 与 回测/perf_audit/README 为准(年化一律 bar 数 / ppy)。

出处格式:来源:16章 §16.7 / notebook 12_dsr_validation(章 = 教材章目录;§ = README 小节;notebook = .py/.ipynb 文件名,可 ls 复核)。


一、清单主表(16 条 · 每条含出处与三态判定)

「本库判定」是对本库现有三处产出(engine_v1 / engine_multi / perf_audit)的汇总三态,明细见 §二。

#陷阱来源(可追溯出处)表现(怎么露馅)本库自查命令 / 字段本库判定
1前视偏差(look-ahead)16章 §16.2 / notebook 01_backtest_first_principles(next-open fill);02章 §2.5 / 14_point_in_time_validation信号用了 t 日之后才知道的信息;重采样把期末信息塞到 tgrep -n "shift(|t+1 日生效|无前视" 回测/engine_*/**.py符合
2幸存者偏差02章 §2.5 / notebook 15_survivorship_bias_detection、01_us_equities_eda标的池只含"活到今天"的品种;退市/换合约被静默删除grep -n "ASSET|资产池|起始年" 回测/engine_multi/*.py;池切换点须显式符合(低风险:标的为指数/现货/ETF)
3数据窥探 / 多重检验16章 §16.7 / notebook 11_sharpe_ratio_inference、12_dsr_validation、13_ras_protocol;07章 §7.4 / 07_multiple_testing试了很多参数只报最好那个;把"选出来的夏普"当"真实夏普"ls 回测/engine_v1/wf/;python3 -c "import json;print(json.load(open('回测/engine_v1/wf/oos_summary.json')))"存疑(engine_v1 有折;engine_multi 无滚动 OOS 记账)
4交易成本与滑点(含容量/盈亏平衡换手)16章 §16.6 / notebook 14_cost_sensitivity;18章 §18.2 / §18.4 / 12_commission_slippage_comparison、03_market_impact_calibration用 0 成本或只算佣金;换手率当成本;无盈亏平衡点grep -n "cost_bps|6bps" 回测/engine_*/**.py;tables/D_再平衡x成本矩阵.csv符合
5样本外与参数稳定性16章 §16.7 / 11_sharpe_ratio_inference;06章 / 02_cv_foundations;11章 / 04_nested_cv_hpo全样本调参;OOS 与 IS 差距不报;参数对邻域极敏感ls 回测/engine_v1/wf/(fold_0..5 + oos_summary)存疑(engine_multi 阶段 1 未做滚动 OOS)
6复权 / 分红处理02章 §2.3 / notebook 02_corporate_actions、06_futures_continuous(Panama/ratio 拼接)复权价与真实收盘混用;债券用复权价 → 波动系统性低估grep -rn "fqt|复权|adj" 回测/ 数据/;框架/数据口径定义 §9.5符合(债券腿 v5.2 已改未复权真实收盘)
7频率与年化口径一致性16章 §16.5 / notebook 09_performance_reporting、07_engine_divergence_anatomy(§16.3)年化用日历跨度、波动用 bar 数;两处 ppy 不一致grep -n "ppy|365.25|years =" 回测/engine_multi/*.py;回测/perf_audit/README §四违背 → 已修复(v5.3.2)(engine_multi L240 日历跨度 → bar/ppy)
8单一资产 beta 与分散幻觉17章 §17.3 / §17.4;01章 §1.4 / factor_regimes把"分散 + beta 选择"当"资产类别分散";两腿高度相关仍称分散tables/E_分段相关系数.csv;optimization/报告/决策备忘_核心底仓是否改为金加纳指_2026-09-27存疑(权益腿仅 NDX;换腿仅 2016 起)
9执行时序与成交价16章 §16.2 / 01_backtest_first_principles;§16.3 / 07_engine_divergence_anatomy(逐字段分解成交)用收盘价成交却用收盘价定信号;市价单假设无限流动性grep -n "next|成交|fill|开盘" 回测/;grep -n "shift(1)" 回测/engine_*/**.py符合(t 收盘定信号 → t+1 生效)
10现金约束与隐性杠杆16章 §16.2 / 01_backtest_first_principles(cash constraint、next-open 扣费)权重和 > 1 被当满仓;负现金不拦截grep -n "1/n|1/3|avg_exposure" 回测/engine_multi/*.py;tables/C_同风险对比.csv符合(曾修 1/3→1/n,敞口恒 1.000)
11指标定义分歧16章 §16.5 / 09_performance_reporting;本库 回测/perf_audit/README §三索提诺/卡玛两边定义不同却直接比大小;卡玛漏传 periods 被高估grep -n "sortino|calmar|periods=" 回测/perf_audit/crosscheck_quantstats.py符合(perf_audit 为仲裁基准)
12制度切片 / 事后窗口16章 §16.6 / notebook 10_regime_backtest_analysis;01章 §1.4子区间"恰好都赢"是用事后挑的窗口;把 regime 当择时信号grep -n "子区间|regime|窗口" 回测/engine_multi/*.py符合(regime 只作风险透镜)
13尾部风险与回撤路径(只报波动/夏普)19章 §19.4(drawdowns / path risk / time-to-recovery)/ notebook 01_var_cvar、02_exit_strategies;§19.6 / 06_stress_testing只报波动与夏普,不报 VaR/CVaR、回撤时长与恢复期;危机期不单独看grep -rn "VaR|CVaR|underwater|水下|恢复" 回测/*/**.py存疑(有 最大回撤,但无 VaR/CVaR/回撤时长系统产出)
14风控自适应泄漏19章 §19.7 / notebook 10_ml4t_backtest_risk_demo、07_drift_detection波动目标/止损/仓位上限用了未来信息;自适应参数在 IS 上挑grep -n "vol_target|rolling(" 回测/engine_v1/*.py符合(vol_target 用 sigma60 = rolling(60).std(),无前视)
15似然退化 / 方差参数弱识别 → 边界解(v1.0,2026-10-02 新增)本库实测(回测/kalman/报告_卡尔曼嵌入评估_2026-10-02 §五/§七);ML4T §9.2 原话「the bound is the only thing standing between this filter and the identity function」状态空间模型的 MLE 看起来收敛(success=True、无 traceback),但解落在优化边界上:所有重估窗的 logθ 100% 钉在下界、参数漂移 max/min = 1.000、std(标准化残差)≈0.18(理想 ≈1);放松边界后 nll 继续下降(−526.66 → −1356.81)= 似然无上界python3 回测/kalman/kalman_selftest.py --only 3(重估逐条日志);python3 回测/kalman/kalman_report.py 表 2/表 4;放松边界诊断 kf_bounds_diag.py不适用(本库 engine_v1/engine_multi/portfolio.py 均未使用状态空间/卡尔曼类滤波器 ⇒ §二 三处自查不受影响);对使用此类滤波器的新产出判 违背(不可部署)
16阈值闸 / 状态闸的工程校验(v1.0,2026-10-02 新增)本轮实测(回测/kalman/报告_卡尔曼嵌入评估_2026-10-02 §七·补);方法论判据 B任何"阈值触发"的闸门上线前必须验三件事:① 被比较的量的量纲与分位(是否无量纲、是否近似常量);② 触发率合理(不得 ≈0% 或 ≈80%——两个极端都说明阈值语义失效);③ 闸门输出真能进入决策链(迟滞/状态机是否会把它吞掉)。反例(本库实测):|kf_innovation| ≥ 3 在残差 std≈0.18 上触发 0/104 = 0%;kf_uncertainty > 扩张 90% 分位 在近似常量(折内 p0=p90=0.00423)上恒定触发 76%;两者置「无法评估」后又被引擎 l1_cand != "无法评估" 规则在 l1_confirm_days=2 的折里静默吞掉python3 回测/kalman/v2_gate_diag.py(逐折两条闸条数 + 量纲分位;输出留档 cache/v2_gate_diag.log)对已上线闸门不适用(本库 engine_v1 现有闸门为 L0 阈值/L1 迟滞/L2 门控,均为文档定义且量化门槛明确 ⇒ §二 三处自查不受影响);对新产出判:未过三验即 违背(闸门语义未证)

二、本库三处产出 · 机械自查(2026-09-27 实测)

规则:发现"违背"不许在本次审核中修改被审对象,只登记;修复必须另立任务(唯一例外:engine_multi 年化口径由用户单独授权,见 §三/P3-③)。

① 回测/engine_v1/(单资产四因子择时引擎)

#陷阱判定证据行
1前视偏差符合duckerry_backtest.py:12「只用过去信息(信号 t 日收盘生成,t+1 日生效),无前视偏差」;:747 主循环同声明
4成本与滑点符合README.md:52「成本 6bps 单边(1bp 佣金 + 5bps 滑点);核心底仓不产生换手成本,只对卫星换手计费」
5样本外/稳定性符合ls wf/ → fold_0..5.json + oos_equity.csv + oos_summary.json(滚动 walk-forward,参数只在训练段择优)
7年化口径符合用 bar/ppy;perf_audit 实测与 quantstats 相对差 0.08%(= round(4) 量化)
11指标定义符合索提诺/卡玛定义已由 perf_audit 定位并记录
13尾部/路径风险存疑有 最大回撤_策略(duckerry_backtest.py:1042),但无 VaR/CVaR/回撤时长产出
14风控自适应泄漏符合sigma60 = gold_ret.rolling(60, min_periods=40).std()(duckerry_backtest.py:361),滚动窗口无前视
8分散幻觉不适用单资产卫星(其"无 alpha"结论是 §8 的反面证据:等敞口对比三项全输)

结论:engine_v1 全项符合(尾部指标列为存疑)。 其 README 已自述"跑输被动持有"。

② 回测/engine_multi/(多资产组合,阶段 1)

#陷阱判定证据行
1前视偏差符合设计原则 3「无前视:t 期收盘算权重 → t+1 生效;成本在调仓当刻计」
4成本与滑点符合tables/D_再平衡x成本矩阵.csv 存在(成本多点扫描)
5样本外/稳定性存疑tables/B_子区间.csv / B2_子区间_对齐口径.csv 是子区间切片,非滚动 walk-forward;阶段 1 未做 OOS(如实登记)
7年化口径违背 → 已修复(v5.3.2)原 multiasset_backtest.py:240 years = (idx[-1]-idx[0]).days/365.25(日历跨度)→ 与 engine_v1/quantstats 的 bar/ppy 差 0.36%;P3-③ 已统一为 bar/ppy(复用 infer_ppy),重跑 perf_audit 实测相对差 0.36% → 0.05%
10现金约束/隐性杠杆符合曾修「恒定配比 1/N」硬编码 1/3 → 1/n,现平均敞口恒 1.000;avg_exposure 写入表
8分散幻觉存疑tables/E_分段相关系数.csv 有腿间相关,但权益腿仅 NDX(单一国家、高度集中科技巨头)→ 备忘 §六已警告:赢的子区间恰是纳指大牛市 = beta 选择,非资产类别分散;换腿稳健性仅 2016 起(弱检验)
2幸存者偏差符合(低风险)标的为指数/现货/ETF,无个股退市;池切换(WTI 2016 起等)显式记录

结论:engine_multi 1 处违背(年化口径,已修复(v5.3.2))+ 2 处存疑(无滚动 OOS;权益腿单一 = beta 选择)。

③ 回测/perf_audit/(绩效指标交叉验证,研究层只读审计)

#陷阱判定证据行
11指标定义分歧符合crosscheck_quantstats.py:289 记录 quantstats 索提诺 dn = x[x<0].std() 定义差异;卡玛漏传 periods 已于 v1.1 修复
7年化口径符合(且为仲裁源)README.md §四 已知口径;实测 quantstats.stats.cagr 用 years = returns.count()/periods = bar/ppy,与 engine_v1 同源
3多重检验不适用该目录是审计工具,不是策略搜索

结论:perf_audit 全项符合,并作为本库「年化/卡玛/索提诺」口径的仲裁基准。


三、结论

  • 第 15 条(2026-10-02 新增):对本项目新增的卡尔曼模块(回测/kalman/README)判 违背(不可部署)——

重估窗 100% 钉在事前边界、参数漂移 1.000、似然随放松边界继续下降;该模块未接入生产,结论「无改善 → 不引入」。 本条不改变 §二 三处产出的判定。

  • 第 16 条(2026-10-02 新增):阈值闸工程校验(量纲分位 / 触发率不得 ≈0% 或 ≈80% / 输出须真能进入决策链)。

本轮实测反例:innovation 闸 0%、uncertainty 闸恒定 76%、confirm=2 时被迟滞规则吞掉;本轮未修(先解决第 15 条的退化,再谈闸门)。

  • 三处产出共发现:1 处违背(engine_multi 年化用日历跨度)、3 处存疑(engine_multi 无滚动 OOS;engine_multi 权益腿单一 = beta 选择;engine_v1 无 VaR/CVaR/回撤时长),其余全部符合。
  • 违背项的修复不在本审核动作内(未改被审对象);engine_multi 口径统一由用户单独授权执行(v5.3.2 / P3-③),修复后其年化与 quantstats 相对差实测 0.36% → 0.05%(2026-09-27;残留 0.05% = len(eq) vs returns.count() 的 1 个观测之差)。
  • 诚实口径:本清单是审核脚手架,不是"通过即安全"的证书。ML4T §16.1 原话——回测不是"策略有效"的证明,而是"它能否在现实假设下被证伪"的结构化尝试。
  • 未完成 / 下一轮:[待办] 为 engine_multi 补滚动 walk-forward(补 #5 存疑);[待办] 补长历史非权益分散腿数据后重做换腿稳健性(补 #8 存疑);[待办] 补 VaR/CVaR/回撤时长(补 #13 存疑);[候选] PyPortfolioOpt risk_models.py 收缩估计评估(用户已列为下一轮)。

四、出处索引(本次只读材料 → 用到的位置)

材料用到的清单条目
01_process_is_edge/README §1.4(regime 是风险透镜,非择时信号)#8 #12
16_strategy_simulation/README §16.1(回测即证伪)/ §16.2(协议)/ §16.3(引擎对比)/ §16.5(指标)/ §16.6(经济价值)/ §16.7(回测过拟合)全表
16.../01_backtest_first_principles(signal timing、next-open fill、cash constraint)#1 #9 #10
16.../07_engine_divergence_anatomy(逐字段分解引擎分歧)#7 #9
16.../10_regime_backtest_analysis(事前可观测状态切片)#12
16.../11_sharpe_ratio_inference(夏普抽样分布 / 置信区间)#3 #5
16.../12_dsr_validation(Deflated Sharpe / 选择偏差)#3
16.../14_cost_sensitivity(成本网格 / 盈亏平衡费)#4
18_transaction_costs/README §18.2(成本分类)/ §18.3(微观结构制度)/ §18.4(基线成本模型)/ §18.5–18.6(执行算法 / Almgren-Chriss)#4 #9
19_risk_management/README §19.3(VaR/CVaR)/ §19.4(回撤与路径风险)/ §19.6(压力测试)/ §19.7(无泄漏自适应风控)/ §19.8(kill switch)#13 #14
17_portfolio_construction/README §17.3(分散/集中度)/ §17.4(简单基准不是稻草人)#8
02_financial_data_universe/README §2.3 / §2.5(复权 / PIT / 幸存者)#1 #2 #6
07_defining_the_learning_task/README §7.4(搜索记账与多重检验)#3
09_model_based_features/04_kalman_filter.py §9.2(只读参考;原文自述边界是拦住滤波器退化为恒等映射的唯一屏障)+本库实测#15
本轮闸门机制诊断(回测/kalman/v2_gate_diag.py,2026-10-02)+方法论判据 B#16