🚀 AI 一键生成 joinquant 策略代码

在 JoinQuant 聚宽平台如何处理期货回测中的换月(主力合约切换)?

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

问题描述

期货 换月

老师你好:
我在做期货回撤的时候,换月怎么处理呢?

解决方案

在 JoinQuant(聚宽)平台上进行期货回测时,处理“换月”(即主力合约切换)是非常关键的一步。因为在聚宽中,不能直接对主力连续合约(如 RB9999.XSGE)进行下单,必须获取具体的真实合约代码(如 RB1905.XSGE)才能交易。

以下是处理期货换月的标准流程和代码示例:

1. 核心 API 介绍

处理换月最核心的 API 是 get_dominant_future

  • get_dominant_future(underlying_symbol, date=None):获取指定品种在指定日期的主力合约代码。
    • underlying_symbol: 期货合约品种,如 'RB' (螺纹钢)。
    • 返回值: 具体的期货合约代码,如 'RB1905.XSGE'

2. 换月处理逻辑

标准的换月逻辑通常在每天开盘前或盘中定期执行,步骤如下:

  1. 获取当前最新的主力合约:使用 get_dominant_future
  2. 检查当前持仓:遍历账户中该品种的持仓合约。
  3. 平旧开新(移仓换月):如果发现持仓的合约已经不是最新的主力合约,则将旧合约平仓,并将相应的仓位转移到新的主力合约上。

3. 完整代码示例

以下是一个简单的螺纹钢(RB)多头策略换月处理示例:

# 导入聚宽函数库
import jqdata

def initialize(context):
    # 设定基准
    set_benchmark('000300.XSHG')
    # 开启动态复权模式(真实价格)
    set_option('use_real_price', True)
    
    # 设定期货账户
    set_subportfolios([SubPortfolioConfig(cash=100000, type='futures')])
    
    # 定义要交易的期货品种
    g.underlying_symbol = 'RB'
    # 记录当前的主力合约
    g.dominant = None
    
    # 每天开盘前检查换月
    run_daily(check_rollover, time='08:50', reference_security='RB9999.XSGE')
    # 每天盘中执行交易逻辑
    run_daily(trade_logic, time='09:30', reference_security='RB9999.XSGE')

def check_rollover(context):
    """
    检查并处理换月逻辑
    """
    # 获取当前最新的主力合约
    current_dominant = get_dominant_future(g.underlying_symbol)
    
    # 如果主力合约发生变化
    if g.dominant and current_dominant != g.dominant:
        log.info(f"主力合约发生切换: {g.dominant} -> {current_dominant}")
        
        # 检查旧合约是否有持仓
        if g.dominant in context.portfolio.long_positions:
            # 获取旧合约的多单持仓量
            old_position_amount = context.portfolio.long_positions[g.dominant].total_amount
            if old_position_amount > 0:
                log.info(f"平仓旧合约: {g.dominant},数量: {old_position_amount}")
                # 平掉旧合约多单
                order_target(g.dominant, 0, side='long')
                
                # 在新合约上开同等数量的多单(移仓)
                log.info(f"开仓新合约: {current_dominant},数量: {old_position_amount}")
                order_target(current_dominant, old_position_amount, side='long')
                
        # 如果有空单持仓,同理处理(此处省略空单处理代码)
        
    # 更新记录的主力合约
    g.dominant = current_dominant

def trade_logic(context):
    """
    具体的交易信号逻辑
    """
    # 确保已经获取到主力合约
    if not g.dominant:
        return
        
    # 这里写你的策略逻辑,例如简单的买入持有
    # 注意:下单时必须使用 g.dominant (具体合约),而不是 'RB9999.XSGE'
    if g.dominant not in context.portfolio.long_positions:
        order(g.dominant, 1, side='long')
        log.info(f"买入开仓: {g.dominant}")

4. 注意事项

  1. 不能对指数或主连下单:切记 RB9999.XSGE(主连)和 RB8888.XSGE(指数)只能用来获取数据或作为定时任务的参考标的(reference_security),绝对不能传入 order 函数中。
  2. 换月成本:换月操作本质上是一次平仓加一次开仓,会产生交易手续费和滑点。在回测时,频繁换月会影响收益,这是符合真实市场情况的。
  3. 交割日风险:如果不处理换月,持仓合约到达交割日时,聚宽系统会以当天结算价自动平仓,且没有手续费。但在实盘中,个人投资者通常不允许进入交割月,因此策略中必须包含换月逻辑。