ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

量化交易因子挖掘实战:动量、波动率与资金流三方向详解

量化交易因子挖掘实战:动量、波动率与资金流三方向详解 从零开始系统学量化交易这件事我在ptrade平台上已经整理到第166期了。前面聊过很多策略框架、回测技巧、绩效评价今天换个更关键的视角在写策略之前怎么从零开始找可用因子。这期分享三个因子挖掘思路不是什么玄学秘籍是实打实在ptrade上能落地的研究路径包括因子逻辑怎么设计、数据怎么取、回测怎么验、坑在哪里。如果你是刚开始接触量化或者写了一阵子单因子策略感觉瓶颈明显这篇内容会比较对胃口。我会尽量少讲理论废话多给可直接上手的思路和代码片段争取你看完就能在自己的ptrade环境里跑一轮因子测试。1. 因子挖掘的核心逻辑先搞明白因子是什么、为什么有效1.1 因子不等同于指标关键在“定价逻辑”很多人一开始做量化就把“写指标”当成“做因子”比如到处找MACD、KDJ、布林带到代码里跑回测然后发现回测好看、实盘变脸。原因其实很简单指标只是价格数据的数学变形它本身不解释股票为什么涨跌。而因子要解释的是“某种特征未来是否带来超额收益”这个特征背后需要有一个相对稳定的行为逻辑比如价值因子背后的逻辑是市场对基本面过度悲观动量因子背后的逻辑是信息传播存在时滞。我在ptrade上做因子研究时第一步从来不是写代码而是先写一段文字这个因子代表什么、为什么它会预测未来收益、逻辑失效的边界在哪里。不发这笔功夫后面所有统计检验都是在自欺欺人。大家可以养成一个习惯任何因子入库之前先把这个“逻辑声明”写在函数注释里后续维护也方便。1.2 因子挖掘的三种基本路径从实操角度因子挖掘基本可以归为三类路径。第一类叫“逻辑驱动法”从行为金融学或市场微观结构理论出发找到可量化的代理变量比如用换手率代理市场情绪用买卖价差代理流动性。第二类叫“数据驱动法”不预设逻辑通过统计手段从海量特征中筛选机器学习里常用的特征重要性评估就属于这个范畴。第三类是“混合驱动法”以逻辑驱动为主生成候选因子池再用统计手段做筛选和降维这是我个人比较推荐的方式。今天分享的三个因子方向就是典型的第一类混合第三类思路。每个方向会从行为逻辑开始再到数据构造最后落到ptrade的代码实现和验证方法。这样整个链条是闭合的不是拍脑袋选个参数就完事。1.3 为什么从三个方向入手而不是做一个大而全的因子库很多人研究因子容易犯一个毛病今天看到一篇论文做一个明天看到一篇研报又加一个最后库里堆了几百个因子相关性却高得吓人。真实情况是大多数因子之间存在共线性真正提供独立信息的维度并不多。我从实盘经验出发的体会是先做深三五个逻辑清晰、相关性低的因子远好过做一百个逻辑重叠的因子。选择“动量、波动率、资金流”这三个方向有一个重要考虑它们各自背后代表的是不同的市场参与力量。动量反映的是交易者行为惯性波动率反映的是市场情绪和风险偏好资金流反映的是大资金的行为痕迹。这三个维度之间天然相关性较低组合起来能覆盖市场较宽的收益来源。下面的内容就按这三条线分别展开。2. 三个因子的设计思路与逻辑依据2.1 动量类因子抓住趋势的惯性但要小心反转时段动量因子是行为金融学里被研究得最充分的因子之一核心逻辑是资产价格的短期趋势在统计上倾向于延续因为新信息在投资者之间扩散需要时间最初的过度反应会推动价格继续朝原有方向运动。在实际操作中我通常会把动量拆成两个时间尺度来处理短期动量看最近一到四周中期动量看三到十二个月两者逻辑有所不同。在ptrade上实现动量因子比较直接。第一步是用历史行情数据计算区间收益率第二步是做均值回归化处理第三步是行业市值中性化。之所以要中性化是为了避免因子信号里掺杂行业和市值的影响否则你测出来的收益可能其实是行业暴露带来的。这个处理步骤经常被初学朋友忽略但实际上它在因子有效性检验里的作用特别大。动量因子最核心的坑在于反转效应。市场上经常出现这种场景某只股票过去两个月涨得很好动量信号持续为正结果第三个月突然大幅回调动量因子净值跟着快速回落。这提示我们在做动量因子时不能简单用单一持有期需要做多周期叠加或者加入过滤条件。比如我常用的方法用短期动量20日和中期动量60日做差形成“动量加速度”指标加速度由正转负时即使绝对动量仍为正也选择不配置或减仓。2.2 波动率类因子低波动异象的实战价值波动率因子很有意思它背后的“低波动异象”已经被实证研究反复验证了很多年在大多数市场中低波动率的股票组合长期收益反而高于高波动率的股票组合。传统金融理论认为高风险应有高回报但现实里因为投资者偏爱彩票型高波动股票、机构投资者存在强制买入高波动股票的限制等原因高波动股票的预期回报被系统性压低。基于这个逻辑我一般在因子设计里用过去20日收益率的年化标准差作为波动率的代理变量。但直接把这个值作为因子会有个问题不同股票的固有波动水平差异很大而且行业之间本身的波动率就不一样科技股天然比公用事业股波动大。所以同样需要做行业中性化然后在行业内取相对排名让同一个行业的股票之间比较谁更“低波动”。在ptrade上实现这个因子时我会再做一个改进用下行波动率替换全波动率。什么叫下行波动率就是只统计收益率低于零的那些日子的标准差为什么这么做逻辑是投资者对下行风险更敏感下行风险溢价更强。实际回测里我发现下行波动率因子在下跌市里的防御性明显优于全波动率因子它在风险控制上的贡献比对收益的贡献更突出。2.3 资金流类因子追踪大资金的行动痕迹资金流因子是我个人觉得在A股市场最值得投入研究的因子方向之一因为A股散户占比高资金进出对短期价格的影响非常明显。这里讲的资金流不是简单看主力净流入的那个软件指标而是用高频量价数据构造出来的代理变量比如大单净流入占比、资金流向一致性、主动性买卖盘比例等。在ptrade里我们拿不到逐笔委托数据但通过分钟数据和五档盘口行情仍然可以构造出比较接近的资金流因子。比如一种常用的方法利用分钟级成交量与价格变动的配对关系估计大单方向。具体做法是把每分钟成交量和涨跌方向结合计算“主动买量”和“主动卖量”的差值再用过去一段时间累计得到净资金流。这个因子最常见的失效场景是“资金流入但价格不涨”。当资金流因子强烈为正而股价中长期保持横盘时通常意味着有人在刻意吸筹或对倒信号可信度下降。所以我在使用资金流因子时会叠加一个确认条件资金流连续N天为正且价格创出近20日新高两个条件同时满足才触发买入信号。过滤之后信号数量会少很多但胜率明显提升这个取舍值得。3. 在ptrade中实现因子计算与策略落地的关键细节3.1 数据获取是最重要的地基API选型和数据频率因子挖掘离不开数据数据质量直接决定因子质量的边界。ptrade平台自带的数据API在量化研究里已经够用但要注意一个分工回测时用平台历史数据实盘时用实时行情推送。如果你们自己维护数据我倒是建议把日线、分钟线、财务数据分开存储不要混在一个表里读写慢而且容易出错。在ptrade上获取数据最常用的API是 get_price、get_history 和 get_k_data它们分别适合不同的场景。get_price适合取一段时间的行情get_history适合以当前时刻为基准拿过往N条K线get_k_data可以取前复权和后复权数据。做因子计算时我习惯用get_price因为需要明确指定起始结束时间便于复现而实盘策略里用get_history更多因为信号触发时你需要的是“截至当前”的数据而不是重新计算整个历史区间。数据频率方面日线数据适合周频调仓的中低频策略分钟线适合日内或隔日短周期策略。做因子研究时我建议先用日线验证逻辑是否成立如果日线层面因子IC很低那分钟层面的复杂性通常并不会让因子“起死回生”反而会引入更多噪音。3.2 因子计算实现用向量化操作避免循环很多刚上手的朋友写因子计算时喜欢用for循环逐行遍历数据量小看不出问题数据一多速度就非常慢甚至直接把回测卡死。ptrade虽然是精简版Python环境但同样支持numpy和pandas能向量化就向量化。这里给一个动量因子计算的代码示例大家可以参考这个写法三个因子都可以套用这个框架# 动量因子计算示例 def calc_momentum_factor(data, short_days20, long_days60): 动量加速度因子 短期动量 - 长期动量 逻辑短期趋势强于长期趋势时说明正在加速买入反之卖出。 # 用收益率求和代替价格比更稳健 short_return data[close].pct_change().rolling(short_days).sum() long_return data[close].pct_change().rolling(long_days).sum() # 动量加速度 momentum_acceleration short_return - long_return # 标准化处理便于跨股票对比 factor (momentum_acceleration - momentum_acceleration.rolling(100).mean()) / \ momentum_acceleration.rolling(100).std() return factor需要注意的是因子计算前一定要处理好停牌、ST、上市不足N日的股票数据这些特殊状态会严重干扰因子取值。比如上市不足60日的次新股60日动量本身就计算不全如果直接填NaN然后统一处理会引入幸存者偏差。我的做法是所有因子计算前先做数据清洗剔除上市时间不足的股票剔除停牌期数据若因子值为缺失则自动置为该股票所在行业内因子的均值。3.3 中性化处理别让因子偷偷变成行业和市值因子因子中性化这个概念很多新手第一次听到会觉得复杂其实就是一句话把因子中由行业和市值解释的那部分方差剔除掉剩下纯因子本身的信息。如果不去掉这部分你后面检验出来的收益搞不清楚它究竟是因子贡献的还是行业配置贡献的。具体做法分两步。第一步是行业中性化用虚拟变量回归因子对行业的暴露取残差作为新因子。第二步是市值中性化同样做回归但解释变量换成对数市值。如果你的股票池不是很大也可以简化为行业内排序累加等处理。我一般在ptrade里用pandas的groupby加rank实现行业内分位数秩速度快、效果接近回归法的结果更实用。3.4 策略框架搭建信号、持仓、权重三个环节拿到因子值以后怎么把它变成实际可交易的策略这里有一个标准流程排序打分、确定持仓名单、分配权重。排序打分一般用因子值在截面上做百分位排名把因子值映射到0到100之间然后根据排名高低取前百分之十或者按分数阈值筛选权重分配可以等权也可以按因子值大小做线性加权。在ptrade的策略代码里持仓调仓的框架一般是 initialize 里设定调仓周期 handle_data 里定期执行调仓再用 order_target_percent 或 order_target_value 等API去调整仓位。下面的示例展示了一个最简单的月度调仓动量因子策略框架def initialize(context): set_benchmark(000300.SH) set_slippage(PriceSlippage(0.002)) set_order_cost(OrderCost(open_tax0.001, close_tax0.001, open_commission0.0003, close_commission0.0003, close_today_commission0, min_commission5)) run_monthly(rebalance, 1, timeopen) def rebalance(context): # 获取股票池 stocks get_index_stocks(000300.SH) current_data get_current_data() stock_pool [s for s in stocks if not current_data[s].is_st() and not current_data[s].paused] # 计算因子 factor_data {} for stock in stock_pool: hist get_price(stock, count60, frequencydaily, fields[close, paused]) if len(hist) 60: continue factor_data[stock] calc_momentum_factor(hist).iloc[-1] # 股票排序打分 if not factor_data: return factor_sorted sorted(factor_data.items(), keylambda x: x[1], reverseTrue) selected [stock for stock, fv in factor_sorted[:20]] # 调仓 stock_weight 1.0 / len(selected) for stock in context.portfolio.positions: if stock not in selected: order_target_percent(stock, 0) for stock in selected: order_target_percent(stock, stock_weight)这个代码是个简化版真实使用时要加上异常处理和日志记录还有调仓成本的控制。不过它能体现核心思路数据获取 - 因子计算 - 排序选股 - 调仓执行。4. 因子回测的评估方法与常见坑实战问题排查实录4.1 用IC和分层回测评估因子有效性而不是只盯策略净值很多人测试因子喜欢直接搭一个完整策略跑回测然后看总收益率、最大回撤、夏普比率。但这样做有一个很大的问题策略净值是“因子 交易规则 运气”的综合结果你根本拆不出因子的独立贡献。做因子研究时我更推荐先做两类检验IC检验和分层回测。ICInformation Coefficient是因子值与未来收益的截面相关系数一般用Spearman秩相关系数来算。IC均值代表因子预测能力的平均水平IC标准差代表稳定性IC均值和IR IC均值 / IC标准差IR综合反映预测能力和稳定性。实操中IC均值绝对收益超过0.03IR大于0.3的因子就算比较有潜力了当然这个阈值根牲市场有关系A股里优秀因子通常IC在0.05左右。分层回测则是把股票按因子值分成5层或者10层每层等权持有然后看各层的年化收益是否单调递增。如果第1层和第5层有明显收益差说明因子有区分度如果中间几层的收益没有单调性说明因子信号有非线性部分这时候信号可能更适合做分类而不是打分。4.2 因子衰减与换手率验证周期的选择因子不是均匀衰减的有的因子在第5天最强到第20天就消失殆尽有的因子则需要累积数月才见效。理论上因子研究需要测试多个持有期1日、5日、10日、20日观察 IC 值的衰减曲线找到信号最有效的时间窗口。衰减测试还有一个直接作用和交易成本挂钩。假设一个因子在第5天IC最大你却在第20天才调仓那得到的最多只是衰减后剩下的残羹。反过来如果因子仅在第1天有效但你使用月度调仓多数的预测能力就被浪费了。在ptrade回测里我常用 run_daily 搭配不同的调仓间隔做参数扫描大致可以找出换手率和因子IC衰减的平衡点。根据我的经验动量类因子通常是5到20个交易日内有效波动率因子的有效性持续时间更长30到60天都能看到一定贡献资金流因子的衰减速度最快往往只有3到5天的有效期。这个差异直接决定了调仓频率的设置三个因子混合使用的时候我会给每个因子设定不同的调仓周期而不是强行统一成月度或者周度。4.3 三个真实踩坑场景与排查方法第一个坑因子值看起来有规律一实盘就失效。这个通常是对未来数据不小心用了前视偏差导致的。你以为是昨天算出的因子实际上可能用到了今天甚至明天的数据。比如用复权因子计算收益率时如果取数函数里没有指定 end_date 而是默认“当前时间”回测系统会认为你获取的是当时的数据但如果你手动拼接数据源时拿的是右边界含当天的序列信号里就偷看了未来。排查方法很土但有效把因子值的最后一行打印出来和当时线上存的因子值做对比凡是有偏差就说明数据引用有问题。第二个坑低波动因子选出来的股票全是银行保险。这个问题我在行业中性化前经常遇到低波动因子天然偏好金融股和公用事业如果你不加行业中性化整个组合最后变成一个大盘金融ETF。后来加了行业内排名和行业配置约束之后组合分散度明显改善但随之而来的是收益贡献也降了一些。这里需要做个取舍是因子纯收益重要还是组合的可解释性重要我自己的选择是加约束因为纯多因子组合如果不考虑行业均衡行情风格切换的时候容易吃大亏。第三个坑资金流因子在涨跌停板上严重失真。涨停板上主动性买盘会无限放大跌停板反之因子值瞬间冲到极端。如果不对涨跌停做特殊处理资金流因子会频繁给出错误信号。我的处理逻辑是当日开盘或盘中触及涨跌停的股票资金流因子统一置空或设为最近一个正常交易日的值。这个方法不算完美但回测和实盘效果改善明显。4.4 常见问题速查表问题现象可能原因排查思路与解决方案回测收益极高但实盘亏损前视偏差、滑点设置过小检查取数是否有未来数据将滑点调为0.2%以上重测因子IC为正但分层不单调因子存在非线性用分组观察收益结构考虑改为分类信号低波动组合全是银行保险未做行业中性化增加行业内打分或行业暴露约束资金流因子信号频繁翻转涨跌停导致数据失真剔除或置空极值数据换手率过高导致收益被手续费吞噬因子持有期过短拉长调仓周期或增加交易成本过滤因子收益率逐年下滑市场风格切换或因子拥挤暂停使用等待模型重新评估后再决策4.5 样本外验证与因子组合的再构建最后一步也是很多个人量化者容易忽略的因子测试必须做样本外验证。什么叫样本内就是你在一段历史数据上发现因子有效然后直接拿同一段数据回测这只能证明因子“拟合”了历史。正确做法是留出最后6到12个月的数据做样本外测试确保因子参数不是过度优化出来的。如果要更进一步可以做滚动训练和滚动预测对每个时间点只用过去一段窗口的数据来估计因子参数然后用下一期的数据预测这样最大程度模拟了真实实盘中“你只有过去数据可用”的状态。ptrade回测引擎本身是逐bar推进的但如果你把因子计算和信号生成都放在策略主函数里没有调用未来数据回测过程本身就是一个天然的样本外验证流程。三因子组合构建方面我目前的做法是等权合成三个因子的排名得分然后用排名均值作为综合因子。等权看似简单但好处是稳定和可解释尤其当三个因子相关性不高时等权就不比复杂的权重优化差多少。等之后积累了足够多的实盘数据再考虑用IC均值加权的动态权重帮助控制因子的时效性风险。5. 一些补充心得与进阶方向前面把主体框架都说完了最后再分享几个实操层面的心得。关于数据API很多人问ptrade的数据够不够用我的感受是日线和分钟线数据做常规因子的研究基本够了但如果你想深入研究资金流、盘口微观结构类的因子可能需要额外引入level2数据或者自己做tick级的数据沉淀。这倒不是平台限制而是因子精度的天然需求。关于代码组织我强烈建议把因子计算函数、数据清洗函数、回测主逻辑分文件存放每个文件职责单一。回测策略文件可以当“调度器”因子函数都import进来。你单看一次回测没感觉但当你维护第166期、第167期甚至更多期策略时一个整洁的工程结构能剩不少返工成本。还有一点关于学习路径。因子挖掘是个系统工程不是看几个指标能跑出曲线就算会了。真正需要长期积累的是对市场微观结构的理解、对数据的敏感度、对统计检验的严格态度。这三点互相依赖缺一不可。我这些年做下来的体会是写代码的时间其实只占三成剩下七成都在“发现问题、理解问题、修正逻辑”的循环里。如果你跟着这期思路把三个因子在ptrade上从计算到回测完整跑了一遍应该会对因子挖掘有一个比较清晰的地图。下一阶段可以试着把三个因子合成起来做成一个多因子轮动或者打分选股的策略逻辑通则万变不离其宗。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进