相关性分析:皮尔逊、斯皮尔曼与协整检验

说到统计套利,相关性分析是绕不开的基础。我刚开始做量化那会儿,总觉得相关性就是「两个东西一起涨一起跌」,后来踩了不少坑才明白——相关不等于因果,更不等于套利机会

这一节我们聊四种工具:皮尔逊相关系数、斯皮尔曼秩相关系数、Engle-Granger协整检验,还有滚动相关性窗口。它们各有各的脾气,用对了是利器,用错了就是陷阱。

皮尔逊相关系数:最常用的,也是最容易被误用的

皮尔逊相关系数衡量的是线性关系。公式我就不抄了,你肯定见过。它的值在-1到1之间,0表示没有线性关系。

但这里有个大坑——它只对线性关系敏感。我见过有人拿皮尔逊去算比特币和黄金的相关性,结果接近0,就下结论说两者没关系。其实它们可能是非线性相关,比如一个涨10%另一个才涨2%,这种皮尔逊算出来就很低。

避坑指南:皮尔逊对异常值极其敏感。我曾经处理过一组数据,明明两个序列走势几乎一样,就因为某一天有个数据点异常,相关系数直接从0.9掉到0.3。所以用之前,一定要做异常值处理

代码实现很简单,用pandas或scipy都行:

import pandas as pd
import numpy as np

# 假设df有两列:'A'和'B'
corr_pearson = df['A'].corr(df['B'])
print(f"皮尔逊相关系数: {corr_pearson:.4f}")

# 或者用scipy
from scipy.stats import pearsonr
r, p_value = pearsonr(df['A'], df['B'])
print(f"r={r:.4f}, p-value={p_value:.4f}")

注意那个p-value。它告诉你这个相关性是不是统计显著的。如果p-value大于0.05,那这个相关性可能只是随机噪声。

斯皮尔曼秩相关系数:不挑食的排序选手

斯皮尔曼和皮尔逊最大的区别是什么?它不关心具体数值,只关心排名

举个例子:股票A和股票B,A的价格是100、101、102,B的价格是50、55、60。皮尔逊算出来可能很高,因为都是线性增长。但如果A是100、102、101,B是50、60、55,皮尔逊就会下降,因为步调不一致了。但斯皮尔曼只看排名——A的排名是1、3、2,B的排名是1、3、2,完全一致,所以斯皮尔曼系数是1。

我个人习惯在数据分布不明或者有异常值的时候优先用斯皮尔曼。它比皮尔逊稳健得多。

经验之谈:我在做商品期货配对交易时,经常遇到数据有跳空缺口。皮尔逊会被这些缺口带偏,但斯皮尔曼几乎不受影响。所以我的流程是:先用斯皮尔曼快速筛选候选对,再用皮尔逊做精细化分析。
from scipy.stats import spearmanr

rho, p_value = spearmanr(df['A'], df['B'])
print(f"斯皮尔曼秩相关系数: {rho:.4f}, p-value: {p_value:.4f}")

协整检验:Engle-Granger方法

相关性高不代表能套利,但协整关系可以。为什么?因为协整意味着两个序列的价差是平稳的,会均值回归。

Engle-Granger方法分两步走:

  1. 第一步:用OLS回归估计协整关系。比如 y = α + βx + ε,得到残差ε。
  2. 第二步:对残差做单位根检验(通常是ADF检验)。如果残差是平稳的,就说明存在协整关系。

嗯,这里要注意:第一步的回归方向会影响结果。你用y对x回归,和用x对y回归,得到的残差不一样,检验结果也可能不同。我建议两个方向都试一下,取p-value更小的那个。

核心要点:协整检验的p-value小于0.05,才说明存在统计显著的协整关系。但别高兴太早——样本量太小的时候,协整检验容易出假阳性。我一般要求至少200个交易日的数据。
import statsmodels.api as sm
from statsmodels.tsa.stattools import adfuller

# 第一步:OLS回归
X = sm.add_constant(df['A'])
model = sm.OLS(df['B'], X).fit()
residuals = model.resid

# 第二步:ADF检验
adf_result = adfuller(residuals, autolag='AIC')
print(f"ADF统计量: {adf_result[0]:.4f}")
print(f"p-value: {adf_result[1]:.4f}")

if adf_result[1] < 0.05:
    print("存在协整关系,可以进一步分析价差")
else:
    print("没有协整关系,别浪费时间了")

滚动相关性窗口:动态视角

静态的相关性只能告诉你「过去整体上」的关系。但市场是变化的——两个资产可能上半年高度相关,下半年就分道扬镳了。

滚动相关性就是用一个固定大小的窗口,不断滑动计算。比如窗口设为60天,每天计算过去60天的相关性,这样你就能看到相关性随时间的变化。

窗口大小怎么选?我个人的经验是:

  • 短窗口(20-30天):对市场变化敏感,但噪声大,容易频繁误判
  • 长窗口(120-250天):信号稳定,但反应迟钝,可能错过拐点
  • 我常用的:60-90天,算是个折中方案
我曾经踩过的坑:滚动相关性在窗口边缘会出现「跳跃」。比如第59天和第60天,因为窗口里换掉了一个数据点,相关性可能从0.8突然变成0.3。这不是市场变了,只是数据点的更替。所以别看到一次跳跃就急着调仓。
# 计算滚动相关性
rolling_corr = df['A'].rolling(window=60).corr(df['B'])

# 可视化
import matplotlib.pyplot as plt
plt.figure(figsize=(12, 6))
plt.plot(rolling_corr.index, rolling_corr.values, label='60天滚动相关性')
plt.axhline(y=0, color='gray', linestyle='--')
plt.axhline(y=0.5, color='red', linestyle='--', alpha=0.5)
plt.axhline(y=-0.5, color='green', linestyle='--', alpha=0.5)
plt.legend()
plt.title('滚动相关性窗口')
plt.show()

四种方法的对比与选择

我把它们放在一起对比一下,方便你快速决策:

方法 适用场景 优点 缺点
皮尔逊相关系数 线性关系、数据正态分布 计算快、解释直观 对异常值敏感、只捕捉线性
斯皮尔曼秩相关系数 非线性关系、有异常值 稳健、不挑分布 丢失数值信息、对单调性敏感
Engle-Granger协整检验 寻找均值回归的配对 直接服务于套利策略 两步法有误差累积、样本量要求高
滚动相关性窗口 观察关系随时间的变化 动态视角、可做预警 窗口选择主观、边缘效应明显

你想想看,实际做策略的时候,我通常怎么用?先用斯皮尔曼粗筛,再用协整检验确认,最后用滚动窗口监控。皮尔逊嘛,更多是作为辅助参考,或者用在已经确认线性关系的场景里。

一个小技巧:如果你发现两个资产的滚动相关性在快速下降,别急着认为配对关系失效了。先看看是不是市场整体波动率在变化——波动率上升时,相关性往往会下降,这是统计现象,不是结构变化。

好了,相关性分析这块就聊到这儿。记住一句话:工具是死的,市场是活的。别迷信任何一个指标,多从不同角度交叉验证,才能找到真正靠谱的套利机会。


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