🚀 AI 一键生成 joinquant 策略代码

如何用 JoinQuant 获取某品种所有期货合约并分析期限结构?

joinquant | 发布时间: 2025/12/8
以下内容由 EasyQuant 生成。

问题描述

如何获取某个品种所有可交易的期货合约列表,并进行分析?

解决方案

在 JoinQuant 聚宽平台上,获取某个期货品种(如螺纹钢 RB、沪深300 IF)当前所有可交易合约列表的核心 API 是 get_future_contracts

获取列表后,通常结合 get_current_dataget_price 获取这些合约的价格、持仓量(Open Interest)等数据,进而分析期限结构(Term Structure)主力与次主力合约的价差

以下是详细的 API 说明和一个完整的策略代码示例。该示例展示了如何获取螺纹钢(RB)的所有合约,并分析其持仓量分布和价格结构。

核心 API 说明

get_future_contracts(security, date=None)

  • 功能:获取某期货品种在指定日期的可交易合约标的列表。
  • 参数
    • security: 期货合约品种代码,字符串格式,例如 'RB' (螺纹钢), 'IF' (沪深300股指), 'AG' (白银)。
    • date: 查询日期。回测中若不填,默认为回测当前日期;研究中若不填,默认为最新日期。
  • 返回值:包含合约代码的列表 (List),例如 ['RB2310.XSGE', 'RB2401.XSGE', ...]

策略代码示例

以下代码实现了一个完整的策略:

  1. 每天开盘时获取螺纹钢(RB)的所有可交易合约。
  2. 获取这些合约的最新价格和持仓量。
  3. 打印合约列表及其对应的价格和持仓量(用于分析期限结构)。
  4. 找出持仓量最大的合约(主力)和持仓量第二大的合约(次主力)。
  5. 计算并打印主力与次主力的价差。
# -*- coding: utf-8 -*-
# 导入函数库
from jqdata import *

def initialize(context):
    # 设定沪深300作为基准
    set_benchmark('000300.XSHG')
    # 开启动态复权模式(真实价格)
    set_option('use_real_price', True)
    # 过滤掉order系列API产生的比error级别低的log
    log.set_level('order', 'error')
    
    # 设定要分析的期货品种,这里以螺纹钢为例
    g.future_code = 'RB'
    
    # 设定期货账户
    # 获取初始资金
    init_cash = context.portfolio.starting_cash 
    # 设定账户为期货账户
    set_subportfolios([SubPortfolioConfig(cash=init_cash, type='futures')])
    
    # 每天开盘时运行分析
    run_daily(analyze_futures_structure, time='09:30')

