8.5 分层回测:把股票按因子分组看收益
课前导读
本章目标
学完能解决什么困惑:不只看一个 RankIC 数字,还能把股票按因子高低分组,观察高分组和低分组未来收益是否真的拉开差距。 难度:中级入门,需要理解 pandas 分组、排序和平均值。 用时:约 40 分钟。
知识正文
一、从“按成绩分班”理解分层回测
上一节我们用考试成绩类比 RankIC。
这一节继续用学校的例子。
假设老师想知道“入学摸底考试”是否能预测后续学习表现。
除了看排名相关,老师还可以把全班学生按摸底成绩分成 5 组。
第一组是成绩最低的 20%。
第五组是成绩最高的 20%。
然后老师观察一个学期后的平均成绩。
如果第五组平均成绩明显高于第四组,第四组高于第三组,第三组高于第二组,第二组高于第一组,那么摸底成绩很可能有参考价值。
如果五组平均成绩乱跳,说明摸底成绩的解释力不稳定。
把这个想法放到 A 股因子研究里,就是分层回测。
你把同一天的股票按因子值从低到高分成几组。
再看每一组未来一段时间的平均收益。
如果高因子组长期跑赢低因子组,因子就更值得继续研究。
关键直觉
分层回测不是为了马上做实盘,而是为了看“因子高低”能不能把未来收益分出层次。层次越清楚,因子的研究价值越高。
二、先把“回测”两个字说清楚
本节标题里有“回测”。
但这里讲的是最小版分层检验。
它只回答一个问题:按因子分组后,未来收益有没有呈现高低差?
它不处理完整交易系统里的所有细节。
比如复杂调仓、组合优化、成交排队、资金容量、实盘监控,都不是本节重点。
新手阶段先不要被“完整回测引擎”吓住。
你只需要把分层回测当成一张更有结构的研究表。
这张表把股票分为 5 个篮子。
每个篮子记录未来收益。
最后比较篮子之间是否有规律。
三、分层回测的四个术语
| 术语 | 通俗解释 | 本节用法 |
|---|---|---|
| 股票池 | 参与比较的一批股票 | 例如沪深300或中证500成份股 |
| 分层 | 按因子值高低分组 | 常用5组或10组,新手先用5组 |
| 未来收益 | 分组后下一段时间的收益 | 例如未来20个交易日收益 |
| 单调性 | 组别越高收益越高,或越低收益越高 | 判断因子是否有清晰方向 |
分层回测里最重要的是“同一天比较”。
你在某个观察日,把当天股票池里的所有股票按因子排序。
然后切成 5 组。
每组包含大致相同数量的股票。
接着观察这些股票未来 20 个交易日的平均收益。
再把这个过程在多个观察日重复。
最后看每一层的平均表现。
flowchart TD
A[选择观察日和股票池] --> B[计算每只股票因子值]
B --> C[按因子从低到高排序]
C --> D[切成5个分层]
D --> E[计算每层未来收益]
E --> F[跨多个日期求平均]
F --> G[观察高低层差距和单调性]四、为什么只分 5 组
你可能会问:为什么不是 3 组、10 组、20 组?
答案是:新手先用 5 组最容易看清楚。
3 组太粗,可能看不出中间变化。
10 组更细,但每组股票数量变少,结果更容易受个别股票影响。
5 组像把温度计分成“很冷、偏冷、中等、偏热、很热”。
既能看方向,又不至于太细。
在 A 股样本里,如果你用沪深 300 做股票池,每组大约 60 只股票。
这个数量对入门研究比较友好。
如果你只看 30 只股票,每组只有 6 只,结论就会脆弱很多。
五、A 股案例:低估值因子的分层观察
假设你想研究一个简单的低估值因子。
估值可以先用 PE 粗略表示。
PE 越低,代表市场价格相对公司盈利越便宜。
但为了让“因子值越高越好”,我们不直接用 PE。
我们可以定义一个 value_score。
value_score 越高,代表越便宜。
例如可以用 PE 的倒数,或把 PE 从低到高排名后转换成分数。
现在你在每个月最后一个交易日,对沪深 300 成份股计算 value_score。
然后把股票分成 5 层。
未来 20 个交易日后,得到类似下面的平均收益表。
| 分层 | 因子含义 | 未来20日平均收益 |
|---|---|---|
| 第1层 | 最不便宜 | 0.2% |
| 第2层 | 偏不便宜 | 0.5% |
| 第3层 | 中等 | 0.8% |
| 第4层 | 偏便宜 | 1.1% |
| 第5层 | 最便宜 | 1.6% |
这张表给人的第一感觉是:越便宜的组,未来平均收益越高。
这就是较好的单调性。
如果你多个月份重复后仍然类似,那么低估值因子值得继续研究。
但如果只有某一个月出现这种表,不能急着下结论。
还要看更长时间、不同市场环境、不同股票池。
现实提醒
A 股里低 PE 不一定都是便宜,也可能是公司盈利突然变差前的“表面便宜”。分层结果只能说明统计关系,不能替代基本面检查。
六、pandas 最小实现
假设你已经有一张 df。
每一行代表某个观察日的一只股票。
字段包括:date、code、value_score、future_20d_return。
目标是按 value_score 分成 5 层。
import pandas as pd
labels = ["第1层最低", "第2层", "第3层", "第4层", "第5层最高"]
def add_layer(one_day: pd.DataFrame) -> pd.DataFrame:
valid = one_day.dropna(subset=["value_score", "future_20d_return"]).copy()
if len(valid) < 50:
valid["layer"] = pd.NA
return valid
ranked = valid["value_score"].rank(method="first")
valid["layer"] = pd.qcut(ranked, 5, labels=labels)
return valid
layered = df.groupby("date", group_keys=False).apply(add_layer)
layer_return = (
layered.dropna(subset=["layer"])
.groupby(["date", "layer"], observed=True)["future_20d_return"]
.mean()
.reset_index()
)
avg_by_layer = layer_return.groupby("layer", observed=True)["future_20d_return"].mean()
print(avg_by_layer)这段代码分成四步。
第一步,dropna 去掉缺失数据。
没有因子值或未来收益的股票,不应该参与当期分层。
第二步,rank(method="first") 先做排名。
这样即使有多个股票因子值一样,也能稳定分组。
第三步,pd.qcut 把排名切成 5 个数量接近的组。
因为我们对排名切分,所以每层股票数量更平均。
第四步,按 date 和 layer 分组,计算每层未来收益平均值。
最后再跨日期求平均,就能看到 5 层的整体表现。
七、看结果时不要只看最高层
很多新手只盯着第 5 层。
如果第 5 层收益高,就说因子有效。
这不够。
专业老师会追问:第 4 层是否也比第 3 层好?第 3 层是否也比第 2 层好?
投资者会追问:最高层收益是不是由一两只暴涨股票贡献?
量化开发会追问:缺失值、停牌、ST、上市不足股票有没有处理清楚?
所以分层回测要看三件事。
第一,看单调性。
理想情况是高分层平均收益逐步高于低分层。
不一定每次都完美,但长期不应完全乱跳。
第二,看高低差。
第 5 层减第 1 层的收益差,能帮助你观察因子区分能力。
这个差值只是研究指标,不代表新手可以直接做多做空。
A 股普通投资者做空工具和限制较多,本课程不把它当成实盘方案。
第三,看持续性。
如果分层只在某一年好,其他年份都不好,因子可能依赖特殊环境。
这时应该在研究日志里写清楚,而不是强行说它有效。
八、常见错误清单
错误一:把未来收益混进分层依据。
分层只能使用观察日已经知道的因子值。
未来收益只能在分组完成后用来评价。
错误二:因子方向没有统一。
如果 PE 原始值越低越好,但你按 PE 从高到低分层,就会把最贵股票放到最高层。
这会让结论反过来。
错误三:股票池变化不记录。
今天用沪深 300,明天用全市场,结果很难比较。
错误四:忽略样本数量。
每层股票太少时,某只股票的异常涨跌会严重影响平均值。
错误五:把分层检验当成实盘收益承诺。
分层检验只说明历史样本中的统计现象。
它不承诺未来,也不等于可以直接买入最高层。
九、把分层结果写成研究结论
建议你用固定格式写结论。
例如:
在 2018 至 2023 年的沪深 300 月度样本中,低估值分数从第 1 层到第 5 层的未来 20 日平均收益整体上升,第 5 层相对第 1 层有正差值。该因子具备继续研究价值,但需要进一步检查行业影响、财报可得性和交易成本。
这段结论有三个优点。
它说明了样本范围。
它说明了观察到的现象。
它也说明了限制。
这比一句“低估值有效”专业得多。
交互实验室
练习一:10 只股票分 5 层
下面是一张练习表。
假设因子值越高越好。
请你按因子值从低到高排序,每 2 只股票分成一层。
| 股票 | 因子值 | 未来20日收益 | 应分层 |
|---|---|---|---|
| A | 91 | 3.2% | 待填写 |
| B | 35 | -1.5% | 待填写 |
| C | 78 | 2.0% | 待填写 |
| D | 50 | 0.1% | 待填写 |
| E | 66 | 0.8% | 待填写 |
| F | 20 | -2.2% | 待填写 |
| G | 88 | 4.1% | 待填写 |
| H | 44 | -0.4% | 待填写 |
| I | 59 | 0.6% | 待填写 |
| J | 72 | 1.4% | 待填写 |
操作步骤:
找出因子最低的 2 只股票,放入第 1 层。
接着找出次低的 2 只股票,放入第 2 层。
依次完成第 3、4、5 层。
计算每层未来 20 日收益平均值。
判断收益是否从第 1 层到第 5 层逐步提高。
练习二:写一段自己的分层结论
请用下面模板完成一句研究结论。
我研究的因子是:。 股票池是:。 分层数量是:。 未来收益窗口是:。 结果显示:____。 因此我的下一步是:继续研究 / 暂缓研究 / 调整因子方向。
写完后检查两点。
第一,你有没有说明样本范围。
第二,你有没有把“历史观察”误写成“未来一定赚钱”。
核心复盘
知识清单:
- [ ] 分层回测是把股票按因子高低分组,再比较各组未来收益。
- [ ] 新手先用 5 组即可,既能看方向,又不至于每组样本太少。
- [ ] 好因子通常应该让高低分层呈现较清楚的收益差和一定单调性。
- [ ] 第 5 层减第 1 层的差值是研究观察,不等于普通投资者可以直接做多做空。
- [ ] 分层只能用当时可见的因子值,未来收益只能用于事后评价。
- [ ] 分层检验不是完整实盘回测,不承诺未来收益。
金句总结
“RankIC 看排序像不像,分层回测看队伍之间有没有拉开距离。”