第四章:ARIMA模型——自回归与移动平均,差分操作,模型定阶与诊断
ARIMA模型,说白了就是时间序列分析里最经典的“三板斧”。我刚开始做量化的时候,觉得这东西太老套了,不如深度学习时髦。后来在实盘回测中吃了不少亏,才老老实实回来把ARIMA吃透。你想想看,一个模型能火几十年,一定有它的道理。
4.1 从平稳性说起
ARIMA的核心前提是什么?平稳性。我见过太多新手一上来就套模型,结果预测出来全是垃圾。为什么?因为金融数据大多是非平稳的。
平稳性简单说就是:统计性质不随时间变化。均值稳定、方差稳定、自协方差只跟时间间隔有关。你想想看,如果一只股票今天的均值和去年的均值不一样,你用历史数据去预测未来,那不是刻舟求剑吗?
平稳性的三种类型:
- 严平稳:联合分布不随时间平移而变化。太严格了,实际中几乎用不到。
- 弱平稳:均值恒定、方差恒定、自协方差只与滞后阶数有关。我们通常说的平稳就是指这个。
- 趋势平稳:去掉确定性趋势后是平稳的。比如加上一个时间趋势项。
怎么判断平稳性?我习惯用ADF检验。原假设是“存在单位根”,也就是非平稳。p值小于0.05,就拒绝原假设,认为序列平稳。我在项目中遇到过一只股票,ADF检验p值0.08,看着不显著,但我强行差分后建模,效果反而更差。后来发现是结构突变导致的伪非平稳。
4.2 差分操作——让数据“老实”下来
非平稳怎么办?差分。这是ARIMA里“I”的部分,也就是Integrated。
一阶差分:Δy_t = y_t - y_{t-1}
二阶差分:Δ²y_t = Δy_t - Δy_{t-1}
大多数金融时间序列,一阶差分就够了。我做过一个国债收益率预测的项目,发现二阶差分后数据方差反而变大,这就是过度差分的典型症状。记住一个原则:能不用差分就不用,能用一阶就别用二阶。
过度差分的危害:
- 丢失长期记忆信息
- 引入额外的噪声
- 模型预测方差增大
我曾经在原油价格预测中犯了过度差分的错误,结果模型预测的置信区间宽得离谱,完全没法用。
4.3 AR模型:用过去预测未来
AR,自回归。说白了就是“昨天的我影响今天的我”。
AR(p)模型的数学形式:
y_t = c + φ₁y_{t-1} + φ₂y_{t-2} + ... + φ_py_{t-p} + ε_t
这里p是阶数,φ是自回归系数。ε_t是白噪声。
AR模型有个关键约束:平稳性条件。对于AR(1)模型,要求|φ₁| < 1。如果φ₁接近1,那就是随机游走,非平稳。我见过有人用AR(1)拟合比特币价格,φ₁估计出来是0.998,他还觉得模型很好。嗯,这其实是在用平稳模型拟合非平稳数据,预测效果可想而知。
4.4 MA模型:用误差修正未来
MA,移动平均。不是算数平均,而是对过去误差的加权平均。
MA(q)模型的数学形式:
y_t = c + ε_t + θ₁ε_{t-1} + θ₂ε_{t-2} + ... + θ_qε_{t-q}
MA模型有个特点:记忆有限。q阶MA模型,只有q期的记忆。超过q期,自相关函数就截尾了。这在金融中很常见,比如某些高频交易策略的收益序列,往往只有短期自相关。
AR vs MA 怎么选?
- 如果自相关函数(ACF)拖尾、偏自相关函数(PACF)p阶截尾 → AR(p)
- 如果ACF q阶截尾、PACF拖尾 → MA(q)
- 如果都拖尾 → ARMA或ARIMA
我个人习惯先看PACF,因为AR的阶数判断更直观。但记住,这只是初步判断,最终要用信息准则来定阶。
4.5 ARIMA模型:三合一
ARIMA(p,d,q)就是把AR、差分、MA组合起来。d是差分阶数。
数学形式(用滞后算子表示):
(1 - φ₁L - φ₂L² - ... - φ_pLᵖ)(1-L)ᵈy_t = c + (1 + θ₁L + θ₂L² + ... + θ_qLᵠ)ε_t
看着复杂,其实逻辑很简单:先差分让数据平稳,再用AR和MA捕捉剩余的结构。
下面我用一张图来展示ARIMA的核心逻辑:
4.6 模型定阶——找到最优的p和q
定阶是ARIMA建模中最考验经验的环节。我总结了三个方法:
方法一:ACF和PACF图
| 模型 | ACF | PACF |
|---|---|---|
| AR(p) | 拖尾(逐渐衰减) | p阶后截尾 |
| MA(q) | q阶后截尾 | 拖尾 |
| ARMA(p,q) | 拖尾 | 拖尾 |
但说实话,真实数据很少这么完美。我见过ACF和PACF都拖尾的情况,这时候就要靠信息准则了。
方法二:信息准则
AIC和BIC是最常用的。公式我就不写了,记住原则:越小越好。但要注意,AIC倾向于选更复杂的模型,BIC惩罚更严厉。我个人的习惯是:样本量大的时候用BIC,样本量小的时候用AIC。
方法三:滚动验证
这是我最推荐的方法。把数据分成训练集和测试集,滚动预测,看哪个模型的预测误差最小。虽然计算量大,但结果最可靠。
定阶的实战建议:
- p和q一般不超过5,金融数据很少需要高阶
- 先尝试p=1,q=1,这是最常用的起点
- 如果AIC/BIC在某个阶数附近波动,选更简单的模型
- 别忘了检查模型是否可逆(MA部分)和是否平稳(AR部分)
4.7 模型诊断——别让残差骗了你
模型建好了,怎么知道好不好?看残差。好的模型,残差应该是白噪声。
我通常做三个检查:
- 残差的自相关检验:用Ljung-Box检验。p值大于0.05,说明残差没有自相关,模型捕捉到了所有结构。
- 残差的正态性检验:用QQ图或Jarque-Bera检验。虽然不是必须的,但正态残差对预测区间估计有帮助。
- 残差的异方差检验:用ARCH检验。如果残差有异方差,说明可能需要GARCH模型。
我曾经踩过的坑:
有一次我建了一个ARIMA模型,AIC很低,预测曲线看着也很漂亮。但Ljung-Box检验的p值只有0.03。我心想“差不多就行了”,结果实盘预测连续出错。后来发现是残差中还有周期成分没捕捉到。从那以后,我坚持残差诊断不过关就不上线模型。
4.8 代码实战:用Python实现ARIMA
理论说完了,上代码。我用的是statsmodels库,这是Python里最成熟的时间序列库。
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from statsmodels.tsa.stattools import adfuller
from statsmodels.graphics.tsaplots import plot_acf, plot_pacf
from statsmodels.tsa.arima.model import ARIMA
from statsmodels.stats.diagnostic import acorr_ljungbox
# 1. 加载数据(以沪深300指数为例)
data = pd.read_csv('hs300.csv', index_col='date', parse_dates=True)
y = data['close']
# 2. 平稳性检验
result = adfuller(y)
print(f'ADF统计量: {result[0]:.4f}')
print(f'p值: {result[1]:.4f}')
# 3. 如果非平稳,做差分
if result[1] > 0.05:
y_diff = y.diff().dropna()
print('做了1阶差分')
else:
y_diff = y
# 4. 画ACF和PACF图
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(10, 6))
plot_acf(y_diff, lags=20, ax=ax1)
plot_pacf(y_diff, lags=20, ax=ax2)
plt.show()
# 5. 拟合ARIMA模型(假设p=2, d=1, q=2)
model = ARIMA(y, order=(2, 1, 2))
result = model.fit()
print(result.summary())
# 6. 残差诊断
residuals = result.resid
lb_test = acorr_ljungbox(residuals, lags=[10], return_df=True)
print(f'Ljung-Box p值: {lb_test["lb_pvalue"].values[0]:.4f}')
# 7. 预测
forecast = result.forecast(steps=5)
print('未来5期预测值:')
print(forecast)
代码小贴士:
- statsmodels的ARIMA函数会自动处理差分,你只需要指定d
- summary()输出里看P>|z|列,如果某个系数不显著(p值大),考虑简化模型
- 预测时注意置信区间,金融预测的区间通常很宽
4.9 金融应用中的注意事项
ARIMA在金融中到底怎么用?我分享几个经验:
- 短期预测优于长期:ARIMA适合预测未来1-5期,超过10期误差会急剧增大
- 结合基本面:纯ARIMA只用了历史价格信息,如果能加入外生变量(ARIMAX),效果会更好
- 警惕结构突变:金融危机、政策变化会导致模型失效,需要定期重新估计
- 不要过度优化:我见过有人用网格搜索找最优p和q,结果在样本外表现一塌糊涂。过拟合在时间序列中同样致命
ARIMA不是万能的,但它是理解更复杂模型的基础。你想想看,如果你连ARIMA都搞不定,怎么去理解VAR、状态空间模型、甚至深度学习?把这一章吃透,后面的路就好走了。
公众号:蓝海资料掘金营,微信deep3321