You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.14 16:44:30