第二章 品种选择与相关性分析

做跨品种套利,第一步不是写代码,不是调参数。

第一步是——选品种。

品种选错了,后面再花哨的模型都是白搭。我见过太多人一上来就搞什么协整、卡尔曼滤波,结果两个品种压根儿就没关系,纯属浪费时间。说白了,品种选择是地基,地基不稳,楼盖得再高也得塌。

品种筛选逻辑

我个人习惯,先画一个圈。这个圈怎么画?

  • 同产业链:比如螺纹钢和热卷,豆粕和豆油,焦煤和焦炭。它们之间有天然的上下游关系,价格传导机制清晰。
  • 同交易所:同一个交易所的品种,交易时间、交割规则、保证金制度都一致,省去很多麻烦。
  • 流动性充足:日均成交量低于10万手的品种,我基本不看。流动性差,滑点能吃掉你所有利润。
  • 合约连续性:主力合约切换频繁的品种,做回测时数据拼接很头疼。我个人偏好那些主力合约能持续3个月以上的品种。

嗯,这里要注意一点:别只看相关性系数高就往上冲。我踩过这个坑。

避坑指南:我曾经选了一组相关性高达0.95的品种,结果实盘一个月亏了8%。后来一查,两个品种虽然走势像,但背后的驱动逻辑完全不同——一个是国内定价,一个是国际定价。相关性不等于因果关系,切记。

相关系数计算

相关系数,最常用的就是皮尔逊相关系数。公式我就不写了,大家都会。我直接给代码。

import numpy as np
import pandas as pd

def calc_pearson(series1, series2):
    """
    计算皮尔逊相关系数
    """
    return series1.corr(series2)

# 示例:螺纹钢和热卷的日收益率相关性
rb_returns = rb_prices.pct_change().dropna()
hc_returns = hc_prices.pct_change().dropna()

corr = calc_pearson(rb_returns, hc_returns)
print(f"螺纹钢与热卷收益率相关性:{corr:.4f}")

但说实话,光看一个相关系数不够。为什么?因为相关系数只能衡量线性关系,而且对异常值极其敏感。你想想看,如果数据里有一天出现极端行情,相关系数可能直接从0.8掉到0.3。

所以我一般会同时算三个指标:

指标 说明 我的经验阈值
皮尔逊相关系数 衡量线性相关性 绝对值 > 0.7
斯皮尔曼秩相关系数 衡量单调关系,对异常值不敏感 绝对值 > 0.6
肯德尔相关系数 更稳健,适合小样本 绝对值 > 0.5

三个指标都达标,我才敢说这两个品种「有关系」。

协整检验入门

相关系数高,不代表能套利。你想想看,两个随机游走的序列,相关系数也可能很高,但它们的价差会发散,没法回归。

协整检验,就是用来判断两个序列之间是否存在长期均衡关系。说白了,就是看价差会不会「均值回归」。

最常用的方法是Engle-Granger两步法。我直接上代码:

from statsmodels.tsa.stattools import coint

def check_cointegration(series1, series2):
    """
    Engle-Granger协整检验
    返回:p值,如果p < 0.05,说明存在协整关系
    """
    score, pvalue, _ = coint(series1, series2)
    return pvalue

# 示例
p_val = check_cointegration(rb_prices, hc_prices)
if p_val < 0.05:
    print(f"存在协整关系,p值={p_val:.4f}")
else:
    print(f"不存在协整关系,p值={p_val:.4f}")
小技巧:我在项目中遇到过一个问题——协整检验对数据频率很敏感。日线数据可能不协整,但小时线数据却协整。所以我的习惯是:多试几个时间频率,找到最稳定的那个。

另外,协整检验的p值不是万能的。p值小于0.05只说明存在协整关系,但不代表这个关系能持续多久。我见过一些品种,历史数据协整性很好,但一进入实盘,协整关系就断了。为什么?因为市场结构变了,比如政策变化、交割规则调整。

滚动窗口分析

静态的协整检验有个大问题——它假设关系是恒定的。但市场是动态的,协整关系也会随时间变化。

所以,我强烈建议用滚动窗口来做动态分析。

def rolling_cointegration(series1, series2, window=252):
    """
    滚动窗口协整检验
    window: 窗口大小,默认252个交易日(约1年)
    """
    p_values = []
    for i in range(window, len(series1)):
        s1 = series1[i-window:i]
        s2 = series2[i-window:i]
        _, p_val, _ = coint(s1, s2)
        p_values.append(p_val)
    return p_values

# 绘制p值变化
p_vals = rolling_cointegration(rb_prices, hc_prices)
# 如果p值持续大于0.05,说明协整关系已经破裂

我个人习惯用252天的窗口(约1年),步长设成5天(每周更新一次)。这样既能捕捉到关系的变化,又不会太频繁导致信号噪音。

下面这张图,是我自己总结的品种选择与相关性分析的整体框架:

品种选择与相关性分析框架 第一步:品种筛选 同产业链 同交易所 流动性充足 合约连续 第二步:相关性分析 皮尔逊 > 0.7 斯皮尔曼 > 0.6 肯德尔 > 0.5 第三步:协整检验 + 滚动窗口 三步层层递进,缺一不可

这个框架我用了好几年,基本没出过大问题。每一步都有它的意义:品种筛选是粗筛,相关性分析是细筛,协整检验是最终确认。滚动窗口则是持续监控,防止关系破裂。

核心要点
  • 品种筛选:同产业链 + 同交易所 + 流动性 + 合约连续
  • 相关系数:至少算三种,别只看皮尔逊
  • 协整检验:p值 < 0.05 才算有长期均衡关系
  • 滚动窗口:动态监控,防止关系破裂

好了,这一章的内容就到这里。品种选好了,相关性也确认了,下一步就是构建套利策略的核心——价差模型与交易信号。不过那是下一章的事了。

专注资料整理