← 返回文章列表 因子研究

IC、IR 与分组单调性:因子体检的最小集合

三个指标各自会漏掉什么,配一张能直接复用的评估函数。

三个指标,三种盲区

IC 看方向、IR 看稳定性、分组单调性看线性度。任何一个单独看都会骗人,三个一起看才能判断一个因子值不值得进入组合。

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因子评估分层回测
下一篇

用 Parquet 存分钟线:分区、压缩与读取速度实测