ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

机器学习多因子研究框架:从因子构建到滚动训练实战

机器学习多因子研究框架:从因子构建到滚动训练实战 简介这份资源是一套面向金融量化研究者与数据科学从业者的机器学习多因子研究框架覆盖从因子选择、收益预测到风险建模与组合配置的完整链路适合具备一定Python与金融基础、希望系统实践量化策略的中高级学习者。压缩包共306个文件约38.98MB以csv数据、ipynb实验笔记、py脚本为主辅以db数据库、java与c源码、makefile及readme说明兼顾数据、代码与文档的完整复现。框架重点实现XGBoost与lightGBM收益模型并引入贝叶斯优化进行超参数寻优同时包含波动率、VaR与条件VaR等风险度量以及均值-方差和Black-Litterman组合优化思路。已有349人学习读者可据此理解多因子建模全流程掌握参数调优与风险约束下的权重配置方法并借助现成脚本与笔记快速搭建自己的研究环境。1. 从一份「机器学习多因子研究框架」说起它到底解决什么问题很多人第一次听到「基于机器学习的多因子研究框架」脑子里浮现的是量化私募里那种动辄几十个因子、跑在集群上的庞然大物。但真正落到个人或小团队手里它其实是一套很朴素的东西把若干条能解释收益差异的指标因子算出来用机器学习模型去拟合它们和未来收益的关系再拿这套关系去给当下的标的打分排序。它解决的核心痛点只有一个——人工拍脑袋定权重太脆弱市场风格一变昨天好用的因子今天就失效而机器学习能自动从历史数据里学出「当前该信谁多一点」。这套框架适合谁如果你手上有结构化的行情或基本面数据会写 Python想验证「某个因子到底有没有用」「几个因子怎么组合」那它就是你的工作台。它不适合指望开箱即用就能赚钱的人因为框架本身不产生 alpha它只是把「提出假设—验证—组合—回测」这条链路标准化让你少写重复代码、少踩数据对齐的坑。热搜里「机器学习项目」「机器学习应用流程」被反复搜本质就是大家卡在「知道算法但不知道怎么串成一个能跑的研究闭环」这篇就按这个闭环来讲。2. 框架的骨架因子、标签、模型三段式怎么搭2.1 为什么是「因子—标签—模型」而不是端到端深度学习先讲选型理由这决定了后面所有代码长什么样。多因子研究的本质是横截面排序问题在每个时间截面上给一堆标的按预期收益排个序买前面的卖后面的。这个任务的数据特点是「样本量中等、信噪比极低、因子之间高度相关」端到端深度学习在这种场景下极易过拟合而且黑匣子特性让你没法解释「为什么今天这个标的排第一」。所以主流做法是显式构造因子再用一个相对简单的模型线性回归、树模型、浅层神经网络去学因子到收益的映射。常见做法是因子层负责「把原始数据变成有经济含义的数值」标签层负责「定义什么叫未来会涨」模型层负责「学权重」。三层解耦的好处是任何一层出问题你都能单独定位——是因子算错了还是标签泄漏了还是模型过拟合了。热搜里「机器学习假设」「机器学习模型」这些词落到这里就是假设因子与未来收益存在某种稳定哪怕时变的关系模型只是去逼近它。2.2 用 pandas 搭一个最小可跑的因子计算管线下面这段代码是整个框架的地基给定一张包含日期、标的代码、收盘价和成交量的长表算出动量、波动率、换手率三个最基础的因子。注意它是按标的、按时间滚动计算的这是避免未来函数的第一道防线。import pandas as pd import numpy as np def build_factors(df, windows(5, 20, 60)): df 列: date, symbol, close, volume, amount 返回: 每个 symbol 每个 date 的因子值 df df.sort_values([symbol, date]).copy() g df.groupby(symbol, group_keysFalse) # 动量因子: 过去 N 日收益率, 用 shift 保证只用历史 for w in windows: df[fmom_{w}] g[close].apply(lambda s: s / s.shift(w) - 1) # 波动率因子: 过去 N 日日收益标准差 df[ret] g[close].pct_change() for w in windows: df[fvol_{w}] g[ret].apply(lambda s: s.rolling(w).std()) # 换手率代理: 成交额 / 20日均额, 衡量相对活跃度 df[turn_20] df[amount] / g[amount].apply( lambda s: s.rolling(20).mean() ) return df逻辑说明groupby(symbol)保证每个标的独立滚动shift(w)和rolling(w)都只回看历史天然规避未来函数。参数说明windows控制回看周期短周期5捕捉近期动量长周期60更稳但滞后实际研究里通常同时保留多组让模型自己选。turn_20用成交额比值而非绝对量是为了消除标的规模差异。跑完这一步你会得到一张宽表每行是一个「标的—日期」样本后面所有环节都基于它。2.3 标签构造未来收益怎么算才不泄漏标签是新手翻车最狠的地方。常见错误是用当日收盘价算未来收益时把当天也算进去了。正确做法是在第 T 日收盘后决策用 T1 开盘买入持有到 TN 收盘卖出标签就是这段收益。def build_label(df, horizon5): df df.sort_values([symbol, date]).copy() g df.groupby(symbol, group_keysFalse) # 未来 horizon 日收益, shift(-horizon) 表示未来 df[fwd_ret] g[close].apply( lambda s: s.shift(-horizon) / s.shift(-1) - 1 ) return df这里shift(-1)是买入价次日shift(-horizon)是卖出价中间不含当日避免泄漏。参数horizon决定预测周期5 日适合中频1 日噪声太大20 日以上样本衰减快。注意最后 horizon 行标签是 NaN训练前必须 drop否则模型会学到空值。3. 把因子喂给模型训练、验证与防过拟合的实操3.1 时序切分为什么不能随机 train_test_split这是多因子框架里最容易被忽略、后果最严重的一点。金融数据是时序的随机切分会让「未来样本」混进训练集模型在验证集上表现虚高实盘一塌糊涂。正确做法是按时间切前 70% 训练中间 15% 验证调参最后 15% 测试。def time_split(df, train0.7, valid0.15): dates np.sort(df[date].unique()) n len(dates) tr_end dates[int(n * train)] va_end dates[int(n * (train valid))] train_df df[df[date] tr_end] valid_df df[(df[date] tr_end) (df[date] va_end)] test_df df[df[date] va_end] return train_df, valid_df, test_df逻辑说明按唯一日期排序后切保证同一日期的所有标的落在同一集合避免横截面泄漏。参数说明train/valid比例不是死的样本少时可以 80/10/10但测试集必须留出足够长的时间跨度至少覆盖一轮风格切换否则你测不出模型的稳健性。3.2 用 LightGBM 跑通第一版模型并看特征重要性选 LightGBM 的理由对缺失值和非线性友好、训练快、自带特征重要性非常适合因子研究这种「快速试错」的场景。下面是最小训练脚本。import lightgbm as lgb FEATURES [c for c in train_df.columns if c.startswith((mom_, vol_, turn_))] params { objective: regression, learning_rate: 0.05, num_leaves: 31, min_data_in_leaf: 200, # 关键: 防止叶子过拟合 feature_fraction: 0.8, bagging_fraction: 0.8, bagging_freq: 1, verbose: -1, } dtrain lgb.Dataset(train_df[FEATURES], train_df[fwd_ret]) dvalid lgb.Dataset(valid_df[FEATURES], valid_df[fwd_ret]) model lgb.train( params, dtrain, num_boost_round500, valid_sets[dvalid], callbacks[lgb.early_stopping(50)], ) imp pd.Series(model.feature_importance(gain), indexFEATURES) print(imp.sort_values(ascendingFalse))参数说明min_data_in_leaf是防过拟合的第一道闸金融数据信噪比低叶子样本太少必然记住噪声一般设几百到上千learning_rate配early_stopping是标准组合验证集不再改善就停。特征重要性用gain而非split因为 gain 反映真实贡献。跑完你会看到哪些因子被模型重视但这只是起点——重要性高不代表未来有效还要看下一章的滚动验证。3.3 滚动训练让模型跟着市场一起走一次性训练出的模型半年后大概率失效。工程上的解法是滚动窗口每隔一段时间用最近 N 个月数据重训一次预测下一段。def walk_forward(df, features, train_months24, retrain_freqM): results [] df df.set_index(date) for end in pd.date_range(df.index.min(), df.index.max(), freqretrain_freq): start end - pd.DateOffset(monthstrain_months) tr df.loc[start:end] # 下一期预测区间 nxt df.loc[end:end pd.DateOffset(months1)] if len(tr) 1000 or len(nxt) 0: continue m lgb.train(params, lgb.Dataset(tr[features], tr[fwd_ret]), num_boost_round300) nxt nxt.copy() nxt[pred] m.predict(nxt[features]) results.append(nxt[[symbol, pred, fwd_ret]]) return pd.concat(results)逻辑说明每个调仓周期用过去train_months的数据重训预测下一个月模拟真实研究节奏。参数说明train_months太短模型不稳太长反应迟钝24 个月是常见起点retrain_freq决定重训频率月度是平衡成本与时效的常用值。这一步跑通你才真正拥有一个「能持续产出预测」的框架而不是一次性的玩具。4. 避坑与排查多因子框架里最容易翻车的五件事4.1 因子值出现未来函数现象回测收益高得离谱夏普 5 以上实盘完全对不上。原因某个因子在计算时用了当日或未来数据比如用当日收盘价算的动量却当作开盘前可得。解决所有因子统一在「决策时点」之前可得写完因子后做一次「时间旅行测试」——把数据截断到某日看该日因子值是否变化变了就是泄漏。4.2 标签与因子时间错位现象模型训练 loss 很低但预测和实际收益几乎不相关。原因标签用了 T 日到 TN 日收益因子却包含了 T 日收盘信息而实盘 T 日收盘后才能算因子等于用未来信息预测过去。解决明确「因子可得时点」和「标签起算时点」中间至少隔一个交易日的开盘。4.3 缺失值填充引入偏差现象某些标的因子全是 NaN填充后模型给出异常高分。原因用全样本均值填充把横截面信息混进了时序。解决缺失值优先按标的时序前向填充仍缺则按当日横截面中位数填绝不跨日期用未来均值。4.4 特征重要性高但实盘无效现象某因子 gain 排第一单独回测却亏钱。原因模型在训练集上利用了该因子与噪声的偶然相关验证集没暴露是因为切分不够长。解决用滚动验证替代单次验证看因子在多个时间窗口的稳定性而不是一次的重要性排名。4.5 回测忽略交易成本与停牌现象换手率极高的策略回测很美实盘被手续费吃光。原因回测假设随时能按收盘价成交没扣成本、没处理停牌。解决回测里加入双边手续费和滑点停牌日不产生交易信号涨跌停日限制成交。这一步不做前面所有工作都是自欺欺人。5. 让框架真正可用从单因子检验到组合打分的一个技巧走到这里你已经有了能跑的管线但「能跑」和「有用」之间还差一步单因子有效性检验。我的习惯是在把任何因子丢进模型之前先做一次横截面 IC信息系数分析——算每个截面上因子值与未来收益的秩相关看它的均值、标准差和 IC_IR。IC 均值稳定为正、IC_IR 大于 0.3 的因子才值得进模型否则模型再强也是在拟合噪声。def factor_ic(df, factor, labelfwd_ret): 按日计算横截面秩相关, 返回 IC 序列 ics df.groupby(date).apply( lambda x: x[factor].corr(x[label], methodspearman) ) return ics.dropna() ic factor_ic(df, mom_20) print(fIC均值: {ic.mean():.4f}, IC_IR: {ic.mean()/ic.std():.4f})这个技巧的价值在于它把「模型黑匣子」拆开了一角如果单因子 IC 都不稳定指望模型组合出稳定收益是不现实的。反过来如果几个因子各自 IC 尚可但相关性低模型组合往往能带来超额。参数上methodspearman用秩相关而非皮尔逊是为了抗极端值按日分组保证是横截面比较不是时序比较。再进一步可以把模型预测值也做一次 IC 分析对比「单因子最优 IC」和「模型 IC」如果模型没有明显提升说明因子间没有互补信息该回去找新因子而不是调模型参数。这套「先检验、再组合、后验证」的顺序是我踩了无数次坑之后固定下来的习惯——它不能保证你赚钱但能保证你不被自己的回测骗。希望帮到你。本文还有配套的精品资源点击获取
返回列表