出现该问题的原因是 BacktestingEngine 中的 cross_stop_order 函数没有对 stop_order 的状态进行判断。该函数的最后会调用 self.strategy.on_trade(trade) 函数,而类似 KingKeltnerStrategy 中的 on_trade 函数会调用 cancel_order 取消某条 stop_order 报单,将 active_stop_orders 中的 该条 stop_order 报单 pop 出去,但是在 cross_stop_order 中循环时还是可能会访问到该条 stop_order 报单,如果这条报单正好可以成交,会导致再次 pop 而报错。
解决方式为在 cross_stop_order 函数最开始加一条判断就好了:
if stop_order.status == StopOrderStatus.CANCELLED:
continue