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/

    Need help with problem with positions closing code.

    General Code/Help
    1
    1
    500
    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
      Vithal Patil last edited by

      Hi,

      I am trying to code strategy based on SuperTrend indicator where the initial transaction is done with BUY or Sell Order but subsequent transactions are done with stop order used for switching the positions.

      But the code seems to be working with some parameters and fail with other for the same daily data. Below is both indicator code and Strategy Code.

      import backtrader as bt
      import numpy as np
      
      
      class SuperTrend(bt.Indicator):
          lines = ('overunder',)
          plotinfo = dict(subplot=False)
          params = dict(period=7, multiplier=3, ticksize=0.01)
      
          def __init__(self):
              self.addminperiod(self.params.period)
              self.atr = bt.ind.ATR(period=self.params.period)
              #self.l.overunder = ( self.data.high + self.data.low ) / 2
              self.__tick = self.params.ticksize
              decimal = str(self.params.ticksize).split('.')
              if len(decimal) is not 1:
                  self.__decimal = len(decimal[1])
              else:
                  self.__decimal = 0
              self.__prevClose = 0
              self.__prevFUP = 0
              self.__prevFDN = 0
              self.__prevSuperTrend = 0
              self.__prevHL = 0
              
          def next(self):
              HL =  ( self.datas[0].high.get(size=1).tolist()[0] + self.datas[0].low.get(size=1).tolist()[0] ) / 2
              Close = self.datas[0].close.get(size=1).tolist()[0]
              FUP = 0.00
              FDN = 0.00
              SuperTrend = Close
              mul = self.params.multiplier
              atr = np.around(self.atr[0],self.__decimal)
              
              if atr is not None:
                  UPPER = HL+(mul*np.around(atr,self.__decimal))
                  LOWER = HL-(mul*np.around(atr,self.__decimal))
                  if( UPPER < self.__prevFUP or self.__prevClose > self.__prevFUP ):
                      FUP = self.roundSP(np.around(UPPER,self.__decimal))
                  else:
                      FUP = self.__prevFUP
                      
                  if( LOWER > self.__prevFDN or self.__prevClose < self.__prevFDN ):
                      FDN = self.roundSP(np.around(LOWER,self.__decimal))
                  else:
                      FDN = self.__prevFDN
                      
                  if( self.__prevSuperTrend == self.__prevFUP and Close <= FUP ):
                      SuperTrend = FUP
                  else:
                      if( self.__prevSuperTrend == self.__prevFUP and Close >= FUP ):
                          SuperTrend = FDN
                      else:
                          if( self.__prevSuperTrend == self.__prevFDN and Close >= FDN ):
                              SuperTrend = FDN
                          else:
                              if( self.__prevSuperTrend == self.__prevFDN and Close <= FDN ):
                                  SuperTrend = FUP
                      
                  self.__prevFUP = FUP
                  self.__prevFDN = FDN
                  self.__prevSuperTrend = SuperTrend
                      
              
              self.__prevClose = Close
              self.l.overunder[0] = SuperTrend
              
          def roundSP( self, num ):
              return np.around((np.around((num+(self.__tick/2))/self.__tick)*self.__tick)-self.__tick,self.__decimal)
      
      # -*- coding: utf-8 -*-
      """
      Created on Sun Apr  1 04:58:49 2018
      
      @author: Vithal Patil
      """
      
      from datetime import datetime
      import backtrader as bt
      import backtrader.analyzers as btanalyzers
      import backtrader.strategies as btstrats
      import numpy as np
      import btSupertrend
      
      class SuperTrendStrategy(bt.SignalStrategy):
          params = (('pfast', 10), ('pslow', 30),)
          
          def __init__(self):
              self.dataclose = self.datas[0].close
              self.supertrend = btSupertrend.SuperTrend(period=7, multiplier=2, ticksize=1)
              self.trade = None
              self.buystop_order = None
              self.sellstop_order = None
              self.qty = 1
              
          def next(self):
              if self.supertrend[0] < self.dataclose:
                  if self.trade == None:
                      self.buy()
                      #self.log('LONG %s ' % ( self.trade ))
                  elif self.trade == 'buy_stop':
                      if self.buystop_order:
                          self.cancel(self.buystop_order)
                      self.buystop_order = self.sell(exectype=bt.Order.Stop, price=self.supertrend[0], size=self.qty) 
                      #self.log('SHORT STOP %s ' % ( self.trade ))
              if self.supertrend[0] > self.dataclose:
                  if self.trade == None:
                      self.sell()
                      #self.log('SHORT %s ' % ( self.trade ))
                  elif self.trade == 'sell_stop':
                      if self.sellstop_order:
                          self.cancel(self.sellstop_order)
                      self.sellstop_order = self.buy(exectype=bt.Order.Stop, price=self.supertrend[0], size=self.qty) 
                      #self.log('SHORT STOP %s ' % ( self.trade ))
                      
          def notify_order(self, order):
              if not order.status == order.Completed:
                  #self.log('LONG @ %s and qty %s' % ( order.executed.price,order.executed.size ))
                  return  # discard any other notification
              elif order.status in [order.Canceled, order.Margin, order.Rejected]:
                  self.log('Order Canceled/Margin/Rejected')
              else:
                  if order.isbuy():
                      if self.trade == None or self.trade == 'buy_hit':
                          if self.supertrend[0] < self.dataclose:
                              self.trade = 'buy_stop'
                              self.qty = 2
                              self.log('FRESH LONG STARTED, @ %s and qty %s  Trade %s  varTrade %s' % ( order.executed.price, order.executed.size, self.position.size, self.trade ))
                          if self.supertrend[0] > self.dataclose:
                              self.sell(size=self.qty)
                              self.trade = 'sell_hit'
                              self.log('BUY STOP HIT, @ %s and qty %s Trade %s varTrade %s' % ( order.executed.price, order.executed.size, self.position.size, self.trade ))
                      if self.trade == 'sell_stop':
                          if self.supertrend[0] > self.dataclose:
                              self.sell(size=self.qty)
                              self.trade = 'sell_hit'
                              self.log('BUY STOP HIT, @ %s and qty %s Trade %s varTrade %s' % ( order.executed.price, order.executed.size, self.position.size, self.trade ))
                          if self.supertrend[0] < self.dataclose:
                              self.trade = 'buy_stop'
                              self.log('LONG SWITCH, @ %s and qty %s  Trade %s  varTrade %s' % ( order.executed.price, order.executed.size, self.position.size, self.trade ))
                  if order.issell():
                      if self.trade == None or self.trade == 'sell_hit':
                          if self.supertrend[0] > self.dataclose:
                              self.qty = 2
                              self.trade = 'sell_stop'
                              self.log('FRESH SHORT STARTED, @ %s and qty %s Trade %s varTrade %s' % ( order.executed.price, order.executed.size, self.position.size, self.trade ))
                          if self.supertrend[0] < self.dataclose:
                              self.buy(size=self.qty)
                              self.trade = 'buy_hit'
                              self.log('SELL STOP HIT, @ %s and qty %s Trade %s varTrade %s' % ( order.executed.price, order.executed.size, self.position.size, self.trade ))
                      if self.trade == 'buy_stop':
                          if self.supertrend[0] < self.dataclose:
                              self.buy(size=self.qty)
                              self.trade = 'buy_hit'
                              self.log('SELL STOP HIT, @ %s and qty %s Trade %s varTrade %s' % ( order.executed.price, order.executed.size, self.position.size, self.trade ))
                          if self.supertrend[0] > self.dataclose:
                              self.trade = 'sell_stop'
                              self.log('SHORT SWITCH, @ %s and qty %s Trade %s varTrade %s' % ( order.executed.price, order.executed.size, self.position.size, self.trade ))
      
                              
      
                      
                      
              #self.log('STATUS %s' % ( self.position.size ))
                  
          def log(self, txt, dt=None):
              ''' Logging function for this strategy'''
              dt = dt or self.datas[0].datetime.date(0)
              print('%s, %s' % (dt.isoformat(), txt))
      
      cerebro = bt.Cerebro()
      data = bt.feeds.GenericCSVData(
          dataname='GOLDPETAL.csv',
          fromdate=datetime(2012, 10, 29),
          todate=datetime(2018, 4, 20),
          nullvalue=0.0,
          dtformat=('%Y-%m-%d'),
          tmformat=('%H:%M:%S'),
          datetime=0,
          time=1,
          high=3,
          low=4,
          open=2,
          close=5,
          volume=6,
          openinterest=-1,
          decimals=0,
          compression=1,
          timeframe=bt.TimeFrame.Days
      )
      cerebro.adddata(data)
      
      cerebro.addstrategy(SuperTrendStrategy)
      
      cerebro.broker.setcommission(mult=1)
      cerebro.addanalyzer(btanalyzers.AnnualReturn, _name='annualreturns')
      cerebro.addanalyzer(btanalyzers.DrawDown, _name='drawdown')
      cerebro.addanalyzer(btanalyzers.Returns, _name='positionvalue')
      cerebro.addanalyzer(btanalyzers.SQN, _name='sqn')
      cerebro.addanalyzer(btanalyzers.TradeAnalyzer, _name='trades')
      thestrats = cerebro.run()
      thestrat = thestrats[0]
      
      ar = thestrat.analyzers.annualreturns.get_analysis()
      print('\n\nAnnual Returns:\n')
      for key, value in ar.items():
          print("%s - %s" % (key, value))
          
      draw = thestrat.analyzers.drawdown.get_analysis()
      print('\n\nDrawDown:\n')
      for key, value in draw.items():
          print("%s - %s" % (key, value))
          
      returns = thestrat.analyzers.positionvalue.get_analysis()
      print('\n\nReturns:\n')
      for key, value in returns.items():
          print("%s - %s" % (key, value))
          
      sqn = thestrat.analyzers.sqn.get_analysis()
      print('\n\nSQN:\n')
      for key, value in sqn.items():
          print("%s - %s" % (key, value))
          
      cerebro.plot(iplot=False,style='bar',volume=True)
      

      Also below the screenshot for the reference with SuperTrend with params as 7 -- 3 and 7 -- 2 respectively.

      1_1522837843068_SuperTrend 7 and 3.png

      0_1522837843068_SuperTrend 7 and 2.png .

      1 Reply Last reply Reply Quote 0
      • 1 / 1
      • First post
        Last post
      Copyright © 2016, 2017, 2018 NodeBB Forums | Contributors
      $(document).ready(function () { app.coldLoad(); }); }