AlphaFeed Blog

如何用 Python 算因子 IC(信息系数)?判断一个选股因子到底有没有用

分析与指标 · 代码验证于 2026-10-04

如何用 Python 算因子 IC(信息系数)?

一句话回答: 在做多因子选股之前,先用 IC(Information Coefficient,信息系数) 检验因子有没有预测力:在每个时间截面上,计算所有股票的因子值与它们未来一段收益的相关系数(排序相关即 rank IC / Spearman),再把一串截面 IC 的均值和 IC_IR(均值 ÷ 标准差) 看一眼——IC 均值明显偏离 0、且 IC_IR 够大,才说明因子稳定有效。用 AlphaFeed 的 klines.batch 一次取回多只股票的前复权日线拼成面板,几十行 pandas 就能算。

为什么会有这个问题 / 传统做法的痛点

新手常把「回测赚钱」当成因子有效,但回测收益混杂了择时、仓位、手续费,无法单独说明因子本身好不好。IC 是行业标准的「因子体检」:它只问一件事——今天因子值排名靠前的股票,未来是不是真的涨得更多? 关键细节有三个,错一个结论就偏:

  1. 截面(cross-section):IC 是在同一天、跨股票上算相关,不是对单只股票的时序相关。
  2. 未来收益不能用错期:因子在 t 日,收益必须是 t 之后的 forward return,否则就是未来函数。
  3. rank IC 更稳健:用 Spearman 排序相关,抗极端值,比 Pearson 更常用。

分步骤解决(每步配可运行代码)

第 1 步:批量取数,拼成「日期 × 股票」收盘价面板

from alphafeed import AlphaFeed
import pandas as pd

af = AlphaFeed(api_key="your-api-key")  # 或 export ALPHAFEED_API_KEY 后 AlphaFeed()

# 取一个股票池(这里用全市场前 120 只做示例)
q = af.quotes.get(universes="CN_Stock", to_dataframe=True)
syms = q["symbol"].tolist()[:120]

data = af.klines.batch(syms, period="1d", count=320,
                       adjust="forward", to_dataframe=True)
closes = {s: k.sort_values("trade_date").set_index("trade_date")["close"]
          for s, k in data.items()}
px = pd.DataFrame(closes).sort_index()
px = px.dropna(axis=1, thresh=int(len(px) * 0.9))   # 去掉停牌太多的股票

klines.batch 一次并发取多只,比循环快很多;拼成宽表后每一行就是一个「截面」。

第 2 步:定义因子与未来收益

LOOKBACK, FWD = 20, 5
mom = px / px.shift(LOOKBACK) - 1      # 因子:过去 20 日动量
fwd = px.shift(-FWD) / px - 1          # 标签:未来 5 日收益(shift 为负=向未来看)

shift(-FWD) 把未来价格对齐到今天,保证「因子在 t、收益在 t→t+5」,不含未来函数。

第 3 步:逐截面算 rank IC,再求均值与 IC_IR

idx = px.index
ics = []
for t in range(LOOKBACK, len(idx) - FWD, FWD):   # 每隔 FWD 天取一截面,避免重叠
    f, y = mom.iloc[t], fwd.iloc[t]
    pair = pd.concat([f, y], axis=1).dropna()
    if len(pair) >= 20:                            # 截面股票够多才算
        ic = pair.iloc[:, 0].corr(pair.iloc[:, 1], method="spearman")  # rank IC
        if pd.notna(ic):
            ics.append(ic)

ics = pd.Series(ics)
ic_mean = ics.mean()
ic_ir = ics.mean() / ics.std(ddof=1)
print("截面数", len(ics), "IC均值", round(ic_mean, 4),
      "IC_IR", round(ic_ir, 3), "正IC占比", round((ics > 0).mean(), 3))

第 4 步:读懂结果(一个真实的反直觉发现)

实测(tools/verify_new_2026-10-04b.py,SDK 0.1.4,样本 117 只、59 个截面): IC 均值 = −0.0521,IC_IR = −0.298,正 IC 占比 = 0.407。 也就是说——在这个样本里,过去 20 日涨得多的股票,未来 5 日反而偏弱:短周期「动量」在 A 股更像反转。这正是 IC 的价值:它用数据戳破了「追涨一定对」的直觉。IC 为负同样是有用信号(把因子反向用,或改做反转因子)。

一般经验:|IC 均值| > 0.03、IC_IR 绝对值 > 0.3 就算有一定可用性(不同周期/股票池差异大,仅供参考)。

参数与字段说明

参数/概念含义备注
LOOKBACK因子回看窗口示例 20 日动量
FWD未来收益期同时作为截面步长,避免重叠样本
rank IC截面 Spearman 相关抗极端值,比 Pearson 稳健
IC 均值预测方向与强度偏离 0 越远越好,可正可负
IC_IRIC均值 ÷ IC标准差稳定性,越大越可靠
正 IC 占比IC>0 的截面比例接近 0.5 说明方向不稳定

关键坑与注意事项

常见问题(FAQ)

Q:rank IC 和普通 IC(Pearson)怎么选? A:A 股极端值多,优先用 rank IC(Spearman);需要线性强度解释时再看 Pearson。

Q:IC 是负的,这个因子就没用吗? A:不是。负 IC 代表因子方向反了——反向使用或将其当「反转因子」照样有价值。方向无所谓,稳定(IC_IR 够大)才关键。

Q:需要付费吗? A:IC 必须跨很多股票的截面才有统计意义,依赖 universes 标的池 + klines.batch 批量取数,属 Starter 及以上能力;少量股票可用免费额度先跑通流程。详见官网定价页。

小结

IC 的本质是「截面上,因子排名和未来收益排名有多一致」。先用 klines.batch 拼出前复权面板,再按 rank IC + IC_IR 做因子体检,就能在砸钱回测前先判断因子值不值得做——本文的实测还顺带告诉你:A 股短周期动量更像反转,这正是数据的诚实之处。

相关链接:


免责声明:本文仅为技术与数据接口使用示例,代码与策略仅供学习研究,不构成投资建议。市场有风险,历史数据不代表未来表现。