第4章:ADF检验实战——用Python做协整检验的第一步

说实话,很多做量化的人一上来就搞协整、搞配对交易,结果跑出来的策略回测漂亮得不行,实盘一跑就崩。为什么?因为连最基础的平稳性检验都没做对。ADF检验,说白了就是帮你判断一个时间序列是不是“随机游走”的——如果它是,那均值回归策略基本没戏。

我个人习惯,做任何配对交易之前,第一件事就是跑ADF检验。不是跑一次,而是反复跑,换参数跑,换样本跑。今天我们就来把这个过程彻底讲透。

4.1 ADF检验到底在测什么?

先别急着写代码。你得先理解ADF检验的逻辑。

ADF检验的全称是Augmented Dickey-Fuller检验。它检验的原假设是:序列存在单位根(即非平稳)。如果p值小于某个显著性水平(比如0.05),我们就拒绝原假设,认为序列是平稳的。

你想想看,如果两个股票的价格序列都是非平稳的,但它们的线性组合是平稳的,那它们就存在协整关系。这就是配对交易的基础。

核心要点:ADF检验的p值越小,越说明序列平稳。但要注意,这里的“平稳”是指统计意义上的弱平稳——均值、方差不随时间变化。

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。

我的小技巧:我习惯把ADF统计量和临界值画在一起看。如果统计量比临界值更负,就像考试成绩超过了分数线,说明序列平稳。

4.4 常见陷阱:我踩过的坑

做ADF检验这么多年,我踩过的坑真不少。下面这几个是最常见的,你一定要注意。

陷阱一:对差分后的序列做ADF检验

我曾经犯过一个低级错误——对价格序列做了一阶差分,然后跑ADF检验,发现p值很小,就以为价格是平稳的。其实差分后的序列平稳,只能说明原序列是I(1)过程,即一阶单整。

正确的做法是:先对原序列做ADF检验,如果不平稳,再对差分序列做ADF检验,确认它是几阶单整。

陷阱二:忽略结构性断点

我记得有一次做ETF配对交易,两只基金的价差序列ADF检验显示平稳,但实盘时突然崩了。后来发现是因为样本期内有一次分红除权,造成了结构性断点。标准的ADF检验对结构性断点非常敏感,容易误判。

如果你怀疑数据有结构性断点,可以用Zivot-Andrews检验,它允许在未知时间点发生结构性变化。

陷阱三:样本期选择不当

你想想看,如果用过去5年的数据做ADF检验,结果很平稳,但最近半年市场结构变了,那这个检验结果就没意义了。我建议至少用两种样本期:

  • 全样本期:看长期关系
  • 滚动窗口期:看关系是否稳定
警告:ADF检验对样本量有要求。太短的数据(比如少于50个观测值)检验效力很低。我一般要求至少250个交易日的数据。

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检验在整个协整检验流程中的位置,我画了一张图。

ADF检验在协整检验中的位置 1. 数据准备 获取价格序列 2. ADF检验 检验单序列平稳性 3. 判断结果 平稳/非平稳 非平稳 → 差分处理 直到序列变为平稳 平稳 → 进入协整检验 进行Johansen或EG两步法 构建配对交易策略

4.7 总结:ADF检验的黄金法则

最后,我把自己多年总结的几条黄金法则分享给你:

  1. 先检验单序列,再检验组合——不要跳过第一步直接做协整检验
  2. p值不是唯一标准——结合ADF统计量和临界值一起看
  3. 样本期要足够长——至少250个交易日,越长越好
  4. 注意结构性变化——如果样本期内有重大事件,分段检验
  5. 滚动检验更可靠——固定窗口滚动做ADF,看平稳性是否稳定

一句话总结:ADF检验是协整检验的守门员。守门员没站好位置,后面的策略全是白搭。我见过太多人在这步偷懒,结果亏得底裤都不剩。

好了,ADF检验就讲到这里。代码你拿去跑,坑我帮你踩过了,剩下的就是你自己动手实践。记住,量化交易没有银弹,每一步都要扎实。


公众号:蓝海资料掘金营,微信deep3321