问题描述
回测发现股票的停止单没有执行。如,在开盘的时候下一个股票的停止单,希望在当天盘中价格超过某一特定价格(order_price)的时候,将该单转为市价单或者限价单买入;如果盘中价格没有达到order_price,就不执行。但是在回测中发现不能成交,为何?
代码如下:
order_value(stk_code,stk_val,style=StopLimitOrderStyle("stop_loss", order_price, order_price))
试过StopLimitOrderStyle和StopMarketOrderStyle都不行。
解决方案
在 JoinQuant(聚宽)平台中,停止单(Stop Order)未执行或无法成交通常由以下几个核心原因导致。针对您希望“在盘中价格超过某一特定价格时买入”的需求,请逐一排查以下几点:
1. 触发模式(Mode)与当前价格的关系
根据 JoinQuant API 文档,停止单分为 stop_loss(止损模式)和 take_profit(止盈模式)。
- 买入/做多时的止损模式(stop_loss):触发价必须大于下单时的最新价。
- 买入/做多时的止盈模式(take_profit):触发价必须小于下单时的最新价。
排查点:如果您在开盘时下单,且开盘价已经高于或等于您设定的 order_price,系统会认为触发价不满足“大于最新价”的条件,该停止单会立即触发。如果此时资金不足或发生其他校验失败,订单会直接作废。
2. 资金未提前锁定导致触发时委托失败
API 文档明确指出:“停止单不会提前锁定持仓和资金,触发时不满足委托条件(如资金不足或可交易数量不足)直接委托失败。”
排查点:您使用的是 order_value。如果在开盘下达停止单后,您的策略又下达了其他买入订单消耗了可用资金(available_cash),当盘中价格真正突破 order_price 触发该停止单时,账户中可能已经没有足够的资金,导致订单直接被拒(Rejected)。建议在日志中检查是否有 WARNING 或 ERROR 提示资金不足。
3. 限价单(Limit Order)的撮合机制问题
您使用的代码是:
order_value(stk_code, stk_val, style=StopLimitOrderStyle("stop_loss", order_price, order_price))
这表示当价格向上突破 order_price 时,触发一个限价为 order_price 的买单。
排查点:在真实的上涨行情中,当价格突破 order_price 时,市场最新价往往已经高于 order_price。此时触发的限价买单(买入价 = order_price)会因为出价低于市场现价而挂单等待,如果价格继续上涨不回头,这个限价单将永远无法成交,并在收盘后自动撤销。
解决办法:如果您希望突破后必定买入,建议使用 StopMarketOrderStyle("stop_loss", order_price),触发后会以市价单(Market Order)参与撮合。
4. 回测频率(Frequency)的限制
停止单的盘中触发依赖于细粒度的价格切片。
排查点:如果您使用的是按天回测(Daily),引擎每天只在指定时间点(如 09:30)运行一次,无法精确捕捉盘中的价格突破轨迹。要使盘中停止单准确触发,必须使用按分钟(Minute)或按 Tick 回测。
💡 综合修改建议
如果您确认回测频率已经是分钟级,且资金充足,建议将代码修改为市价停止单,并增加日志打印以追踪订单状态:
# 确保在分钟级回测下运行
def handle_data(context, data):
# 获取当前最新价
current_price = data[stk_code].price
# 确保触发价严格大于当前价,否则会立即触发
if order_price > current_price:
# 使用 StopMarketOrderStyle 确保突破后以市价成交,避免限价单挂单不成交
order = order_value(
stk_code,
stk_val,
style=StopMarketOrderStyle("stop_loss", order_price)
)
if order:
log.info(f"成功下达停止单,触发价: {order_price}")
else:
log.error("停止单下达失败,请检查资金或标的状态")
else:
log.info(f"当前价 {current_price} 已超过目标价 {order_price},可直接下市价单买入")
order_value(stk_code, stk_val)
总结检查清单:
- 检查回测频率是否为分钟级。
- 检查下单那一刻的
current_price是否严格小于order_price。 - 检查触发瞬间账户是否有足够的
available_cash。 - 改用
StopMarketOrderStyle避免突破后限价单无法成交。