因子IC分析:从定义到实战

因子IC分析,说白了就是回答一个问题:我这个因子,到底有没有预测能力?

我刚开始做量化那会儿,经常遇到这种情况——回测曲线漂亮得不行,一上实盘就拉胯。后来才明白,问题就出在IC分析没做透。今天咱们就把这块硬骨头啃下来。

IC(信息系数)定义与计算

IC的全称是Information Coefficient,信息系数。它衡量的是因子值与未来收益之间的相关性

数学上,IC就是Spearman秩相关系数。为什么用秩相关?因为我们要的是排序能力,不是线性关系。你想想看,选股本质上就是排序——因子值排名靠前的股票,未来收益排名也应该靠前。

IC的核心公式:

IC_t = corr(rank(Factor_t), rank(Return_{t+1}))

其中,Factor_t是t时刻的因子值,Return_{t+1}是t+1时刻的收益

计算IC的步骤其实很简单:

  1. 在每个时间截面上,对所有股票的因子值排序
  2. 对同一时间截面的未来收益排序
  3. 计算两个排序序列的相关系数

来看一段Python代码,这是我实际项目中一直在用的计算方式:

import pandas as pd
import numpy as np
from scipy.stats import spearmanr

def calc_ic(factor_df, return_df):
    """
    计算截面IC序列
    factor_df: 因子值,index为股票,columns为时间
    return_df: 未来收益,index为股票,columns为时间
    """
    ic_series = pd.Series(dtype=float)
    
    for date in factor_df.columns:
        # 获取当前截面的因子值和收益
        factor = factor_df[date].dropna()
        ret = return_df[date].reindex(factor.index).dropna()
        
        # 取交集
        common = factor.index.intersection(ret.index)
        if len(common) < 30:  # 样本太少时跳过
            continue
            
        # 计算秩相关系数
        ic, _ = spearmanr(factor[common], ret[common])
        ic_series[date] = ic
    
    return ic_series

个人经验:我习惯在计算IC前先做一次极值处理。曾经有个因子,因为某只股票的数据异常,IC直接从0.05跳到了-0.12。后来加了MAD去极值,IC序列就稳定多了。

IC序列的统计检验

拿到IC序列之后,别急着高兴。我们需要回答三个问题:

  • 均值:IC的平均水平是多少?正还是负?
  • 标准差:IC的波动大不大?
  • t统计量:IC显著不为零吗?

我见过太多人只看均值。均值0.05就觉得是好因子,结果标准差0.15,t值才1.2——根本不显著。说白了,就是运气成分太大。

统计检验的公式:

def ic_statistics(ic_series):
    """
    IC序列的统计检验
    """
    mean_ic = ic_series.mean()
    std_ic = ic_series.std()
    t_stat = mean_ic / (std_ic / np.sqrt(len(ic_series)))
    p_value = 2 * (1 - stats.t.cdf(abs(t_stat), df=len(ic_series)-1))
    
    return {
        'mean_ic': mean_ic,
        'std_ic': std_ic,
        't_stat': t_stat,
        'p_value': p_value,
        'obs': len(ic_series)
    }

避坑指南:我曾经遇到一个因子,全样本IC均值0.03,t值2.1,看起来挺不错。但分年度一看,2018年IC是-0.02,2019年是0.08,2020年又变成-0.01。这种不稳定的因子,实盘大概率要翻车。

ICIR(信息比率)计算

ICIR = mean(IC) / std(IC)

这个指标衡量的是单位风险下的IC收益。ICIR越高,说明因子的预测能力越稳定。

我个人习惯用ICIR来筛选因子:

ICIR范围 因子质量 我的建议
< 0.5 较差 直接放弃,别浪费时间
0.5 - 1.0 一般 可以继续观察,但别重仓
1.0 - 1.5 良好 值得深入研究的候选因子
> 1.5 优秀 赶紧纳入组合,但注意过拟合

嗯,这里要注意:ICIR的计算周期要和你的交易频率匹配。做日频交易的,就看日度ICIR;做周频的,就看周度ICIR。混着用会出问题。

IC衰减与换手率分析

这部分是我觉得最容易被忽视的。因子不是永远有效的,它会衰减。

IC衰减指的是:随着持有期的延长,因子的预测能力逐渐下降。我们通常用分层IC衰减曲线来观察这个现象。

计算方式:

def ic_decay_analysis(factor_df, return_df, max_lag=20):
    """
    IC衰减分析
    max_lag: 最大滞后天数
    """
    decay_results = []
    
    for lag in range(1, max_lag + 1):
        # 将收益向前移动lag期
        shifted_ret = return_df.shift(-lag)
        ic = calc_ic(factor_df, shifted_ret)
        decay_results.append({
            'lag': lag,
            'mean_ic': ic.mean(),
            'icir': ic.mean() / ic.std()
        })
    
    return pd.DataFrame(decay_results)

实战经验:我记得有个动量因子,1日IC是0.04,5日IC是0.03,10日IC就变成0.01了。这说明它的预测能力只能维持一周左右。如果我用月频调仓,这个因子基本没用。

换手率分析和IC衰减是孪生兄弟。换手率越高,交易成本越大,因子收益被侵蚀得越厉害。

我一般这样算换手率:

def turnover_analysis(factor_df, top_pct=0.2):
    """
    分析因子多空组合的换手率
    top_pct: 多头/空头比例
    """
    turnover_list = []
    
    for i in range(1, len(factor_df.columns)):
        prev_date = factor_df.columns[i-1]
        curr_date = factor_df.columns[i]
        
        # 获取前后两期的多头股票
        prev_long = factor_df[prev_date].nlargest(
            int(len(factor_df) * top_pct)
        ).index
        curr_long = factor_df[curr_date].nlargest(
            int(len(factor_df) * top_pct)
        ).index
        
        # 计算换手率
        turnover = 1 - len(
            prev_long.intersection(curr_long)
        ) / len(prev_long)
        turnover_list.append(turnover)
    
    return np.mean(turnover_list)

我曾经踩过的坑:有个因子ICIR高达1.8,但换手率每周80%。算上双边千三的交易成本,年化收益直接从15%掉到6%。后来我加了换手率约束,虽然ICIR降到了1.2,但实盘收益反而更好了。

本章知识体系

下面这张图总结了IC分析的核心逻辑,我建议你保存下来:

因子IC分析知识体系 因子IC分析 IC定义与计算 统计检验 ICIR计算 衰减与换手率 Spearman秩相关 截面计算 极值处理 均值检验 t统计量 p值判断 均值/标准差 因子筛选阈值 频率匹配 衰减曲线 换手率计算 成本影响 核心目标:找到IC稳定、ICIR高、衰减慢、换手率低的因子 四个维度缺一不可,只看单一指标容易踩坑

最后说一句:IC分析不是一次性工作。因子会随着市场环境变化而失效,我建议你每月至少做一次IC回顾。如果发现IC均值持续下降或者波动率变大,就要考虑是不是该换因子了。

我的习惯:每次新因子入库前,我会跑一套完整的IC分析流程——全样本IC、滚动IC、分行业IC、分年度IC。全部通过之后,才敢放到实盘组合里。这套流程帮我过滤掉了至少60%的伪因子。


公众号:蓝海资料掘金营,微信deep3321