框架

四因子框架回测引擎 v2.0 · 报告(2026-09-27)

核心底仓永久持有黄金不择时;

optimization · 资产·机制 · optimization/报告/四因子框架回测引擎v2.0_报告_2026-09-27.md · 17533 B

四因子框架回测引擎 v2.0 · 报告(2026-09-27)

一句话结论:把四因子框架封装成可运行回测引擎并按三条设计指令(降频 / 宏观否决权 / 核心卫星)重构后,

样本外夏普由 0.286 提升到 0.754(框架"降频"判断正确),

但在等敞口对比下,自适应卫星在收益、夏普、回撤三项上全部输给"同平均敞口的被动持有" ——

卫星没有 alpha。因此本文的建议是:不要再调这个模型的参数,应该换问题(见 §六、§七)。


一、交付物

1.1 引擎(回测/engine_v1/,独立可运行)

文件说明
duckerry_backtest.py主引擎(约 1490 行):L0–L4 决策栈 + 四因子 A/B/C + 降频 + 核心卫星 + 否决权 + walk-forward
plot_compare.py独立绘图脚本(从已落盘 equity.csv 出图,规避 iSH 长进程被 kill)
README.md使用说明与口径边界 → 回测/engine_v1/README

1.2 资产曲线与回测数据(已随引擎入库)

文件内容
engine_v1/compare.csv六策略横向对比表(实测值)
engine_v1/compare_curve.png六策略净值对比图(对数轴)
engine_v1/curves/{BuyHold,Cash6040,D-L0L2VT,W-Adp60,W-Adp60NoEv,M-Adp60}.csv各策略净值曲线(date, equity, dd, sat_pos),可直接画图
engine_v1/wf/oos_equity.csv样本外 walk-forward 拼接净值(626 条周线,2014-01→2025-12)
engine_v1/wf/oos_summary.json样本外汇总指标
engine_v1/wf/fold_0..5.json各折择优参数、网格前四、测试段表现
engine_v1/metrics_weekly_core60.json主推配置的完整指标 + 实际生效 config

数据口径:回测口径 ≠ 实盘 ≠ 生产管线(数据/panel.csv + paper_engine.py),数字不可互相引用。


二、三条设计指令与实现

指令 1:强制降频(不用日频)

  • --freq D|W|M;重采样发生在指标计算之前,所有周期长度以 bar 为单位(5 bar = 5 周)
  • 日频校准阈值按 √(252/ppy) 自动缩放(周 ×2.20、月 ×4.58),覆盖 L0-1/L0-2/L0-3 与 L1 强弱档
  • 年化口径随频率切换(252 / 52 / 12),夏普与波动不再误用日频因子
  • 无前视:bar 值在周期末才可知,信号在下一 bar 生效

指令 2:宏观主观否决权

否决来源口径
L0 断路金/美同跌、VIX 跳升、股债金三杀(阈值已按频率缩放)
分布型极端日|收益| ≥ veto_z × σ(默认 2.5σ,即"−3σ 日"级别)
重大宏观事件规则化「非农」= 每月第一个周五;--event-calendar 可追加 FOMC/CPI
L0 警告默认不否决,--veto-warn 打开
  • --veto-mode flat(默认):否决 → 卫星直接清仓进现金
  • --veto-mode noentry:只禁止新开仓
  • --veto-scope auto:事件否决只在 D/W 生效,月频自动禁用(见 §五 P2-a)

指令 3:核心 60% + 卫星 40%

总仓位 = core_pct + (1 − core_pct) × 卫星仓位
成本   = (1 − core_pct) × |Δ卫星仓位| × 单边成本      # 只有卫星换手计费

核心底仓永久持有黄金不择时;卫星在趋势态(ADX(14)≥20 且 Kaufman 效率比 ER(20)≥0.30,可选 Hurst≥0.5)顺势做多,在震荡态做超卖均值回归。


三、实测结果(2006-01-03 → 2026-09-25,含 6bps 单边成本)

3.1 策略横向对比

策略总收益年化波动夏普最大回撤卡玛交易
买入持有(100% 金)703.5%10.63%18.2%0.646−44.6%0.2381
被动 60/40(金/现金)279.3%6.68%10.9%0.646−28.7%0.2330
日频·L0–L2 + 波动目标77.1%2.81%7.3%0.418−17.9%0.157894
周频·自适应 + 核心60%263.0%6.39%12.6%0.556−33.0%0.194208
周频·同上但无事件否决320.2%7.14%13.5%0.579−33.6%0.213126
月频·自适应 + 核心60%339.9%7.40%14.7%0.562−39.7%0.18637

