3 分钟快速生成代码
输入想法,AI 即刻生成可运行代码
在 JoinQuant (聚宽) 平台中,调用 order_target_value 进行调仓时,出现 order.amount != order.filled(即订单未完全成交)是一个非常常见的现象。这通常是由平台的撮合机制、市场实际情况以及 A 股交易规则共同决定的。
以下是导致该问题的常见原因及相应的解决方法:
原因:为了模拟真实市场的流动性,JoinQuant 默认设置了 order_volume_ratio = 0.25。这意味着你的单笔市价单成交量不能超过该标的当前 Bar(分钟或天)真实市场总成交量的 25%。超出这个限制的部分,如果是市价单会被直接撤单,导致 filled < amount。
解决方法:
如果你在做大资金回测,或者交易的是流动性较差的标的(如某些冷门基金或小盘股),可以适当调高这个比例,甚至设置为 1.0(即允许吃掉市场 100% 的成交量,但注意这在实盘中不现实)。
def initialize(context):
# 将成交量比例限制放宽至 100%
set_option('order_volume_ratio', 1.0)
原因:A 股市场规定买入股票或场内基金必须是 100 股(份)的整数倍(科创板为 200 股起)。当你使用 order_target_value 时,系统会根据 (目标价值 - 当前持仓价值) / 最新价 计算出需要买卖的股数,然后向下取整到 100 的倍数。这必然会导致实际成交价值与你的 target_value 存在微小的偏差。
解决方法:
这是市场规则,无法完全消除。在量化逻辑中,应当容忍这种因“整手”规则带来的资金零头偏差。不要在代码中强求 持仓价值 == target_value。
原因:在买入调仓时,系统会根据当前价格计算需要的资金。但由于滑点 (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)
原因:
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)
原因:如果你在 order_target_value 中传入了 style=LimitOrderStyle(price),如果市场价格没有达到你的限价,订单就会挂在盘口,直到收盘未成交的部分会被系统自动撤销。
解决方法:
如果希望尽快成交,请使用默认的市价单(不传 style 参数,或传 MarketOrderStyle())。如果必须用限价单,需自行编写逻辑在 after_trading_end 或下一个 Bar 检查 get_open_orders() 并处理未成交的挂单。
WARNING 提示(如“成交量超过限制”、“资金不足”等)。order_volume_ratio 设置。