问题描述
解决方案
在聚宽(JoinQuant)平台进行回测或模拟交易时,下单后未成交或仅部分成交通常是由撮合机制、市场流动性限制、资金持仓限制或交易规则导致的。
以下是导致该情况的详细原因分析及排查方法:
1. 撮合机制与价格原因
- 限价单(Limit Order)未达到成交价
- 原因:如果您下的是限价单,只有当市场价格满足条件时才会成交。
- 买入:市场价 $\le$ 您的委托价。
- 卖出:市场价 $\ge$ 您的委托价。
- 现象:订单状态一直为
open(已委托),直到收盘后被系统自动撤销。
- 原因:如果您下的是限价单,只有当市场价格满足条件时才会成交。
- 涨跌停限制
- 买入时:如果标的涨停,市价单会被直接撤销;限价单会挂单排队,但通常因为没有卖盘而无法成交。
- 卖出时:如果标的跌停,市价单会被直接撤销;限价单会挂单排队,但通常因为没有买盘而无法成交。
- 滑点(Slippage)影响
- 原因:系统默认或用户设置了滑点(
set_slippage)。 - 逻辑:如果
最新价 + 滑点超过了涨停价(买入时)或低于跌停价(卖出时),订单可能无法成交或被撤销。
- 原因:系统默认或用户设置了滑点(
2. 成交量与流动性限制(最常见原因)
聚宽为了模拟真实的交易环境,防止策略对市场产生过大冲击,对成交量有严格限制。
- 成交量比例限制 (
order_volume_ratio)- 机制:回测中默认开启了成交量限制。默认情况下,您的策略在某一根K线(Bar)上的成交量,不能超过该标的在真实市场中该K线总成交量的 25%(默认值)。
- 现象:如果您下单数量很大,而该股票当天/当分钟交易不活跃,系统会强制只成交一部分,或者完全不成交。
- 调整方法:可以在
initialize中通过set_option('order_volume_ratio', value)修改比例(例如设为 1.0 表示允许成交该分钟全部真实成交量,但这会降低回测真实性)。
- 盘口撮合限制(模拟交易)
- 机制:如果在模拟交易中开启了盘口撮合(
set_option('match_with_order_book', True)),系统会严格按照买一/卖一等盘口数据撮合。如果对手盘挂单量不足,您的订单将只能部分成交。
- 机制:如果在模拟交易中开启了盘口撮合(
3. 账户资金与持仓限制
- 资金不足
- 原因:账户
available_cash不足。 - 注意:买入时不仅需要支付股价,还需要支付手续费(佣金、印花税等)。如果资金刚好只够买股票但不够付手续费,订单会被拒绝或调整数量。
- 原因:账户
- 持仓不足(卖出时)
- 原因:尝试卖出的数量超过了
closeable_amount(可卖持仓)。
- 原因:尝试卖出的数量超过了
- T+1 规则
- 原因:A股实行 T+1 制度。当天买入的股票,当天不能卖出。
- 现象:虽然
total_amount(总持仓)显示有货,但closeable_amount(可卖持仓)为 0,导致卖单无法生成或无效。
4. 数据与系统机制
- 停牌
- 如果股票在回测期间停牌,无法进行买卖操作。
- 未上市或已退市
- 在标的未上市或退市后的日期下单,订单无效。
- 收盘自动撤单
- 机制:所有未完成的订单(
open状态)将在本交易日结束后(通常是 15:00 后)自动撤销。如果当天没成交,第二天不会自动补单,需要策略重新下单。
- 机制:所有未完成的订单(
- Bar 数据撮合逻辑
- 分钟/日频回测:限价单是在当前 Bar 结束时撮合的。如果这一分钟内价格波动虽然触及了限价,但 Bar 的收盘/最高/最低价逻辑判定未满足(取决于具体的撮合设置),也可能导致不成交。
5. 如何排查?
建议在代码中添加以下检查逻辑:
- 检查未完成订单:使用
get_open_orders()查看订单状态。 - 检查日志:聚宽系统会在日志中打印警告信息(Warning),例如“资金不足”、“成交量超过限制”等。
- 打印账户信息:在下单前打印
context.portfolio.available_cash和context.portfolio.positions[security].closeable_amount。
Q&A
Q: 为什么我的市价单(Market Order)在涨停板买入失败?
A: 在回测和模拟中,如果标的涨停,市价买单会被直接撤销,因为在真实市场中涨停板通常无法以市价买入。
Q: 如何解决“成交量限制”导致的部分成交?
A: 您可以在 initialize 函数中设置 set_option('order_volume_ratio', 1.0) 来允许策略成交该时间段内市场真实成交量的 100%,但这可能会导致回测结果失真(高估了策略的资金容量)。
Q: 为什么我明明有持仓,却提示可卖数量为0?
A: 请检查是否受 T+1 规则限制。如果是当日买入的股票,当日不可卖出,closeable_amount 会为 0,直到下一个交易日才会变成可卖持仓。
Q: 为什么收盘后我的挂单不见了?
A: 聚宽遵循交易所规则,所有当日未成交的委托单会在收盘后(日终清算时)自动撤销。如果需要继续交易,需要在下一个交易日重新下单。