4. 平稳性检验
各位好,欢迎来到第四章。
前面我们聊了协整和配对交易的基本概念,也看了价差序列的样子。但有个问题一直悬着:凭什么两个不平稳的序列,它们的线性组合就能变得平稳?
说白了,平稳性就是整个统计套利大厦的地基。地基不稳,后面建的模型再漂亮也是空中楼阁。我早年做CTA策略时,就吃过这个亏——用非平稳数据跑回归,结果回测曲线漂亮得像假的一样,实盘直接崩了。
4.1 为什么需要平稳性?
先问个问题:你拿一把尺子去量一个不断变长的东西,能量准吗?
当然不能。平稳性要解决的就是这个事——它保证时间序列的统计性质不随时间漂移。
平稳序列的核心特征:
- 均值恒定:序列围绕一个固定水平波动,不会越走越远
- 方差有限且稳定:波动幅度不会无限膨胀
- 自协方差只与时间间隔有关:两点的相关性只取决于它们相隔多远,与具体时刻无关
在配对交易里,我们为什么死磕平稳性?因为只有价差序列是平稳的,我们才能用均值回归的逻辑去交易——价差偏离均值后,我们有信心它会回来。如果价差是非平稳的,它可能一去不返,你的仓位就变成无底洞。
我的经验:我习惯在拿到任何一对股票后,先画价差图,肉眼扫一眼。如果价差明显有趋势或漂移,基本可以判断非平稳,后面就不用浪费时间了。这招虽然粗糙,但能帮你快速过滤掉80%的无效配对。
4.2 平稳性的两种类型
教科书上把平稳性分成两种,但实战中我们主要关心一种。
| 类型 | 定义 | 实战意义 |
|---|---|---|
| 严平稳 | 序列的联合分布不随时间平移而变化 | 太严格,实战中几乎无法验证 |
| 弱平稳(宽平稳) | 均值、方差恒定,自协方差只与滞后阶数有关 | 我们实际用的就是它,够用 |
嗯,这里要注意:我们平时说的「平稳性检验」,检验的都是弱平稳。别被严平稳吓到,那玩意在金融数据里基本不存在。
4.3 ADF检验原理
ADF检验,全称Augmented Dickey-Fuller检验。名字挺长,但核心思想很简单:检验序列是否存在单位根。
什么是单位根?我尽量不绕弯子。
假设一个最简单的模型:y_t = ρ * y_{t-1} + ε_t
- 如果 |ρ| < 1,序列是平稳的——冲击会逐渐衰减
- 如果 ρ = 1,序列就带单位根——冲击的影响永久存在,序列随机游走
- 如果 |ρ| > 1,序列爆炸性增长——金融数据里很少见
ADF检验的原假设就是:H0: ρ = 1(存在单位根,非平稳)。备择假设是 ρ < 1(平稳)。
检验统计量是t统计量,但它的分布不是标准t分布,得查专门的临界值表。如果计算出的统计量小于临界值,就拒绝原假设,认为序列平稳。
避坑指南:我曾经犯过一个低级错误——直接用OLS的t检验临界值去判断ADF结果。结果发现怎么测都是平稳的,差点把非平稳序列当宝贝。后来才意识到,ADF的临界值比标准t分布更靠左,必须用专用临界值表。Python的statsmodels会自动处理,但如果你手算,千万注意。
ADF检验的扩展版本加入了滞后项,用来处理序列中的自相关。公式长这样:
Δy_t = α + β*t + γ*y_{t-1} + δ₁*Δy_{t-1} + ... + δₚ*Δy_{t-p} + ε_t
其中γ就是我们要检验的核心——如果γ显著为负,说明序列有均值回归倾向,即平稳。
4.4 KPSS检验原理
ADF检验有个问题:它的原假设是非平稳。这就意味着,如果数据不够多,它可能「无法拒绝」非平稳,但也不代表数据就是平稳的。说白了,ADF倾向于认为数据非平稳。
KPSS检验正好反过来。它的原假设是:H0: 序列是平稳的。
KPSS检验的思路是把序列分解成确定性趋势、随机游走和平稳误差三部分。如果随机游走部分的方差为零,序列就是平稳的。
检验统计量基于残差的累积和。如果统计量超过临界值,就拒绝平稳的原假设。
| 检验方法 | 原假设 | 备择假设 | 倾向 |
|---|---|---|---|
| ADF | 非平稳(有单位根) | 平稳 | 倾向于认为非平稳 |
| KPSS | 平稳 | 非平稳 | 倾向于认为平稳 |
我的建议:两个检验一起用,交叉验证。如果ADF说平稳,KPSS也说平稳,那基本稳了。如果ADF说非平稳,KPSS也说非平稳,那肯定非平稳。最麻烦的是两者矛盾——这时候我一般倾向于相信数据量更大的那个检验,或者直接画图判断。
4.5 实战:用Python做平稳性检验
光说不练假把式。我们直接用代码跑一遍。
import numpy as np
import pandas as pd
import yfinance as yf
from statsmodels.tsa.stattools import adfuller, kpss
# 下载数据
tickers = ['XOM', 'CVX']
data = yf.download(tickers, start='2020-01-01', end='2023-12-31')['Adj Close']
# 计算价差(假设协整系数为1,实际需要先估计)
spread = data['XOM'] - data['CVX']
# ADF检验
adf_result = adfuller(spread, autolag='AIC')
print(f'ADF统计量: {adf_result[0]:.4f}')
print(f'p值: {adf_result[1]:.4f}')
print(f'临界值:')
for key, value in adf_result[4].items():
print(f' {key}: {value:.4f}')
# KPSS检验
kpss_result = kpss(spread, regression='c', nlags='auto')
print(f'\nKPSS统计量: {kpss_result[0]:.4f}')
print(f'p值: {kpss_result[1]:.4f}')
print(f'临界值:')
for key, value in kpss_result[3].items():
print(f' {key}: {value:.4f}')
输出解读:
- ADF的p值小于0.05 → 拒绝非平稳原假设 → 价差平稳
- KPSS的p值大于0.05 → 不能拒绝平稳原假设 → 价差平稳
- 两者一致,说明这对价差适合做配对交易
关键点:ADF的p值要小于显著性水平(通常0.05)才说明平稳;KPSS的p值要大于显著性水平才说明平稳。别搞反了,我见过有人把KPSS的p值小于0.05当成平稳,结果模型全错了。
4.6 知识体系总览
下面这张图把本章的核心逻辑串起来了。你可以把它当作一个决策流程图。
这张图从左到右展示了:为什么需要平稳性 → 平稳序列的特征 → 两种检验方法 → 各自的假设和判断逻辑 → 最终交叉验证得出结论。你可以把它当作一个检查清单,每次做配对交易前过一遍。
最后说一句:平稳性检验不是万能的。有些序列在某个时间段平稳,换段时间就不平稳了。我习惯用滚动窗口做平稳性检验——比如每60个交易日测一次,看平稳性能不能持续。如果经常在平稳和非平稳之间切换,这对股票可能不太适合做长期配对。