)
从零到一跑通多因子选股Alpha101与Alpha191量化因子库实战教程附IC检验与分层回测代码【免费下载链接】jqdatasdk简单易用的量化金融数据包(easy utility for getting financial market data of China)项目地址: https://gitcode.com/gh_mirrors/jq/jqdatasdk很多入门量化的朋友第一次接触 Alpha因子都是先从网上抄公式开始的把 WorldQuant 的 101 个表达式搬进本地脚本再用 pandas 一行行实现rank、correlation、ts_rank。我也经历过这个阶段直到某天发现自己的 alpha_004 计算结果和行情软件的指标对不上——原因很琐碎除零没处理、复权口径不一致、停牌日没剔除。就是这些不起眼的细节让照着公式实现变成了一场漫长的排错。后来我切换到 jqdatasdk 这套量化金融数据包直接调用它内置的 Alpha101 与 Alpha191 量化因子库才发现把公式交给经过验证的服务端去算省下的不只是时间还有一整套容易踩坑的数据处理环节。本文就记录我从零搭建因子研究流程的完整路径包含可直接运行的代码。一次因子失效的复盘为什么要用现成的量化因子库先讲一个真实教训。2022 年三季度我手工实现的一个反转因子突然失效IC 从 -0.05 掉到接近 0。排查了整整两天最后定位到三个问题某只股票某天成交量是 0delta(volume, 1)里出现了 NaN而我用的fillna(0)把本该是缺失的样本硬生生变成了涨跌幅为 0送转除权后不复权价格出现跳空反转因子被假信号污染次新股上市前 20 天没有历史数据窗口函数算出来的排名严重失真。这三类问题本质是因子计算和数据清洗被混在了一起。而 jqdatasdk 的 alpha101、alpha191 两个模块把公式封装成一行函数调用数据口径、缺失值、复权逻辑都在服务端统一处理本地拿到的就是干净的因子值序列。这对把精力放在策略本身而非公式翻译的研究者来说是实打实的效率提升。开工前准备安装、认证与两张因子地图环境准备三步走先装包、认证、验证连通性。pip install jqdatasdk之后用官方申请的账号登录即可# 这段代码解决如何初始化 jqdatasdk 环境的问题 import jqdatasdk # 用账号密码或 token 完成认证 jqdatasdk.auth(你的用户名, 你的密码) # 或者jqdatasdk.auth_by_token(你的token) # 确认认证是否成功 print(jqdatasdk.is_auth()) # 输出 True 说明已就绪 # 可选通过 git 方式获取源码源码仓库地址见项目主页 # git clone https://gitcode.com/gh_mirrors/jq/jqdatasdk认证失败最常见的报错是Please run jqdatasdk.auth first这类错误都源自utils.py里的assert_auth装饰器它会拦截一切未认证的函数调用。两个因子库的分工差异动手前先搞清楚 alpha101 和 alpha191 的定位区别否则很容易传错参数维度alpha101alpha191计算维度全市场截面一次算一个交易日自选股票池按code传入函数签名alpha_xxx(enddate, indexall)alpha_xxx(code, end_dateNone, fqpre)返回类型Seriesindex 为股票代码按传入股票池返回因子值适用场景全市场打分、截面排序盯住自选池做深度研究一个典型的组合用法是用 alpha101 在全市场做初筛再用 alpha191 对进入视野的几十只标的做精细对比。第一步把候选因子做成一张截面快照因子研究的第一步是把因子表达式变成每个交易日、每只股票都有一个数值的表格。这段代码展示如何用 alpha101 批量取全市场因子值# 这段代码解决如何一次性拿到全市场某天的多个Alpha因子值的问题 import pandas as pd from jqdatasdk import alpha101 # 取 2023-06-30 收盘后的三个因子截面 # alpha_101: (close - open) / (high - low 0.001)捕捉日内价格位置 # alpha_012: sign(delta(volume,1)) * (-1 * delta(close,1))量价背离信号 # alpha_004: -1 * Ts_Rank(rank(low), 9)短期低点反转信号 factor_date 2023-06-30 snapshot pd.DataFrame({ alpha_101: alpha101.alpha_101(factor_date), alpha_012: alpha101.alpha_012(factor_date), alpha_004: alpha101.alpha_004(factor_date), }) # 剔除缺失值避免脏数据污染后续分析 snapshot snapshot.dropna() print(snapshot.head()) print(有效样本数:, len(snapshot))如果你关心的是自己跟踪的 30 只股票而不是全市场就换 alpha191# 这段代码解决如何对自选股票池计算Alpha191因子的问题 from jqdatasdk import alpha191 watch_list [000001.XSHE, 600519.XSHG, 000858.XSHE, 601318.XSHG, 600036.XSHG] # fqpre 表示前复权避免除权跳空干扰因子值 factor_191 alpha191.alpha_001(codewatch_list, end_date2023-06-30, fqpre) print(factor_191)值得注意的一点alpha191 的因子表达式面向单只股票的时间序列例如alpha_001是成交量变化与开盘涨幅的 6 日相关性而 alpha101 里同名的alpha_001是截面排名类公式。同名不同义引用前务必看清模块前缀。第二步用 IC 检验给因子做体检拿到因子值只是开始接下来要回答这个因子到底有没有预测力。IC信息系数就是因子值与未来收益的秩相关系数可以把它理解成体检报告上的一个核心指标绝对值接近 1 说明因子和未来收益高度相关接近 0 则说明因子基本是噪声。# 这段代码解决如何量化评估因子预测能力IC检验的问题 import numpy as np import pandas as pd from scipy.stats import spearmanr from jqdatasdk import alpha101, get_price def calc_ic(factor_series, enddate, horizon20): 计算某一天因子值与未来horizon日收益的秩相关(IC) codes list(factor_series.index) # 取未来收益用 horizon 个交易日后价格计算涨幅 fwd get_price(codes, start_dateenddate, end_dateNone, counthorizon 1, fields[close], frequencydaily) close fwd[close].unstack() # 未来收益 最后一日收盘 / 因子日收盘 - 1 ret close.iloc[-1] / close.iloc[0] - 1 ret ret.reindex(factor_series.index) valid factor_series.notna() ret.notna() if valid.sum() 30: return np.nan ic, _ spearmanr(factor_series[valid], ret[valid]) return ic # 连续滚动 20 个交易日看因子IC的稳定性 dates pd.date_range(2023-06-01, periods20, freqB).strftime(%Y-%m-%d) ic_series pd.Series({d: calc_ic(alpha101.alpha_101(d), d) for d in dates}) print(滚动IC序列:) print(ic_series.round(3)) print(IC均值: %.3f, IC标准差: %.3f % (ic_series.mean(), ic_series.std())) print(IC0占比: %.0f%% % ((ic_series 0).mean() * 100))经验判断标准仅供参考不构成投资建议IC 绝对值均值在 0.03 以上且正负方向稳定才值得继续往下做IC 的标准差过大说明因子在不同市场环境里忽好忽坏建议至少用 20 个交易日以上的 IC 均值做判断单日 IC 噪声太大。第三步分层回测验证因子的区分度IC 高不等于能赚钱还需要看因子的单调性。分层回测的做法很直观按因子值把股票分成 5 组算每组未来一段时间的平均收益。如果第 1 组因子值最小到第 5 组因子值最大的收益单调递增或递减说明因子确实能把股票区分开。# 这段代码解决如何用分层回测验证因子区分度的问题 def layered_backtest(factor_series, enddate, groups5, horizon20): 按因子值分5组比较各组未来20日平均收益 codes list(factor_series.index) fwd get_price(codes, start_dateenddate, end_dateNone, counthorizon 1, fields[close], frequencydaily) close fwd[close].unstack() ret (close.iloc[-1] / close.iloc[0] - 1).reindex(factor_series.index) df pd.DataFrame({factor: factor_series, fwd_ret: ret}).dropna() # 按因子值分位数打组标签1最小5最大 df[group] pd.qcut(df[factor], groups, labelsFalse) 1 return df.groupby(group)[fwd_ret].mean() # 用第一步的截面快照做演示 from jqdatasdk import alpha101 snap alpha101.alpha_004(2023-06-30) # 反转因子 result layered_backtest(snap, 2023-06-30) print(result.round(4))分层结果解读若各组收益呈单调阶梯状如 -1.2%、-0.5%、0.1%、0.8%、1.5%因子区分度良好若中间组收益高于两端U 形或倒 U 形说明因子只有排序能力而没有线性区分能力需要警惕分层回测样本太少时结论不可靠最好跨多个时间段重复验证避免过拟合。组合与风控别把仓位押在单一因子上单一因子再优秀也有阶段性失效的风险。更稳的做法是把多个低相关的因子加权合成。关键在于相关性监控——两个因子如果相关系数常年高于 0.7它们本质上是同一个信号的两种写法组合起来并不能分散风险。# 这段代码解决如何构建多因子组合并监控因子间相关性的问题 from jqdatasdk import alpha101 date 2023-06-30 # 挑选逻辑上互补的三类因子动量、反转、量价 factor_dict { momentum: alpha101.alpha_001(date), # 趋势强度 reversal: alpha101.alpha_004(date), # 短期反转 volume_price: alpha101.alpha_012(date) # 量价背离 } mat pd.DataFrame(factor_dict) # 因子之间相关性过高时考虑剔除冗余因子 print(因子相关系数矩阵:) print(mat.corr().round(3)) # 用 IC 均值作为权重的简易合成实际可按滚动IC动态调整 weights pd.Series({momentum: 0.4, reversal: 0.35, volume_price: 0.25}) composite sum(mat[c] * w for c, w in weights.items()) print(合成因子前10名:) print(composite.sort_values(ascendingFalse).head(10))风控层面的三个习惯暴露度控制合成因子里单一风格如纯小市值的权重设上限相关性监控每月重算一次因子间相关矩阵发现相关性陡增就复查数据动态调权用滚动 IC 序列给因子赋权让表现好的因子阶段性获得更高权重但要控制调仓频率避免过度交易。性能与避坑缓存机制和四个常见错误理解源码里的 LRU 缓存翻看jqdatasdk/alpha101.py源码会发现每个因子函数都叠了两个装饰器assert_auth # 校验是否已认证 hashable_lru(maxsize3) # 最近使用的3个结果缓存 def alpha_001(enddate, indexall): ...hashable_lru来自utils.py它做了两件额外的事一是把 list/dict 这类不可哈希的参数序列化后再进缓存二是返回时copy.deepcopy一份防止调用方意外修改缓存对象。实际使用中这意味着在同一个进程中重复计算相同日期、相同股票池的因子不会重复请求服务端。批量研究时尽量复用同一进程、同一批日期能明显减少等待。四个高频踩坑点忘记认证所有因子函数都被assert_auth包裹必须先auth或auth_by_token日期格式混乱源码里to_date_str会把字符串、datetime、整数统一转成YYYY-MM-DD格式所以传入20230630或datetime.date都能工作但传 None 会有歧义建议显式给日期alpha101 的 index 参数默认indexall是全市场想限定某个指数成分股时传入对应指数代码注意返回的 Series 是当日截面不是时间序列alpha191 忘传 fq复权口径默认fqpre如果研究里混用了不同复权方式的数据因子值之间不可比。进阶方向把因子流程接到机器学习因子研究走到后期自然想引入机器学习。jqdatasdk 的因子结果直接就是 pandas Series/DataFrame与 sklearn 的特征矩阵天然兼容。标准流程是用 alpha101/alpha191 滚动生成多期因子截面堆叠成样本 × 特征矩阵用未来 N 日收益构造标签按时间顺序划分训练集/验证集务必避免随机切分导致的未来函数泄漏用标准化 随机森林或 LightGBM 做非线性因子组合用分层回测第三步的方法检验模型输出的打分是否仍有单调性。这里要提醒机器学习模型在因子研究里是把低相关的因子组合这件事自动化它不会凭空创造信息。如果输入因子本身没有预测力再复杂的模型也只是在拟合噪声。写在最后回看这次流程重构我最大的体会是因子的价值在于解释和验证而不在于实现。把公式翻译、数据清洗、复权处理这些重复劳动交给 jqdatasdk 的量化因子库把精力留给 IC 检验、分层回测和组合风控这些真正决定策略质量的事情上才是这套工具最正确的打开方式。如果你的研究也卡在公式实现没问题但结果总对不上的怪圈里不妨按本文的路径重走一遍先取截面再做 IC 体检然后分层回测最后合成与风控。四个环节走完你对每个因子的性格会有一个清晰的认识那时候再谈策略优化心里就有底了。【免费下载链接】jqdatasdk简单易用的量化金融数据包(easy utility for getting financial market data of China)项目地址: https://gitcode.com/gh_mirrors/jq/jqdatasdk创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考