基于指标策略与QP优化的量化投资方法:从信号生成到组合仓位分配

发布时间:2026/10/19 7:07:45
基于指标策略与QP优化的量化投资方法:从信号生成到组合仓位分配
1. 从一根均线到组合优化这套量化方法到底在解决什么问题做量化投资的人几乎都经历过这样一个阶段先用一两个技术指标写个策略回测曲线漂亮得不行一上模拟盘就发现完全不是那么回事。问题出在哪儿大多数时候不是指标本身失效了而是你只盯着单一标的、单一信号在跑没有考虑仓位怎么分配、风险怎么控制、多个策略之间怎么协同。这套“基于指标策略和QP优化的量化投资方法”核心就是解决从“单信号”到“多资产组合”的跨越问题。先说清楚它是什么。简单来讲这套方法分两层第一层用技术指标比如均线、RSI、布林带、MACD等生成每个标的的买卖信号判断“现在该不该动手”第二层用二次规划Quadratic Programming简称QP来求解最优仓位分配回答“该用多少钱、怎么分”的问题。两层结合起来就形成了一个从信号生成到组合构建的完整链路。它能做什么最直接的价值是当你同时跟踪十几个甚至几十个标的时不再需要凭感觉分配资金而是用数学优化方法给出一个在给定风险约束下预期收益最大化的配置方案。同时QP优化天然支持约束条件比如“单个标的仓位不超过20%”“整体组合波动率不超过目标值”“行业暴露不超过某个阈值”等等这些在实际投资中非常关键。适合谁来参考如果你已经写过简单的均线策略或者动量策略但苦于不知道怎么把多个策略组合起来或者不知道怎么科学地分配仓位那这套方法就是为你准备的。如果你是完全零基础的新手建议先补一下Python基础、pandas数据处理和基本的投资组合理论再来看这篇内容会更顺畅。我自己的体会是量化投资里“信号”和“仓位”是两件事很多人把精力全花在找信号上却忽略了仓位管理才是决定长期收益曲线形状的关键因素。QP优化就是解决仓位问题的利器但它也不是万能的后面我会详细讲它的适用边界和踩坑经验。2. 整体方案设计与核心思路拆解2.1 为什么选“指标策略QP优化”这个组合市面上做量化的技术路线很多有纯机器学习的、有做高频统计套利的、有做基本面因子模型的。我选择“技术指标QP优化”这条路线主要基于几个现实考量。第一技术指标策略的门槛低、可解释性强。均线金叉死叉、RSI超买超卖这些概念不管是自己调试还是跟别人沟通都很容易说清楚。相比之下机器学习模型虽然可能拟合能力更强但黑箱问题严重一旦回撤加大你很难判断到底是模型过拟合了还是市场风格切换了。第二QP优化在组合层面的数学性质非常好。二次规划的目标函数是二次的通常是组合方差约束是线性的这类问题有成熟的求解器可以高效求解而且能保证找到全局最优解凸优化问题。这意味着你不需要担心陷入局部最优给定输入就能得到确定性的输出。第三两者的结合非常自然。指标策略负责生成“观点”——哪些标的看多、哪些看空、信号强度如何QP优化负责把这些观点转化为实际仓位。观点可以来自不同频率、不同类型的指标QP统一处理不会因为策略多了就手忙脚乱。2.2 整体架构长什么样整个系统的运转流程可以拆成四个环节数据层获取标的的历史行情数据日线或分钟线做清洗和对齐。这一步看起来简单但实际做的时候数据缺失、停牌、除权除息这些问题会消耗你大量时间。信号层对每个标的分别计算技术指标根据预设规则生成信号。信号可以是离散的买/卖/持有也可以是连续的比如动量强度打分。优化层把信号转化为预期收益向量结合协方差矩阵估计构建QP问题并求解最优权重。执行层根据优化结果生成调仓指令考虑交易成本、最小交易单位等实际约束。这四个环节里信号层和优化层是核心。信号层决定了你的“方向判断”准不准优化层决定了你的“资金分配”合不合理。两者缺一不可。2.3 关键设计决策背后的逻辑在设计这套方法时有几个关键决策点需要想清楚。信号如何转化为预期收益指标信号本身是离散的但QP优化需要的是一个预期收益向量。我的做法是对每个标的根据信号的强度和方向赋予一个预期收益率。比如均线金叉给1%的预期日收益RSI超卖给0.5%多个信号叠加则加权汇总。这个映射关系没有标准答案需要根据回测调参。协方差矩阵怎么估计这是QP优化的核心输入之一。最朴素的做法是用历史收益率算样本协方差矩阵但这种方法在标的数量多、历史数据短的时候非常不稳定。我通常会用收缩估计Shrinkage方法比如Ledoit-Wolf收缩把样本协方差矩阵向对角矩阵“拉”一下提高稳定性。这一步对最终结果影响很大后面会详细讲。约束条件怎么设约束是QP优化相比其他组合方法的最大优势。我一般会设以下几类约束单标的权重上限比如15%、单标的权重下限比如0%即不允许做空、整体杠杆约束权重和不超过1、换手率约束限制每次调仓的幅度。这些约束既反映了实际投资限制也能防止优化器给出极端仓位。3. 核心细节解析与实操要点3.1 技术指标策略的构建细节先讲信号层。技术指标有成百上千种但真正适合做量化信号的不多。我的筛选标准是逻辑清晰、参数少、在不同市场环境下都有一定适应性。最终我选了以下几类指标作为信号来源。趋势类指标双均线系统。短期均线如5日上穿长期均线如20日给买入信号下穿给卖出信号。这个指标的好处是逻辑简单趋势行情下表现好缺点是震荡行情下会频繁打脸。为了缓解这个问题我加了一个过滤器只有当长期均线的斜率大于某个阈值时才认可金叉信号。超买超卖类指标RSI。RSI低于30视为超卖给买入信号高于70视为超买给卖出信号。但单纯用RSI在强趋势中会过早反向所以我结合了趋势过滤——只在长期均线向上时接受RSI超卖信号。波动率类指标布林带。价格触及下轨给买入信号触及上轨给卖出信号。布林带的优势是自带波动率自适应带宽会随市场波动自动调整。动量类指标过去N日收益率排名。这个指标在横截面策略中非常有效直接对标的进行排序排名靠前的给正预期收益靠后的给负预期收益。每个指标生成的信号需要归一化到统一的尺度上。我的做法是每个指标信号映射到[-1, 1]区间然后根据历史回测的IC信息系数或夏普比率给每个指标分配权重加权汇总得到每个标的的综合信号得分。注意指标参数不要过度优化。我见过太多人把均线参数从5/20调到7/23再调到6/21就为了让回测曲线好看一点。这种过拟合在实盘中必然失效。我的建议是参数选大众认可的经典值如5/20、10/60把精力花在信号组合和仓位优化上。3.2 QP优化问题的数学形式与求解QP优化的标准形式是这样的minimize (1/2) * w^T * Σ * w - λ * μ^T * w subject to sum(w) 1 w_min w w_max |w - w_prev| turnover_limit其中w是权重向量Σ是协方差矩阵μ是预期收益向量λ是风险厌恶系数。目标函数的第一项是组合方差风险第二项是预期收益λ控制两者之间的权衡。λ越大优化器越倾向于追求收益λ越小越保守。这个问题的求解可以直接用Python的cvxpy库或者scipy.optimize中的二次规划求解器。我一般用cvxpy因为它的语法更直观约束条件的表达更自然。import cvxpy as cp import numpy as np def optimize_weights(mu, Sigma, w_prev, lambda_risk1.0, w_max0.15, turnover0.3): n len(mu) w cp.Variable(n) objective cp.Minimize(0.5 * cp.quad_form(w, Sigma) - lambda_risk * mu w) constraints [ cp.sum(w) 1, w 0, w w_max, cp.norm(w - w_prev, 1) turnover ] prob cp.Problem(objective, constraints) prob.solve() return w.value这段代码里lambda_risk需要根据你的风险偏好来调。我一般会跑一组λ值比如0.5、1、2、5、10看哪个λ下的回测夏普比率最高。但要注意λ的选择也不能过度拟合历史数据。3.3 协方差矩阵估计的实操技巧协方差矩阵估计是QP优化里最容易被忽视但影响最大的环节。样本协方差矩阵在标的数量N大于历史天数T的时候是奇异的根本无法求逆优化问题会变得不稳定。即使NT样本协方差矩阵的估计误差也很大。我的解决方案是Ledoit-Wolf收缩估计。它的核心思想是把样本协方差矩阵向一个结构化的目标矩阵通常是对角矩阵收缩收缩强度由数据自动确定。这样既保留了样本中的相关性信息又提高了矩阵的稳定性和可逆性。from sklearn.covariance import LedoitWolf def estimate_covariance(returns): lw LedoitWolf() lw.fit(returns) return lw.covariance_除了收缩估计我还会做两件事一是用指数加权的方式计算收益率让近期数据权重更高二是对协方差矩阵做特征值修正把过小的特征值截断到一个下限防止优化器利用估计误差给出极端仓位。实操心得协方差矩阵的估计窗口不宜太短也不宜太长。太短如20天会导致矩阵不稳定太长如500天会包含太多过时信息。我的经验是60到120个交易日比较合适具体取决于你的调仓频率。日频调仓用60天周频调仓用120天。3.4 约束条件的设置艺术约束条件的设置直接决定了优化结果是否“可用”。设得太松优化器会给出极端仓位设得太紧优化器没有发挥空间结果趋近于等权。我的约束设置经验是这样的约束类型推荐值作用单标的权重上限10%-20%防止过度集中单标的权重下限0%不允许做空A股多数标的总仓位上限100%不允许加杠杆换手率上限20%-40%控制交易成本行业暴露上限±10%控制行业风险换手率约束特别重要。没有这个约束优化器可能会今天满仓A、明天满仓B交易成本会吃掉大量收益。我一般把单次调仓的换手率控制在30%以内对应大约每周调仓一次、每次调整三分之一的仓位。4. 实操过程与核心环节实现4.1 数据准备与预处理数据是量化的地基。我用的数据包括标的的日线OHLCV数据、复权因子、交易日历。数据来源可以是本地数据库也可以从公开数据接口获取。不管来源是什么以下几件事必须做复权处理用后复权价格计算收益率避免除权除息造成的价格跳空被误判为信号。复权因子要仔细核对不同数据源的复权方式可能不一致。缺失值处理停牌、涨跌停导致的数据缺失不能简单用前值填充。我的做法是停牌期间不生成信号复牌后根据复牌首日的价格变化重新计算指标。涨跌停时如果无法成交信号也要做相应处理。对齐处理多个标的的交易日历可能不同比如有的标的在某些日子停牌需要对齐到统一的交易日历上。我一般用内连接只保留所有标的都有数据的日子。异常值处理收益率中出现极端值如超过10倍标准差时需要检查是数据错误还是真实事件。如果是数据错误修正或剔除如果是真实事件如并购重组保留但做缩尾处理。4.2 信号生成与回测框架信号生成的核心代码逻辑是这样的def generate_signals(prices, short_window5, long_window20, rsi_window14): signals pd.DataFrame(indexprices.index, columnsprices.columns) for col in prices.columns: price prices[col] ma_short price.rolling(short_window).mean() ma_long price.rolling(long_window).mean() trend_signal np.where(ma_short ma_long, 1, -1) delta price.diff() gain delta.where(delta 0, 0).rolling(rsi_window).mean() loss -delta.where(delta 0, 0).rolling(rsi_window).mean() rs gain / loss rsi 100 - 100 / (1 rs) rsi_signal np.where(rsi 30, 1, np.where(rsi 70, -1, 0)) signals[col] 0.6 * trend_signal 0.4 * rsi_signal return signals这段代码生成了一个综合信号趋势信号权重0.6RSI信号权重0.4。权重是根据历史IC确定的不是拍脑袋定的。回测框架我建议自己写不要用现成的回测平台。原因很简单QP优化需要自定义的仓位分配逻辑现成平台往往不支持。自己写的回测框架虽然前期投入大但后期灵活度高想改什么改什么。回测时要注意几个关键点一是用滚动窗口不能用未来数据二是交易成本要算进去我一般按单边万分之三计算三是滑点要模拟特别是流动性差的标的。4.3 QP优化的完整实现把前面几部分串起来完整的优化流程是这样的def run_optimization(prices, returns, signals, w_prev, lambda_risk1.0): mu signals.mean(axis0).values * 0.01 Sigma estimate_covariance(returns) w_opt optimize_weights(mu, Sigma, w_prev, lambda_risk) return w_opt这里mu的计算方式是把信号得分乘以一个缩放系数0.01作为预期日收益率。这个缩放系数需要根据回测调整太大太小都不行。整个流程跑下来每天或每周执行一次计算信号→估计协方差→求解QP→生成调仓指令。调仓指令要考虑最小交易单位比如A股100股一手把优化权重转化为实际股数。4.4 参数调优与回测评估参数调优是量化里最容易过拟合的环节。我的原则是参数要少、要稳、要有逻辑支撑。需要调的参数主要有指标窗口长度、信号权重、λ风险厌恶系数、换手率上限、协方差估计窗口。我一般用网格搜索加交叉验证的方式把数据分成训练集和验证集在训练集上调参在验证集上评估。如果验证集表现和训练集差距很大说明过拟合了需要简化模型。回测评估指标不能只看收益率。我重点关注以下几个夏普比率风险调整后收益、最大回撤极端风险、Calmar比率收益回撤比、换手率交易成本、胜率信号质量。这几个指标要综合看不能只看一个。注意回测中表现最好的参数组合往往在实盘中表现最差。这不是玄学而是过拟合的必然结果。我的做法是选参数时不要选最优的选次优的、在参数空间中比较稳定的区域。比如λ1和λ2的表现差不多那就选λ1.5而不是选表现最好的λ1.2。5. 常见问题与排查技巧实录5.1 优化器给出极端仓位怎么办这是QP优化最常见的问题。优化器为了追求目标函数的最优值可能会把某个标的的权重打到上限或者把大部分仓位集中在少数几个标的上。原因通常是预期收益向量μ的估计误差太大或者协方差矩阵不稳定。解决方法有几个一是加强约束把单标的权重上限调低二是对μ做收缩处理把极端值向均值拉三是在目标函数里加正则项惩罚权重过于集中。我一般会同时用这几个方法效果比较稳。5.2 回测表现好但实盘表现差这个问题几乎每个做量化的人都遇到过。原因可能有很多过拟合、交易成本低估、滑点没算、数据质量问题、市场风格切换。排查的时候要逐一排除。我的排查顺序是先检查交易成本假设是否合理再检查是否有未来数据泄露然后看回测期的市场环境是否特殊比如单边牛市最后才怀疑模型本身。很多时候问题出在前几步而不是模型不行。5.3 协方差矩阵估计不稳定前面讲过用Ledoit-Wolf收缩但有时候收缩还不够。如果标的数量超过50个即使收缩估计也可能不稳定。这时候可以考虑用因子模型来估计协方差矩阵先提取几个主要风险因子比如市场因子、行业因子、风格因子用因子暴露和因子协方差来重构标的协方差矩阵。这样既降低了估计维度又保留了主要风险结构。5.4 信号衰减与策略失效技术指标策略有一个天然缺陷一旦被广泛使用有效性就会下降。均线策略在几十年前可能很有效现在效果大打折扣。这不是说技术指标没用了而是说不能指望一个固定参数、固定逻辑的策略永远有效。我的应对方式是定期评估策略表现当滚动夏普比率持续低于阈值时降低该策略的权重或暂停使用。同时保持策略库的多样性趋势、反转、动量、波动率各类策略都配一些东方不亮西方亮。5.5 常见问题速查表问题现象可能原因排查方法解决方案优化器不收敛协方差矩阵非正定检查特征值收缩估计或特征值修正仓位极端集中μ估计误差大检查信号分布加强约束或μ收缩换手率过高信号频繁翻转统计信号变化频率加换手率约束或信号平滑回撤突然加大市场风格切换分析回撤期市场环境降低仓位或暂停策略实盘与回测差距大过拟合或成本低估对比回测与实盘细节简化模型、提高成本假设6. 我在这套方法上踩过的坑和总结的经验做这套方法的过程中我踩过不少坑有些坑到现在还在填。分享几个印象最深的。第一个坑是过度依赖回测。早期我花了很多时间优化回测曲线把夏普比率从1.5调到2.0结果实盘一跑完全不是那么回事。后来我才明白回测只是验证逻辑的工具不是预测未来的水晶球。回测好看不代表实盘能赚钱回测一般但逻辑扎实的策略反而更有可能在实盘中存活。第二个坑是忽视交易成本。QP优化给出的仓位调整可能非常频繁如果不加换手率约束交易成本会吃掉大量收益。我现在的做法是把交易成本直接纳入优化目标在目标函数里加一项交易成本惩罚让优化器自己权衡收益和成本。第三个坑是协方差矩阵估计太随意。一开始我直接用样本协方差矩阵结果优化器经常给出莫名其妙的仓位。后来改用收缩估计效果好了很多。再后来加了因子模型又上了一个台阶。协方差矩阵的估计质量直接决定了QP优化的效果上限。第四个坑是策略参数过拟合。我曾经把均线参数从5/20调到7/23再调到6/21就为了让回测好看一点。结果实盘一跑还不如最初的5/20。现在我定了一个规矩参数只选经典值不做过细调优。把精力花在信号组合和风险控制上收益反而更好。最后分享一个我觉得最有用的经验量化投资里简单的方法往往比复杂的方法更有效。这套“指标策略QP优化”的方法核心逻辑其实很简单——用指标判断方向用优化分配仓位。但就是这么一个简单的框架只要执行到位就能跑出不错的收益曲线。复杂的方法不一定更好适合自己的才是最好的。