def analyze_futures_structure(context):
    # 1. 获取当前日期所有可交易的 RB 合约列表
    # get_future_contracts 会自动根据回测时间返回当时的合约列表
    contract_list = get_future_contracts(g.future_code)
    
    if not contract_list:
        log.info("未找到品种 %s 的合约" % g.future_code)
        return

    # 2. 获取这些合约的当前快照数据(包含价格、持仓量等)
    current_data = get_current_data()
    
    # 用于存储合约信息的列表
    contracts_info = []
    
    for code in contract_list:
        # 获取该合约的数据对象
        data = current_data[code]
        
        # 过滤掉停牌或未上市无数据的合约
        if data.paused or np.isnan(data.last_price):
            continue
            
        # 收集信息:代码、最新价、持仓量
        # 注意:get_current_data在回测中返回的是前一分钟或前一天的收盘数据,视频率而定
        # 若需要更长周期的历史数据,可使用 attribute_history
        info = {
            'code': code,
            'price': data.last_price,
            'open_interest': data.open_interest # 持仓量
        }
        contracts_info.append(info)
    
    # 3. 数据分析
    # 按照合约代码排序(通常意味着按到期月份排序),展示期限结构
    contracts_info.sort(key=lambda x: x['code'])
    
    log.info("====== %s 期限结构分析 (日期: %s) ======" % (g.future_code, context.current_dt.date()))
    log.info(f"{'合约代码':<15} | {'价格':<10} | {'持仓量':<10}")
    
    for info in contracts_info:
        log.info(f"{info['code']:<15} | {info['price']:<10.2f} | {info['open_interest']:<10.0f}")
        
    # 4. 寻找主力与次主力合约(按持仓量排序)
    # 按持仓量从大到小排序
    sorted_by_oi = sorted(contracts_info, key=lambda x: x['open_interest'], reverse=True)
    
    if len(sorted_by_oi) >= 2:
        dominant_contract = sorted_by_oi[0] # 主力
        sub_dominant_contract = sorted_by_oi[1] # 次主力
        
        spread = dominant_contract['price'] - sub_dominant_contract['price']
        
        log.info("-" * 30)
        log.info(f"主力合约: {dominant_contract['code']} (持仓: {dominant_contract['open_interest']})")
        log.info(f"次主力合约: {sub_dominant_contract['code']} (持仓: {sub_dominant_contract['open_interest']})")
        log.info(f"主力-次主力 价差: {spread:.2f}")
        
        # 示例交易逻辑:如果价差过大(例如大于100),可以考虑套利(此处仅为演示,不构成策略建议)
        # if spread > 100:
        #     order_target(dominant_contract['code'], -1) # 卖主力
        #     order_target(sub_dominant_contract['code'], 1) # 买次主力
    else:
        log.info("可交易合约数量不足,无法计算主力价差")

代码解析

  1. get_future_contracts(g.future_code): 这是核心步骤。在回测的每一天,它都会返回当时那个时间点该品种所有在市交易的合约代码(例如 RB1801.XSGE, RB1805.XSGE 等)。
  2. get_current_data(): 获取当前时间点的快照数据。在期货分析中,我们重点关注 last_price (最新价) 和 open_interest (持仓量)。
  3. 数据清洗: 代码中增加了 if data.paused or np.isnan(data.last_price): 判断,用于过滤掉停牌或者刚上市还没有产生成交数据的合约,防止后续计算报错。
  4. 期限结构展示: 通过按合约代码排序(即按交割月排序),打印出价格序列。如果远月价格高于近月,称为升水(Contango);反之称为贴水(Backwardation)。
  5. 主力判断: 虽然聚宽提供了 get_dominant_future 直接获取主力合约,但通过 get_future_contracts 获取所有合约并按 open_interest 排序,可以让我们同时找到“次主力”合约,这对于跨期套利策略非常重要。

常见分析应用场景

  1. 跨期套利: 监控主力合约与次主力合约(通常是近月和远月)的价差变化。
  2. 展期信号: 当远月合约的持仓量逐渐接近并超过近月合约时,是主力换月的信号。
  3. 期限结构因子: 计算远月与近月的价格斜率,作为多空因子的输入(例如:贴水结构往往利多,升水结构往往利空)。

Q&A

Q1: get_future_contracts 返回的合约列表是按什么顺序排列的?
A1: 返回的列表通常是按照合约代码的字母和数字顺序排列的,对于期货而言,这通常意味着按照交割月份的先后顺序排列(例如 2301, 2305, 2310)。

Q2: 如何直接获取主力合约而不需要自己计算持仓量?
A2: 可以使用 get_dominant_future(underlying_symbol, date=None) 函数。例如 get_dominant_future('RB') 会直接返回当前持仓量最大的合约代码。

Q3: 为什么有时候获取到的合约价格是 NaN?
A3: 这通常发生在合约刚刚上市的早盘集合竞价阶段,或者该合约极度不活跃、当天尚未有成交时。在使用数据前,建议检查 np.isnan(price)

Q4: 这个 API 支持商品期货以外的品种吗?
A4: 支持。get_future_contracts 支持所有期货品种,包括金融期货(如 'IF', 'IC', 'IH', 'TS', 'TF', 'T')和商品期货。只需传入对应的品种代码即可。