第4章:ADF检验实战——用Python做协整检验的第一步
说实话,很多做量化的人一上来就搞协整、搞配对交易,结果跑出来的策略回测漂亮得不行,实盘一跑就崩。为什么?因为连最基础的平稳性检验都没做对。ADF检验,说白了就是帮你判断一个时间序列是不是“随机游走”的——如果它是,那均值回归策略基本没戏。
我个人习惯,做任何配对交易之前,第一件事就是跑ADF检验。不是跑一次,而是反复跑,换参数跑,换样本跑。今天我们就来把这个过程彻底讲透。
4.1 ADF检验到底在测什么?
先别急着写代码。你得先理解ADF检验的逻辑。
ADF检验的全称是Augmented Dickey-Fuller检验。它检验的原假设是:序列存在单位根(即非平稳)。如果p值小于某个显著性水平(比如0.05),我们就拒绝原假设,认为序列是平稳的。
你想想看,如果两个股票的价格序列都是非平稳的,但它们的线性组合是平稳的,那它们就存在协整关系。这就是配对交易的基础。
4.2 Python实战:一行代码跑ADF
Python里做ADF检验,最常用的就是statsmodels库。代码其实很简单,但解读结果才是关键。
import numpy as np
import pandas as pd
import yfinance as yf
from statsmodels.tsa.stattools import adfuller
import matplotlib.pyplot as plt
# 下载数据
ticker = 'AAPL'
data = yf.download(ticker, start='2020-01-01', end='2023-12-31')
price = data['Close']
# ADF检验
result = adfuller(price, autolag='AIC')
print(f'ADF Statistic: {result[0]:.4f}')
print(f'p-value: {result[1]:.4f}')
print(f'Critical Values:')
for key, value in result[4].items():
print(f' {key}: {value:.4f}')
跑完这段代码,你会看到类似这样的输出:
ADF Statistic: -1.2345
p-value: 0.6543
Critical Values:
1%: -3.432
5%: -2.862
10%: -2.567
嗯,这里要注意:p值0.65,远大于0.05,说明我们不能拒绝原假设——AAPL的价格序列是非平稳的。这很正常,股票价格大多是非平稳的。
4.3 结果解读:别只看p值
很多新手拿到结果,只看p值。其实ADF检验的输出有四个关键部分,我一个个说。
| 输出项 | 含义 | 我的经验 |
|---|---|---|
| ADF Statistic | 检验统计量 | 越负越好,比临界值更负才显著 |
| p-value | 显著性概率 | 小于0.05通常认为平稳 |
| Critical Values | 1%、5%、10%临界值 | 我一般用5%作为标准 |
| Lags Used | 使用的滞后阶数 | autolag='AIC'会自动选择最优滞后 |
举个例子:如果ADF统计量是-3.5,而5%临界值是-2.86,那-3.5比-2.86更负,说明在5%水平上显著。这时候p值通常也会小于0.05。
4.4 常见陷阱:我踩过的坑
做ADF检验这么多年,我踩过的坑真不少。下面这几个是最常见的,你一定要注意。
陷阱一:对差分后的序列做ADF检验
我曾经犯过一个低级错误——对价格序列做了一阶差分,然后跑ADF检验,发现p值很小,就以为价格是平稳的。其实差分后的序列平稳,只能说明原序列是I(1)过程,即一阶单整。
正确的做法是:先对原序列做ADF检验,如果不平稳,再对差分序列做ADF检验,确认它是几阶单整。
陷阱二:忽略结构性断点
我记得有一次做ETF配对交易,两只基金的价差序列ADF检验显示平稳,但实盘时突然崩了。后来发现是因为样本期内有一次分红除权,造成了结构性断点。标准的ADF检验对结构性断点非常敏感,容易误判。
如果你怀疑数据有结构性断点,可以用Zivot-Andrews检验,它允许在未知时间点发生结构性变化。
陷阱三:样本期选择不当
你想想看,如果用过去5年的数据做ADF检验,结果很平稳,但最近半年市场结构变了,那这个检验结果就没意义了。我建议至少用两种样本期:
- 全样本期:看长期关系
- 滚动窗口期:看关系是否稳定
4.5 实战案例:检验两只股票的价差平稳性
好了,理论讲完了,我们来个完整的实战。假设我们要检验XOM(埃克森美孚)和CVX(雪佛龙)的价差是否平稳。
# 下载两只股票数据
tickers = ['XOM', 'CVX']
data = yf.download(tickers, start='2020-01-01', end='2023-12-31')['Close']
# 计算价差(假设协整系数为1,实际需要先估计)
spread = data['XOM'] - data['CVX']
# ADF检验
result = adfuller(spread, autolag='AIC')
print(f'价差ADF检验结果:')
print(f'统计量: {result[0]:.4f}')
print(f'p值: {result[1]:.4f}')
if result[1] < 0.05:
print('价差序列平稳,存在协整关系')
else:
print('价差序列非平稳,不存在协整关系')
跑出来的结果,如果p值小于0.05,说明价差是平稳的,这两只股票存在协整关系,可以做配对交易。如果p值很大,那就别硬做,换一对股票试试。
4.6 知识体系总览
为了让你更直观地理解ADF检验在整个协整检验流程中的位置,我画了一张图。
4.7 总结:ADF检验的黄金法则
最后,我把自己多年总结的几条黄金法则分享给你:
- 先检验单序列,再检验组合——不要跳过第一步直接做协整检验
- p值不是唯一标准——结合ADF统计量和临界值一起看
- 样本期要足够长——至少250个交易日,越长越好
- 注意结构性变化——如果样本期内有重大事件,分段检验
- 滚动检验更可靠——固定窗口滚动做ADF,看平稳性是否稳定
一句话总结:ADF检验是协整检验的守门员。守门员没站好位置,后面的策略全是白搭。我见过太多人在这步偷懒,结果亏得底裤都不剩。
好了,ADF检验就讲到这里。代码你拿去跑,坑我帮你踩过了,剩下的就是你自己动手实践。记住,量化交易没有银弹,每一步都要扎实。
公众号:蓝海资料掘金营,微信deep3321