如何 3 步快速算出因子 IC 半衰期:gs-quant 的 IC 衰减分析完整指南

📅 发布时间:2026/9/13 7:14:57
如何 3 步快速算出因子 IC 半衰期:gs-quant 的 IC 衰减分析完整指南
如何 3 步快速算出因子 IC 半衰期gs-quant 的 IC 衰减分析完整指南【免费下载链接】gs-quantPython toolkit for quantitative finance项目地址: https://gitcode.com/GitHub_Trending/gs/gs-quant你的多因子策略最近因子解释力变弱了——是因子失效还是调仓频率没跟上因子IC衡量因子对收益的预测力从IC衰减曲线能拟合出IC半衰期反推出合理的调仓频率。下面用gs-quant跑完这条流水线。① 场景每月调仓一次因子的保质期到底有多长很多多因子组合都是月度调仓但因子信号未必能撑满一整月。有的因子两三周后预测力就掉了一半有的却能吃满一个月。你没法凭感觉判断自己的组合是调早了白付交易成本还是调晚了吃到过期信号唯一稳妥的办法是把因子的预测力随时间的变化画出来。三句话讲清 IC 半衰期的原理每天算一个 IC当天因子值与下一期收益的相关性连起来就是一条 IC 时间序列。这条序列往往近似指数衰减$IC(t) IC_0 \cdot e^{-\lambda t}$其中 $\lambda$ 是衰减速度。令衰减到一半解出 $t_{1/2} \ln(2) / \lambda$这个天数就是因子的保质期。大白话翻译半衰期就是因子的保质期——保质期 21 个交易日的话天天调仓基本是在白付手续费等两个月再调则信号多半已经失效。整条流水线的路线如下② 因子暴露与远期收益怎么取取数用 gs_quant/models/risk_model.py 里的FactorRiskModelget_universe_exposure拉成分资产的因子暴露get_factor_returns_by_name拉因子收益。注意两个参数细节name_filter/factors传的是因子名称字符串get_factors_by_nameTrue让结果按因子名而不是内部 ID 组织后面对齐会省事。下面这段代码一次性取齐原料暴露序列和错开一期的远期收益。import datetime as dt from gs_quant.models.risk_model import FactorRiskModel model FactorRiskModel.get(MODEL_ID) # 替换为实际模型ID exposures model.get_universe_exposure( dt.date(2024, 1, 1), dt.date(2024, 12, 31), factors[MOMENTUM], get_factors_by_nameTrue) fwd_returns model.get_factor_returns_by_name( dt.date(2024, 1, 1), factors[MOMENTUM]).shift(-1)暴露和远期收益的对齐要点关键是错一期t 日的暴露对应的是 t1 期的收益用.shift(-1)平移即可千万别用当天收益那会高估预测力。大白话翻译这一步备好的是两杯原料一杯是因子今天的读数一杯是它明天的表现IC 就是看这两杯东西贴不贴。③ 用 gs-quant 滚动窗口算 IC 序列滚动相关函数correlation定义在 gs_quant/timeseries/econometrics.py直接从gs_quant.timeseries导入即可。它的窗口参数w既接受整数交易日数也接受1m这类相对时长字符串缺失值按滚动窗口的常规规则处理。窗口选 22约一个月是起步值后面第四节会讲怎么取舍。下面这行就得到一条带日期的滚动 IC 序列from gs_quant.timeseries import correlation ic correlation(exposures, fwd_returns, w22) # 22个交易日滚动窗口两点说明如果你的输入已经是收益序列按签名传入type_SeriesType.RETURNS避免函数替你再做一次差分如果你做的是截面 IC每天在全体股票上算暴露与下期收益的横截面相关用 pandas 逐日聚合成一条日度 IC 序列后后续拟合流程完全一样。大白话翻译IC 序列上每个点是因子当天的体检结果连起来看才能判断它是稳定变差还是随机波动。 ④ 指数衰减拟合两个参数解出半衰期IC 序列到手后套上指数衰减模型用scipy.optimize.curve_fit拟合出 $IC_0$ 与 $\lambda$半衰期即刻可得。拟合前先dropna()因为滚动窗口前段是空的。下面两段代码分别完成拟合与出图import numpy as np from scipy.optimize import curve_fit def decay(t, ic0, lam): return ic0 * np.exp(-lam * t) t np.arange(len(ic.dropna())) (ic0, lam), _ curve_fit(decay, t, ic.dropna().values) half_life np.log(2) / lam # 单位交易日import matplotlib.pyplot as plt plt.plot(ic.index, ic, label滚动IC) plt.plot(ic.dropna().index, decay(t, ic0, lam), r--, labelf拟合曲线半衰期{half_life:.0f}天) plt.title(因子IC衰减曲线) plt.legend(); plt.show()拿到half_life后别急着下结论先看拟合曲线和原始序列的贴合程度。大白话翻译算出半衰期 20 天意味着——按月调仓时信号还剩一半强度隔月再调就基本吃的是旧信息。拟合窗口与噪声的取舍窗口太小比如只拟合近 60 天参数对个别异常点敏感半衰期会跳窗口太大两年以上不同行情段拼在一起衰减形状可能已经不是单指数了。常见做法先全区间拟合看形状再截取最近 120 个交易日复核两者差太多说明因子状态在变此时报告区间均值比给单点数字更诚实。 ⑤ 常见坑交付前自问四个问题拟合出来的 λ 是负的怎么办曲线不衰减反升时别硬套模型多半是区间选错了或因子正在换逻辑改报滚动均值 IC并检查数据窗口是否跨了结构性变化。算出的半衰期和直觉对不上先查哪里查对齐暴露是否真的对应下一期收益、w窗口是否被误当成调仓周期。错位一期足以把半衰期拉偏一倍。t 的单位到底是天还是交易日上面代码里t是序号对应交易日。对外汇报时统一口径需要自然日时再除以 252/365 换算别让两份报告各说各话。拟合前要不要先平滑 IC 序列建议要。原始逐日 IC 噪声大用 gs_quant/timeseries/technicals.py 里的exponential_moving_average平滑一轮再拟合参数会稳很多但平滑系数本身也算一个需要说明的假设。⑥ 延伸把半衰期变成调仓规则经验上调仓间隔设在半衰期的 1~1.5 倍附近比较稳早了多付成本晚了信号折损超过一半。把这个数字写进你的调仓手册之前先用 gs_quant/models/risk_model_utils.py 里的工具在不同子区间复核一次稳定性确认半衰期不是某段行情的偶然。所以动手很简单挑你当前贡献最大的那个因子把它的 IC 半衰期先算出来直接作为调仓频率的基准线。等单因子流程跑顺后下一步可以扩展成多因子版本——给每个因子各算一个半衰期用它决定每个因子拿多久再交给 gs_quant/markets/optimizer.py 做动态权重把静态调仓表升级成一套动态持有期规则。【免费下载链接】gs-quantPython toolkit for quantitative finance项目地址: https://gitcode.com/GitHub_Trending/gs/gs-quant创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考