4、价差计算与可视化:价差序列计算、使用Matplotlib绘制价差图、识别异常点
跨期套利的核心,说白了就是盯着两个合约的价差做文章。你想想看,如果价差偏离了正常范围,迟早会回归。那问题来了——怎么算价差?怎么看出它不正常?
这一节,我就带你手把手搞定价差计算、可视化,以及异常点的识别。嗯,都是实战中每天要用的东西。
4.1 价差序列的计算方法
价差计算本身不复杂,但细节决定成败。我个人习惯用近月合约价格减去远月合约价格,这样价差为正时,说明近月比远月贵,市场处于back结构;为负时,说明远月更贵,是contango结构。
具体计算步骤:
- 获取数据:从行情接口拉取两个合约的1分钟或5分钟收盘价
- 时间对齐:确保两个合约的时间戳完全匹配
- 计算价差:
spread = price_near - price_far - 处理缺失值:遇到停牌或数据缺失,直接剔除或向前填充
来看一段代码,这是我常用的价差计算函数:
import pandas as pd
import numpy as np
def calc_spread(near_df, far_df):
"""
计算跨期价差序列
:param near_df: 近月合约DataFrame,包含['datetime', 'close']
:param far_df: 远月合约DataFrame,包含['datetime', 'close']
:return: 价差序列DataFrame
"""
# 合并数据,按时间对齐
merged = pd.merge(
near_df[['datetime', 'close']],
far_df[['datetime', 'close']],
on='datetime',
how='inner',
suffixes=('_near', '_far')
)
# 计算价差
merged['spread'] = merged['close_near'] - merged['close_far']
# 去掉缺失值
merged.dropna(inplace=True)
return merged[['datetime', 'spread']]
这里有个坑——合约换月。每个月主力合约会切换,价差序列会跳变。我曾经因为这个没处理好,回测曲线漂亮得不行,实盘一跑就崩。后来我加了换月处理逻辑,才稳住。
4.2 使用Matplotlib绘制价差图
光看数字不行,得画出来。一张好的价差图,能让你一眼看出趋势、波动和异常。
我个人偏爱用Matplotlib,虽然它有点老派,但胜在灵活。下面是我常用的绘图模板:
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
def plot_spread(spread_df, title='跨期价差图',
mean_line=True, std_lines=True):
"""
绘制价差序列图
:param spread_df: 包含['datetime', 'spread']的DataFrame
"""
fig, ax = plt.subplots(figsize=(12, 6))
# 绘制价差曲线
ax.plot(spread_df['datetime'], spread_df['spread'],
color='#2196F3', linewidth=1.5, label='价差')
# 添加均值线
if mean_line:
mean_val = spread_df['spread'].mean()
ax.axhline(y=mean_val, color='#FF5722', linestyle='--',
linewidth=1, label=f'均值: {mean_val:.2f}')
# 添加标准差线
if std_lines:
std_val = spread_df['spread'].std()
for i in [1, 2, 3]:
ax.axhline(y=mean_val + i*std_val,
color='#9E9E9E', linestyle=':',
linewidth=0.8, alpha=0.5)
ax.axhline(y=mean_val - i*std_val,
color='#9E9E9E', linestyle=':',
linewidth=0.8, alpha=0.5)
# 美化
ax.set_title(title, fontsize=14, fontweight='bold')
ax.set_xlabel('时间', fontsize=11)
ax.set_ylabel('价差', fontsize=11)
ax.legend(loc='best')
ax.grid(True, alpha=0.3)
# 时间轴格式化
ax.xaxis.set_major_formatter(mdates.DateFormatter('%m-%d'))
ax.xaxis.set_major_locator(mdates.WeekdayLocator())
plt.tight_layout()
plt.show()
这段代码画出来的图,包含了价差曲线、均值线和1/2/3倍标准差线。你想想看,价差跑到3倍标准差外面,基本就是异常了。
4.3 识别异常点
异常点,就是价差偏离正常范围太远的地方。怎么定义「太远」?我一般用两种方法:
| 方法 | 原理 | 适用场景 |
|---|---|---|
| 标准差法 | 价差超过均值±2倍或3倍标准差 | 价差分布接近正态分布时 |
| 百分位法 | 价差超过历史数据的1%或99%分位数 | 价差分布偏态严重时 |
我个人更常用标准差法,简单粗暴。但要注意——金融数据往往有厚尾,3倍标准差之外的事件比正态分布假设下更常见。所以我会把阈值设到2.5倍标准差,既不过于敏感,也不过于迟钝。
来看异常点检测的代码:
def detect_outliers(spread_df, method='std', threshold=2.5):
"""
检测价差异常点
:param spread_df: 价差序列DataFrame
:param method: 'std' 或 'percentile'
:param threshold: 标准差倍数或百分位阈值
:return: 异常点DataFrame
"""
spread = spread_df['spread'].values
if method == 'std':
mean_val = np.mean(spread)
std_val = np.std(spread)
upper = mean_val + threshold * std_val
lower = mean_val - threshold * std_val
elif method == 'percentile':
upper = np.percentile(spread, 100 - threshold)
lower = np.percentile(spread, threshold)
# 标记异常点
outliers = spread_df[
(spread_df['spread'] > upper) |
(spread_df['spread'] < lower)
].copy()
outliers['label'] = '异常'
return outliers, upper, lower
检测出异常点后,我会在图上用红圈标出来:
def plot_with_outliers(spread_df, outliers, upper, lower):
"""在价差图上标注异常点"""
fig, ax = plt.subplots(figsize=(12, 6))
# 绘制价差曲线
ax.plot(spread_df['datetime'], spread_df['spread'],
color='#2196F3', linewidth=1, alpha=0.7)
# 标注异常点
ax.scatter(outliers['datetime'], outliers['spread'],
color='#F44336', s=50, zorder=5,
label=f'异常点 ({len(outliers)}个)')
# 阈值线
ax.axhline(y=upper, color='#FF9800', linestyle='--',
linewidth=1, label=f'上阈值: {upper:.2f}')
ax.axhline(y=lower, color='#FF9800', linestyle='--',
linewidth=1, label=f'下阈值: {lower:.2f}')
ax.set_title('价差异常点识别', fontsize=14, fontweight='bold')
ax.legend(loc='best')
ax.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
为什么异常点重要?因为跨期套利的入场信号,往往就来自这些异常点。价差跑到阈值外面,意味着市场情绪过度反应,接下来大概率会回归。
4.4 本章知识体系
下面这张图,把价差计算与可视化的核心逻辑串起来了:
从数据输入到价差计算,再到可视化和异常检测,最后输出候选信号——这就是一套完整的价差分析流水线。你在实战中,可以把这个流程封装成一个类,每天跑一遍,自动标记异常点。
好了,价差计算与可视化就讲到这里。记住一句话:图比数字直观,异常比常态重要。把图画好,把异常点抓准,你的套利系统就成功了一半。
公众号:蓝海资料掘金营,微信deep3321