第4章:价格序列的平稳性检验

做统计套利,第一步就是看数据稳不稳。

你想想看,如果两个品种的价格序列像醉汉走路一样,东倒西歪没个规律,那你还怎么指望它们能回归均值?我刚开始做套利那会儿,就吃过这个亏——拿了两组非平稳数据硬跑回归,结果回测曲线漂亮得不行,实盘一跑直接崩了。

后来我才明白:平稳性检验,是所有统计套利模型的基石

核心观点:只有平稳的时间序列,才能用统计模型去预测和套利。非平稳序列会带来"伪回归"问题,让你看到假的相关性。

4.1 什么是平稳性?

平稳性说白了就是:统计性质不随时间变化

具体来说,一个平稳序列满足三个条件:

  • 均值恒定——长期来看,数据围绕一个固定值波动
  • 方差恒定——波动幅度不会越变越大或越变越小
  • 协方差只与时间间隔有关——两个时间点的相关性只取决于它们相隔多远,跟具体在哪个时间点无关

举个例子:白噪声就是最完美的平稳序列。而股票价格,通常是非平稳的——它可能一路涨上去,均值一直在变。

我的经验:在实际交易中,我们很少遇到天然平稳的价格序列。价差序列倒是经常能通过一些处理变成平稳的。这就是套利机会所在。

4.2 ADF检验原理

ADF检验,全称是Augmented Dickey-Fuller检验。名字挺长,但原理不复杂。

它的核心思路是:检验序列是否存在单位根

什么叫单位根?我简单解释一下:

  • 如果一个序列的当前值 = 前一个值 + 随机扰动,那它就有一个单位根
  • 有单位根的序列,就是非平稳的
  • ADF检验的原假设H₀:序列存在单位根(非平稳)
  • 备择假设H₁:序列不存在单位根(平稳)

检验结果看p值:

  • p值 < 0.05 → 拒绝原假设 → 序列平稳
  • p值 ≥ 0.05 → 不能拒绝原假设 → 序列非平稳

避坑指南:我曾经遇到一个序列,ADF检验p值0.04,刚好小于0.05,我就以为它平稳了。结果回测一塌糊涂。后来发现,样本量太小导致检验功效不足。记住:样本量至少要有50个以上,最好100+,ADF检验才靠谱。

4.3 Python实现ADF检验

代码其实很简单,statsmodels库已经封装好了。

import pandas as pd
import numpy as np
from statsmodels.tsa.stattools import adfuller
import matplotlib.pyplot as plt

# 模拟一个非平稳序列(随机游走)
np.random.seed(42)
n = 200
random_walk = np.cumsum(np.random.randn(n)) + 100

# 模拟一个平稳序列(白噪声)
white_noise = np.random.randn(n) * 5

# ADF检验函数
def adf_test(series, name=''):
    result = adfuller(series, autolag='AIC')
    print(f'=== {name} ADF检验结果 ===')
    print(f'ADF统计量: {result[0]:.4f}')
    print(f'p值: {result[1]:.4f}')
    print(f'临界值:')
    for key, value in result[4].items():
        print(f'  {key}: {value:.4f}')
    
    if result[1] < 0.05:
        print('结论: 序列平稳 (拒绝H₀)')
    else:
        print('结论: 序列非平稳 (不能拒绝H₀)')
    print('-' * 40)
    return result[1]  # 返回p值

# 检验随机游走(非平稳)
p1 = adf_test(random_walk, '随机游走')

# 检验白噪声(平稳)
p2 = adf_test(white_noise, '白噪声')

# 可视化对比
plt.figure(figsize=(12, 5))
plt.subplot(1, 2, 1)
plt.plot(random_walk)
plt.title(f'随机游走 (p值={p1:.4f})')
plt.subplot(1, 2, 2)
plt.plot(white_noise)
plt.title(f'白噪声 (p值={p2:.4f})')
plt.tight_layout()
plt.show()

运行结果你会看到:随机游走的p值很大(比如0.5以上),白噪声的p值很小(接近0)。

我个人习惯:除了看p值,我还会对比ADF统计量和临界值。如果ADF统计量比1%的临界值还小,那基本可以放心了。这比单看p值更稳妥。

4.4 KPSS检验

ADF检验有个问题:它的原假设是"非平稳"。有时候我们想要反过来验证——假设序列是平稳的,看能不能被拒绝。

