4、单因子测试框架:IC分析、IR分析、分组回测、多空组合收益
单因子测试,说白了就是给每个候选因子做「体检」。
我入行那会儿,以为找个好因子就能躺赚。结果呢?回测曲线漂亮得不行,实盘一跑就崩。后来才明白——因子测试不是走过场,是帮你排雷的。
这一章,咱们把四个核心测试工具讲透:IC分析、IR分析、分组回测、多空组合收益。嗯,一个一个来。
4.1 IC分析:因子和收益的相关性
IC(Information Coefficient),信息系数。衡量的是因子值跟未来收益之间的相关性。
简单说:因子值高的股票,未来是不是涨得更好?
- Spearman秩相关系数:看排名相关性,对极端值不敏感。我个人更常用这个。
- Pearson相关系数:看线性相关性,但容易被极端值带偏。
我在项目中遇到过一件事:某个因子Pearson IC高达0.12,但Spearman IC只有0.03。一查,原来是某只小盘股因子值异常高,把相关性拉上去了。去掉它,啥也不是。
import pandas as pd
import scipy.stats as stats
# 假设 factor_values 是因子值,forward_returns 是未来N日收益
def calc_ic(factor_values, forward_returns, method='spearman'):
if method == 'spearman':
ic, p_value = stats.spearmanr(factor_values, forward_returns)
else:
ic, p_value = stats.pearsonr(factor_values, forward_returns)
return ic, p_value
# 示例
ic_val, p_val = calc_ic(df['factor'], df['ret_5d'])
print(f'IC: {ic_val:.4f}, p-value: {p_val:.4f}')
4.2 IR分析:IC的稳定性比大小更重要
IR(Information Ratio),信息比率。公式很简单:IR = mean(IC) / std(IC)。
说白了,就是IC的「均值」除以「波动率」。你想想看,一个因子IC均值0.08,但波动率0.15,IR才0.53。另一个因子IC均值0.05,波动率0.03,IR高达1.67。哪个更靠谱?
我曾经踩过一个坑:某个因子IC均值0.10,看着不错。但IR只有0.3,因为IC时正时负,波动极大。实盘一跑,收益曲线跟过山车似的。后来我给自己定了个规矩:IR低于0.5的因子,直接pass。
| 指标 | 因子A | 因子B | 因子C |
|---|---|---|---|
| IC均值 | 0.08 | 0.05 | 0.12 |
| IC标准差 | 0.15 | 0.03 | 0.25 |
| IR | 0.53 | 1.67 | 0.48 |
| 结论 | 一般 | 优秀 | 不稳定,慎用 |
4.3 分组回测:看因子能不能分层
分组回测,就是把股票按因子值从大到小分成N组(通常是5组或10组),然后看每组未来的平均收益。
好的因子,应该能清晰分层:第1组收益最高,第5组收益最低,中间组依次排列。
我记得有一次测试一个「营收增长率」因子,分组结果出来,第1组和第5组收益差不多,反而是第3组收益最高。这说明什么?这个因子跟收益不是线性关系,可能是个「倒U型」。嗯,这种因子用起来要小心。
def group_backtest(df, factor_col, ret_col, n_groups=5):
# 按因子值分组
df['group'] = pd.qcut(df[factor_col], n_groups, labels=False)
# 计算每组平均收益
group_returns = df.groupby('group')[ret_col].mean()
return group_returns
# 示例
group_ret = group_backtest(df, 'factor', 'ret_20d', 5)
print(group_ret)
- 各组收益是否单调递增/递减?
- 第1组和第N组的收益差是否显著?
- 中间组有没有「异常凸起」?
- 不同时间段(牛市/熊市)分组效果是否稳定?
4.4 多空组合收益:最直接的赚钱检验
多空组合,就是做多第1组(因子值最高的),做空第N组(因子值最低的)。
这个指标最直观——如果多空组合能稳定赚钱,说明因子确实有区分能力。
我习惯把多空组合的累计收益曲线画出来。如果曲线平稳向上,回撤小,那这个因子基本靠谱。如果曲线大起大落,甚至长期横盘,那就要打个问号了。
def long_short_return(df, factor_col, ret_col, n_groups=5):
df['group'] = pd.qcut(df[factor_col], n_groups, labels=False)
# 做多第1组,做空第5组
long = df[df['group'] == 0][ret_col].mean()
short = df[df['group'] == n_groups-1][ret_col].mean()
return long - short
# 示例
ls_ret = long_short_return(df, 'factor', 'ret_20d', 5)
print(f'多空组合收益: {ls_ret:.4f}')
4.5 知识体系总览
下面这张图,是我自己整理的单因子测试框架。每次做因子测试前,我都会瞄一眼,确保没漏掉哪个环节。
4.6 四个指标怎么配合使用?
我个人的筛选流程是这样的:
- 先看IC:IC均值有没有超过0.05?p-value是否显著?不满足直接淘汰。
- 再看IR:IR有没有超过0.5?IC的稳定性如何?波动太大也不行。
- 分组回测:收益是否单调?第1组和第5组差距是否明显?
- 多空组合:累计收益曲线是否平稳?最大回撤是否可控?
四个维度都过了,这个因子才算「初步合格」。为什么说初步?因为还有后续的因子相关性分析、因子合成、样本外测试等等。嗯,那是后面章节的事了。