Navigation

    Backtrader Community

    • Register
    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    For code/output blocks: Use ``` (aka backtick or grave accent) in a single line before and after the block. See: http://commonmark.org/help/

    Best way to issue an ATR based trail order?

    Indicators/Strategies/Analyzers
    1
    1
    66
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • V
      Vypy1 last edited by

      Hi, my strategy buys when some condition is met, it will set a stop loss say 2 ATR below the buy price.

      I want to trail the price if it goes up without using a fixed percentage or amount value, basically by using 3 ATR of a bar and recalculating what the trail level should be.

      What is the best way I can do this? Where I only issue an order when the close price is crossed below a level that is 3 ATRs below that close price? Currently I am trying to issue the order if I am in position and those conditions are met. But I am facing some challenge in using this. I am sharing my code below:

      class bo(bt.Strategy):
          
          params = (('fma', 20), ('sma', 50), ('trail', 0.08),)
          
          
          def __init__(self):
              
              self.vix = self.datas[2].close
              
              self.inds = {}
              
              for d in self.datas[:2]:
                  
                  self.inds[d] = {}
                  
                  self.inds[d]['open'] = d.open
                  self.inds[d]['close'] = d.close
                  self.inds[d]['high'] = d.high
                  self.inds[d]['low'] = d.low
      
                  self.inds[d]['atr'] = bt.talib.ATR(self.inds[d]['high'], self.inds[d]['low'], self.inds[d]['close'], timeperiod = 14)
                  self.inds[d]['maxatr'] = d.close - (self.inds[d]['atr'] * 3)
      #             self.inds[d]['atrema'] = bt.talib.EMA(self.inds[d]['atr'], timeperiod = 30)
                  self.inds[d]['highest'] = bt.indicators.Highest(self.inds[d]['high'], period = 20)
                  self.inds[d]['lowest'] = bt.indicators.Lowest(self.inds[d]['low'], period = 20)
              
                  self.trigger_price = []
                  self.buy_exec = 0
                  self.daily_atrs = {}
                  self.daily_atrs[d] = []
                  
                  self.orders = {}
      
                  self.sellprice = {}
                  self.execprice = {}
              
      
                   
          def log(self, txt, dt=None):
              dt = self.datas[0].datetime.date()
              print(f'Date: {dt}, {txt}')
              
          
          def notify_order(self, order):
                  
              if order.status in [order.Submitted, order.Accepted]:
                  return
      
      
              if order.status in [order.Completed]:
                  
                  if order.isbuy():
      
                      self.execprice[order.data] = order.executed.price
                      self.totalcost = order.executed.value
                      self.buy_exec = len(self)
                      
                      self.log(f'NAME: {order.data._name}, BUY EXECUTED: {self.execprice[order.data]}, Cost: {self.totalcost}')
          
                  elif order.issell():
                  
                      self.sellprice[order.data] = order.executed.price
                      self.sellcost = order.executed.value
                      
                      self.log(f'NAME: {order.data._name}, SELL EXECUTED: {self.sellprice[order.data]}, COST: {self.sellcost}')
                      
      
              elif order.status in [order.Canceled, order.Margin, order.Rejected]:
                  self.log('Order Canceled/Margin/Rejected')
      
      
              order_name = ['Main', 'Stop', 'Limit', 'Close'] 
              if not order.alive():
      
                  dorders = self.orders[order.data]
      #             print(f'DORDERS: {dorders}')
                  idx_orders = dorders.index(order)
      #             print(f'IDX OF ORDER: {idx_orders}')
                  dorders[idx_orders] = None
      #             print(f'REMAINING ORDERS: {dorders}')
                  self.log('-- No longer alive {} Order'.format(order_name[idx_orders]))
      
                  if all(x is None for x in dorders):
                      dorders[:] = []
      
      
          
          def notify_trade(self, trade):
              if trade.isopen:
                  return  
              
              
              else:
                  self.log(f'OPERATION PROFIT: GROSS {trade.pnl}, NET {trade.pnlcomm}, Trade PnL: {trade.pnlcomm/self.totalcost}')
                  self.log(f'Updated Account Balance: {cerebro.broker.getcash()}')
          
      
                  
          def next(self):
      
      
              for d in self.datas[:2]:
                  
                  name = d._name
                  pos = self.getposition(d).size
                  atr = self.inds[d]['atr'][0]
      
              
                  self.log(f'NAME: {name}, CLOSE: {d.close[0]}, POS: {pos}')
      
      
                  
                  if not pos:
      
                      if self.inds[d]['close'][0] > self.inds[d]['highest'][-1]:
                          
      #                     if not np.isnan(self.inds[d]['atrema'][0]):
                              
                              buy_execprice = self.inds[d]['open'][1]
      
                              o1 = self.buy(data = d)
                              o2 = self.sell(data = d, exectype=bt.Order.Stop, price = (buy_execprice - (atr * 2)))
                              self.log(f'{name}, BUY CREATED: {o1.created.price}, STOP: {o2.created.price}, SIZE: {o1.created.size}, ATR: {atr}')
      
                              self.orders[d] = [o1, o2]
      
      
                  else:
      
                      if pos > 0:
                          
                          atr_stop = self.inds[d]['maxatr'][0]
                          self.daily_atrs[d].append(atr_stop)
                          self.log(f'ATRS: {self.daily_atrs}')
                                              
      
                          if self.inds[d]['close'][0] <= atr_stop:
                              
      
                              o3 = self.sell(data = d, oco = self.orders[d][1])
      
                              self.orders[d].append(o3)
      
      
                  
              
                      
      cerebro = bt.Cerebro()
      cerebro.broker.set_cash(200000)
      
      print(f'Starting Portfolio Value: {cerebro.broker.getvalue()}')
      
      for n in range(len(df)):
          dataset = list(zip(df, names))
          data = bt.feeds.PandasData(dataname=dataset[n][0], datetime=None, open=-1, high=-1, low=-1, close=-1, volume=-1)
          cerebro.adddata(data, name = dataset[n][1])
      
      
      data1 = bt.feeds.PandasData(dataname=vix, datetime=None, open=-1, high=-1, low=-1, close=-1, volume=-1)
      cerebro.adddata(data1, name = 'vix')
      
      
      cerebro.addstrategy(bo)
      cerebro.addsizer(bt.sizers.FixedSize, stake = 10)
      cerebro.addanalyzer(trades_list, _name = 'listrades')
      
      
      strat = cerebro.run(tradehistory = True)
      strats = strat[0].analyzers.listrades.get_analysis()
      listrades = pd.DataFrame(strats)
      # cerebro.run()
      
      print(f'Final Portfolio Value: {cerebro.broker.getvalue()}')
      
      1 Reply Last reply Reply Quote 0
      • 1 / 1
      • First post
        Last post
      Copyright © 2016, 2017, 2018, 2019, 2020, 2021 NodeBB Forums | Contributors