🚀 AI 一键生成 qmt 策略代码
立即体验

qmt 期货跨期套利:跨期价差套利模型与自动化下单实战(附 Python 源码)

qmt | 发布时间: 2026/7/24
以下内容由 EasyQuant 生成。

问题描述

请根据以下 SEO 主题生成完整页面内容:

Title: qmt 期货跨期套利:跨期价差套利模型与自动化下单实战

Question: 请帮我写一个 qmt 期货跨期价差套利策略

解决方案

qmt 期货跨期套利:跨期价差套利模型与自动化下单实战

在期货量化交易中,跨期套利(Calendar Spread Arbitrage)通过同时买入和卖出同一品种不同到期月份的期货合约,捕捉两者价差回归带来的统计套利机会。QMT 平台通过原生 API 提供了高效的组合套利接口 passorder,支持多合约的原子化或自动化组合下单。


一、跨期套利策略原理

跨期套利的核心是价差(Spread)
$$\text{Spread} = \text{Price}{\text{近月}} - \text{Price}{\text{远月}}$$

  1. 均值回归模型(布林带)
    • 当价差高于均值一定标准差(上轨)时,认为价差过高,执行卖出近月、买入远月(做空价差)。
    • 当价差低于均值一定标准差(下轨)时,认为价差过低,执行买入近月、卖出远月(做多价差)。
    • 当价差回归至均值(中轨)附近时,平仓获利结算。

二、QMT 跨期套利核心接口说明

在 QMT 中,套利交易既可以使用单合约接口分别下单,也可以使用组合套利专属下单模式:

  • ContextInfo.get_market_data_ex():高效获取近月与远月合约的历史行情与实时 Tick。
  • passorder():组合套利模式支持通过设置账号与代码参数,一次性发送对冲订单,降低单边成交风险。
    • 操作类型(opType):40(组合开多)、43(组合开空)、46(组合平多,优先平今)、48(组合平空,优先平今)等。
    • 下单方式(orderType):2331(合约价值自动套利按组合股票数量方式下单)。

Three, QMT 跨期价差套利源码实现

以下为基于 QMT Python API 编写的跨期价差套利策略完整示例:

#encoding:gbk
import numpy as np

def init(ContextInfo):
    # 1. 设定套利合约组合
    ContextInfo.near_contract = 'IF2309.IF'  # 近月合约
    ContextInfo.far_contract = 'IF2312.IF'   # 远月合约
    ContextInfo.set_universe([ContextInfo.near_contract, ContextInfo.far_contract])
    
    # 2. 交易参数设置
    ContextInfo.account = '110476'  # 替换为您的期货资金账号
    ContextInfo.set_account(ContextInfo.account)
    ContextInfo.period = '5m'       # 运行周期:5分钟K线
    
    # 3. 策略指标参数
    ContextInfo.window = 20         # 计算均值的窗口期
    ContextInfo.num_std = 2.0       # 标准差倍数
    ContextInfo.trade_lots = 1      # 每次套利一手
    
    # 4. 状态变量
    ContextInfo.pos = 0             # 当前持仓状态:0无持仓,1做多价差,-1做空价差
    print("【初始化完成】期货跨期套利策略成功加载。")

def handlebar(ContextInfo):
    # 仅在最新 Bar 稳定后计算
    if not ContextInfo.is_last_bar():
        return
        
    # 获取近月与远月合约的历史收盘价
    data_near = ContextInfo.get_market_data_ex(['close'], [ContextInfo.near_contract], period=ContextInfo.period, count=ContextInfo.window + 1)
    data_far = ContextInfo.get_market_data_ex(['close'], [ContextInfo.far_contract], period=ContextInfo.period, count=ContextInfo.window + 1)
    
    if ContextInfo.near_contract not in data_near or ContextInfo.far_contract not in data_far:
        return
        
    df_near = data_near[ContextInfo.near_contract]
    df_far = data_far[ContextInfo.far_contract]
    
    if len(df_near) < ContextInfo.window or len(df_far) < ContextInfo.window:
        return
        
    # 计算价差序列
    spread_series = df_near['close'] - df_far['close']
    current_spread = spread_series.iloc[-1]
    
    # 计算布林带轨道
    mean_spread = np.mean(spread_series.iloc[-ContextInfo.window:-1])
    std_spread = np.std(spread_series.iloc[-ContextInfo.window:-1])
    upper_bound = mean_spread + ContextInfo.num_std * std_spread
    lower_bound = mean_spread - ContextInfo.num_std * std_spread
    
    print(f"当前价差: {current_spread:.2f}, 上轨: {upper_bound:.2f}, 中轨: {mean_spread:.2f}, 下轨: {lower_bound:.2f}")
    
    # 交易逻辑判定与执行
    # 1. 开仓逻辑
    if ContextInfo.pos == 0:
        if current_spread > upper_bound:
            # 价差过高 -> 做空价差(卖近买远)
            print("【信号】价差突破上轨,开仓做空价差")
            # 使用 passorder 发送单边对冲指令
            passorder(3, 1101, ContextInfo.account, ContextInfo.near_contract, 5, -1, ContextInfo.trade_lots, ContextInfo)
            passorder(0, 1101, ContextInfo.account, ContextInfo.far_contract, 5, -1, ContextInfo.trade_lots, ContextInfo)
            ContextInfo.pos = -1
            
        elif current_spread < lower_bound:
            # 价差过低 -> 做多价差(买近卖远)
            print("【信号】价差突破下轨,开仓做多价差")
            passorder(0, 1101, ContextInfo.account, ContextInfo.near_contract, 5, -1, ContextInfo.trade_lots, ContextInfo)
            passorder(3, 1101, ContextInfo.account, ContextInfo.far_contract, 5, -1, ContextInfo.trade_lots, ContextInfo)
            ContextInfo.pos = 1
            
    # 2. 平仓逻辑(价差回归中轨)
    elif ContextInfo.pos == 1 and current_spread >= mean_spread:
        print("【信号】做多价差回归中轨,执行平仓")
        passorder(6, 1101, ContextInfo.account, ContextInfo.near_contract, 5, -1, ContextInfo.trade_lots, ContextInfo)
        passorder(8, 1101, ContextInfo.account, ContextInfo.far_contract, 5, -1, ContextInfo.trade_lots, ContextInfo)
        ContextInfo.pos = 0Concat
        
    elif ContextInfo.pos == -1 and current_spread <= mean_spread:
        print("【信号】做空价差回归中轨,执行平仓")
        passorder(8, 1101, ContextInfo.account, ContextInfo.near_contract, 5, -1, ContextInfo.trade_lots, ContextInfo)
        passorder(6, 1101, ContextInfo.account, ContextInfo.far_contract, 5, -1, ContextInfo.trade_lots, ContextInfo)
        ContextInfo.pos = 0

四、实战注意事项与风控建议

  1. 腿部滑点与瘸腿风险
    实盘交易中,两个合约同时下单可能出现一腿成交而另一腿未成交(瘸腿)的风险。可通过 get_trade_detail_data 实时监控委托状态,设置未成交撤单重发机制。
  2. 主力合约换月
    使用 ContextInfo.get_main_contract() 可动态获取最新的期货主力合约,避免硬编码导致合约退市或流动性不足。
  3. 保证资金充足
    套利策略虽然降低了单边市场方向风险,但双边开仓会占用双份保证金,需预留足够的资金应对保证金波动。