跨期套利是期货市场中最经典的套利策略之一,通过同时买卖同一品种不同月份的合约,利用价差回归获利。相比单边趋势交易,套利策略风险更低、收益更稳定。
本文将介绍:
- 跨期套利的基本原理
- 价差计算与监控
- 套利信号判断
- TqSdk完整实现代码
在众多期货量化工具中,**天勤量化(TqSdk)**是目前国内最受欢迎的开源期货量化框架之一:
| 特点 |
说明 |
| 完全免费 |
开源免费,无需付费即可获取实时行情 |
| 数据全面 |
支持国内所有期货交易所的实时行情和历史数据 |
| 上手简单 |
几行Python代码即可获取数据 |
| 文档完善 |
官方文档详细,示例代码丰富 |
安装方法:
bash
复制代码
pip install tqsdk
跨期套利(Calendar Spread)是指在同一期货品种的不同交割月份合约上建立数量相等、方向相反的头寸。
| 类型 |
操作 |
预期 |
| 正套 |
买近月卖远月 |
价差扩大 |
| 反套 |
卖近月买远月 |
价差缩小 |
| 价差形态 |
说明 |
常见品种 |
| 正价差(Contango) |
远月价格 > 近月价格 |
仓储成本品种 |
| 负价差(Backwardation) |
近月价格 > 远月价格 |
供需紧张品种 |
| 优势 |
说明 |
| 风险较低 |
对冲了大部分方向性风险 |
| 保证金优惠 |
交易所通常有套利保证金优惠 |
| 收益稳定 |
价差波动相对可预测 |
| 适合大资金 |
容量大、冲击成本低 |
python
复制代码
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
功能:跨期价差实时监控
说明:本代码仅供学习参考
"""
from tqsdk import TqApi, TqAuth
# ============ 合约配置 ============
SYMBOL_NEAR = "SHFE.rb2505" # 近月合约
SYMBOL_FAR = "SHFE.rb2510" # 远月合约
# ============ 初始化 ============
api = TqApi(auth=TqAuth("快期账户", "快期密码"))
quote_near = api.get_quote(SYMBOL_NEAR)
quote_far = api.get_quote(SYMBOL_FAR)
print("=" * 60)
print("跨期价差监控")
print("=" * 60)
print(f"近月合约: {SYMBOL_NEAR}")
print(f"远月合约: {SYMBOL_FAR}")
print("-" * 60)
# 价差历史
spread_history = []
while True:
api.wait_update()
# 获取最新价格
price_near = quote_near.last_price
price_far = quote_far.last_price
# 计算价差(远月 - 近月)
spread = price_far - price_near
spread_history.append(spread)
# 保留最近100个数据计算统计值
if len(spread_history) > 100:
spread_history = spread_history[-100:]
# 计算统计指标
avg_spread = sum(spread_history) / len(spread_history)
max_spread = max(spread_history)
min_spread = min(spread_history)
print(f"\r近月={price_near:.0f} 远月={price_far:.0f} "
f"价差={spread:.0f} 均值={avg_spread:.0f} "
f"区间=[{min_spread:.0f}, {max_spread:.0f}]", end="")
python
复制代码
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
功能:跨期套利策略
说明:本代码仅供学习参考
"""
from tqsdk import TqApi, TqAuth, TqSim
from tqsdk.lib import TargetPosTask
import numpy as np
# ============ 合约配置 ============
SYMBOL_NEAR = "SHFE.rb2505" # 近月合约
SYMBOL_FAR = "SHFE.rb2510" # 远月合约
LOTS = 1 # 每腿手数
# ============ 策略参数 ============
LOOKBACK = 60 # 回看周期
ENTRY_THRESHOLD = 2.0 # 开仓阈值(标准差倍数)
EXIT_THRESHOLD = 0.5 # 平仓阈值
MAX_HOLD_BARS = 100 # 最大持仓K线数
# ============ 初始化 ============
api = TqApi(TqSim(init_balance=500000), auth=TqAuth("快期账户", "快期密码"))
quote_near = api.get_quote(SYMBOL_NEAR)
quote_far = api.get_quote(SYMBOL_FAR)
kline_near = api.get_kline_serial(SYMBOL_NEAR, 300, LOOKBACK + 20)
kline_far = api.get_kline_serial(SYMBOL_FAR, 300, LOOKBACK + 20)
# 持仓管理
target_pos_near = TargetPosTask(api, SYMBOL_NEAR)
target_pos_far = TargetPosTask(api, SYMBOL_FAR)
account = api.get_account()
print("=" * 60)
print("跨期套利策略")
print("=" * 60)
print(f"近月: {SYMBOL_NEAR}")
print(f"远月: {SYMBOL_FAR}")
print(f"开仓阈值: {ENTRY_THRESHOLD}倍标准差")
print(f"平仓阈值: {EXIT_THRESHOLD}倍标准差")
print("-" * 60)
# 状态变量
position = 0 # 1=正套(买近卖远), -1=反套(卖近买远), 0=空仓
hold_bars = 0 # 持仓K线数
while True:
api.wait_update()
if api.is_changing(kline_near.iloc[-1], "datetime"):
# 获取收盘价序列
close_near = kline_near["close"].values[-LOOKBACK:]
close_far = kline_far["close"].values[-LOOKBACK:]
# 计算价差序列
spread = close_far - close_near
# 统计指标
spread_mean = np.mean(spread)
spread_std = np.std(spread)
# 当前价差
current_spread = close_far[-1] - close_near[-1]
# 计算z-score
z_score = (current_spread - spread_mean) / spread_std if spread_std > 0 else 0
print(f"\n价差={current_spread:.0f} 均值={spread_mean:.0f} "
f"标准差={spread_std:.0f} Z值={z_score:.2f}")
# ============ 交易逻辑 ============
if position == 0:
# 无持仓,判断开仓
if z_score > ENTRY_THRESHOLD:
# 价差过大,做反套(卖近买远)
target_pos_near.set_target_volume(-LOTS)
target_pos_far.set_target_volume(LOTS)
position = -1
hold_bars = 0
print(f"[开仓] 反套:卖{SYMBOL_NEAR} 买{SYMBOL_FAR}")
elif z_score < -ENTRY_THRESHOLD:
# 价差过小,做正套(买近卖远)
target_pos_near.set_target_volume(LOTS)
target_pos_far.set_target_volume(-LOTS)
position = 1
hold_bars = 0
print(f"[开仓] 正套:买{SYMBOL_NEAR} 卖{SYMBOL_FAR}")
else:
# 有持仓,判断平仓
hold_bars += 1
should_close = False
close_reason = ""
# 条件1:价差回归
if position == 1 and z_score > -EXIT_THRESHOLD:
should_close = True
close_reason = "价差回归"
elif position == -1 and z_score < EXIT_THRESHOLD:
should_close = True
close_reason = "价差回归"
# 条件2:超时平仓
if hold_bars >= MAX_HOLD_BARS:
should_close = True
close_reason = "持仓超时"
if should_close:
target_pos_near.set_target_volume(0)
target_pos_far.set_target_volume(0)
print(f"[平仓] {close_reason},持仓{hold_bars}根K线")
position = 0
hold_bars = 0
# 显示账户状态
print(f" 账户权益: {account.balance:.0f} 浮盈: {account.float_profit:.0f}")
| 代码 |
说明 |
spread = far - near |
计算价差 |
z_score = (spread - mean) / std |
标准化价差 |
z_score > 2.0 |
价差偏大,做反套 |
z_score < -2.0 |
价差偏小,做正套 |
abs(z_score) < 0.5 |
价差回归,平仓 |
python
复制代码
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
功能:价差统计分析
说明:本代码仅供学习参考
"""
from tqsdk import TqApi, TqAuth
import numpy as np
# ============ 合约配置 ============
SYMBOL_NEAR = "SHFE.rb2505"
SYMBOL_FAR = "SHFE.rb2510"
api = TqApi(auth=TqAuth("快期账户", "快期密码"))
# 获取日K线
kline_near = api.get_kline_serial(SYMBOL_NEAR, 86400, 60)
kline_far = api.get_kline_serial(SYMBOL_FAR, 86400, 60)
api.wait_update()
# 计算价差
close_near = kline_near["close"].values
close_far = kline_far["close"].values
spread = close_far - close_near
# 统计分析
print("=" * 50)
print("价差统计分析")
print("=" * 50)
print(f"数据天数: {len(spread)}")
print("-" * 50)
# 基础统计
print(f"均值: {np.mean(spread):.2f}")
print(f"标准差: {np.std(spread):.2f}")
print(f"最大值: {np.max(spread):.2f}")
print(f"最小值: {np.min(spread):.2f}")
print(f"当前值: {spread[-1]:.2f}")
# 分位数
print(f"\n分位数:")
for p in [10, 25, 50, 75, 90]:
print(f" {p}%分位: {np.percentile(spread, p):.2f}")
# Z-Score
current_z = (spread[-1] - np.mean(spread)) / np.std(spread)
print(f"\n当前Z-Score: {current_z:.2f}")
if current_z > 2:
print("建议: 价差偏大,可考虑反套")
elif current_z < -2:
print("建议: 价差偏小,可考虑正套")
else:
print("建议: 价差正常,观望")
api.close()
| 要点 |
说明 |
| 流动性 |
选择成交量大的合约 |
| 月份间隔 |
通常选3-6个月间隔 |
| 避免临近交割 |
近月合约避免进入交割月 |
| 风险 |
说明 |
应对 |
| 价差不回归 |
价差持续扩大或缩小 |
设置止损 |
| 流动性风险 |
无法同时成交 |
选流动性好的合约 |
| 保证金风险 |
极端行情追保 |
控制仓位 |
| 交割风险 |
近月合约进入交割 |
提前移仓 |
python
复制代码
# 根据波动率动态调整开仓阈值
def get_dynamic_threshold(spread_std, base_threshold=2.0):
"""
波动率大时提高阈值,波动率小时降低阈值
"""
# 假设历史标准差为50
NORMAL_STD = 50
ratio = spread_std / NORMAL_STD
# 限制调整范围
ratio = max(0.5, min(ratio, 2.0))
return base_threshold * ratio
python
复制代码
# 使用价差比率而非绝对价差
spread_ratio = close_far / close_near - 1
# 适用于不同价位品种的横向比较
| 要点 |
内容 |
| 策略原理 |
利用价差回归获利 |
| 核心指标 |
Z-Score标准化价差 |
| 开仓条件 |
Z值超过±2倍标准差 |
| 平仓条件 |
Z值回归到±0.5以内 |
| 风险控制 |
设置止损和持仓时间限制 |
免责声明:本文仅供学习交流使用,不构成任何投资建议。期货交易有风险,入市需谨慎。
更多资源: