声称与实测
这份手册不讲怎么选基金。它讲一件更重要的事:怎么判断你的回测在不在骗你。 全部例子来自你自己的两个项目 —— Fund_strategy_X 与 Fund_strategy_Pareto —— 用的是真实跑出来的数字。
为什么你没有自己看出来
先说清楚一件事:你没看出来,不是因为你的基金知识不够。
这些项目里出问题的地方,没有一个是关于基金的。它们全部是关于「测量」的 —— 怎么在一份有限的数据上做出不会骗自己的判断。这是一门独立的手艺,和懂不懂基金几乎无关。 专业量化团队常年在同样的地方翻车,学术界给这类错误起了名字、写了论文、发明了专门的检验方法。
更麻烦的是,这类错误在发生时看起来像成功。回测收益在涨,冠军在刷新, 日志里全是「发现了更好的策略」。所有反馈信号都是正的。等到实盘告诉你真相时, 已经过去很久了。
下面 11 节课,每一节讲一个可以独立使用的判断工具。学完之后, 你应该能拿着任何一份回测报告,问出让它现原形的问题。
信息预算:你能买得起多少个假设
每试一个策略,你就花掉一点数据里的信息。数据是有限的,所以假设是要花钱买的。 第一步永远是算清楚你有多少预算。
三个必须先算的数
把 Fund_strategy_X 的真实数字代进去:
| 量 | 值 | 怎么来的 |
|---|---|---|
| 交易日 / 交易笔数 | 663 | 看起来样本很大 |
| 独立样本 n_eff | ≈157 | Newey-West 修正后;粗算 663÷8 = 83 偏保守 |
| 池内基金数 | 499 | 看起来选择很多 |
| 有效独立资产 ENB | 4.4 | 平均两两相关 0.25,PC1 解释 39% |
| 注册策略数 | 958 | STRATEGY_REGISTRY 条目 |
读法:你名义上在 663 天里从 499 只基金选 1 只。 实际上你只有约 157 份独立信息,在大约 4 个独立方向上下注 —— 而你用它检验了 958 个假设。
那个冠军策略过不过关?把它的 t 统计量和门槛放一起看:
它连样本内都不显著。5.81 是怎么来的:把 663 笔重叠交易当成 663 个独立样本, 标准误的分母 √n 被放大了两倍多。这是最常见的一种自我欺骗,而且完全无意。
「每天都是一次新评判」—— 为什么不成立
最自然的反驳是:每天都做一次选择,8 天后都有一个结果,那不就是 663 次独立评判吗?
这个说法可以直接检验 —— 如果每次评判独立,相邻两笔的收益应该不相关。实测:
相邻两笔的相关性是 +0.79,不是 0。
第 T 天买的那笔覆盖 T+1~T+9 的价格路径,第 T+1 天买的覆盖 T+2~T+10 ——
两笔共享 8 天里的 7 天。第 T+5 天大跌 5%,两笔一起中招。
它们不是两次独立评判,是同一段价格波动被数了两次。
663 笔交易背后只有约 671 天的价格数据,你不可能从中提取出比这 671 天本身更多的独立信息。
相关性要到间隔 6 笔以后才接近 0 —— 正好是持有期的长度。
这个冠军的 663 个「决策」里,实际只有 196 段不同的持仓,最长一段 65 天没换过。它根本没在每天做新决策。
让它成立的办法在第 6 课和第 11 课:把钱分散到多只(单只的路径重叠被稀释), 以及让续持不占用新额度(想继续持有就持有,每天的新额度去买别的)。 决策真的变新了,独立信息才会真的变多。
然后问:我试过多少个假设?我的 t 有没有超过 √(2·ln N)?
过拟合长什么样 —— 八个肉眼可见的特征
过拟合不需要统计学就能认出来。它有很稳定的外观。下面八条全部取自 Fund_strategy_X, 每一条你都可以在五分钟内检查。
- 01策略名字里有一串数字。
vol10_net33_win223_ret11_e85_ma129_ove54_qb3_vus3_netreg0020_dd5_n15w10r19e4_sharpreflt52_nm020—— 13 个以上被调过的参数,且没有任何机制陈述。名字本身就是拟合痕迹的化石。 - 02前十名挤在一起。 Top-10 的 cum_profit 从 ¥32,008 到 ¥31,764,只差 0.8%。这不是「找到了一个好策略」, 这是「在一片噪声里取了最大值」。
- 03中位数也赚钱。 355 个策略里,中位数赚 ¥25,320,冠军 ¥32,008。随便挑一个都赚 —— 说明赚的是 beta,不是能力。
- 04几乎没有策略是亏的。 5% 分位的 avg_ret 还有 +0.148%。健康的搜索应该有大量失败品。
- 05收益量级不属于这个世界。 1.64%/8 天 ≈ 年化 90%+。任何时候回测给出这个量级,正确反应是「哪里错了」,不是「上实盘」。
- 06代码在失控膨胀。
backtest.py61,808 行 / 2.85 MB / 958 个注册策略。 搜索失控会在文件尺寸上留下痕迹。 - 07冠军天天在变。 20 笔实盘交易用了 10 个不同的冠军策略 —— 每天部署的都是「最新鲜的过拟合」。
- 08系统里根本没有样本外的入口。
backtest.py有--start-date, 没有--end-date。架构上就无法留出验证集。这是最致命的一条。
样本内与样本外:唯一诚实的检验
把数据切两段:训练段用来挑策略,验证段只用来报告、绝不参与挑选。 这是整套方法论里最简单也最有力的一步。
用 2026-05-01 切开 Fund_strategy_X,同一批策略跑两段:
关键读法在最后一行。冠军相对等权池的超额,样本内 +1.394%,样本外 −0.133%。 全部 alpha 蒸发并转负。注意基准本身也从 +0.187% 变成 −0.187%(市场转弱了)—— 所以只看绝对收益会误判成「市场不好」,看超额才知道策略的选基能力本来就不存在。
为什么会这样?把冠军的收益按季度摊开就一清二楚了 —— 它的全部收益来自几个牛市季度:
| 季度 | 笔数 | 每笔平均 | 胜率 |
|---|---|---|---|
| 2024 Q1 | 65 | −0.07% | 55% |
| 2024 Q3 | 65 | +1.85% | 42% |
| 2025 Q2 | 65 | +0.97% | 60% |
| 2025 Q3 | 66 | +5.06% | 76% |
| 2025 Q4 | 66 | −0.08% | 47% |
| 2026 Q2 | 65 | +4.20% | 74% |
| 2026 Q3 | 12 | −10.77% | 0% |
2026 Q3:十二笔,零胜率。这不是运气差。这个策略的结构是 「先筛出全池波动最大的基金,再在里面挑涨得最久的」—— 行情一反转,它必然满仓最脆的资产。样本期里科技/半导体大涨, 所以这个结构必然是样本内冠军。
没有基准,就没有 alpha
两个项目都报告一个叫 oracle efficiency 的指标:
你的收益 ÷ 完美预知每天买最好那只的收益。它能回答「离上界还有多远」,
但回答不了「到底有没有能力」 —— 牛市里一个纯 beta 策略也会有体面的 efficiency。
你需要的是零技能基线:每天等权买下当日所有合格基金。差额才是能力。
「同样那些交易日」这几个字是关键。选择性策略和每日策略交易的日子不同, 拿它跟全时段池均值比,等于给它记上一份它从未表达过的择时。
这两个池子的超额还需要经过样本外检验才能算数 —— 第 3 课已经演示过, 样本内的超额可以整个蒸发。但至少现在这条分割线存在了,问题变得可以问了。
指标会塑造行为:你优化什么,就会得到什么
Fund_strategy_X 的目标函数是 cum_profit,定义是:
这个定义里完全没有风险。重叠持仓被当成互相独立的交易加总, 所以「同一时刻把所有钱押在一只基金上」不会受到任何惩罚。
于是搜索出来的冠军,长成了这样:
| 指标 | 值 | 含义 |
|---|---|---|
| 交易笔数 / 用到的基金数 | 663 / 44 | 高度集中 |
| 第一大持仓占比 | 20.1% | 1/5 的交易在同一只 |
| 连续买同一只的最长记录 | 65 天 | 连续 65 个决策日买同一只基金 |
| 同一只基金最多同时在手 | 6 笔 | ¥18,000 全押一只 = 全部组合 |
| 策略自身最大回撤 | −70.6% | 中位策略也是 −70.6% |
注意最后一行:冠军自己的回撤是 −70.6%,而选冠军的时候完全不看回撤。 实盘印证:8 天池 20 笔交易只买了 3 只基金,13 笔是同一只。这不是组合,是单票重复下注。
更讽刺的是:两个项目的 oracle/engine.py 里
都写好了一个真正的组合引擎 —— 有现金、有 T+2 交收、有最大持仓数、
有单基金敞口上限的 simulate_strategy()。
它在两个项目里都从未被调用过。
唯一的免费午餐:组合构建
前面全是坏消息。这一课是好消息,而且是这份手册里唯一一个不需要预测能力的收益来源。
当信号很弱时(这类系统的信息系数通常只有 0.02~0.05), 风险的下降主要来自分散化,不是来自选股精度。分散化是数学,不是判断 —— 它不会因为市场变了就失效。
日预算 ÷ N。总投入和峰值占用资金不变。这是「同样的钱摊到更多只」,不是「加杠杆买更多」 —— 只有这样, 多选变体才能和单选放在同一条风险轴上比较。
下面是在 Pareto 项目上真实跑出来的结果:
| 组合宽度 | 每笔收益 | 年化波动 | 最大回撤 | Sharpe | Calmar | 用到基金 |
|---|---|---|---|---|---|---|
| 买 1 只(原设计) | 0.463% | 10.99% | 17.49% | 0.790 | 0.611 | 142 |
| 买 3 只 | 0.401% | 9.13% | 11.99% | 0.901 | 0.853 | 272 |
| 买 8 只 | 0.337% | 7.71% | 10.96% | 0.949 | 0.850 | 380 |
| 买 5 只 + 单基金≤2 笔 | 0.318% | 7.04% | 10.17% | 0.950 | 0.853 | 411 |
最大回撤 −42%,Sharpe +20%,Calmar +45%。 代价是每笔收益从 0.463% 降到 0.318% —— 但风险降得更多,所以风险调整后是净赚。 QDII 池效果更大:最大回撤从 30.10% 降到 13.71%(−54%),Calmar +72%。
还有一个副作用值得单独说。第 5 课那个「连续 65 天买同一只」的病理, 用「单基金最多 2 笔同时在手」这一条约束就直接消掉了 —— 而且这条约束不需要你对未来有任何判断。
回测与实盘对账:区分两种病
实盘亏钱时,只有两种可能,而它们的药完全不同:
分辨方法只有一个:对账。 取实盘的每一笔,用回测引擎重放同一天、同一策略,比较两边的收益。
回测引擎早就「知道」这些票要亏 10%,只是从来没被问过这个问题。 它是诚实的 —— 出错的是挑选策略的过程,不是计算过程。 这一条结论把后续所有修复的方向定死了:不用查数据管线,要改研究方法论。
验证的三层:只有一层是干净的
Pareto 项目设计了三层验证。理解它们的差别,是理解整套方法论的核心。
| 层 | 是什么 | 窥探程度 | 代价 |
|---|---|---|---|
| L1 | 全部历史上算三目标 | 完全窥探 —— 选择就是在这上面做的 | 立刻可得 |
| L2 | 留出每年 1/5/9 月不参与训练 | 部分干净 —— 但见下方陷阱 | 立刻可得 |
| L3 | 记录入档日,只统计入档之后新到的数据 | 零窥探 —— 数据当时还不存在 | 要等好几个月 |
L3 的思想是整个体系里最正确的一点:真正的测试集是未来,这一层就是对未来的持续记账。 它无法伪造 —— 因为策略入档时,用来评价它的数据还没产生。
L2 的陷阱:固定日历会把季节性混进来
留出月固定选 1 月、5 月、9 月,看起来很合理 —— 规则明确、可审计。 但这样切出来的「样本外」和季节性共线了。
QDII 池的实测结果暴露了这一点:
后果有两层:第一,「留出月收益 > 0」这道门槛在 QDII 上人人通过,零筛选力; 第二,更糟 —— 它会奖励那些恰好在这三个月上载荷更重的策略。
修法是把固定日历换成随机/轮转分块(组合式 purged 交叉验证)。 Pareto 做 PBO 时用的就是这套分块机制,搬过来即可。
PBO 与 DSR:给「挑选过程」本身打分
这两个指标不评价策略,它们评价你挑策略的那个过程。这是它们特别的地方。
PBO — 回测过拟合概率
把时间切成很多块,反复地「用一半块挑出最好的策略,看它在另一半块里排第几」。 PBO = 挑出来的冠军在另一半里排到中位数以下的概率。
DSR — 收缩后夏普比率
把「你试过多少个假设」这件事折算进显著性里。试得越多,同样的夏普越不值钱。 DSR 是一个概率:这个策略的真实夏普大于 0 的概率。习惯上要求 > 0.95。
| 诊断 | 8 天池 | QDII 池 | 读法 |
|---|---|---|---|
| PBO | 0.475 | 0.557 | 挑选过程 ≈ 抛硬币 / 比抛硬币还差 |
| DSR > 0.95 的策略数 | 0 / 20 | 2 / 21 | 8 天池最高只有 0.769 |
| 计入的试验数 | 391 | 364 | 不重复的候选版本数 |
| L3 已积累数据 | 无 | 无 | 入档日最早 2026-07-09 |
这三个数字合起来说:目前没有统计上可部署的东西。
这不是坏消息 —— 这是这套架构最有价值的产出。Fund_strategy_X 没有这个能力,
于是一个月亏了 8.3%(−¥8,411 / ¥101,290,24 笔已结算交易胜率 8.3%)。
知道「还不能上」,本身就是巨大的价值。
正确做法不是把它们变成硬门槛(那会砍掉低风险的有效锚点), 而是变成仓位函数:
资金比例 = 基准 × DSR × (1 − PBO) × min(1, L3样本数 / 30)今天算出来接近 0 —— 而这正是正确答案。 随 L3 累积自动放大,这是唯一「时间会站在你这边」的机制。
搜索不是选择 —— 无限搜索的正确形态
如果算力是免费的,你当然想无限地搜。这一课说明为什么这完全可以, 以及需要什么条件。
关键在于:DSR 和 PBO 惩罚的不是「你搜了多少」,而是「你用同一份数据做了多少次选择」。 这两件事可以分开。
| 环节 | 约束 | 为什么 |
|---|---|---|
| 生成候选 | 完全无界,随便跑 | 搜索本身不产生统计代价 |
| 进入 L3 跟踪的名额 | 有界(建议 20~50),淘汰规则预先写死 | 这才是真正的「试验数」 |
| 实盘选择 | 只看 L3 | L3 数据在候选入档时还不存在 |
用训练数据筛选「哪些假设值得拿去新数据上检验」是完全合法的 —— 那叫筛选阶段。过拟合发生在你用同一份数据既筛选又下结论。 把结论推到 L3,你之前搜了 1 万个还是 100 万个,对 L3 的有效性毫无影响。
配套:让日志从「试过的东西」变成「检验过的假设」
还有一个办法能让无限搜索和有意义的统计共存:在「机制」层做推断,而不是在「参数变体」层。
要求每个候选声明一个 mechanism_id,取自一个受控词表 —— 加新机制是一个需要写清经济理由的、慢的动作。于是:
族内可以无限变异(免费、无代价),统计推断在族层做(有界、有意义)。 有一个前提要注意:族代表不能按训练表现挑,否则族内多重检验又回来了 —— 用族内等权,或者用 L3 表现来定。
每个假设该写清楚的四件事:经济机制 / 预期方向 / 预期量级 / 失效条件。 参数不超过 2 个。写完存档,再跑数据。
vol10_net33_win223_ret11_e85_ma129_ove54…
—— 13+ 个参数,零机制陈述。正例:「板块动量延续:过去 20 日涨幅前 20% 的板块,未来 8 日跑赢等权池。 机制 = 资金流惯性 + 基金申赎滞后。失效条件 = 市场波动率进入高位区间时反转。」
持有期还是额度:一个被写死的决策
最后一课来自一个容易被忽略的观察:「8 天持有」到底是什么?
它是免赎回费的资格日,不是强制退出日。到期后仓位变成可以回收, 不是必须回收。如果策略今天还想要这只基金,你根本不用动 —— 直接继续持有就行。
持有期是自由变量,换手是内生的,不是外生给定的。
但现在的系统把这个决策删掉了。回测里 future_return 是固定的
8 日前瞻收益 —— 每个候选都是强制的 8 天往返。
整个候选空间里没有「续持还是换仓」这个选择。
这解释了那个 65 天的谜团
回到第 5 课那个「连续 65 天买同一只基金」。之前我们把它归为集中度病理。 但按正确的框架重看 ——
反过来说:如果续持不消耗新额度,那么每天的 ¥4,000 自然会去别的地方 —— 分散化会免费出现,不需要强制。
再看那两笔最惨的实盘:5.4055 → 4.0572(−24.9%)、
5.0748 → 3.9466(−22.2%)。强制在第 8 天卖在坑里。
有「续持还是换仓」的决策的话,这是可选的。
| 环节 | 固定 8 天(现在) | 变持有期 |
|---|---|---|
| 评估核心 | 固定前瞻收益求和 | 真正的组合状态机 |
| 目标一 | 每笔平均收益 | 权益曲线年化收益 |
| 目标二、三 | 波动 / 回撤 | 不变 |
| 回撤归一化分母 | 日预算 × 持有天数 | 不变 —— 它本来就是「额度」 |
好消息是风险轴的结构完全存活 —— 因为当初把分母定义成「额度」而不是「持有期」。 只有「每笔平均收益」需要换成「年化收益」(变长持有下每笔不再可比)。
上实盘前的十二个问题
任何回测报告递到你面前,按顺序问这些。答不上来的,就是问题所在。
- 我的独立样本数是多少?不是交易笔数。先看相邻交易的自相关,再用 Newey-West 修正标准误。
- 我一共试过多少个假设?算上所有变体。t 有没有超过 √(2·ln N)?
- 相对什么基准?超额是多少?没有基准的绝对收益,在牛市里一律好看。
- 样本外表现是样本内的百分之几?低于 50% 就该怀疑,转负说明什么都没有。
- 这段样本覆盖了几种市场状态?有熊市吗?只有涨的样本,测不出结构性风险。
- 用来判断「样本外」的那份数据,在做选择时存在吗?不存在才叫真样本外。
- 切分规则会不会和季节性共线?固定日历月是常见陷阱。
- 策略名字里有几个数字?超过 3 个就是拟合痕迹。
- 参数扰动 ±10%,结论还成立吗?只在一个点上成立的,是噪声。
- 目标函数没有惩罚什么?没惩罚的东西,优化器一定会拿去换收益。
- 这个收益量级,在真实世界存在吗?年化 90% 不存在。
- 实盘和回测对得上账吗?对不上是执行问题,对得上还亏是策略问题。
词汇表
- 样本内 / 样本外(in-sample / out-of-sample)
- 样本内 = 用来挑选策略的那段数据;样本外 = 完全没参与挑选的数据。只有后者的表现能当证据。
- 过拟合(overfitting)
- 模型学到的是这份数据里的噪声,而不是可重复的规律。表现是样本内极好、样本外崩塌。
- 多重检验(multiple testing)
- 试的假设越多,「最好的那个」越可能只是运气好。校正方式是抬高显著性门槛:
√(2·ln N)。 - 独立样本数(effective sample size)
- 持有期重叠的交易高度相关,不算独立观测。粗算取
交易日 ÷ 持有天数(偏保守); 严谨做法是用 Newey-West 修正标准误后反推。 - Newey-West 标准误
- 对自相关与异方差稳健的标准误。持有期重叠时必用,滞后阶通常取「持有天数 − 1」。 它不改变均值,只放大标准误 —— 也就是把虚高的 t 打回原形。
- 有效独立资产数(ENB)
- 一组高度相关的资产,实际提供的独立选择数。500 只相关性 0.25 的基金 ≈ 4.4 个独立方向。
- beta / alpha
- beta = 跟着市场一起涨跌白拿的那部分;alpha = 超出基准的部分,才是能力。
- PBO(回测过拟合概率)
- 你挑出的冠军,在另一半数据上排到中位数以下的概率。0.5 = 挑选过程等于抛硬币。
- DSR(收缩后夏普比率)
- 把试验次数折算进去之后,「真实夏普 > 0」的概率。习惯要求 > 0.95。
- Purge / Embargo
- 切分训练与验证时,删掉那些「结果落在验证段里」的训练样本。持有期重叠会造成信息泄漏,必须清除。
- Pareto 前沿 / 非支配
- 多目标下,没有任何其他方案在所有目标上都不差且至少一项更好的那些方案。它呈现权衡,不提供「最优解」。
- 最大回撤(MDD)
- 权益曲线从历史高点跌下来的最大幅度。衡量「最难受的时候有多难受」。
- Calmar / Sharpe
- Calmar = 收益 ÷ 最大回撤;Sharpe = 超额收益 ÷ 波动率。都是风险调整后收益。
- 观测对齐(observation alignment)
- 净值按「你实际能看到它的那天」标注,而不是「它对应的那天」。境内 T→T+1,QDII T→T+2。防止前视偏差。
- 前视偏差(look-ahead bias)
- 回测里用到了当时还拿不到的信息。最隐蔽也最致命的一类回测错误。
- 幸存者偏差(survivorship bias)
- 只统计活到今天的基金,忽略了中途清盘的。会系统性地高估历史收益。
把预期校准到正确的量级
学完这些之后,最重要的调整可能是预期。
一个诚实的目标是:长期稳定跑赢等权基金池 2~5%/年,且最大回撤显著更小。 这已经是很扎实的成果。不是年化 90%。
Fund_strategy_X 走到那一步的根源,就是它的目标函数从一开始就默认了「年化 90% 是可达的」—— 于是所有搜索都朝着噪声最大的方向去了。
你能可靠拿到的东西,按可靠性排序
- 分散化 —— 纯数学,不依赖预测。实测让回撤降 42%~54%。
- 不部署过拟合的东西 —— 需要把 PBO/DSR/L3 接进仓位决定。
- 零费率 —— 已经有了,别用高换手浪费掉。
- 选基 alpha —— 第四位,而且最不可靠。
如果目标是盈利,「8 天轮动境内基金是不是正确的载体」这个问题值得单独问一次 —— 一个更慢、更分散、更低换手的版本,单纯因为长周期信噪比更好、多重检验负担更小, 风险调整后大概率更优。