🚀 AI 一键生成 joinquant 策略代码

如何让 JoinQuant 回测更真实?详解 set_option('order_volume_ratio')

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

问题描述

请编写一个策略,其中回测下单量不超过当日成交量的一定比例

解决方案

在聚宽(JoinQuant)中,限制回测下单量不超过当日成交量一定比例的关键函数是 set_option('order_volume_ratio', value)

该函数通常在 initialize 中调用。例如,设置 value 为 0.1,则意味着每一笔委托的成交量不会超过该标的当日(或该分钟Bar)总成交量的 10%。如果策略生成的订单数量超过这个限制,系统会自动将成交数量截断至该限制值,剩余部分会自动撤单(市价单)或挂单(限价单)。

以下是一个完整的策略示例:

# -*- coding: utf-8 -*-
import jqdata

def initialize(context):
    """
    初始化函数,设定基准、复权模式及成交量限制
    """
    # 设定沪深300作为基准
    set_benchmark('000300.XSHG')
    
    # 开启动态复权模式(真实价格)
    set_option('use_real_price', True)
    
    # 过滤掉order系列API产生的比error级别低的log,避免日志过多
    log.set_level('order', 'error')
    
    # ------------------------------------------------------------------
    # 【核心设置】设置成交量比例限制
    # 这里设置为 0.1 (即 10%)
    # 含义:策略下单时,如果下单数量超过了该标的当日(或当前Bar)总成交量的10%,
    # 系统会自动限制成交数量为总成交量的10%。
    set_option('order_volume_ratio', 0.1)
    # ------------------------------------------------------------------
    
    # 定义一个全局变量, 保存要操作的股票 (例如:平安银行)
    g.security = '000001.XSHE'
    
    # 每天开盘时运行
    run_daily(market_open, time='09:30')

def market_open(context):
    """
    每日交易逻辑
    """
    security = g.security
    
    # 获取当前现金
    cash = context.portfolio.available_cash
    
    # 如果没有持仓,则尝试全仓买入
    # 注意:虽然我们下达的是全仓买入指令,但受限于 order_volume_ratio,
    # 实际成交量可能远小于全仓资金能购买的数量。
    if context.portfolio.positions[security].closeable_amount == 0:
        log.info("尝试全仓买入: %s" % security)
        order_value(security, cash)
        
    # 如果有持仓,且盈利超过10%,则卖出
    elif context.portfolio.positions[security].closeable_amount > 0:
        # 获取持仓成本和当前价格
        cost = context.portfolio.positions[security].avg_cost
        price = context.portfolio.positions[security].price
        
        if price > cost * 1.1:
            log.info("盈利超过10%,尝试卖出所有持仓: %s" % security)
            order_target(security, 0)

def after_trading_end(context):
    """
    收盘后运行,打印当天的成交情况以验证限制是否生效
    """
    trades = get_trades()
    for trade in trades.values():
        log.info("今日成交ID: %s, 标的: %s, 成交数量: %s" % (trade.trade_id, trade.security, trade.amount))

代码解析

  1. set_option('order_volume_ratio', 0.1):

    • 这是实现需求的核心代码。
    • 参数 0.1 代表 10%。
    • 在回测中,如果当天该股票总成交量为 1,000,000 股,而策略试图买入 200,000 股(20%),系统会强制只成交 100,000 股(10%),超出的部分对于市价单会被撤销。
  2. 应用场景:

    • 此设置主要用于模拟资金量较大的策略(如机构资金),防止回测结果因为“冲击成本”或“流动性不足”而失真。
    • 如果不设置,默认为 1.0(即允许成交量达到当日总成交量的 100%),这在小资金回测中没问题,但大资金回测时会产生严重的虚假高收益。

Q&A

Q: set_option('order_volume_ratio', value) 中的 value 范围是多少?
A: value 是一个浮点数,通常在 0 到 1 之间。例如 0.05 代表 5%,1.0 代表 100%。

Q: 如果我的下单量被限制了,剩余未成交的部分会怎么样?
A: 这取决于订单类型:

  • 市价单:超出限制的部分会被直接撤单。
  • 限价单:超出限制的部分会继续挂单,在后续的撮合(如分钟回测的下一分钟)中继续尝试成交,直到订单过期或全部成交。

Q: 这个设置对模拟交易(实盘模拟)生效吗?
A: 生效。在模拟交易中,系统同样会根据实时的市场成交量来限制策略的成交量,以防止模拟盘对流动性预估过于乐观。

Q: 如何在回测中查看是否触发了成交量限制?
A: 可以在回测详情页面的“日志”中查看。如果订单因为流动性限制被部分成交或撤单,系统通常会输出相应的 Warning 日志,或者你可以通过对比 order.amount (下单数量) 和 order.filled (成交数量) 来判断。