第三章 跨市场价差分析
好,咱们进入正题。跨市场价差分析,说白了就是盯着两个市场里同一个东西的价格差。比如同一只股票在A股和港股的价格差,或者黄金在纽约和伦敦的价差。我做了这么多年,发现很多人一上来就想着套利,结果被价差的"假动作"晃得晕头转向。今天我就把价差分析的底牌给你翻一遍。
3.1 价差的计算方法
价差计算本身不复杂,但细节决定成败。我个人习惯用三种方式:
- 简单价差:P₁ - P₂。最直观,但受价格水平影响大。比如茅台和五粮液的价差,茅台2000块,五粮液150块,价差1850,这数字看着大,其实没意义。
- 对数价差:ln(P₁) - ln(P₂)。我比较推荐这个。它相当于百分比差,而且统计性质好。我在做股指期货期现套利时,基本都用对数价差。
- 标准化价差:(P₁ - P₂) / σ。把价差除以标准差,方便比较不同品种的偏离程度。嗯,这个在均值回归策略里特别有用。
实战代码:计算沪深300股指期货与ETF的价差
import numpy as np
import pandas as pd
# 假设我们有期货价格和ETF价格数据
futures_prices = np.array([4100, 4115, 4120, 4105, 4090])
etf_prices = np.array([4.08, 4.10, 4.11, 4.09, 4.07])
# 简单价差(注意单位差异,ETF要乘以1000)
simple_spread = futures_prices - etf_prices * 1000
print("简单价差:", simple_spread)
# 对数价差
log_spread = np.log(futures_prices) - np.log(etf_prices * 1000)
print("对数价差:", log_spread)
# 标准化价差
mean_spread = np.mean(simple_spread)
std_spread = np.std(simple_spread)
normalized_spread = (simple_spread - mean_spread) / std_spread
print("标准化价差:", normalized_spread)
我曾经犯过一个低级错误:用简单价差做统计建模,结果模型在价格高位时疯狂开仓,低位时又不敢动。后来换成对数价差,问题就解决了。你想想看,价格从100涨到110,和从1000涨到1100,百分比变化是一样的,但简单价差差了10倍。
3.2 价差的统计特征
价差不是随机游走的,它有自己的一套脾气。我一般会看这几个统计量:
- 均值:价差的长期中枢。比如沪港通开通后,AH股溢价指数长期在120-140之间晃悠。
- 标准差:价差的波动幅度。标准差越小,套利机会越少,但一旦出现就是大机会。
- 偏度:价差分布是否对称。正偏度意味着价差经常在均值下方,偶尔冲到上方。我记得做原油跨期套利时,价差偏度经常是负的,因为近月合约更容易受突发事件影响。
- 峰度:价差分布的"尖峰"程度。峰度大于3,说明极端值比正态分布多。嗯,这对风控很重要。
我的经验:价差的峰度通常大于3。这意味着你按正态分布算出来的VaR会低估风险。我一般用t分布或者极值理论来建模尾部风险。
举个例子,我统计过2018-2023年黄金在纽约和伦敦的价差数据:
| 统计量 | 数值 | 解读 |
|---|---|---|
| 均值 | 0.15美元/盎司 | 纽约略高于伦敦,基本合理 |
| 标准差 | 0.42美元/盎司 | 大部分时间价差在±0.8美元内 |
| 偏度 | 0.87 | 正偏,偶尔出现大的正价差 |
| 峰度 | 5.23 | 尖峰厚尾,极端值比正态分布多 |
3.3 价差的均值回归特性
这是跨市场套利的理论基础。价差为什么会均值回归?因为套利者会搬砖。价差大了,买低卖高,价差就缩回去了。但要注意,不是所有价差都会回归。
我判断一个价差是否具有均值回归特性,主要看三点:
- 单位根检验:ADF检验或PP检验。p值小于0.05,说明价差是平稳的,会回归。
- 半衰期:价差偏离均值后,回到均值一半所需的时间。半衰期越短,套利机会越频繁。
- 回归速度:用AR(1)模型估计。回归系数越接近1,回归越慢;越接近0,回归越快。
代码示例:检验价差的均值回归特性
from statsmodels.tsa.stattools import adfuller
import statsmodels.api as sm
# 假设我们有一个价差序列
spread = np.array([0.1, 0.2, -0.1, 0.3, -0.2, 0.0, 0.1, -0.1, 0.2, -0.3])
# ADF检验
result = adfuller(spread)
print(f"ADF统计量: {result[0]:.4f}")
print(f"p值: {result[1]:.4f}")
if result[1] < 0.05:
print("价差是平稳的,存在均值回归特性")
else:
print("价差非平稳,小心!可能不回归")
# 估计半衰期
# 用AR(1)模型:spread_t = alpha + beta * spread_{t-1} + error
spread_lag = spread[:-1]
spread_curr = spread[1:]
X = sm.add_constant(spread_lag)
model = sm.OLS(spread_curr, X).fit()
beta = model.params[1]
half_life = -np.log(2) / np.log(abs(beta))
print(f"半衰期: {half_life:.2f} 个周期")
我曾经遇到过一个坑:某商品在国内外市场的价差,ADF检验显示平稳,但实际交易中价差就是不回归。后来发现是因为汇率波动把价差给扭曲了。所以,做跨市场价差时,一定要把汇率因素剥离出来。
3.4 价差的波动率聚类
波动率聚类,说白了就是"大波动跟着大波动,小波动跟着小波动"。价差的波动率不是均匀的,它会扎堆出现。我记得2015年股灾期间,股指期货的期现价差波动率突然飙升,然后持续了好几个月才恢复正常。
我一般用GARCH模型来捕捉这个特性:
- GARCH(1,1):最常用,假设当前波动率受上一期波动率和上一期残差的影响。
- EGARCH:能捕捉"杠杆效应",即负冲击比正冲击对波动率的影响更大。
- GJR-GARCH:也是处理非对称性的,我个人比较喜欢这个。
注意:波动率聚类意味着价差的方差不是常数。如果你用普通最小二乘法做回归,标准误会低估,导致假阳性。我建议用Newey-West标准误或者GARCH模型来修正。
举个例子,我做过一个统计:在2019-2023年,黄金跨市场价差的波动率有明显的聚类现象。当波动率低于0.3美元时,未来5天波动率仍然低于0.3美元的概率是68%;但当波动率高于0.8美元时,未来5天波动率仍然高于0.8美元的概率是52%。这说明高波动状态有"惯性"。
这对交易有什么影响?简单说两点:
- 开仓时机:在低波动率时期,价差偏离均值时,回归速度通常较慢,可以耐心等待更好的入场点。
- 止损设置:在高波动率时期,价差可能继续扩大,止损要设得宽一些,否则容易被震出去。
我的习惯:我会用滚动窗口计算价差的波动率,然后根据波动率水平动态调整仓位。波动率高时减仓,波动率低时加仓。这比固定仓位要稳健得多。
好了,价差分析的核心就这些。你想想看,价差的计算是基础,统计特征是体检报告,均值回归是理论基础,波动率聚类是实战细节。把这四点吃透了,跨市场套利你就入门了。
公众号:蓝海资料掘金营,微信deep3321