IC、IR 与分组单调性:因子体检的最小集合
三个指标各自会漏掉什么,配一张能直接复用的评估函数。
三个指标,三种盲区
IC 看方向、IR 看稳定性、分组单调性看线性度。任何一个单独看都会骗人,三个一起看才能判断一个因子值不值得进入组合。
- IC 高但 IR 低:因子只在少数几个月里猛烈生效,其余时间是噪声。通常意味着它捕捉的是某个特定事件而非持续规律。
- IR 高但分组不单调:多空两头有效、中间一片混乱,说明因子实际是个哑变量,用排名打分等于浪费了大部分信息。
- 分组单调但 IC 低:单调性来自极少数极端样本,中间八组差异都在噪声范围内,换个时间段就翻转。
def factor_report(f, ret, n_group=10): """因子体检:返回 IC 序列、IR 和分组平均收益 f : 因子值,index=date, columns=code ret : 未来一期收益,与 f 同形状 """ fwd = ret.shift(-1) # Rank IC:对异常值更稳健 ic = f.rank(axis=1).corrwith(fwd.rank(axis=1), axis=1) ir = ic.mean() / ic.std() # 分组:按截面分位切成 n_group 层 q = f.rank(axis=1, pct=True) groups = {} for g in range(n_group): lo, hi = g / n_group, (g + 1) / n_group mask = (q > lo) & (q <= hi) groups[g + 1] = fwd.where(mask).mean(axis=1).mean() * 252 return {'ic_mean': ic.mean(), 'ic_std': ic.std(), 'ir': ir, 'groups': groups}
用 Rank IC 而不是 Pearson IC
原始因子值常有厚尾,Pearson 相关会被几个极端点主导。Rank IC 只用序信息,和后续按分位数构建组合的逻辑也一致。
还要看衰减
把未来收益从 1 天推到 20 天,画出 IC 随持有期的衰减曲线。衰减太快意味着信号只能靠高换手兑现,加上成本后大概率不剩什么;衰减太慢则说明它和某个慢变的风格因子高度重合,值得先做一次中性化再评估。
decay = {h: f.rank(axis=1).corrwith(
ret.shift(-h).rolling(h).sum().rank(axis=1), axis=1).mean()
for h in [1, 3, 5, 10, 20]}
体检不是回测
上面所有指标都不含成本、不含约束、不含容量。一个 IR 0.5 的因子通过体检只是拿到了进入组合优化的入场券,它最终能不能贡献超额收益,要等到加上换手约束和冲击成本之后才知道。
下一篇把这份体检函数扩展成多因子相关性矩阵,处理因子之间的共线性。
IC因子评估分层回测