3.2 ⭐ 等敞口公平对比(最关键)

卫星版本平均敞口 > 60%,必须与同平均敞口的被动组合比:

变体均敞口收益夏普回撤等敞口被动 收益 / 夏普 / 回撤
周频·自适应+核心60%(事件否决)68.4%263.0%0.556−33.0%345.1% / 0.644 / −31.5%
周频·自适应+核心60%(无事件否决)72.8%320.2%0.579−33.6%383.9% / 0.644 / −33.2%
月频·自适应+核心60%75.3%339.9%0.562−39.7%383.9% / 0.640 / −32.3%

三个自适应变体在收益、夏普、回撤三项上全部输给"等敞口的被动持有"。

即「会择时的卫星」不如「把同样的平均仓位傻傻拿住」。

3.3 样本外 walk-forward(周频·自适应+核心60%,训练 8y → 测试 2y,6 折)

样本外窗口 2014-01-03 → 2025-12-26(626 条周线,全部为样本外)

指标策略(OOS)100% 买入持有等敞口被动(敞口 67.6%)
总收益126.2%251.0%139.8%
年化7.02%—7.54%
年化波动9.61%——
夏普0.7540.8120.812
最大回撤−15.7%−23.6%−16.3%
卡玛0.447~0.34~0.46

各折样本外收益:−9.3% / +17.9% / +10.1% / +8.7% / +7.1% / +64.9% 网格择优:vol_target 6 折中 4 折选 0(不缩放)、2 折选 0.10;hard_stop 5 折选 8% —— 参数选择不稳定。


四、三条设计指令的实测评价

指令是否有效证据
1 降频✔ 明确有效日频纯策略 OOS 夏普 0.286(落后基准 0.236)→ 周频核心卫星 OOS 夏普 0.754(落后等敞口被动仅 0.058)
2 宏观否决权⚠ 有效但代价明确同配置下非农否决使总收益 320% → 263%(−57pp),回撤仅改善 0.6pp(−33.6% → −33.0%)。这是"用真实收益买的保险"
3 核心60%+卫星40%✔ 方向正确(限损有效)核心底仓贡献约 +250%,把总回撤从 −44.6% 压到 −33.0%;但卫星本身的净贡献很小甚至为负

五、本次回测暴露的问题

P1 · 方法论层面(核心,未解决)

#问题证据
P1-1等敞口下卫星无 alpha§3.2 三项全输;OOS 也低于等敞口被动(0.754 vs 0.812)
P1-2网格择优不稳定vol_target 6 折中 4 折选 0;hard_stop 5 折选 8% → 不存在稳定可择优的结构,择优本身接近噪声
P1-3有效样本极少周频 1082 bar、月频 249 bar;且 2006–2026 是单一样本(黄金大牛市)→ 统计功效严重不足
P1-4无多重检验校正12 组网格 × 6 折 = 72 次尝试,取最优必然被乐观估计(选择偏差)。未做 Deflated Sharpe / White's Reality Check
P1-5四因子权重不可检验权重是主观先验;实测 L2 二值门控是 no-op(完整 L0–L2 与 L1 基线 逐日相同);分数加权虽介入但仓位常年偏轻(持仓 21%)
P1-6唯一正 alpha 的态样本太小B 态(风险溢价)年化 +65%,但只有 374 天 → 无法据此下注
P1-7L2 与 L1 存在结构性重叠价格因子与 L1 共用输入,按总纲 §3.3 已去重,但去重后 L2 的独立信息几乎只剩宏观腿

P2 · 实现层面(已修复,留档备查)

#问题修法
P2-a月频否决把每个月都否掉 —— 按"月内有非农"映射 → 每月都有首个周五 → 卫星永不交易(交易次数 0,结果退化成"60%金+40%现金"却看不出来)新增 --veto-scope auto:月频自动禁用事件否决
P2-b年化因子硬编码 252 —— 周/月频夏普与波动被高估 √(252/ppy) 倍(周频"1.32"实为 0.556)新增 infer_ppy(),按索引间距推断 252/52/12
P2-cbuild_event_veto 每 bar 调 pd.date_range —— 单次 34s改 searchsorted 向量化 + 三层缓存(原始帧/降频帧/层级判定),--compare 由 ~10 分钟压到 ~1 分钟
P2-dtgt = tgt * w 使 int 变 float,f"{tgt:+d}" 抛 ValueError改 {tgt:+.2f}

