4. 基差计算与可视化:计算主力合约基差,绘制基差时序图与分布直方图
好,咱们进入第四步。这一步说白了,就是把基差从「理论概念」变成「能看见、能分析的数据」。我个人觉得,这是整个套利模型里最直观、也最容易出成就感的一环。
你想想看,基差就是现货价格减去期货价格。但实际算起来,坑不少。我刚开始做的时候,就吃过「合约换月」的亏——主力合约一换,基差直接跳空,我还以为是行情异动,差点下了错单。
核心逻辑:基差 = 现货价格 - 期货价格。正值叫「升水」,负值叫「贴水」。我们做套利,盯的就是这个值的波动。
4.1 数据准备:你需要什么?
要算基差,你得有两样东西:
- 现货价格序列:比如沪深300指数、螺纹钢现货价、比特币现货价。注意,要选同一标的。
- 期货主力合约价格序列:这里有个关键点——「主力合约」不是固定的。每个月或每季度,持仓量和成交量最大的合约会变。
我在项目中遇到过最头疼的事,就是主力合约切换时,数据源没同步更新。结果基差图里出现了一个巨大的尖峰,我还以为是套利机会,差点冲进去。后来我养成了一个习惯:每次跑模型前,先手动确认一下当前主力合约是哪个月份。
4.2 基差计算:代码实现
好,咱们直接上代码。这里我用的是Python,pandas处理数据,matplotlib画图。
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
# 假设你已经有了两个DataFrame
# spot_df: 包含 'date' 和 'price' 列
# futures_df: 包含 'date', 'contract', 'price' 列
# 第一步:筛选主力合约
# 我习惯用持仓量来判定,但如果没有持仓量数据,也可以用成交量
# 这里简化处理:假设我们已经有主力合约的标识
main_contract = futures_df[futures_df['is_main'] == True]
# 第二步:合并数据
merged = pd.merge(spot_df, main_contract, on='date', how='inner', suffixes=('_spot', '_futures'))
# 第三步:计算基差
merged['basis'] = merged['price_spot'] - merged['price_futures']
# 看看结果
print(merged[['date', 'price_spot', 'price_futures', 'basis']].head())
避坑指南:我曾经直接用「成交量最大」来判定主力合约,结果遇到股指期货交割周,成交量异常放大,选错了合约。后来我改用「持仓量+成交量」加权判断,准确率高很多。
4.3 基差时序图:看趋势
时序图能告诉你基差在时间轴上是如何变化的。我一般会叠加现货和期货的价格线,这样能直观看到基差是怎么形成的。
fig, axes = plt.subplots(2, 1, figsize=(14, 10))
# 上图:现货 vs 期货价格
axes[0].plot(merged['date'], merged['price_spot'], label='现货', color='#2E86AB')
axes[0].plot(merged['date'], merged['price_futures'], label='期货主力', color='#A23B72')
axes[0].set_ylabel('价格')
axes[0].legend()
axes[0].set_title('现货 vs 期货主力价格')
# 下图:基差
axes[1].plot(merged['date'], merged['basis'], color='#F18F01', linewidth=1.5)
axes[1].axhline(y=0, color='gray', linestyle='--', alpha=0.7)
axes[1].set_ylabel('基差')
axes[1].set_title('基差时序图')
plt.tight_layout()
plt.show()
嗯,这里要注意:如果基差长期在0轴上方,说明市场处于升水状态;反之则是贴水。我见过最极端的案例是2020年原油期货,基差一度跌到-40美元,那真是活久见。
4.4 分布直方图:看统计特征
时序图看趋势,直方图看分布。它能告诉你基差通常落在什么区间,有没有极端值。
fig, ax = plt.subplots(figsize=(10, 6))
# 绘制直方图
sns.histplot(merged['basis'], bins=50, kde=True, color='#2E86AB', ax=ax)
ax.axvline(x=merged['basis'].mean(), color='red', linestyle='--', label=f'均值: {merged["basis"].mean():.2f}')
ax.axvline(x=merged['basis'].median(), color='green', linestyle='--', label=f'中位数: {merged["basis"].median():.2f}')
ax.set_xlabel('基差')
ax.set_ylabel('频次')
ax.set_title('基差分布直方图')
ax.legend()
plt.show()
关键统计量:
| 指标 | 含义 | 套利意义 |
|---|---|---|
| 均值 | 基差的平均水平 | 判断当前基差是否偏离常态 |
| 标准差 | 基差的波动程度 | 决定套利开仓的阈值 |
| 偏度 | 分布是否对称 | 正偏态说明贴水机会更多 |
| 峰度 | 极端值出现的概率 | 高峰度意味着需要更严格的风控 |
我一般会结合这两个图来做决策:如果基差偏离均值超过2个标准差,而且分布直方图显示这个位置属于极端值区域,那就是一个潜在的套利机会。
4.5 本章知识体系
下面这张图,是我自己总结的基差计算与可视化的完整流程。你照着这个走,基本不会漏掉关键步骤。
重要提醒:基差计算看似简单,但数据频率一定要对齐。我见过有人用日频的现货数据,配了分钟频的期货数据,算出来的基差完全没法用。记住:时间戳必须精确匹配。
好了,基差计算和可视化这部分就讲到这里。你拿到数据后,先画时序图看看整体趋势,再画直方图看看分布特征。这两个图配合起来,基本能帮你判断当前市场处于什么状态。
我个人习惯是把这两个图做成自动化报表,每天开盘前跑一遍。这样心里有底,知道基差是处于正常波动范围,还是出现了极端机会。