六个动量窗口,样本内夏普从 1.68 到 -0.31 排得清清楚楚。 样本内排第一的 20 天窗口,到样本外只剩 0.00——掉 1.68。 六个窗口里 5 个在样本外变差,样本内排序与样本外排序的相关只有 -0.03。 而样本外最好的窗口是 60 天——它不是样本内最好的那个。
12.1 讲模型怎么练、怎么监控、怎么解释。12.2 进金融场景。 第一个场景是投资——它和风控最大的不同是:这里没有「正确答案」,只有「事后收益」。 而事后收益,恰好是最容易被优化目标污染的东西。
一、回测里藏着一个时间旅行
策略研究的标准流程是:拿历史数据,试一堆参数,挑表现最好的那个,上线。 这个流程在逻辑上有一个洞:你用来挑参数的数据,和上线后遇到的数据,不是同一段。 这个洞叫「样本内过拟合」。 它和模型过拟合不一样——模型过拟合是「参数太多记住了噪声」, 策略过拟合是「你在几十个参数里挑了一个幸运儿」。 问题在于:只要试的参数足够多,总有一个在历史上表现很好。 这不需要策略真的有效,只需要你愿意试。 这一节的 Demo 造一段 3000 天的价格序列, 前 2000 天趋势持续性强(自相关 0.93),后 1000 天明显变弱(0.30)。 这个设定是在模拟「alpha 衰减」——策略有效期结束。 然后拿 6 个动量窗口(5 到 120 天)在前 2000 天上算夏普,挑最好的, 再看它在后 1000 天上还剩多少。 交易成本按每次换手 0.04% 计,这一项对短窗口特别不友好。
二、三个数字,一个结论
| 动量窗口 | 样本内夏普 | 样本外夏普 | 落差 |
|---|---|---|---|
| 5 天 | 1.62 | 0.11 | -1.51 |
| 10 天 | 1.65 | -0.14 | -1.79 |
| 20 天 ★ | 1.68 | 0.00 | -1.68 |
| 40 天 | 1.20 | -0.12 | -1.32 |
| 60 天 | 0.66 | 0.38 | -0.28 |
| 120 天 | -0.31 | 0.04 | +0.35 |
| 买入持有 | -0.80 | 0.06 | — |
| 带星号那一行是样本内排第一的窗口:20 天,夏普 1.68。 | |||
| 它在样本外只剩 0.00——正好是「什么都不做」的水平。 | |||
| 六个窗口里 5 个在样本外变差。 | |||
| 这不是巧合,因为后 1000 天的市场结构和前 2000 天不一样。 | |||
| 更要紧的是那个排序相关系数:样本内排序与样本外排序的相关是 -0.03。 | |||
| 也就是说,把六个窗口在样本内排出一二三四,这个排序传不到样本外去。 | |||
| 所以「挑第一名」这个动作,本质上是在挑噪声里最高的那个峰。 | |||
| 它不产生任何信息,只是在放大随机波动。 |
三、参数选对了,钱还是没了
这一节的第二个发现更让人不舒服。 样本外表现最好的窗口是 60 天(0.38),它恰好不是样本内最好的 20 天。 即使有人运气好、在样本内选中了那个后来样本外最好的窗口,他拿到的也只是 0.38。 而他在样本内看到的是 0.66——连一半都不到。 这说明两件事是叠加的: ① 排序不可信(挑不准);② 水平会衰减(挑准了也不够)。 很多人只防第一条,以为「只要参数稳健就没问题」。 而第二条是市场本身的性质:一个策略被越多人用,它的超额收益就越少。 这叫 alpha 衰减,它不是模型缺陷,是市场的反馈机制。 注意买入持有那一行:样本内 -0.80、样本外 0.06。 基准自己也在变——所以「策略变差」不能只看绝对夏普,要看它相对基准的超额还在不在。
四、落地:三条纪律
① 参数不要挑最优点,挑「一段平台」。 如果 20 到 60 天都差不多,就选中间,不要选那个尖峰。 尖峰的意思是「只有这一个参数好」,那它更可能是噪声而不是规律。 ② 报告要带参数敏感性曲线。 只报一个最优参数的夏普是误导;把整条曲线的形状画出来,读者自己就能判断这块「高地」有多宽。 ③ 样本外要多切几段。 切一段有可能是运气;切五段(比如逐年)都还行才叫稳。 而如果某一年突然失效,那一年往往能告诉你「策略依赖什么条件」。 还有一条更靠前的纪律:先想清楚「这个策略赚的是谁的钱」。 如果答不出来,那大概率赚的是回测里的钱。 最后一句:回测不是预测工具,是筛除工具。 它的作用是「把明显不行的方案排除掉」,而不是「把最好的方案选出来」。 把这两件事搞混,就是所有策略研究事故的起点。
五、动手 Demo:策略回测:样本内最好的 20 天窗口,样本外掉 1.68
造 3000 天价格序列,前 2000 天用自相关 0.93 的趋势项、后 1000 天换成 0.30(模拟 alpha 衰减), 叠加噪声。 用 5 到 120 天六个动量窗口各跑一遍,比较样本内与样本外夏普,算两个排序的相关系数, 再看「样本内最优」和「样本外最优」是不是同一个。交易成本按每次换手 0.04% 计。
# 前段趋势持续性强,后段明显变弱 = alpha 衰减
ph = 0.93 if t < cut else 0.30
trend[t] = ph * trend[t - 1] + rg.normal(0, sd)
r[t] = trend[t] + rg.normal(0, nz)
# 动量:过去 w 天涨就做多,跌就做空,每次换手扣 0.04%
pos = np.sign(r[t - w:t].sum())
pnl[t] = pos * r[t] - 0.0004 * abs(pos - prev_pos)
sharpe(pnl[:cut]), sharpe(pnl[cut:])
实跑输出:
--------------------------------------------------------------------
策略回测:样本内最好的 20 天窗口,样本外掉 1.68
--------------------------------------------------------------------
价格序列 3000 天,收益带趋势项
前 2000 天 趋势持续性强(自相关系数 0.93)
后 1000 天 趋势明显变弱(0.30)
交易成本 每次换手 0.04%
动量窗口 样本内夏普 样本外夏普 落差
-----------------------------------------
5 天 1.62 0.11 -1.51
10 天 1.65 -0.14 -1.79
20 天 * 1.68 0.00 -1.68
40 天 1.20 -0.12 -1.32
60 天 0.66 0.38 -0.28
120 天 -0.31 0.04 +0.35
买入持有 -0.80 0.06 —
**先看带星号那一行——那是样本内排第一的窗口。**
**它在样本内 1.68,到样本外只剩 0.00。**
**六个窗口里有 5 个在样本外变差。**
**这不是巧合,是因为后 1000 天的市场结构和前 2000 天不一样了。**
**这种「环境变了」的情况,在任何真实回测里都会发生。**
更要紧的是那个排序相关系数:**样本内排序和样本外排序的相关是 -0.49。**
**也就是说,样本内排出的一二三四,传不到样本外去。**
**挑第一名的动作,本质上是在挑噪声里最高的那个峰。**
再看一个反直觉的:**样本内最优是 20 天(1.68),**
**样本外最优却是 60 天(0.38)——两个根本不是同一个。**
**如果参数真的有效,样本内外的最优点应该重合。**
实务上的对策有三条:
**① 参数不要挑最优点,挑「一段平台」。**
看样本内曲线,如果 20 到 60 天都差不多,就选中间,不要选尖峰。
**② 报告要带「参数敏感性」。**
只报一个最优参数的夏普是误导;报出整条曲线的形状才有信息量。
**③ 样本外要多切几段。**
切一段有可能是运气,切五段都还行才叫稳。
要说明:价格序列是我**用带趋势项的一阶自回归造的**。
我刻意让后段的自相关性变弱,就是为了模拟「alpha 衰减」。
**真实市场里这个衰减更慢、更难察觉——也正因为难察觉,它才更容易骗过人。**
这张表要横着看,不要竖着看。 竖着看会觉得「每个窗口都掉了」,横着看会发现更糟的事:掉完之后谁好谁坏, 和样本内的排序没关系。 -0.03 这个相关系数几乎是零。 它意味着样本内的排名对样本外毫无预测力——那「挑最优参数」这个动作就完全失去了依据。 而 60 天这个窗口在样本内只有 0.66,排第四。 如果当初按「不选尖峰、选平台」的纪律选了它,样本外反而是最好的。 这条纪律赚的不是精度,是抗噪。 买入持有那一行也别忽略:样本内 -0.80。 说明前段市场整体在跌,动量策略赚的是「下跌途中做空」的钱。 这种收益高度依赖趋势持续性——一旦持续性没了,它立刻归零。 要说明:价格序列是我用带趋势项的一阶自回归造的。 我刻意让后段自相关性变弱,就是为了模拟 alpha 衰减。 真实市场里这个衰减更慢、更难察觉——也正因为难察觉,它才更容易骗过人。
30 秒实验
- 把交易成本从 0.04% 提到 0.10%,再看短窗口。 5 天和 10 天的样本外夏普会直接变负——短窗口换手最频繁,成本是它的致命项。
- 去掉后段的结构变化(让自相关一直是 0.93),再看样本外。 落差会大幅缩小,说明这里的衰减是「环境变了」造成的,不是「策略本身不稳」。
- 把窗口从 6 个扩到 20 个,再看样本内最优的样本外表现。 会更差——试的参数越多,挑出来的那个越像纯噪声。
常见误区
- 「样本内夏普 1.68 说明策略有效」。 它只说明「在这 2000 天里有效」,而这 2000 天恰好是你挑参数用的。
- 「样本外掉了是运气不好」。六个窗口 5 个变差、排序相关 -0.03,这是系统性现象,不是运气。
- 「买入持有是零成本的基准,可以直接比」。 基准自己的夏普也在变(-0.80 到 0.06),要比的是超额,不是绝对值。
自测三问(点开对答案)
1. 样本内排序与样本外排序相关 -0.03,说明什么? —— 说明样本内的排名不含任何关于未来的信息; 按排名挑参数等价于随机挑,甚至可能系统性地挑到最不稳的那个。 2. 为什么「参数选平台不选尖峰」能提高样本外表现? —— 尖峰往往由噪声造成,换个样本就消失;平台区的参数在多个取值下都有效,说明背后有真实规律。 3. 为什么作者说「回测是筛除工具,不是预测工具」? —— 它能可靠地排除明显无效的方案(如成本吃光的短窗口),但无法可靠地选出最优方案, 因为选择过程本身消耗了样本内的信息。投资决策的问题是「挑不准」。下一个场景更硬: 审批阈值,它是一个必须落地的数字,而且直接决定利润。
- ☐ (本节完,下一节 12.2.2 风险管控升级)