Backtrader中存在多头持仓时止损卖单(Sellstop)触发后未触发notify_trade通知的问题
Backtrader中存在多头持仓时止损卖单(Sellstop)触发后未触发notify_trade通知的问题
我最近在Backtrader开发策略时碰到了一个诡异的问题,特意跑了两个测试来复现场景,先给大家展示我的notify_order代码,再详细说说测试情况:
Test 1:仅执行1个止损卖单(Sellstop)
当我单独提交一个止损卖单时,流程完全符合预期:
- 在
notify_order中能看到订单被标记为**SUBMITTED(已提交)和ACCEPTED(已接受)**的日志(此时价格还未触及止损价,所以订单还未进入COMPLETED状态) - 当价格到达止损触发价后,
notify_order会收到订单变为**COMPLETED(已完成)**的日志,紧接着notify_trade就会记录卖单成交的日志(我通过trade.justopened来追踪成交状态)
Test 2:先开多头持仓再挂止损卖单
这时候问题就出现了:
- 先提交的多头市价单立刻成交,
notify_order里正常输出SUBMITTED、ACCEPTED、COMPLETED的日志,notify_trade也成功记录了多头成交的信息 - 同时提交的止损卖单,
notify_order里同样能看到SUBMITTED和ACCEPTED的日志(此时价格未到止损价,订单未COMPLETED) - 但当价格触发止损价后,
notify_order确实收到了订单COMPLETED的日志,但notify_trade里完全没有任何卖单成交的日志 - 划重点:两次测试除了Test2多了一步开多头持仓的操作,代码完全没有改动
补充说明:如果换成限价单(Limit Orders)做完全相同的操作,整个流程都正常——限价单和止损单一样都是挂单类型,偏偏只有止损卖单会出现这个异常情况
有没有朋友遇到过类似的问题?Backtrader官方有没有相关的问答或者已知的解决方案?
以下是我的notify_order实现代码:
def notify_order(self, order): """ ORDERS are actions that are unfulfilled/pending (means they are waiting to enter or be triggered into the market) Args: order: order.status can be any of {order.Created, order.Submitted, order.Accepted, order.Partial, order.Completed, order.Canceled, order.Expired, order.Margin, order.Rejected} #todo type hint Returns: None """ if order.status in [order.Submitted]: log.debug(f'{self.datetime.datetime(ago=0).isoformat()} --- Order {order.ref} Submitted at price {order.price}, commission {order.executed.comm}\n{order}') if order.p.exectype == 0 : # Market order if order.isbuy(): log.debug(f'{self.datetime.datetime(ago=0).isoformat()} --- MARKET order of BUY type Ref ID {order.ref} SUBMITTED at Price: {order.price}, commission {order.executed.comm}') elif order.issell(): log.debug(f'{self.datetime.datetime(ago=0).isoformat()} --- MARKET order of SELL type Ref ID {order.ref} SUBMITTED at Price: {order.price}, commission {order.executed.comm}') else: pass elif order.p.exectype == 2 : # Limit order if order.isbuy(): log.debug(f'{self.datetime.datetime(ago=0).isoformat()} --- LIMIT order of BUY type Ref ID {order.ref} SUBMITTED at Price: {order.price}, commission {order.executed.comm}') elif order.issell(): log.debug(f'{self.datetime.datetime(ago=0).isoformat()} --- LIMIT order of SELL type Ref ID {order.ref} SUBMITTED at Price: {order.price}, commission {order.executed.comm}') else: pass elif order.p.exectype == 3 : # Stop order if order.isbuy(): log.debug(f'{self.datetime.datetime(ago=0).isoformat()} --- STOP order of BUY type Ref ID {order.ref} SUBMITTED at Price: {order.price}, commission {order.executed.comm}') elif order.issell(): log.debug(f'{self.datetime.datetime(ago=0).isoformat()} --- STOP order of SELL type Ref ID {order.ref} SUBMITTED at Price: {order.price}, commission {order.executed.comm}') else: pass else: pass return if order.status in [order.Accepted]: log.debug(f'{self.datetime.datetime(ago=0).isoformat()} --- Order {order.ref} Accepted at price {order.price}, commission {order.executed.comm}\n{order}') if order.p.exectype == 0 : # Market order if order.isbuy(): log.debug(f'{self.datetime.datetime(ago=0).isoformat()} --- MARKET order of BUY type Ref ID {order.ref} ACCEPTED at Price: {order.price}, commission {order.executed.comm}') elif order.issell(): log.debug(f'{self.datetime.datetime(ago=0).isoformat()} --- MARKET order of SELL type Ref ID {order.ref} ACCEPTED at Price: {order.price}, commission {order.executed.comm}') else: pass elif order.p.exectype == 2 : # Limit order if order.isbuy(): log.debug(f'{self.datetime.datetime(ago=0).isoformat()} --- LIMIT order of BUY type Ref ID {order.ref} ACCEPTED at Price: {order.price}, commission {order.executed.comm}') elif order.issell(): log.debug(f'{self.datetime.datetime(ago=0).isoformat()} --- LIMIT order of SELL type Ref ID {order.ref} ACCEPTED at Price: {order.price}, commission {order.executed.comm}') else: pass elif order.p.exectype == 3 : # Stop order if order.isbuy(): log.debug(f'{self.datetime.datetime(ago=0).isoformat()} --- STOP order of BUY type Ref ID {order.ref} ACCEPTED at Price: {order.price}, commission {order.executed.comm}') elif order.issell(): log.debug(f'{self.datetime.datetime(ago=0).isoformat()} --- STOP order of SELL type Ref ID {order.ref} ACCEPTED at Price: {order.price}, commission {order.executed.comm}') else: pass else: pass return if order.status in [order.Completed]: log.debug(f'{self.datetime.datetime(ago=0).isoformat()} --- Order {order.ref} Completed at price {order.price}, commission {order.executed.comm}\n{order}') if order.p.exectype == 0 : # Market order if order.isbuy(): log.debug(f'{self.datetime.datetime(ago=0).isoformat()} --- MARKET order of BUY type Ref ID {order.ref} COMPLETED at Price: {order.price}, commission {order.executed.comm}') elif order.issell(): log.debug(f'{self.datetime.datetime(ago=0).isoformat()} --- MARKET order of SELL type Ref ID {order.ref} COMPLETED at Price: {order.price}, commission {order.executed.comm}') else: pass elif order.p.exectype == 2 : # Limit order if order.isbuy(): log.debug(f'{self.datetime.datetime(ago=0).isoformat()} --- LIMIT order of BUY type Ref ID {order.ref} COMPLETED at Price: {order.price}, commission {order.executed.comm}') elif order.issell(): log.debug(f'{self.datetime.datetime(ago=0).isoformat()} --- LIMIT order of SELL type Ref ID {order.ref} COMPLETED at Price: {order.price}, commission {order.executed.comm}') else: pass elif order.p.exectype == 3 : # Stop order if order.isbuy(): log.debug(f'{self.datetime.datetime(ago=0).isoformat()} --- STOP order of BUY type Ref ID {order.ref} COMPLETED at Price: {order.price}, commission {order.executed.comm}') elif order.issell(): log.debug(f'{self.datetime.datetime(ago=0).isoformat()} --- STOP order of SELL type Ref ID {order.ref} COMPLETED at Price: {order.price}, commission {order.executed.comm}') else: pass else: pass return if order.status in [order.Canceled]: log.debug(f'{self.datetime.datetime(ago=0).isoformat()} --- Order {order.ref} Canceled. Specs of order:\n{order}') if order.isbuy(): if order.p.exectype == 0: log.debug(f'{self.datetime.datetime(ago=0).isoformat()} --- MARKET order of BUY type ID {order.info.ref} & Ref ID {order.ref} deleted') elif order.p.exectype == 2: log.debug(f'{self.datetime.datetime(ago=0).isoformat()} --- LIMIT order of BUY type ID {order.info.ref} & Ref ID {order.ref} deleted') elif order.p.exectype == 3: log.debug(f'{self.datetime.datetime(ago=0).isoformat()} --- STOP order of BUY type ID {order.info.ref} & Ref ID {order.ref} deleted') else: pass elif order.issell(): if order.p.exectype == 0: log.debug(f'{self.datetime.datetime(ago=0).isoformat()} --- MARKET order of SELL type ID {order.info.ref} & Ref ID {order.ref} deleted') elif order.p.exectype == 2: log.debug(f'{self.datetime.datetime(ago=0).isoformat()} --- LIMIT order of SELL type ID {order.info.ref} & Ref ID {order.ref} deleted') elif order.p.exectype == 3: log.debug(f'{self.datetime.datetime(ago=0).isoformat()} --- STOP order of SELL type ID {order.info.ref} & Ref ID {order.ref} deleted') else: pass if order.status in [order.Expired]: log.info(f'{self.datetime.datetime(ago=0).isoformat()} --- Order {order.ref} Expired and could not be executed') self.remove_open_order(order.p.tradeid) return if order.status in [order.Margin]: log.error(f'{self.datetime.datetime(ago=0).isoformat()} --- Insufficient cash to execute order - increase starting cash or improve strategy: Order {order.ref} Margin')
备注:内容来源于stack exchange,提问作者Pierre Cilliers
相关产品推荐
相关产品推荐

