第四章:基差统计特征——均值回归、波动率、分布与季节性

各位交易员朋友,大家好。今天我们来聊聊基差的“脾气”。

做基差交易,说白了就是跟统计规律打交道。你想想看,如果基差完全随机游走,那我们还分析个啥?直接抛硬币得了。但现实不是这样。基差有它自己的性格——它会回归、会波动、会呈现特定的分布形态,还会跟着季节走。

我个人习惯,拿到一个品种的基差数据,第一件事就是做四件事:测回归速度、算波动率、看分布形态、找季节性规律。这四板斧砍下去,基差的底裤基本就扒干净了。

4.1 基差均值回归特性

均值回归,是基差交易最核心的信仰。说白了,就是基差不会永远偏离一个合理范围,它迟早会“回家”。

我在项目中遇到过最典型的例子是螺纹钢。2018年那会儿,螺纹钢基差一度拉到800块以上,市场一片恐慌。但我当时看了历史数据,这种极端偏离平均能持续多久?平均回归周期是多久?心里有数了,反而敢逆势建仓。

核心指标:

  • 半衰期(Half-life):基差偏离均值后,回到一半所需的时间。半衰期越短,回归越快。
  • 均值回复速度(Mean Reversion Speed):通常用Ornstein-Uhlenbeck过程建模,速度参数θ越大,回归越猛。
  • 回归区间:基差在±1倍标准差内震荡的概率约68%,±2倍约95%。

怎么算半衰期?我一般用这个简单方法:

import numpy as np
import statsmodels.api as sm

# 假设基差序列 basis_series
def half_life(basis_series):
    # 计算滞后一期
    lag = basis_series.shift(1).dropna()
    current = basis_series.iloc[1:]
    
    # 回归:Δbasis = α + β * basis_lag
    X = sm.add_constant(lag)
    model = sm.OLS(current - lag, X).fit()
    beta = model.params.iloc[1]
    
    # 半衰期 = -ln(2) / ln(1 + β)
    hl = -np.log(2) / np.log(1 + beta)
    return hl

# 举个例子
hl_days = half_life(basis_series)
print(f"基差半衰期:{hl_days:.1f} 天")

避坑指南:我曾经犯过一个错误——直接用日频数据算半衰期,结果发现不同品种差异巨大。后来我意识到,数据频率要跟交易周期匹配。你做日内交易,就用分钟级数据;做月频套利,用日频就够了。

4.2 基差波动率

波动率,是基差交易的“油门”。波动率太低,没利润空间;波动率太高,容易翻车。

我习惯把基差波动率分成两类:

  • 历史波动率(HV):过去N天的实际波动。我一般用20天、60天两个窗口。
  • 隐含波动率(IV):从期权价格反推出来的市场预期。这个对基差交易特别重要——如果IV远高于HV,说明市场在恐慌,这时候做回归策略要小心。

计算历史波动率的代码很简单:

def basis_volatility(basis_series, window=20):
    # 计算对数收益率
    log_returns = np.log(basis_series / basis_series.shift(1))
    # 滚动标准差,年化
    vol = log_returns.rolling(window).std() * np.sqrt(252)
    return vol

# 看看当前波动率处于什么水平
current_vol = basis_volatility(basis_series, 20).iloc[-1]
historical_median = basis_volatility(basis_series, 20).median()
print(f"当前波动率:{current_vol:.2%},历史中位数:{historical_median:.2%}")

注意:基差波动率有“聚集效应”——大波动后面往往跟着大波动。我见过有人看到波动率低就重仓,结果第二天一个黑天鹅直接爆仓。所以,波动率低的时候,反而要警惕“波动率爆发”

4.3 基差分布形态

基差的分布形态,决定了你的止损线该设在哪里。

我刚开始做基差交易时,天真地以为基差是正态分布。结果被市场狠狠教育了一顿——基差分布往往有厚尾特征。什么意思?就是极端值出现的概率,比正态分布预测的要高得多。

分布特征 含义 对交易的影响
偏度(Skewness) 正偏:右尾更长;负偏:左尾更长 正偏时,基差容易突然拉大,做空基差要小心
峰度(Kurtosis) 高峰度:厚尾,极端值多 止损要设得更宽,否则容易被假突破打掉
Jarque-Bera检验 检验是否正态分布 如果p值小于0.05,别用正态假设做风控

怎么快速看分布?我一般画个直方图加QQ图:

import matplotlib.pyplot as plt
import scipy.stats as stats

fig, axes = plt.subplots(1, 2, figsize=(12, 4))

# 直方图
axes[0].hist(basis_series, bins=50, density=True, alpha=0.6)
axes[0].set_title('基差分布直方图')

# QQ图
stats.probplot(basis_series, dist="norm", plot=axes[1])
axes[1].set_title('QQ图 - 正态性检验')

plt.tight_layout()
plt.show()

个人经验:我见过最极端的例子是动力煤。2021年那波行情,基差分布峰度超过10,意味着极端值出现的概率是正态分布的几十倍。如果你用正态分布设止损,一天能被打穿三次。所以,厚尾品种,止损要放大到3倍标准差以上

4.4 基差季节性规律

季节性,是基差交易里最“稳”的规律。为什么?因为很多商品的供需本身就跟着季节走。

举个例子:

  • 农产品:收获季节,现货供应充足,基差往往走弱;青黄不接时,基差走强。
  • 能源品:冬季取暖需求,天然气基差通常走强;夏季需求淡季,基差走弱。
  • 黑色系:春节前后工地停工,螺纹钢基差容易走弱;3月复工后,基差走强。

我一般用“季节性指数”来量化这个规律:

def seasonal_index(basis_series, period=252):
    # 计算每年同一天的均值
    daily_avg = basis_series.groupby(basis_series.index.dayofyear).mean()
    # 计算整体均值
    overall_avg = basis_series.mean()
    # 季节性指数 = 日均值 / 整体均值
    seasonal = daily_avg / overall_avg
    return seasonal

# 看看当前处于什么季节位置
today = basis_series.index[-1].dayofyear
current_seasonal = seasonal_index(basis_series).loc[today]
print(f"当前季节性指数:{current_seasonal:.2f}(大于1表示偏强,小于1表示偏弱)")

核心逻辑:季节性规律不是“一定会发生”,而是“概率上更可能发生”。我见过有人把季节性当圣杯,结果遇到极端天气或政策干预,季节性完全失效。所以,季节性只能作为辅助判断,不能作为唯一依据

知识体系总览

下面这张图,是我自己整理的四维分析框架。每次做基差交易前,我都会过一遍:

基差统计特征四维分析 均值回归 半衰期计算 回归速度参数 置信区间判断 核心:偏离终将回归 波动率 历史波动率(HV) 隐含波动率(IV) 波动率聚集效应 核心:波动率决定仓位 分布形态 偏度与峰度 厚尾特征检验 止损线设定 核心:厚尾需宽止损 季节性规律 季节性指数 供需周期匹配 概率辅助判断 核心:概率而非确定性 综合

嗯,这四个维度,说白了就是一套“体检报告”。均值回归看“健康度”,波动率看“风险度”,分布形态看“极端风险”,季节性看“周期规律”。把这四个维度吃透了,基差交易就不再是玄学,而是有据可依的系统工程。

我个人习惯,每周五收盘后,把这四个指标跑一遍,更新到我的交易日志里。时间长了,你会发现每个品种都有自己的“性格”——有的回归快,有的波动大,有的季节性特别强。摸透了这些性格,交易起来就顺手多了。


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