3. 价格序列的平稳性检验:ADF检验、KPSS检验

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

什么叫稳?说白了,就是价格序列的统计性质——均值、方差——不随时间变化。如果价格像脱缰的野马一样乱跑,那它俩之间的价差就没法预测,配对也就无从谈起。

我个人习惯,拿到任何两个股票的价格序列,第一件事就是做平稳性检验。这步不过关,后面所有模型都是白搭。

3.1 为什么平稳性这么重要?

你想想看,如果两个序列都不平稳,它们的线性组合(价差)很可能也是不平稳的。那咱们辛辛苦苦找配对,结果价差一会儿上天一会儿入地,怎么开平仓?

我在项目中遇到过这样的情况:两个看起来走势很相似的股票,直接做回归,R² 高达 0.9。结果一检验,残差序列是非平稳的。嗯,这就是典型的“伪回归”。

所以,平稳性检验是筛选潜在配对的第一道门槛。

核心逻辑: 只有两个非平稳序列的线性组合是平稳的,它们才可能存在协整关系,才能做配对交易。

3.2 ADF检验:单位根检验

ADF检验,全称是Augmented Dickey-Fuller检验。它检验的是序列是否存在单位根。

单位根是什么?你可以简单理解为:序列的当前值 = 上一期的值 + 随机扰动。这种序列会越走越远,不会回到均值附近。

ADF检验的原假设 H₀: 序列存在单位根(非平稳)。

备择假设 H₁: 序列不存在单位根(平稳)。

如果p值小于0.05,就拒绝原假设,认为序列是平稳的。

我的经验: 实际做的时候,ADF检验的p值经常大于0.05,尤其是日线数据。别慌,这是常态。我们找的是两个非平稳序列的配对,不是单个平稳序列。

3.3 KPSS检验:互补检验

KPSS检验和ADF检验正好相反。

KPSS检验的原假设 H₀: 序列是平稳的。

备择假设 H₁: 序列存在单位根(非平稳)。

如果p值小于0.05,就拒绝原假设,认为序列非平稳。

为什么需要两个检验?

因为ADF检验的统计功效有限,有时候会把接近平稳的序列误判为非平稳。KPSS检验可以交叉验证。

避坑指南: 我曾经只依赖ADF检验,结果选出的配对在实盘中表现很差。后来加上KPSS检验,筛选出的配对稳定性明显提升。建议两个检验都做,结果一致才放心。

3.4 实战:对沪深300成分股进行平稳性检验

下面我们动手,对沪深300成分股做平稳性检验。代码用Python,库用statsmodels。

import pandas as pd
import numpy as np
from statsmodels.tsa.stattools import adfuller, kpss
import akshare as ak

# 获取沪深300成分股列表
stock_list = ak.index_stock_cons_csindex("000300")

# 假设我们已经下载了日线收盘价数据,存在price_df中
# price_df的列是股票代码,行是日期

def check_stationarity(series):
    """对单个序列进行ADF和KPSS检验"""
    # ADF检验
    adf_stat, adf_pvalue, _, _, critical_values, _ = adfuller(series.dropna())
    
    # KPSS检验
    kpss_stat, kpss_pvalue, _, _ = kpss(series.dropna(), regression='c')
    
    return {
        'adf_pvalue': adf_pvalue,
        'kpss_pvalue': kpss_pvalue,
        'adf_stationary': adf_pvalue < 0.05,
        'kpss_stationary': kpss_pvalue > 0.05  # KPSS原假设是平稳,p值大才接受
    }

# 对每只股票做检验
results = {}
for stock in stock_list['成分券代码'][:50]:  # 先跑前50只做演示
    try:
        series = price_df[stock]
        results[stock] = check_stationarity(series)
    except:
        continue

# 整理结果
result_df = pd.DataFrame(results).T
result_df['结论'] = result_df.apply(
    lambda row: '平稳' if row['adf_stationary'] and row['kpss_stationary'] 
    else '非平稳' if not row['adf_stationary'] and not row['kpss_stationary']
    else '存疑', axis=1
)

print(result_df['结论'].value_counts())

3.5 筛选潜在配对的逻辑

做完检验,我们得到三类股票:

ADF结果 KPSS结果 结论 是否可用于配对
非平稳 非平稳 非平稳 ✅ 可用于配对(需要协整)
平稳 平稳 平稳 ❌ 不适合配对(本身已平稳)
非平稳 平稳 存疑 ⚠️ 需要进一步分析
平稳 非平稳 存疑 ⚠️ 需要进一步分析

我们真正要找的,是两个都是非平稳的股票。这样它们的价差才有可能形成平稳序列,也就是协整。

一个小技巧: 我习惯把检验结果可视化,画个散点图。横轴是ADF的p值,纵轴是KPSS的p值。左下角(两个p值都小)是平稳的,右上角(两个p值都大)是非平稳的。一眼就能看出哪些股票适合做配对。

3.6 本章知识体系

下面这张图,把本章的核心逻辑串起来了:

平稳性检验知识体系 沪深300成分股价格序列 ADF检验 H₀: 存在单位根(非平稳) KPSS检验 H₀: 序列是平稳的 p值 < 0.05 → 平稳 p值 > 0.05 → 平稳 筛选条件:两个检验都判定为非平稳 → 进入协整检验环节

嗯,这张图把整个流程讲清楚了。从原始价格序列出发,经过ADF和KPSS两个检验的交叉验证,最终筛选出符合条件的非平稳序列,进入下一步的协整检验。

我个人觉得,这一步做得越扎实,后面配对的效果就越稳定。别嫌麻烦,多花点时间在数据清洗和检验上,比后面反复调参要划算得多。

专注资料整理