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

JoinQuant 聚宽 order_target_value 调仓未完全成交(amount != filled)的原因与对策

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

问题描述

order_target_value成交量不及预期

调用order=order_target_value(fund, target_value)进行调仓,但有时order.amount != order.filled,也就是没有完全调整到目标仓位。求问哪位大佬知道这是什么原因?以及得怎么解决?

解决方案

在 JoinQuant (聚宽) 平台中,调用 order_target_value 进行调仓时,出现 order.amount != order.filled(即订单未完全成交)是一个非常常见的现象。这通常是由平台的撮合机制、市场实际情况以及 A 股交易规则共同决定的。

以下是导致该问题的常见原因及相应的解决方法:

1. 成交量比例限制 (order_volume_ratio)

原因:为了模拟真实市场的流动性,JoinQuant 默认设置了 order_volume_ratio = 0.25。这意味着你的单笔市价单成交量不能超过该标的当前 Bar(分钟或天)真实市场总成交量的 25%。超出这个限制的部分,如果是市价单会被直接撤单,导致 filled < amount
解决方法
如果你在做大资金回测,或者交易的是流动性较差的标的(如某些冷门基金或小盘股),可以适当调高这个比例,甚至设置为 1.0(即允许吃掉市场 100% 的成交量,但注意这在实盘中不现实)。

def initialize(context):
    # 将成交量比例限制放宽至 100%
    set_option('order_volume_ratio', 1.0)

2. A股“整手”交易规则限制

原因:A 股市场规定买入股票或场内基金必须是 100 股(份)的整数倍(科创板为 200 股起)。当你使用 order_target_value 时,系统会根据 (目标价值 - 当前持仓价值) / 最新价 计算出需要买卖的股数,然后向下取整到 100 的倍数。这必然会导致实际成交价值与你的 target_value 存在微小的偏差。
解决方法
这是市场规则,无法完全消除。在量化逻辑中,应当容忍这种因“整手”规则带来的资金零头偏差。不要在代码中强求 持仓价值 == target_value

3. 资金不足 (包含滑点和手续费的影响)

原因:在买入调仓时,系统会根据当前价格计算需要的资金。但由于滑点 (Slippage)手续费 (Commission) 的存在,实际扣除的资金会比按最新价计算的要多。如果你的账户可用资金刚好紧巴巴的,系统为了防止透支,会自动减少你的买入数量。
解决方法
在计算目标价值或全仓买入时,预留一小部分现金(例如 1%~2%)作为滑点和手续费的缓冲。

# 错误示范:满仓买入,容易因手续费导致资金不足而少买
# order_target_value(fund, context.portfolio.available_cash + context.portfolio.positions[fund].value)

# 正确示范:预留 1% 的资金
target_v = (context.portfolio.available_cash + context.portfolio.positions[fund].value) * 0.99
order_target_value(fund, target_v)

4. 涨跌停限制或停牌

原因

  • 涨停:如果你要买入调仓,但标的已经涨停,市价买单会被直接撤销(未启用盘口撮合时)或挂单等待(导致当前 Bar 无法成交)。
  • 跌停:如果你要卖出调仓,但标的已经跌停,市价卖单同样会被撤销或挂单。
  • 停牌:标的处于停牌状态,无法进行任何交易。
    解决方法
    在下单前,通过 get_current_data() 检查标的的状态,避免对涨跌停或停牌的标的下单。
def handle_data(context, data):
    current_data = get_current_data()
    if not current_data[fund].paused: # 检查是否停牌
        # 检查是否涨跌停 (简单示例,具体需结合买卖方向)
        if current_data[fund].last_price < current_data[fund].high_limit and current_data[fund].last_price > current_data[fund].low_limit:
            order_target_value(fund, target_value)

5. 使用了限价单 (LimitOrderStyle)

原因:如果你在 order_target_value 中传入了 style=LimitOrderStyle(price),如果市场价格没有达到你的限价,订单就会挂在盘口,直到收盘未成交的部分会被系统自动撤销。
解决方法
如果希望尽快成交,请使用默认的市价单(不传 style 参数,或传 MarketOrderStyle())。如果必须用限价单,需自行编写逻辑在 after_trading_end 或下一个 Bar 检查 get_open_orders() 并处理未成交的挂单。

总结排查步骤:

  1. 检查日志中是否有 WARNING 提示(如“成交量超过限制”、“资金不足”等)。
  2. 确认回测的 order_volume_ratio 设置。
  3. 确认标的当天的流动性(成交额是否极低)。
  4. 接受 A 股 100 股整数倍带来的合理误差。