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

如何利用 get_dominant_future 实现商品期货主力合约的自动监控与平仓换月?

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

问题描述



Title: joinquant 期货主力合约自动移仓换月策略实现

Question: 如何利用 get_dominant_future 实现商品期货主力合约的自动监控与平仓换月?

解决方案

如何利用 get_dominant_future 实现商品期货主力合约的自动监控与平仓换月?

在商品期货量化交易中,由于期货合约具有生命周期(到期交割),长期持仓的策略必须进行移仓换月操作。聚宽(JoinQuant)平台提供了主力连续合约的拼接,但主力合约本身(如 RB9999.XSGE)是不可直接下单交易的。我们需要通过 get_dominant_future 获取当前实际的主力具体合约,并在主力合约发生切换时,自动平掉旧合约持仓,同时等量开仓新的主力合约。


一、 核心 API 介绍

1. get_dominant_future(underlying_symbol, date=None)

  • 作用:获取指定期货品种在指定日期(或当前回测逻辑日期)的主力合约代码。
  • 参数
    • underlying_symbol: 期货品种代码,如 'RB'(螺纹钢)、'CU'(阴极铜)。
    • date: 查询日期。在回测/模拟盘中默认不填,自动获取当前逻辑日期。
  • 返回值:具体合约代码,例如 'RB2310.XSGE'

2. set_subportfolios

  • 作用:初始化期货账户。期货交易必须将子账户类型设置为 'futures',否则无法下单。

二、 自动移仓换月策略逻辑

  1. 初始化:设置子账户类型为期货,定义要监控的期货品种(如螺纹钢 RB)。
  2. 每日开盘前
    • 调用 get_dominant_future 获取最新的主力合约。
    • 检查当前持仓中是否存在该品种的非主力合约(即旧主力合约)。
  3. 移仓操作
    • 如果发现持有旧合约,且新主力合约已发生切换,则在交易时间内平掉旧合约的所有多单/空单。
    • 随后,在新的主力合约上开立相同方向、相同数量的头寸,完成无缝移仓。

三、 完整 Python 策略源码

以下是基于 JoinQuant API 编写的完整自动移仓换月策略模板:

# 导入聚宽函数库
import jqdata
from kuanke.user_space_api import *

def initialize(context):
    # 1. 开启真实价格模式(Tick/期货策略必须开启)
    set_option('use_real_price', True)
    
    # 2. 设置初始资金并初始化期货账户
    init_cash = context.portfolio.starting_cash
    set_subportfolios([SubPortfolioConfig(cash=init_cash, type='futures')])
    
    # 3. 定义需要交易和监控的期货品种(以螺纹钢 RB 为例)
    g.underlying = 'RB'
    
    # 4. 记录当前持有的具体主力合约代码
    g.current_dominant = None
    
    # 5. 设定每日运行函数
    # 每天 09:00 开盘前检查主力合约并进行移仓监控
    run_daily(check_and_switch_dominant, time='09:00', reference_security='RB9999.XSGE')
    # 每天 09:30 开盘时执行常规交易逻辑
    run_daily(market_open, time='09:30', reference_security='RB9999.XSGE')

def check_and_switch_dominant(context):
    """每日开盘前检查主力合约是否切换,若切换则执行移仓"""
    log.info("--- 开始检查主力合约 ---")
    
    # 获取最新主力合约
    new_dominant = get_dominant_future(g.underlying)
    log.info(f"当前最新主力合约为: {new_dominant}")
    
    # 如果是第一次运行,先记录当前主力
    if g.current_dominant is None:
        g.current_dominant = new_dominant
        return
        
    # 如果主力合约发生切换
    if new_dominant != g.current_dominant:
        log.info(f"检测到主力合约切换!旧主力: {g.current_dominant} -> 新主力: {new_dominant}")
        
        # 获取旧合约的持仓情况
        portfolio = context.portfolio
        
        # 检查多头持仓并移仓
        if g.current_dominant in portfolio.long_positions:
            old_long_amount = portfolio.long_positions[g.current_dominant].total_amount
            if old_long_amount > 0:
                log.info(f"正在移仓多头:平仓旧主力 {g.current_dominant} 共 {old_long_amount} 手")
                # 平旧合约多仓(卖出)
                order(g.current_dominant, -old_long_amount, side='long')
                # 开新合约多仓(买入)
                order(new_dominant, old_long_amount, side='long')
                
        # 检查空头持仓并移仓
        if g.current_dominant in portfolio.short_positions:
            old_short_amount = portfolio.short_positions[g.current_dominant].total_amount
            if old_short_amount > 0:
                log.info(f"正在移仓空头:平仓旧主力 {g.current_dominant} 共 {old_short_amount} 手")
                # 平旧合约空仓(买入平仓)
                order(g.current_dominant, -old_short_amount, side='short')
                # 开新合约空仓(卖出开仓)
                order(new_dominant, old_short_amount, side='short')
                
        # 更新全局变量
        g.current_dominant = new_dominant
    else:
        log.info("主力合约未发生变化,无需移仓。")

def market_open(context):
    """常规交易逻辑(示例:若无持仓,则买入开仓一手最新主力合约)"""
    dominant_contract = g.current_dominant
    portfolio = context.portfolio
    
    # 如果当前没有任何持仓,买入一手主力合约
    has_position = False
    if (dominant_contract in portfolio.long_positions and portfolio.long_positions[dominant_contract].total_amount > 0) or \
       (dominant_contract in portfolio.short_positions and portfolio.short_positions[dominant_contract].total_amount > 0):
        has_position = True
        
    if not has_position:
        log.info(f"当前无持仓,开仓买入一手最新主力合约: {dominant_contract}")
        order(dominant_contract, 1, side='long')

四、 策略注意事项

  1. 滑点与交易成本:移仓换月涉及“平旧开新”双重交易,会产生双倍的手续费和滑点损耗。建议使用 set_slippage 设置合理的滑点以贴近实盘。
  2. 保证金占用:在移仓瞬间,如果先开新仓再平旧仓,可能会导致保证金不足。本策略采用先平旧仓、释放保证金后、再开新仓的顺序,避免因保证金不足导致下单失败。
  3. 非交易时间下单:本策略在 09:00 盘前进行逻辑判断,若有移仓需求,订单会以挂单形式进入引擎,并在 09:30 开盘时自动撮合成交。