P3 · 数据层面(已知局限)

#问题
P3-1历史事件日历缺失:仓库 数据/econ_calendar.json 只覆盖 2026-09-18→09-25 一周;回测只能用规则化非农(可复现);FOMC/CPI 需外部日历
P3-2DTWEXBGS 与生产库重构 DXY 不是同一序列(相关性高但口径不同)
P3-32006–2016 缺 SP500 与债券腿完整历史 → L0-3 在该段频繁"无法评估"
P3-4未建模:滑点随波动变化、借贷成本、税、期货/ETF 展期、核心底仓再平衡成本

P4 · 环境层面(iSH,影响复现)

  • 单个 Python 进程约 2 分钟被静默 kill(无报错、rc=0,nohup 也挡不住)→ 全折 walk-forward、批量绘图必须拆成多个短进程串行跑。
  • A && nohup B & 会把 A 也放进后台并随 shell 退出被杀(与 nohup sh -c '…' & 不同)。
  • 容器无任何 CJK 字体,matplotlib 图例必须 ASCII;绘图本身也可能跑过 2 分钟 → 把"算"与"画"拆成两个进程(plot_compare.py 即为此拆出)。

六、是否需要改进?(商榷结论)

6.1 明确不该做的

不要继续在这个模型上调参数。

理由:P1-2(择优不稳定)+ P1-3(单样本、有效样本少)+ P1-4(无多重检验校正)三条同时成立时,

任何"调出来更好看"的参数都极可能是过拟合。黄金尤其容易过拟合——20 年只有一个大牛市样本,

任何在此窗口内表现优异的方向性规则,很可能只是复述了"2006–2026 涨了 7 倍"这一件事。

6.2 建议做的是"换问题",不是"换参数"

方向从到对应工具
① 从猜方向 → 管风险预测黄金涨跌只做风险预算 / 波动目标 / 核心-卫星配比求解PyPortfolioOpt · Riskfolio-Lib · cvxportfolio
② 从单资产择时 → 多资产分散给黄金一个方向把 DXY/实际利率/VIX 等做成各自独立的小仓位预测器,靠分散而非预测取胜pysystemtrade(Carver 路线)
③ 从手搓 regime → 统计 regimeADX + 效率比 + Hurst 阈值HMM / GMM 状态推断(仓库已有 regime_hybrid.py,应对齐而非另起一套)hmmlearn · machine-learning-for-trading
④ 从单次网格 → 正式防过拟合流程训练段取最优嵌套 walk-forward + Deflated Sharpe + White's Reality Check;用组合层回测(含分腿)vectorbt · backtesting.py · bt

6.3 一个更根本的建议

提高样本质量,而不是增加模型复杂度。

  • 用更长历史:LBMA 金价 1968 年起可得(DXY/TIPS 只有 2006 起,但可用代理拓展早期段)
  • 用横截面换时间序列:把"黄金一个品种 1080 周"换成"黄金+白银+铜+油+债券 多品种",有效样本数量级提升,且是 Carver 路线的核心
  • 把"预测方向"降级为"预测风险"(波动可预测性远高于收益可预测性)——本次实测也支持这点:稳定有效的是风险端,不是方向端

七、GitHub 参考仓库(2026-09-27 经 GitHub API 实测核实)

⚠ 先明确一件事:下列几乎全是引擎/工具/方法论,不是现成的"能赚钱的策略公式"。

没有任何仓库能直接给出对黄金有效的 alpha;能拿到的是更可靠的流程与更少的自欺。

这正对应 §6 的结论:缺的不是公式,是流程与样本。

7.1 方法论 / 防过拟合(最对症)