这就是KPSS检验的作用。

检验方法 原假设H₀ 备择假设H₁ 适用场景
ADF 非平稳(有单位根) 平稳 怀疑序列非平稳时
KPSS 平稳 非平稳(有单位根) 怀疑序列平稳时

你可能会问:那到底用哪个?

我的建议是:两个都做

  • ADF显著 + KPSS不显著 → 序列平稳
  • ADF不显著 + KPSS显著 → 序列非平稳
  • 两个都显著或都不显著 → 数据量不够,或者序列有结构性断点
from statsmodels.tsa.stattools import kpss

def kpss_test(series, name=''):
    result = kpss(series, regression='c')
    print(f'=== {name} KPSS检验结果 ===')
    print(f'KPSS统计量: {result[0]:.4f}')
    print(f'p值: {result[1]:.4f}')
    print(f'临界值:')
    for key, value in result[3].items():
        print(f'  {key}: {value:.4f}')
    
    if result[1] < 0.05:
        print('结论: 序列非平稳 (拒绝H₀)')
    else:
        print('结论: 序列平稳 (不能拒绝H₀)')
    print('-' * 40)
    return result[1]

# 对同一个序列做两种检验
print('=== 综合检验 ===')
p_adf = adf_test(random_walk, '随机游走')
p_kpss = kpss_test(random_walk, '随机游走')

if p_adf < 0.05 and p_kpss >= 0.05:
    print('✅ 综合判断: 序列平稳')
elif p_adf >= 0.05 and p_kpss < 0.05:
    print('✅ 综合判断: 序列非平稳')
else:
    print('⚠️ 结果不一致,建议增加数据量或检查结构性断点')

我曾经踩过的坑:有一次两个检验结果都不显著,我以为是数据问题,折腾了半天。后来发现,原来是序列中间有一个明显的断点(政策变化导致的)。遇到这种情况,可以分段检验,或者用Zivot-Andrews检验来处理结构性断点。

4.5 如何处理非平稳序列:差分法

如果序列非平稳,怎么办?

最常用的方法就是差分

一阶差分的公式很简单:

Δyₜ = yₜ - yₜ₋₁

说白了,就是把今天的值减去昨天的值,看变化量。很多金融时间序列,价格本身是非平稳的,但价格的变化(收益率)往往是平稳的。

# 对非平稳序列做差分
def difference(series, order=1):
    diff_series = series.copy()
    for i in range(order):
        diff_series = diff_series.diff().dropna()
    return diff_series

# 对随机游走做一阶差分
diff_rw = difference(pd.Series(random_walk), order=1)

# 检验差分后的序列
print('差分后的ADF检验:')
adf_test(diff_rw.values, '差分后序列')

# 可视化对比
plt.figure(figsize=(12, 5))
plt.subplot(1, 2, 1)
plt.plot(random_walk)
plt.title('原始序列(非平稳)')
plt.subplot(1, 2, 2)
plt.plot(diff_rw.values)
plt.title('一阶差分后(平稳)')
plt.tight_layout()
plt.show()

你会看到:差分后的序列,均值基本在0附近波动,方差也稳定了。ADF检验的p值会变得很小。

关键点:

  • 大多数金融价格序列需要1阶差分就能变平稳
  • 如果1阶差分后还不平稳,试试2阶差分
  • 但别超过2阶——高阶差分会让数据失去经济含义
  • 在统计套利中,我们通常对价差序列做检验,而不是对单个价格

4.6 本章知识体系

下面这张图,是我自己梳理的平稳性检验流程。每次做套利模型前,我都会走一遍这个流程。

平稳性检验流程 原始价格序列 ADF + KPSS 序列平稳 ✅ 可直接建模 序列非平稳 ❌ 需要处理 处理方法:差分 / 对数差分 处理后回到起点重新检验 注:建议同时使用ADF和KPSS两种检验,交叉验证结果

我的工作流:拿到一组价差数据,我一般先画个时序图看看趋势。如果明显有趋势,直接差分。如果没有明显趋势,再做ADF+KPSS检验。这样能省不少时间。

好了,平稳性检验就讲到这里。记住一句话:不检验平稳性,就别谈统计套利。这是血的教训换来的经验。


公众号:蓝海数据掘金营,微信deep3321