拓冰建站拓冰建站
首页 / 资讯中心 / 正文

移动平均模型(MA)解析:用“意外”预测时间序列的未来

移动平均模型MA模型这个主题我第一次听就觉得名字有误导性。它并不是在算K线上的均线也不是模型压缩里说的量化而是在用一组随机冲击的滞后组合去解释时间序列当前的值。用一句话概括MA模型用过去的“意外”预测未来的值。这个“意外”在统计上叫白噪声或新息在金融场景里可以理解为突发消息、超预期的成交变化、短期流动性扰动。它们本身不可预测但一旦发生会对后续几期产生残影效应。量化交易里日收益率经常表现出这种特征某个意外让收益率偏离均值接下来几期可能继续受影响然后慢慢消退。MA模型就是把这个“残影”结构建模出来。这是量化笔记第43篇。我按自己的实操顺序把MA模型拆成六个部分先讲它解决什么问题再讲统计性质然后用 Python 从模拟到建模跑一遍接着讲阶数识别再落到量化场景最后给一份排查清单。适合刚开始学时间序列的人也适合已经在用 ARIMA 但没仔细看 MA 部分的读者。读完你会发现MA模型并不难难点反而在概念区分和数据预处理。1. MA模型到底在做什么把“意外”变成可预测的结构1.1 先搞清楚这里不是均线也不是模型量化MA 这个缩写太容易撞名字了。量化交易社区里搜“MA”会出现两组完全不相关的东西。第一组是移动平均线Moving Average比如 MA5、MA10、MA20。这是 K 线技术指标用来平滑价格是趋势跟踪里最常见的工具。第二组是模型量化Quantization比如把深度学习模型从 FP32 压缩成 INT8、INT4大家经常说“量化模型”那是优化推理速度和显存占用。而本文说的 MA 模型全称是 Moving Average model属于时间序列分析中的经典模型是 ARIMA 模型框架里专门描述短记忆随机冲击的部分。大家平时在统计教材里看到的 MA(1)、MA(2)指的就是它。三个“MA”中只有这个 MA 真正在回答“过去一个无法预测的意外如何通过线性结构影响今天和明天”的问题。我在带量化学员时最常遇到的一种困惑就是去网上一搜“MA模型”搜到一堆均线代码然后越看越绕。所以先把这个概念划分清楚整篇文章才有意义。名称英文核心作用在量化里的常见用途移动平均模型Moving Average model描述白噪声冲击的滞后影响对收益率序列建模、预测短期冲击残影简单移动平均线Moving Average计算过去 N 期价格均值趋势跟踪、均线交叉信号模型量化Quantization压缩模型精度减少显存和计算量部署深度学习模型到低算力设备1.2 用公式看 MA 模型怎么预测未来MA(q) 模型写成公式是y_t μ ε_t θ1 ε_{t-1} θ2 ε_{t-2} ... θq ε_{t-q}其中y_t 是 t 时刻的观测值在量化里通常取收益率序列μ 是序列均值ε_t 是 t 时刻的新息innovation也叫白噪声、随机冲击、意外均值为 0方差恒定θ1 到 θq 是移动平均系数表示过去的冲击对当前值的影响强度。为什么说它“用意外预测未来”因为 MA 模型把当前值分解成两部分一部分是当前新息另一部分是过去 q 期新息的加权组合。如果某个外部消息让今天产生了异常收益这个异常会作为 ε_t 进入模型并且在接下来几期继续通过 θ 系数影响预测值直到 q 期后消失。举个通俗例子。假设某天某只股票因为一条临时监管消息收益率比均值低 2%这是一个“意外”ε_t。如果 MA(1) 的 θ1 是 0.5那么模型会认为这个 -2% 的冲击会对下一次观测值继续产生 -1% 的影响然后逐步衰减。这不是说消息会重复而是说市场消化消息可能需要时间这种短期的滞后效应MA 模型正好能抓住。1.3 MA 和 AR 的分工不同AR 模型自回归模型用过去的“观测值”本身预测未来MA 模型用过去的“误差项”预测未来。这是两者最本质的区别。AR(1)y_t μ φ1 y_{t-1} ε_t MA(1)y_t μ ε_t θ1 ε_{t-1}AR 模型适合描述“今天的位置影响明天的位置”比如惯性、趋势MA 模型适合描述“今天的意外影响明天的位置”比如冲击后的短期回归。两者如果单独不够用就组合成 ARMA 模型。实际操作中做量化收益率建模时很多人一上来就拟合 ARMA(p,q)但从我的经验看先分清“序列里到底是惯性强还是冲击残影强”再去定 p 和 q要比盲目调参靠谱得多。2. 为什么“意外”会留下痕迹MA模型核心性质2.1 MA(q) 序列天然平稳MA(q) 的一个关键性质是只要系数 θ 是固定常数且 ε_t 是稳定的白噪声那么 MA(q) 就一定是平稳的。直观理解模型里所有项都是白噪声的线性组合白噪声本身没有趋势、没有周期性、方差恒定所以它们的线性组合也不会出现单位根或明显漂移。这一点和 AR 模型很不一样。AR 模型需要满足 |φ| 1 之类的平稳条件如果系数太接近 1序列会有很强的持续性甚至近似随机游走。MA 模型的平稳性条件宽松得多代价是它能刻画的记忆也短超过 q 期的自相关直接为 0。在量化场景里这意味着 MA 模型比较适合对经过处理后的收益率序列建模而不是对价格序列建模。价格序列通常是非平稳的不能用 MA 模型硬套。先对价格做对数差分得到收益率再考虑 MA才是常见顺序。2.2 ACF 在 q 阶后截尾这是识别信号MA 模型最容易被利用的性质是自相关函数ACF。对 MA(q) 来说当前值只和过去 q 期的新息相关所以理论上滞后 1 到 q 阶的自相关系数可能显著超过 q 阶的 ACF 为 0 或者接近 0这叫做“ACF 在 q 阶截尾”。这是判断序列是否适合 MA 模型的最直观工具。如果一组序列的 ACF 在滞后 2 阶之后突然掉进置信区间之后几乎没有显著值那就很有可能是 MA(2)。但如果 ACF 衰减得很慢拖着长长的尾巴那可能先考虑 AR 模型或者单位根问题。实际操作中我一般会先画 ACF 和 PACF 两张图。虽然样本估计值会有噪声但“截尾”和“拖尾”的形态差异通常还是能看出来的。2.3 为什么还需要可逆性MA 模型还有一个约束条件叫可逆性。数学上只有当 MA 特征方程的根都在单位圆外时MA(q) 才能写成 AR(∞) 的形式对应的系数才是唯一可估计的。在 statsmodels 里拟合 MA 模型时如果系数估计结果出现异常比如多次运行结果不稳定或者优化器提示收敛到边界往往就是可逆性条件没有被满足或接近边界。对量化应用来说可逆性的实际意义是只有满足可逆性的 MA 模型才可以用历史信息逐步递推得到“当前新息”的估计进而用于预测。如果模型不可逆“意外”就是不可恢复的预测也就无从谈起。3. 先跑通一个 MA 模型Python 实操流程3.1 生成模拟数据先知道真值学习 MA 模型我不建议一开始就直接拿真实行情数据来跑。真实数据噪声大、阶数不明确、还可能夹着缺失和异常出问题时很难判断是模型问题还是数据问题。我建议先构造一组模拟 MA(1) 数据自己知道真实的 θ1 是多少再回头看模型能不能估计出来。模拟代码如下import numpy as np import pandas as pd import matplotlib.pyplot as plt from statsmodels.tsa.arima.model import ARIMA from statsmodels.graphics.tsaplots import plot_acf, plot_pacf np.random.seed(42) n 1000 eps np.random.normal(0, 1, n) theta1 0.6 y np.zeros(n) y[0] eps[0] for t in range(1, n): y[t] eps[t] theta1 * eps[t-1]这里的 eps 就是白噪声序列代表每一天的“意外”。y 就是 MA(1) 序列理论上的 ARIMA 阶数为 (0,0,1)。先画个图观察序列是否存在明显趋势。MA 序列应该是围绕均值波动的不会出现持续上行的形态。3.2 用 statsmodels 估计 MA(q)statsmodels 里的 ARIMA 类可以直接拟合 MA 模型。只要把 order 设为 (0,0,q) 即可model ARIMA(y, order(0, 0, 1)) res model.fit() print(res.summary())注意 ARIMA 的 order 参数顺序order(p,d,q)。p 是自回归阶数d 是差分次数q 是移动平均阶数。MA(q) 就对应 (0,0,q)。拟合完成后summary 里会给出coefθ1 的估计值std err标准误z、P|z|显著性检验AIC、BIC信息准则用于模型比较。理想情况下θ1 估计值应该接近 0.6。如果模拟数据量够大估计结果应该很接近真值。这里不需要把每一步输出都当作硬标准重点是观察估计流程是不是顺利。接着预测未来 5 期forecast res.get_forecast(steps5) print(forecast.predicted_mean) print(forecast.conf_int())MA 模型的预测有一个特点当预测步长超过 q 后预测值很快回到序列均值 μ置信区间也会逐渐变大。这是因为超过 q 期之后模型里没有新的信息可用了。这不是 bug而是 MA 模型本身的短记忆特性。3.3 识别 ACF 和 PACF 的形态拟合完后可以画 ACF 和 PACFfig, axes plt.subplots(1, 2, figsize(12, 4)) plot_acf(y, axaxes[0], lags20) plot_pacf(y, axaxes[1], lags20) plt.show()对于纯 MA(1) 序列ACF 应该在第 1 阶显著之后快速进入置信区间PACF 则表现为逐渐衰减。如果你的序列同时出现 ACF 和 PACF 都拖尾那可能要考虑 ARMA 模型或者序列本身有结构变化。3.4 真实数据里要小心的问题从模拟数据切换到真实行情数据时我一般会先做这些预处理先取对数价格再做一阶差分得到收益率序列处理缺失值和停牌日不要把 NaN 直接交给模型剔除明显的极端值或做 winsorize 处理避免单日异常收益影响参数估计检查序列是否近似平稳必要时用 ADF 检验辅助判断。很多报错比如“convergence failed”“NaN results”其实不是模型问题而是数据里有缺失、无穷或极端值。4. 怎么判断用 MA(q) 而不是其他模型4.1 一张图、一组检验先给出方向识别 MA 阶数最常见的顺序是计算收益率序列的 ACF 和 PACF看 ACF 是否在某一阶后突然截尾看 PACF 是否拖尾或衰减结合信息准则 AIC/BIC对 q0、1、2、3 分别建模选择信息准则最低、且参数显著的模型。举一个典型判断。如果 ACF 在滞后 2 阶后全部落在置信区间内而 PACF 从滞后 3 阶也开始逐渐消失那么可以先按 MA(2) 尝试。如果 ACF 截尾不太明显PACF 同样很快消失可以同时尝试 ARMA(1,1) 和 MA(1)用 AIC 比较。如果只依赖 ACF很容易误判。样本较短时即使理论上 ACF 在 q 阶后为 0估计值也会有波动偶尔冒出一两个超过置信区间的柱子不代表模型真的很复杂。4.2 用 AIC/BIC 做数量上的对比阶数识别不能只看图还需要信息准则做定量比较。AIC、BIC 越低表示模型在拟合优度和复杂度之间取得了更好平衡。一个简单做法是循环几个候选阶数best_aic np.inf best_q 0 for q in range(0, 4): model ARIMA(y, order(0, 0, q)) res model.fit() print(fq{q}, AIC{res.aic:.3f}, BIC{res.bic:.3f}) if res.aic best_aic: best_aic res.aic best_q q print(best_q:, best_q)注意这里只是示例代码。实际数据里q0 代表纯白噪声如果 AIC 最低的是 q0说明序列本身几乎没有短期相关结构就不要勉强加 MA 项。4.3 低样本下的识别误区如果样本量很少比如只有 50 期收益率ACF 和 PACF 的置信区间会很宽识别结果很不稳定。这种情况下即使 AIC 选出了 MA(2)也可能只是过拟合。我更倾向于样本低于 100 时优先使用简单模型比如 MA(1) 或 MA(2)不要轻易尝试太高的阶数。模拟数据里可以任意选阶数但真实量化数据里高阶 MA 参数往往缺乏稳定性输出结果也难解释。另一个常见误区是把“收益率存在自相关”等同于“必须用 MA”。自相关可能来自波动率聚集、市场微观结构效应、交易时段差异等需要先做预处理或加入外生变量再建模。MA 模型只是其中一种建模方式不是万能解法。5. 量化场景里MA 模型到底怎么用5.1 选择适合 MA 模型的数据MA 模型在量化里最适合的建模对象是收益率序列尤其是日频、小时频的收益率。这种数据通常围绕 0 波动偶尔出现冲击冲击会以线性衰减的方式影响后面几期。价格序列不平稳直接建模经常出现伪回归。指数收盘价、个股价格、累计净值都属于“今天和昨天高度相关”的序列先差分再建模是标准做法。哪怕是对数价格也不能直接放进 MA 模型。另外MA 模型对低频数据的适用性一般。如果数据是周频或月频样本量通常不够而且冲击传导路径往往更复杂很难用几阶 MA 描述。这时更适合引入宏观变量、因子暴露或者采用更完整的 ARIMA、状态空间模型。5.2 一个均值回归信号的搭建思路MA 模型本身不产生“买入卖出”信号它更多是描述数据生成过程。量化应用里常见的方式是用 MA 模型拟合收益率后把预测的收益率方向或残差转成信号。比如对某指数的日收益率拟合 MA(1)得到预测值接近 0说明当前看不到明显的冲击残影预测值连续为正说明短期动量还在延续残差出现较大负值说明模型外出现了新意外需要关注均值回归潜力。实际回测时我一般会先构造一个最朴素的规则当模型预测的下一期收益率在历史分布的某个分位点以上或以下时生成做多或做空信号。这种信号不会很复杂但能帮助你验证 MA 模型是否在样本外有增量信息。用 Python 写这个策略代码核心其实就几步取数据、滚动估计、生成信号、回测。需要提醒一句模型只是量化研究中的一个环节不构成投资建议。把信号直接当策略用之前必须做样本外验证尤其要防止参数被反复调整导致过拟合。5.3 从研究到策略要注意的坑这里有三个坑特别常见。第一未来函数。很多人用全样本收益率计算均值、方差、模型参数然后逐日回测这等于把未来信息泄露到了历史回测里。正确做法是每天只用截至当天的数据重新估计参数或者至少使用滚动窗口。第二参数更新频率。MA 模型的参数并不是固定的。市场状态变化后θ 系数可能变化。如果一个月甚至一季度才更新一次参数模型可能早就偏离当前数据。具体更新频率要和持仓周期匹配持仓周期短参数更新也要更频繁。第三过度迷信模型。MA 模型是线性模型只能刻画线性滞后关系。真实市场的冲击传播往往有非线性、不对称性比如利好和利空的衰减速度不同。MA 模型作为基线工具很好但不能要求它解释所有收益率的变动。在聚宽、QMT 这类量化研究环境里取数、回测框架大同小异但核心还是要先把模型逻辑验证清楚再换平台。6. 参数估计、残差诊断和排查清单6.1 参数估计方法最大似然大多数量化工具里的 MA 模型都是用最大似然估计MLE来估计参数。简单理解就是找一组 θ 参数让当前样本出现的概率最大。MLE 估计对样本量有一定要求。样本太少时标准误很大参数显著性不稳定。如果拟合结果里某个 θ 的 P 值大于 0.05说明这个参数可能不显著可以考虑降低阶数。一个更实际的建议是观察拟合结果里的“常数项”和“残差方差”是否合理。常数项应该接近收益率均值残差方差应该和样本方差接近。如果出现异常大的参数或方差很可能数据预处理有问题。6.2 残差要像白噪声才算合格模型拟合完最该看的是残差不是拟合优度。残差应该接近白噪声不存在显著自相关、均值接近 0、方差稳定。可以观察残差 ACF并做 Ljung-Box 检验from statsmodels.stats.diagnostic import acorr_ljungbox lb acorr_ljungbox(res.resid, lags10, return_dfTrue) print(lb)判断标准Ljung-Box 的 p 值大于 0.05表示残差在对应滞后期内没有显著自相关如果 p 值很小说明模型还没把信息提取干净需要增加阶数或改用 ARMA如果残差 ACF 在低阶仍有明显相关优先考虑调整 p 或 q而不是直接加高复杂性模型。很多新手看到训练集拟合得很好就急着进入回测。实际上训练集拟合优度高不代表预测能力强。残差诊断的意义在于确认模型已经把数据中的线性相关结构吸收干净了剩下的部分才是真正的随机意外。6.3 常见报错和排查顺序最后给一份我自己排查 MA 模型问题时的顺序清单。先看现象拟合报错收敛失败拟合出的参数全是 NaN预测结果非常不合理残差 ACF 仍然显著。再看输入数据是否有缺失值、NaN、无穷值是否做了差分数据是否近似平稳是否混入了未来数据收益率是否做了极端值处理。再看环境statsmodels、numpy、pandas 版本是否兼容是否用了过旧的 statsmodels部分版本对 ARIMA 类支持不足模型是否有收敛警告是否被忽略。再看模型设定order 参数是否写错(0,0,1) 才是 MA(1)写成 (1,0,0) 就是 AR(1)q 是否选得过高是否没有添加常数项是否对原始价格直接建模。最后看结果参数是否在合理范围残差白噪声是否通过样本外预测是否比随机基线好。按这个顺序查能省下很多时间。很多看起来很玄的问题最后都是数据或参数写错。写到这里MA 模型的核心内容已经梳理完了。个人建议是先用模拟数据把概念和代码流程跑通再切到真实行情数据先把单条序列的单任务模型跑稳再考虑批量选股、滚动预测和策略回测。MA 模型不是一劳永逸的赚线工具但它是理解 ARIMA、理解短期冲击、理解“什么叫做信息被逐步消化”的好起点。量化交易里能稳定复现的建模思路往往比一个看起来很巧妙的信号更值得花时间。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门