仓库★为什么推荐
[pst-group/pysystemtrade](https://github.com/pst-group/pysystemtrade)(原 robcarver17,已改名)3.5kRob Carver 的系统化交易框架。核心理念正好对症:"不要预测,要分散"、小仓位多品种、forecast scaling、风险目标化。其著作《Advanced Futures Trading Strategies》整本在讲"don't fit"。首选
[stefan-jansen/machine-learning-for-trading](https://github.com/stefan-jansen/machine-learning-for-trading)21.0k含 regime detection 专章(HMM/GMM,可直接替换本文手搓的 ADX/Hurst)、特征重要性、以及回测陷阱(look-ahead / 幸存者偏差)章节
[hmmlearn/hmmlearn](https://github.com/hmmlearn/hmmlearn)3.4k标准 HMM 库(sklearn 风格 API)。仓库已有 regime_hybrid.py(wess_hmm 移植),建议对齐而非另起一套

7.2 回测引擎(替换/增强手写引擎)

仓库★适用点
[polakowo/vectorbt](https://github.com/polakowo/vectorbt)9.2k向量化,参数扫描与 walk-forward 极快——正对我们"网格 + 滚动"的场景。维护活跃(2026-09)
[mementum/backtrader](https://github.com/mementum/backtrader)23.3k最成熟的 Python 回测框架;注意最后 push 为 2024-08,维护放缓
[kernc/backtesting.py](https://github.com/kernc/backtesting.py)9.0k轻量、API 干净,内置优化器与多资产支持
[pmorissette/bt](https://github.com/pmorissette/bt)3.0k组合层回测,天然支持"核心+卫星"分腿与再平衡——恰好对应本项目的结构
[stefan-jansen/zipline-reloaded](https://github.com/stefan-jansen/zipline-reloaded)1.9kZipline 的现代维护版

7.3 组合构建(回答"核心到底该 60% 还是别的")

仓库★适用点
[PyPortfolio/PyPortfolioOpt](https://github.com/PyPortfolio/PyPortfolioOpt)6.1kHRP / Black-Litterman / 有效前沿 —— 可用于正式求解核心-卫星配比与卫星内部权重,替代拍脑袋的 60/40
[dcajasn/Riskfolio-Lib](https://github.com/dcajasn/Riskfolio-Lib)4.5k风险预算 / 风险平价 / 最差回撤优化
[cvxgrp/cvxportfolio](https://github.com/cvxgrp/cvxportfolio)1.3kBoyd 组的凸优化组合回测,多期 + 含交易成本,理论上最严谨

7.4 绩效归因与报告

仓库★适用点
[ranaroussi/quantstats](https://github.com/ranaroussi/quantstats)7.7k一键输出全套绩效报告与回撤图,可直接替换本引擎手写的 performance()
[stefan-jansen/pyfolio-reloaded](https://github.com/stefan-jansen/pyfolio-reloaded)616组合/风险归因(pyfolio 现代维护版)
[stefan-jansen/alphalens-reloaded](https://github.com/stefan-jansen/alphalens-reloaded)657因子层面的 IC / 分层回测——用于检验"四因子到底有没有信息量"

7.5 索引与数据(自己挑)

仓库★说明
[wilsonfreitas/awesome-quant](https://github.com/wilsonfreitas/awesome-quant)29.8k量化资源总索引
[wangzhe3224/awesome-systematic-trading](https://github.com/wangzhe3224/awesome-systematic-trading)5.2k系统化交易资源索引(期货/持仓/组合方向更全)
[akfamily/akshare](https://github.com/akfamily/akshare)22.8k已在「武器库」;A 股/宏观数据接口

八、诚实声明(须与任何"模型有效"表述并列)

  1. 回测口径 ≠ 实盘 ≠ 生产管线(数据/panel.csv + paper_engine.py),数字不可互相引用。
  2. 四因子权重是主观先验 [待验证];A/B/C 评分是可计算操作化代理(原文只给权重未给公式)。
  3. L0 阈值标定未完成(框架/数据口径定义 §9.4),全部 [待验证]。
  4. 样本内单次结果不构成证据;本文所有关键结论均以等敞口对比与样本外为准。
  5. 不构成投资建议。

九、修订记录

  • 2026-09-27 v2.0:按三条设计指令重构(降频 / 宏观否决权 / 核心卫星);新增 --strategy adaptive 与 --l1-method trendstate;新增等敞口公平对比与周频样本外 walk-forward;修 4 个实现缺陷(P2-a~d);产出否定式结论(卫星无 alpha)+ 换问题建议 + GitHub 参考仓库清单。
  • 2026-09-26 v1.1(工作区,未入库):新增 --sizing score 证据分加权 + 日频 walk-forward(7 折,OOS 夏普 0.286)。
  • 2026-09-26 v1.0(工作区,未入库):首版引擎(L0–L4 单资产择时,2006–2026)。