阅读提示
这篇讲解 RobustTest 模块——用”幸运因子”(Lucky Factors)方法检验一个因子的收益是否真的来自该因子,还是被其他因子(如市值、行业)所解释。做完这一步,你的因子研究才算真正经得起推敲。
导言
一个因子的回测收益很漂亮,但你有没有想过:这份收益有多少是因子本身的贡献,有多少是恰好捕获了其他因子(如小市值效应、低估值效应)的暴露?
Lucky Factors 检验的核心思想来自 Harvey、Liu & Zhu (2016) 的论文——通过对大量”假因子”(把真实因子数据随机打乱生成)做回测,评估你的因子在统计上是否比”随机噪声”更强。如果一个因子连随机生成的假因子都跑不赢,那它的收益很可能只是幸运。
Betalens 的 robust 模块提供了这套检验的完整实现。
核心 API
1 | from betalens.robust import RobustTest, bootstrap_once, panel |
检验流程
步骤 1:准备数据
1 | import pandas as pd |
步骤 2:执行 Bootstrap 检验
1 | from betalens.robust import bootstrap_once |
步骤 3:解读结果
| p 值 | 解读 |
|---|---|
| < 0.01 | 极显著,真实因子远超”假因子”,稳健性极强 |
| < 0.05 | 显著,稳健 |
| < 0.10 | 边缘显著,需要更多数据验证 |
| >= 0.10 | 不显著,收益可能来自运气或其他因子 |
panel 回归检验
除了 Bootstrap,还可以用 Fama-MacBeth 截面回归做增量检验:
1 | from betalens.robust import panel |
如果 alpha(截距)显著为正,说明因子收益不能被其他已知因子完全解释,有真正的 alpha。
增量检验:逐步加入控制变量
1 | # 检验 ROE 因子是否真的比市值因子强 |
如果中性化后的因子仍然显著,说明 ROE 因子本身(而非市值暴露)是有价值的。
开发者侧:bootstrap 的实现原理
1 | def bootstrap_once(series, n_samples): |
这叫”时序自助法”(Block Bootstrap 的简化版)。严格的做法应该用”块自助法”(block bootstrap)保持时间相关性,但 n_samples=len(series) 的随机抽样在大多数场景下已经够用。
常见问题
1. 样本量太少导致 p 值不显著
1 | # 少于 3 年的 IC 数据(< 60 个数据点)做 bootstrap 检验,p 值通常不可靠 |
2. 把”不显著”误解为”因子无效”
RobustTest 的零假设是”因子收益来自随机噪声”。不显著只说明”无法拒绝零假设”,不等于”因子无效”。可能是:
- 数据不够(统计功效不足)
- 控制变量不够(其他因子还没被中性化)
- 因子的收益确实依赖特定市场环境
3. 中性化顺序不对
正确顺序:先去极值 → 再标准化 → 再中性化。如果先中性化再做去极值,中性化的效果会被破坏。
延伸阅读
- Betalens 新手系列 · 10:预处理三件套——中性化详解。
- Betalens 新手系列 · 11:因子画像——IC/ICIR 详解。
- Betalens 新手系列 · 20:自建因子端到端——从研报到跑通全流程。
docs/guide/robust.rst——官方稳健性检验文档。