【期货量化实战】跨期套利策略:价差交易完整指南(TqSdk源码详解)

一、前言

跨期套利是期货市场中最经典的套利策略之一,通过同时买卖同一品种不同月份的合约,利用价差回归获利。相比单边趋势交易,套利策略风险更低、收益更稳定。

本文将介绍:

  • 跨期套利的基本原理
  • 价差计算与监控
  • 套利信号判断
  • TqSdk完整实现代码

二、为什么选择天勤量化(TqSdk)

在众多期货量化工具中,**天勤量化(TqSdk)**是目前国内最受欢迎的开源期货量化框架之一:

特点 说明
完全免费 开源免费,无需付费即可获取实时行情
数据全面 支持国内所有期货交易所的实时行情和历史数据
上手简单 几行Python代码即可获取数据
文档完善 官方文档详细,示例代码丰富

安装方法:

bash 复制代码
pip install tqsdk

三、跨期套利基础

3.1 什么是跨期套利

跨期套利(Calendar Spread)是指在同一期货品种的不同交割月份合约上建立数量相等、方向相反的头寸。

类型 操作 预期
正套 买近月卖远月 价差扩大
反套 卖近月买远月 价差缩小

3.2 价差类型

价差形态 说明 常见品种
正价差(Contango) 远月价格 > 近月价格 仓储成本品种
负价差(Backwardation) 近月价格 > 远月价格 供需紧张品种

3.3 套利优势

优势 说明
风险较低 对冲了大部分方向性风险
保证金优惠 交易所通常有套利保证金优惠
收益稳定 价差波动相对可预测
适合大资金 容量大、冲击成本低

四、完整代码实现

4.1 价差监控工具

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="")

4.2 完整套利策略

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}")

4.3 代码解析

代码 说明
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()

六、套利注意事项

6.1 合约选择

要点 说明
流动性 选择成交量大的合约
月份间隔 通常选3-6个月间隔
避免临近交割 近月合约避免进入交割月

6.2 风险提示

风险 说明 应对
价差不回归 价差持续扩大或缩小 设置止损
流动性风险 无法同时成交 选流动性好的合约
保证金风险 极端行情追保 控制仓位
交割风险 近月合约进入交割 提前移仓

七、进阶技巧

7.1 动态阈值

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

7.2 价差比率

python 复制代码
# 使用价差比率而非绝对价差
spread_ratio = close_far / close_near - 1

# 适用于不同价位品种的横向比较

八、总结

要点 内容
策略原理 利用价差回归获利
核心指标 Z-Score标准化价差
开仓条件 Z值超过±2倍标准差
平仓条件 Z值回归到±0.5以内
风险控制 设置止损和持仓时间限制

免责声明:本文仅供学习交流使用,不构成任何投资建议。期货交易有风险,入市需谨慎。

更多资源:

相关推荐
yi0111 天前
LeetCode 643. 子数组最大平均数 I|从暴力枚举到滑动窗口
人工智能·笔记·python·算法·leetcode·滑动窗口
小李不困还能学1 天前
PyCharm远程开发连接失败排查与解决
ide·python·pycharm
pride.li1 天前
Python 安装
linux·python·ubuntu
数据库小学妹1 天前
存算分离到底分离了什么?四条架构变化与选型判断
数据库·数据库架构·云原生数据库·缓存一致性·存算分离
FPGA小徐1 天前
【一生一芯 / PA】异常响应机制:RISC-V 中 ecall → mtvec → mret 的完整代
开发语言·数据库·c#
全栈练习生1 天前
模型上下文协议(MCP)
python·ai
wflynn1 天前
GitHub 日榜趋势速报 | 2026-10-10
开源·github
极光通讯1 天前
服务器内存来料检验(IQC)实操:批次追溯、外观判定与上机验证
java·服务器·算法
泡海椒1 天前
JQuick-Excel 多字段 TRANSFORM:让当前行字段、JContext 与展示列各归其位
开发语言·python·excel
m0_646429971 天前
MySQL 初始化 SQL 中文乱码问题总结
数据库·sql·mysql