Navigation

    Backtrader Community

    • Register
    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    1. Home
    2. jabbarabdullah
    3. Posts
    For code/output blocks: Use ``` (aka backtick or grave accent) in a single line before and after the block. See: http://commonmark.org/help/
    J
    • Profile
    • Following 0
    • Followers 0
    • Topics 3
    • Posts 8
    • Best 0
    • Groups 0

    Posts made by jabbarabdullah

    • RE: ZeroDivisionError not on RSI

      @backtrader Hi Admin,

      Appreciate the prompt response. What do you mean by low variability of data?

      Thanks!

      posted in General Discussion
      J
      jabbarabdullah
    • RE: ZeroDivisionError not on RSI

      Okay, I have narrowed down the problem to:

      self.inds[d]['ADX'] = bt.indicators.AverageDirectionalMovementIndex(d, period=9, plot=False)
      self.inds[d]['PDI'] = bt.indicators.PlusDirectionalIndicator(d, period=9, plot=False)
      self.inds[d]['MDI'] = bt.indicators.MinusDirectionalIndicator(d, period=9, plot=False)  
      

      I believe due to the internal calculation of the indicators, zero division error is triggered.

      I read as many postings as possible in this forum but I can't find a solution to this problem. safediv and safezero parameters only available to RSI and stochastic hence, I cant solve this ADX zero division error.

      Kindly appreciate your guidance to overcome this issue especially on live trading.

      Thanks!

      posted in General Discussion
      J
      jabbarabdullah
    • ZeroDivisionError not on RSI

      Hi all,

      I have codes below that works fine in backtesting but cannot execute in live trade using TWS. it returned the zero error as follows:

      
        File "C:\Users\User\Anaconda3\lib\site-packages\backtrader\linebuffer.py", line 744, in next
          self[0] = self.operation(self.a[0], self.b[0])
      
      ZeroDivisionError: float division by zero
      

      However, i have set the safediv=True on the RSI in it still doesn't work. This strategy is the combination of RSI, ADX and Bollinger Band.

      appreciate if you can take a look at my code and let me know what I missed.

      from __future__ import (absolute_import, division, print_function, unicode_literals)
      
      import backtrader as bt
      import datetime as dt
      import pytz
      
      datalist = ['XXXX', 'YYYY']  #Update data names 
      csh=100000 #Change this accordingly!!!
      port_start_cash=100000 #Change this accordingly!!!
      
      SL=0.025 #stop loss pct
      TP=0.01 #take profit pct
      
      prop=1/len(datalist) #proportion of portfolio
      batch = 5 #rounding
      entrytime = dt.time(9,30) # start trade time
      exittime = dt.time(15,55) # ending trade time
      stakesize=10
      lwbnd=50 #RSI Lower bound
      upbnd=55 #RSI Upper bound
      commis=1 #commission
      TPpct=TP*100 #TP in pctge
      SLpct=SL*100 #SL in pctge
      
      class MainSt(bt.Strategy): #Strategy set up
          
      
          data_live = False #start with data not live
          def notify_data(self, data, status, *args, **kwargs): #notify when data turn to live
              print('*' * 5, '%s DATA NOTIF: %s' % (data._name,data._getstatusname(status)),
                *args)
              if status == data.LIVE:
                  self.data_live = True
                  
          def log(self, txt, dt=None, vlm=None): #self log of data
              dt = dt or self.datas[0].datetime.datetime(0)
              vlm = vlm or self.data.volume[0]
              print('%s) %s, %s' % (len(self), dt.isoformat(), txt))
      
      
          def __init__(self): #pre defined indicators
              self.order = {}
              self.buyprice = {}
              self.buycomm = {}
              self.bar_executed = {}
              self.inds = dict()
              self.o = dict()
              self.lendata = dict()
              
              for i, d in enumerate(self.datas): #iterate the data name
                  self.order[d] = None
                  self.buyprice[d] = None
                  self.buycomm[d] = None   
                  self.bar_executed[d] = None
                  self.inds[d] = dict()
                  self.inds[d]['sma'] = bt.indicators.SimpleMovingAverage(d.close, period=30) #sma
                  self.inds[d]['rsi'] = bt.indicators.RelativeStrengthIndex(d.close, period=9, safediv=True, upperband=upbnd,lowerband=lwbnd, plotname= 'rsi:'+d._name) #rsi
                  self.inds[d]['ADX'] = bt.indicators.AverageDirectionalMovementIndex(d, period=9, plot=False)
                  self.inds[d]['PDI'] = bt.indicators.PlusDirectionalIndicator(d, period=9, plot=False)
                  self.inds[d]['MDI'] = bt.indicators.MinusDirectionalIndicator(d, period=9, plot=False)  
                  self.inds[d]['SD'] = bt.indicators.StandardDeviation(d, period=30, safepow=True)
                  self.inds[d]['TopBB'] = self.inds[d]['sma']+2.5*self.inds[d]['SD']
                  self.inds[d]['BotBB'] = self.inds[d]['sma']-2.5*self.inds[d]['SD']  
                  
          def notify_order(self, order): #notify when order happen
              if order.status in [order.Submitted, order.Accepted]:
                  return    
      
              
              if order.status in [order.Completed]:
                  
                  if order.isbuy(): #when buy order created in next
      
                      self.log('%s: BUY EXECUTED, Price: %.2f, Cost: %.2f, Size: %.2f, Comm %.2f' %
                          (order.data._name,
                           order.executed.price,
                           order.executed.value,
                           order.executed.size,
                           order.executed.comm))
      
                      self.buyprice = order.executed.price
                      self.buycomm = order.executed.comm
                      self.buy_executed_price = order.executed.price
                      self.order = None
                      self.bar_executed = len(self)
                      
                  else:  #when sell order created in next
      
                      # Sell
                      self.log('%s: SELL EXECUTED, Price: %.2f, Cost: %.2f, Size: %.2f, Comm %.2f' %
                               (order.data._name,
                                order.executed.price,
                                order.executed.value,
                                order.executed.size,
                                order.executed.comm))
                     
                      self.sell_executed_price = order.executed.price
                      self.last_size = order.executed.size
                      self.order = None           
                      self.bar_executed = len(self)
      
                  self.bar_executed = len(self)
                  self.last_executed_price = order.executed.price
              elif order.status in [order.Canceled, order.Margin, order.Rejected]:
                  return
                  '''
                  self.log('%s Order Canceled/Margin/Rejected' % (order.data._name))
                  '''
              # Write down: no pending order[order.data._name]
              self.order = None
      
      
          def notify_trade(self, trade): #notify trade info
              if not trade.isclosed:
                  return
      
              self.log('%s: OPERATION PROFIT, GROSS %.2f, NET %.2f' %
                       (trade.data._name, trade.pnl, trade.pnlcomm))
      
          def next_open(self): #define the buy criterias here
              for i, d in enumerate(self.datas):
                  pv = self.broker.getvalue() #get broker value
                  cashd = self.broker.getcash() #get broker cash
                  port_gaind = pv - port_start_cash #calculate total portfolio gain
                  target = csh * prop    # Ideal total value of the position
                  price = d.close[0]
                  shares_ideal = target / price    # How many shares are needed to get target
                  batches = int(shares_ideal / batch)    # How many batches is this trade?
                  shares = batches * batch         
                  
                  if not self.data_live: # make sure live then only trade!!!
                      return
                  
                  if not self.getposition(d).size: #make sure there is no position to start buy
                      
                      if (port_gaind <= -csh*SL): #check if portfolio value less then portfolio stop loss, don't buy
                          return
                      
                      if (port_gaind >= csh*TP): #check if portfolio value less then portfolio stop loss, don't buy
                          return
                      
                      if (d.datetime.time(0) >= exittime): # Don't buy when already end of day
                          return
                      
                      if ((self.inds[d]['rsi'][0] < lwbnd)and(1<(self.inds[d]['MDI'][0]/self.inds[d]['PDI'][0])<1.3)and(30<self.inds[d]['ADX'][0]<40)and(d.datetime.time(0) >= entrytime)): #buy if RSI lower than lower bound and entry time is as defined
                          print('%s pv: %.2f, cash:%.2f, rsi: %.2f, ADX: %.2f, PDI: %.2f, MDI: %.2f'% (d._name, pv, cashd, self.inds[d]['rsi'][0], self.inds[d]['ADX'][0], self.inds[d]['PDI'][0], self.inds[d]['MDI'][0]))
                          self.log('%s: BUY CREATE, %.2f, VLM BOUGHT: %.2f' % (d._name, d.close[0], shares))
                          self.order = self.buy(data=d, size = shares, coo=True, coc=False)        #buy data d shares using maximum allocated size
      
          def next(self): #define the sell criterias here
              for i, d in enumerate(self.datas):
                  pv = self.broker.getvalue() #get broker value
                  cashd = self.broker.getcash() #get broker cash
                  port_gain = pv - port_start_cash #calculate total portfolio gain
                  target = csh * prop    # Ideal total value of the position
                  price = d.close[0]
                  shares_ideal = target / price    # How many shares are needed to get target
                  batches = int(shares_ideal / batch)    # How many batches is this trade?
                  shares = batches * batch    
      
                  '''
                  self.log('%s, Close: %.2f, pv: %.2f, cash: %.2f, rsi: %.2f, ADX: %.2f, PDI/MDI: %.2f, MDI/PDI: %.2f' % (d._name, d.close[0], pv, cashd, self.inds[d]['rsi'][0], self.inds[d]['ADX'][0], self.inds[d]['PDI'][0]/self.inds[d]['MDI'][0], self.inds[d]['MDI'][0]/self.inds[d]['PDI'][0]))
                  '''       
      
                  if not self.data_live: # make sure live then only trade!!!
                      return
        
                  if self.getposition(d).size: #make sure there is position to start sell
                      
                      if (d.close[0] >= (self.getposition(d).price*(1+.005))): #if curent close price >= the SU price, sell position
                          print('%s pv: %.2f, cash:%.2f, rsi: %.2f, ADX: %.2f, PDI: %.2f, MDI: %.2f'% (d._name, pv, cashd, self.inds[d]['rsi'][0], self.inds[d]['ADX'][0], self.inds[d]['PDI'][0], self.inds[d]['MDI'][0]))
                          self.log('%s: SELL CREATE (>%.2fpct), %.2f, VLM BOUGHT: %.2f' % (d._name, 0.5, d.close[0], self.getposition(d).size))
                          self.order = self.sell(data=d, size=abs(self.getposition(d).size), coo=False, coc=True)
                          self.order = self.buy(data=d, size = shares, coo=True, coc=False)
                      
                      else:
                          if ((d.close[0]<=self.inds[d]['BotBB'][0])):
                              print('%s pv: %.2f, cash:%.2f, rsi: %.2f, ADX: %.2f, PDI: %.2f, MDI: %.2f'% (d._name, pv, cashd, self.inds[d]['rsi'][0], self.inds[d]['ADX'][0], self.inds[d]['PDI'][0], self.inds[d]['MDI'][0]))
                              self.log('%s: SELL CREATE (Price<BotBB), %.2f, VLM BOUGHT: %.2f' % (d._name, d.close[0], self.getposition(d).size))
                              self.order = self.sell(data=d, size = abs(self.getposition(d).size), coo=False, coc=True)
                          
                          else:
                              if ((d.close[0]>=self.inds[d]['TopBB'][0])):
                                  print('%s pv: %.2f, cash:%.2f, rsi: %.2f, ADX: %.2f, PDI: %.2f, MDI: %.2f'% (d._name, pv, cashd, self.inds[d]['rsi'][0], self.inds[d]['ADX'][0], self.inds[d]['PDI'][0], self.inds[d]['MDI'][0]))
                                  self.log('%s: SELL CREATE (Price>TopBB), %.2f, VLM BOUGHT: %.2f' % (d._name, d.close[0], self.getposition(d).size))
                                  self.order = self.sell(data=d, size = abs(self.getposition(d).size), coo=False, coc=True)
                                 
                              else:
                                  if (d.datetime.time(0) >= exittime): #exit trade when end of day arrive
                                      print('%s pv: %.2f, cash:%.2f, rsi: %.2f'% (d._name, pv, cashd, self.inds[d]['rsi'][0]))
                                      self.log('%s: EOD STOP, %.2f, VLM BOUGHT: %.2f' % (d._name, d.close[0], self.getposition(d).size))
                                      self.order = self.sell(data=d, size=abs(self.getposition(d).size), coo=False, coc=True)  
                                     
                                  else:
                                      if (port_gain >= csh*TP): #exit trade when portfolio gain >= take profit
                                          print('%s pv: %.2f, cash:%.2f, rsi: %.2f'% (d._name, pv, cashd, self.inds[d]['rsi'][0]))
                                          self.log('%s: TAKE PROFIT VAL CREATE (>%.2fpct), %.2f, VLM BOUGHT: %.2f' % (d._name, TPpct, d.close[0], self.getposition(d).size))
                                          self.order = self.sell(data=d, size=abs(self.getposition(d).size), coo=False, coc=True)
              
                                      else:
                                          if (port_gain <= -csh*SL): #exit trade for stop loss
                                              print('%s pv: %.2f, cash:%.2f, rsi: %.2f'% (d._name, pv, cashd, self.inds[d]['rsi'][0]))
                                              self.log('%s: STOPLOSS VAL CREATE (<%.2fpct), %.2f, VLM BOUGHT: %.2f' % (d._name, SLpct, d.close[0], self.getposition(d).size))
                                              self.order = self.sell(data=d, size=abs(self.getposition(d).size), coo=False, coc=True)
      
      def run(args=None): #run the engine
          cerebro = bt.Cerebro(cheat_on_open=True) #set COO to true to buy on same len
          
          store = bt.stores.IBStore(host='127.0.0.1', port=7496, reconnect=5) #live port is 7496 and paper port is 7497
          
          cerebro.broker = store.getbroker() #connect to broker #must use this to send trade to TWS
          
          for i in datalist: #iterate the data in datalist
              data = store.getdata(dataname=i, timeframe=bt.TimeFrame.Ticks, tz = pytz.timezone('US/Eastern'))
              cerebro.resampledata(data, timeframe=bt.TimeFrame.Seconds, compression=15) #resample all data to live trade
              
          cerebro.addstrategy(MainSt) #add strategy here
          cerebro.run() #run everything
          
          # Plot the result
          
          # Print out the starting conditions
      
      if __name__ == '__main__': #execute run here
      
          run()
           
      
      

      Thank you in advance!

      posted in General Discussion
      J
      jabbarabdullah
    • RE: Assigning independent value for multi assets

      But that will simply divide the total portfolio amount with number of data feeds right? I was thinking of something like
      self.broker.get_value(data=d) for each asset because my take profit is based on the increase in value of data d
      (ie. self.getposition(d).size*d.close[0] >= self.broker.get_cash(d)*(1+take_profit)). However, we cannot simply assign data=d to the get_value, so I am quite lost now/ Really appreciate your help please.

      Thank you.

      posted in General Discussion
      J
      jabbarabdullah
    • Assigning independent value for multi assets

      Hi all,

      I have a multiple data feed strategy and I want to assign the starting cash and value for each and every data in the strategy to be independent in order for my Stop loss/Take Profit strategy to work (Something like
      data_d_cash = portfolio_cash * (1/len(datalist)).

      I need each data to have its own independent proportion for the stop loss/ take profit to work for each d in the strategy below.

      from __future__ import (absolute_import, division, print_function, unicode_literals)
      
      import backtrader as bt
      import datetime as dt
      import pytz
      import math
      
      cn1='XXX'
      cn2='YYY'
      datalist = [cn1,cn2]
      csh=100000
      stdt=dt.datetime(2019,07,2,9,30)
      enddt=dt.datetime(2019,07,2,16,00)
      SL=0.01
      TP=2*SL
      SU=0.005
      SUpct=SU*100
      prop=1/len(datalist) #proportion of portfolio
      batch=10 #rounding
      entrytime = dt.time(9,45)
      exittime = dt.time(15,55)
      stakesize=10
      lwbnd=40
      upbnd=90
      commis=0.05
      TPpct=TP*100
      SLpct=SL*100
      
      def rounddown(x):
          return int(math.floor(x / 1)) * 1
      
      class IBCommission(bt.CommInfoBase):
      
          """A :class:`IBCommision` charges the way interactive brokers does.
          """
      
          params = (('stocklike', True), ('commtype', bt.CommInfoBase.COMM_FIXED),)
      
          def _getcommission(self, size, price, pseudoexec):
              return self.p.commission
      
      class PropSizer(bt.Sizer):
          """A position sizer that will buy as many stocks as necessary for a certain proportion of the portfolio
             to be committed to the position, while allowing stocks to be bought in batches (say, 100)"""
          params = {"prop": prop, "batch": batch}
       
          def _getsizing(self, comminfo, cash, data, isbuy):
              """Returns the proper sizing"""
              
              for i, d in enumerate(self.datas):
                  if isbuy:    # Buying
                      target = csh * self.params.prop    # Ideal total value of the position
                      price = self.data.close[0]
                      shares_ideal = target / price    # How many shares are needed to get target
                      batches = int(shares_ideal / self.params.batch)    # How many batches is this trade?
                      shares = batches * self.params.batch    # The actual number of shares bought
           
                      if shares * price > cash:
                          return 0    # Not enough money for this trade
                      else:
                          return shares
           
                  else:    # Selling
                      return self.broker.getposition(d).size    # Clear the position
                  
      class MainSt(bt.Strategy):
          
      
          data_live = False
          def notify_data(self, data, status, *args, **kwargs):
              print('*' * 5, 'DATA NOTIF:', data._getstatusname(status),
                *args)
              if status == data.LIVE:
                  self.data_live = True
                  
          def log(self, txt, dt=None, vlm=None):
              dt = dt or self.datas[0].datetime.datetime(0)
              vlm = vlm or self.data.volume[0]
              print('%s) %s, %s' % (len(self), dt.isoformat(), txt))
      
      
          def __init__(self):
              self.order = {}
              self.buyprice = {}
              self.buycomm = {}
              self.bar_executed = {}
              self.inds = dict()
              self.o = dict()
              self.lendata = dict()
              
              for i, d in enumerate(self.datas):
                  self.order[d] = None
                  self.buyprice[d] = None
                  self.buycomm[d] = None   
                  self.bar_executed[d] = None
                  self.inds[d] = dict()
                  self.inds[d]['sma'] = bt.indicators.SimpleMovingAverage(d.close, period=54)
                  self.inds[d]['rsi'] = bt.indicators.RelativeStrengthIndex(d.close, period=14,safediv=True, upperband=upbnd,lowerband=lwbnd)
      
          def notify_order(self, order):
              if order.status in [order.Submitted, order.Accepted]:
                  return    
      
              
              if order.status in [order.Completed]:
                  
                  if order.isbuy():
                          
                      self.log('%s: BUY EXECUTED, Price: %.2f, Cost: %.2f, Size: %.2f, Comm %.2f' %
                          (order.data._name,
                           order.executed.price,
                           order.executed.value,
                           order.executed.size,
                           order.executed.comm))
      
                      self.buyprice = order.executed.price
                      self.buycomm = order.executed.comm
                      self.last_executed_price = order.executed.price
                      self.order = None
                      self.bar_executed = len(self)
                  else:
      
                      # Sell
                      self.log('%s: SELL EXECUTED, Price: %.2f, Cost: %.2f, Size: %.2f, Comm %.2f' %
                               (order.data._name,
                                order.executed.price,
                                order.executed.value,
                                order.executed.size,
                                order.executed.comm))
                     
                      self.last_executed_price = order.executed.price
                      self.order = None           
                      self.bar_executed = len(self)
      
                  self.bar_executed = len(self)
          
              elif order.status in [order.Canceled, order.Margin, order.Rejected]:
                  self.log('%s Order Canceled/Margin/Rejected' % (order.data._name))
      
              # Write down: no pending order[order.data._name]
              self.order = None
      
      
          def notify_trade(self, trade):
              if not trade.isclosed:
                  return
      
              self.log('OPERATION PROFIT, GROSS %.2f, NET %.2f' %
                       (trade.pnl, trade.pnlcomm))
      
          def next(self):
              for i, d in enumerate(self.datas):
                  pv = self.broker.get_value(None)
                  pvd = self.broker.get_value()*prop
                  cshd = self.broker.get_cash()*prop
                  self.stakes = abs(rounddown(pv/d.close[0]))
                  target = csh * prop    # Ideal total value of the position
                  price = d.close[0]
                  shares_ideal = pvd / price    # How many shares are needed to get target
                  batches = int(shares_ideal / batch)    # How many batches is this trade?
                  shares = batches * batch         
                  
                  if not self.getposition(d).size:
                      
                      if (pv >= csh*(1+TP)):
                          return
                              
                      
                      if (pv <= csh*(1-SL)):
                          return
                      
                      if (d.datetime.time(-1) >= exittime):
                          return
                      
                      if ((self.inds[d]['rsi'][0] <= lwbnd)and(d.datetime.time(0) >= entrytime)):
                          print('%s pv: %.2f, cash:%.2f, rsi: %.2f'% (d._name, pvd, cshd, self.inds[d]['rsi'][0]))
                          self.log('%s: BUY CREATE, %.2f, VLM BOUGHT: %.2f' % (d._name, d.close[0], shares))
                          self.order = self.buy(data=d, size=shares)
                          
                  else:
                      
                      if (self.inds[d]['rsi'][0] >= upbnd):
                          print('%s pv: %.2f, cash:%.2f, rsi: %.2f'% (d._name, pvd, cshd, self.inds[d]['rsi'][0]))
                          self.log('%s: SELL CREATE (RSI>Upbnd), %.2f, VLM BOUGHT: %.2f' % (d._name, d.close[0], self.getposition(d).size))
                          self.order = self.sell(data=d, size = abs(self.getposition(d).size))       
                          
                      else:
                          if (d.close[0] >= ((self.getposition(d).price*(1+SU)))):
                              print('%s pv: %.2f, cash:%.2f, rsi: %.2f'% (d._name, pvd, cshd, self.inds[d]['rsi'][0]))
                              self.log('%s: SELL CREATE (>%.2fpct), %.2f, VLM BOUGHT: %.2f' % (d._name, SUpct, d.close[0], self.getposition(d).size))
                              self.order = self.sell(data=d, size = abs(self.getposition(d).size))
      
                          else:
                              if (d.close[0] <= ((self.getposition(d).price*(1-SU)))):
                                  print('%s pv: %.2f, cash:%.2f, rsi: %.2f'% (d._name, pvd, cshd, self.inds[d]['rsi'][0]))
                                  self.log('%s: SELL CREATE (<%.2fpct), %.2f, VLM BOUGHT: %.2f' % (d._name, SUpct, d.close[0], self.getposition(d).size))
                                  self.order = self.sell(data=d, size = abs(self.getposition(d).size))
                                  '''
                                      else:
                                          if (pvd >= target*(1+TP)):
                                              print('%s pv: %.2f, cash:%.2f, rsi: %.2f'% (d._name, pvd, cshd, self.inds[d]['rsi'][0]))
                                              self.log('%s: TAKE PROFIT VAL CREATE (>%.2fpct), %.2f, VLM BOUGHT: %.2f' % (d._name, TPpct, d.close[0], self.getposition(d).size))
                                              self.order = self.sell(data=d, size=abs(self.getposition(d).size))
                                          else:
                                              if (pvd <= target*(1-SL)):
                                                  print('%s pv: %.2f, cash:%.2f, rsi: %.2f'% (d._name, pvd, cshd, self.inds[d]['rsi'][0]))
                                                  self.log('%s: STOPLOSS VAL CREATE (<%.2fpct), %.2f, VLM BOUGHT: %.2f' % (d._name, SLpct, d.close[0], self.getposition(d).size))
                                                  self.order = self.sell(data=d, size=abs(self.getposition(d).size))
                                   '''            
                              else:
                                  if (d.datetime.time(0) >= exittime):
                                      print('%s pv: %.2f, cash:%.2f, rsi: %.2f'% (d._name, pvd, cshd, self.inds[d]['rsi'][0]))
                                      self.log('%s: EOD STOP, %.2f, VLM BOUGHT: %.2f' % (d._name, d.close[0], self.getposition(d).size))
                                      self.order = self.sell(data=d, size=abs(self.getposition(d).size))  
      
      def runstrat():
      
          
          # Get a pandas dataframe
          cerebro = bt.Cerebro()
          ibstore = bt.stores.IBStore(port=7497, host='127.0.0.1', clientId=12345)
          #create our data list
          is_first = True
          #Loop through the list adding to cerebro.
          for i in datalist:
              data = ibstore.getdata(dataname=i,fromdate=stdt, historical =True, useRTH=True, tz = pytz.timezone('US/Eastern'),
                                   todate=enddt, timeframe=bt.TimeFrame.Seconds, compression=15)
              '''
              if i in datalist:
                  if is_first:
                      data_main_plot = data
                      is_first = False
                  else:
                      data.plotinfo.plotmaster = data_main_plot
              else:
                  data.plotinfo.plot = False
              '''
              cerebro.adddata(data)   
              
          cerebro.broker.setcash(csh)    
          comminfo = IBCommission(commission=commis)
          cerebro.broker.addcommissioninfo(comminfo)
          cerebro.addwriter(bt.WriterFile, csv=True, rounding=2, out="C:\\Users\\User\\Desktop\\Backtest Library\\TestResults.csv")
          
          start_value = cerebro.broker.getvalue()
      
          cerebro.addstrategy(MainSt)
          # Run over everything
          cerebro.run()  
          
          # Plot the result
          cerebro.plot(volume=False)
          
          # Print out the starting conditions
          print(' ')
          print('--','Summary','--')
          print('Start capital: %.2f' % start_value)
          # Print out the final result
          print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())
          print('Final Portfolio Cash: %.2f' % cerebro.broker.getcash())    
          print('Final PnL Value: %.2f' % (cerebro.broker.getvalue()-start_value))
      
      if __name__ == '__main__':
      
          runstrat()
          
      

      Appreciate your help. Thanks!

      posted in General Discussion
      J
      jabbarabdullah
    • RE: Multi Assets Multi Order Executions Problem

      @backtrader said in Multi Assets Multi Order Executions Problem:

      @jabbarabdullah said in Multi Assets Multi Order Executions Problem:

      Appreciate if you could explain further on what do you mean by 'NO'.

      You say the orders are getting executed twice and the answer is: NO

      @ab_trader said in Multi Assets Multi Order Executions Problem:

      You have two data feeds, you cycle thru them twice and print same info twice. Check if data name is same as order data name, then print.
      On the other side you don't need to go thru all data feeds. Just print order info.

      I quoted the code in notify_order where you do exactly what @ab_trader is telling you. You print the execution twice (which is not the same as two executions), because you loop through the datas in notify_order

      I see, got it. Removed the loop in notify_order and it worked. Thanks @backtrader and @ab_trader !

      Just one more thing. when I tried executing the code with different date which the take profit and stop loss in my code should work, the numbers went crazy and it did not really stop the trade as expected. It worked great for a single asset data feed code but when I change it to multi assets data feeds, it went haywire. What went wrong? The single data feed code for comparison as follows:

      
      from __future__ import (absolute_import, division, print_function, unicode_literals)
      
      import backtrader as bt
      import datetime as dt
      import pytz
      import math
      
      cn1='UUUU'
      cn2='VVVV'
      csh=100000
      stdt=dt.datetime(2019,06,28,9,30)
      enddt=dt.datetime(2019,06,28,16,00)
      SL=0.01
      TP=2*SL
      SU=0.005
      SUpct=SU*100
      prop=1 #proportion of portfolio
      batch=10 #rounding
      entrytime = dt.time(9,45)
      exittime = dt.time(15,55)
      stakesize=10
      lwbnd=40
      upbnd=85
      commis=0.05
      TPpct=TP*100
      SLpct=SL*100
      
      def rounddown(x):
          return int(math.floor(x / 1)) * 1
      
      class IBCommission(bt.CommInfoBase):
      
          """A :class:`IBCommision` charges the way interactive brokers does.
          """
      
          params = (('stocklike', True), ('commtype', bt.CommInfoBase.COMM_FIXED),)
      
          def _getcommission(self, size, price, pseudoexec):
              return self.p.commission
      
      class PropSizer(bt.Sizer):
          """A position sizer that will buy as many stocks as necessary for a certain proportion of the portfolio
             to be committed to the position, while allowing stocks to be bought in batches (say, 100)"""
          params = {"prop": prop, "batch": batch}
       
          def _getsizing(self, comminfo, cash, data, isbuy):
              """Returns the proper sizing"""
       
              if isbuy:    # Buying
                  target = csh * self.params.prop    # Ideal total value of the position
                  price = data.close[0]
                  shares_ideal = target / price    # How many shares are needed to get target
                  batches = int(shares_ideal / self.params.batch)    # How many batches is this trade?
                  shares = batches * self.params.batch    # The actual number of shares bought
       
                  if shares * price > cash:
                      return 0    # Not enough money for this trade
                  else:
                      return shares
       
              else:    # Selling
                  return self.broker.getposition(data).size    # Clear the position
              
      class TestStrategy(bt.Strategy):
          
      
          data_live = False
          def notify_data(self, data, status, *args, **kwargs):
              print('*' * 5, 'DATA NOTIF:', data._getstatusname(status),
                *args)
              if status == data.LIVE:
                  self.data_live = True
                  
          def log(self, txt, dt=None, vlm=None):
              dt = dt or self.datas[0].datetime.datetime(0)
              vlm = vlm or self.data.volume[0]
              print('%s, %s, %s, Volume, %s' % (len(self), dt.isoformat(), txt, vlm))
      
      
          def __init__(self):
              self.dataclose = self.datas[0].close
              self.order = None
              self.buyprice = None
              self.buycomm = None
                  
              self.sma0 = bt.indicators.SimpleMovingAverage(self.datas[0], period=20)
              self.sma = bt.indicators.SimpleMovingAverage(self.datas[0], period=54)
              self.rsi = bt.indicators.RelativeStrengthIndex(period=14,safediv=True, upperband=upbnd,lowerband=lwbnd)
      
          def notify_order(self, order):
              if order.status in [order.Submitted, order.Accepted]:
                  return    
              self.last_executed_price = order.executed.price
              
              if order.status in [order.Completed]:
                  if order.isbuy():
                      self.log(
                          'BUY EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' %
                          (order.executed.price,
                           order.executed.value,
                           order.executed.comm))
      
                      self.buyprice = order.executed.price
                      self.buycomm = order.executed.comm
                      self.last_executed_price = order.executed.price
                      
                      
                  else:  # Sell
                      self.log('SELL EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' %
                               (order.executed.price,
                                order.executed.value,
                                order.executed.comm))
                      
                      self.last_executed_price = order.executed.price
                                 
                      
      
                  self.bar_executed = len(self)
      
              elif order.status in [order.Canceled, order.Margin, order.Rejected]:
                  self.log('Order Canceled/Margin/Rejected')
      
              # Write down: no pending order
              self.order = None
      
      
          def notify_trade(self, trade):
              if not trade.isclosed:
                  return
      
              self.log('OPERATION PROFIT, GROSS %.2f, NET %.2f' %
                       (trade.pnl, trade.pnlcomm))
      
          def next(self):
              pv = self.broker.get_value()
              self.stakes = abs(rounddown(pv/self.dataclose[0]))
              target = csh * prop    # Ideal total value of the position
              price = self.data.close[0]
              shares_ideal = target / price    # How many shares are needed to get target
              batches = int(shares_ideal / batch)    # How many batches is this trade?
              shares = batches * batch         
              if self.order:
                  return
          
              if not self.position:
                  
                  if (pv >= csh*(1+TP)):
                      return
                  
                  if (pv <= csh*(1-SL)):
                      return
      
                  if (self.data.datetime.time(0) >= exittime):
                      return
                  
                  if ((self.rsi[0] <= lwbnd)and(pv > csh*(1-SL))and(self.data.datetime.time(0) >= entrytime)):
                      print('rsi:', self.rsi[0])
                      print('pv: ', pv)
                      self.log('BUY CREATE, %.2f, VLM BOUGHT: %.2f' % (self.dataclose[0], shares))
                      self.order = self.buy() 
              else:
                  if (self.dataclose[0] >= (self.last_executed_price*(1+SU))):
                      print('rsi:', self.rsi[0])
                      print('pv: ', pv)
                      self.log('SELL CREATE (>%.2fpct), %.2f, VLM BOUGHT: %.2f' % (SUpct, self.dataclose[0], self.position.size))
                      self.order = self.sell(exectype=bt.Order.Stop)
                  else:
                      if (self.rsi[0] >= upbnd):
                          print('rsi:', self.rsi[0])
                          print('pv: ', pv)
                          self.log('SELL CREATE (RSI>Upbnd), %.2f, VLM BOUGHT: %.2f' % (self.dataclose[0], self.position.size))
                          self.order = self.close()                        
                      else:
                          if (pv >= csh*(1+TP)):
                              print('rsi:', self.rsi[0])
                              print('pv: ', pv)
                              self.log('TAKE PROFIT VAL CREATE (>%.2fpct), %.2f, VLM BOUGHT: %.2f' % (TPpct, self.dataclose[0], self.position.size))
                              self.order = self.sell(exectype=bt.Order.StopLimit, price=self.dataclose[0])
                          else:
                              if (pv <= csh*(1-SL)):
                                  print('rsi:', self.rsi[0])
                                  print('pv: ', pv)
                                  self.log('STOPLOSS VAL CREATE (<%.2fpct), %.2f, VLM BOUGHT: %.2f' % (SLpct, self.dataclose[0], self.position.size))
                                  self.order = self.sell(exectype=bt.Order.StopLimit, price=self.dataclose[0])
                                  return
                              else:
                                  if (self.data.datetime.time(0) >= exittime):
                                      print('rsi:', self.rsi[0])
                                      print('pv: ', pv)
                                      self.log('EOD STOP, %.2f, VLM BOUGHT: %.2f' % (self.dataclose[0], self.position.size))
                                      self.order = self.close(exectype=bt.Order.Stop)  
      
      def runstrat():
      
          
          # Get a pandas dataframe
          cerebro = bt.Cerebro()
          ibstore = bt.stores.IBStore(port=7497, host='127.0.0.1', clientId=12345)
          data0 = ibstore.getdata(dataname=cn1,fromdate=stdt, historical =True, useRTH=True, tz = pytz.timezone('US/Eastern'),
                               todate=enddt, timeframe=bt.TimeFrame.Seconds, compression=15)
          cerebro.adddata(data0, name=cn1)
      
          data1 = ibstore.getdata(dataname=cn2,fromdate=stdt, historical =True, useRTH=True, tz = pytz.timezone('US/Eastern'),
                               todate=enddt, timeframe=bt.TimeFrame.Seconds, compression=15)
          cerebro.adddata(data1, name=cn2)
          
          data1.plotinfo.plotmaster = data0
          
          cerebro.broker.setcash(csh)    
          comminfo = IBCommission(commission=commis)
          cerebro.broker.addcommissioninfo(comminfo)
          cerebro.addwriter(bt.WriterFile, csv=True, rounding=2, out="C:\\Users\\User\\Desktop\\Backtest Library\\TestResults.csv")
          
          start_value = cerebro.broker.getvalue()
      
          cerebro.addstrategy(TestStrategy)
          cerebro.addsizer(PropSizer)
          # Run over everything
          cerebro.run()  
          
          # Plot the result
          cerebro.plot(volume=False)
          
          # Print out the starting conditions
          print(' ')
          print('--',cn1,'--')
          print('Start capital: %.2f' % start_value)
          # Print out the final result
          print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())
          print('Final PnL Value: %.2f' % (cerebro.broker.getvalue()-start_value))
      
      if __name__ == '__main__':
      
          runstrat()
          
      

      Appreciate your comment on this. Thanks!

      posted in General Discussion
      J
      jabbarabdullah
    • RE: Multi Assets Multi Order Executions Problem

      Hi @backtrader ,

      @backtrader said in Multi Assets Multi Order Executions Problem:

      @jabbarabdullah said in Multi Assets Multi Order Executions Problem:

      it somehow executed the order for each asset twice

      NO

      Appreciate if you could explain further on what do you mean by 'NO'.

      @jabbarabdullah said in Multi Assets Multi Order Executions Problem:

          def notify_order(self, order):
              for i, d in enumerate(self.datas):
      

      @jabbarabdullah said in Multi Assets Multi Order Executions Problem:

      I'm trying to simply execute the multi assets

      The magician inside me can say: multi == 2

      Apologies, but I don't really get that. So how do I remedy the situation then?

      Thanks.

      posted in General Discussion
      J
      jabbarabdullah
    • Multi Assets Multi Order Executions Problem

      Hi,

      I'm trying to simply execute the multi assets order based on the same strategy. However, when I run my strategy, it somehow executed the order for each asset twice and I can't figure out what is the problem. Appreciate if you could take a look at my code below. Thanks!

      from __future__ import (absolute_import, division, print_function, unicode_literals)
      
      import backtrader as bt
      import datetime as dt
      import pytz
      import math
      
      cn1='XXXX'
      cn2='YYYY'
      csh=100000
      stdt=dt.datetime(2019,06,28,9,30)
      enddt=dt.datetime(2019,06,28,16,00)
      SL=0.01
      TP=2*SL
      SU=0.005
      SUpct=SU*100
      prop=1/4 #proportion of portfolio
      batch=1 #rounding
      entrytime = dt.time(9,45)
      exittime = dt.time(15,30)
      stakesize=10
      lwbnd=40
      upbnd=75
      commis=0.05
      TPpct=TP*100
      SLpct=SL*100
      
      def rounddown(x):
          return int(math.floor(x / 1)) * 1
      
      class IBCommission(bt.CommInfoBase):
      
          """A :class:`IBCommision` charges the way interactive brokers does.
          """
      
          params = (('stocklike', True), ('commtype', bt.CommInfoBase.COMM_FIXED),)
      
          def _getcommission(self, size, price, pseudoexec):
              return self.p.commission
      
      class PropSizer(bt.Sizer):
          """A position sizer that will buy as many stocks as necessary for a certain proportion of the portfolio
             to be committed to the position, while allowing stocks to be bought in batches (say, 100)"""
          params = {"prop": prop, "batch": batch}
       
          def _getsizing(self, comminfo, cash, data, isbuy):
              """Returns the proper sizing"""
              
              for i, d in enumerate(self.datas):
                  if isbuy:    # Buying
                      target = csh * self.params.prop    # Ideal total value of the position
                      price = self.data.close[0]
                      shares_ideal = target / price    # How many shares are needed to get target
                      batches = int(shares_ideal / self.params.batch)    # How many batches is this trade?
                      shares = batches * self.params.batch    # The actual number of shares bought
           
                      if shares * price > cash:
                          return 0    # Not enough money for this trade
                      else:
                          return shares
           
                  else:    # Selling
                      return self.broker.getposition(d).size    # Clear the position
                  
      class MainSt(bt.Strategy):
          
      
          data_live = False
          def notify_data(self, data, status, *args, **kwargs):
              print('*' * 5, 'DATA NOTIF:', data._getstatusname(status),
                *args)
              if status == data.LIVE:
                  self.data_live = True
                  
          def log(self, txt, dt=None, vlm=None):
              dt = dt or self.datas[0].datetime.datetime(0)
              vlm = vlm or self.data.volume[0]
              print('%s) %s, %s' % (len(self), dt.isoformat(), txt))
      
      
          def __init__(self):
      
              self.order = {}
              self.buyprice = {}
              self.buycomm = {}
              self.bar_executed = {}
              self.inds = dict()
              self.o = dict()
              self.lendata = dict()
              
              for i, d in enumerate(self.datas):
                  self.order[d] = None
                  self.buyprice[d] = None
                  self.buycomm[d] = None   
                  self.bar_executed[d] = None
                  self.inds[d] = dict()
                  self.inds[d]['sma'] = bt.indicators.SimpleMovingAverage(d.close, period=54)
                  self.inds[d]['rsi'] = bt.indicators.RelativeStrengthIndex(d.close, period=14,safediv=True, upperband=upbnd,lowerband=lwbnd)
      
          def notify_order(self, order):
              for i, d in enumerate(self.datas):
                  
                  if order.status in [order.Submitted, order.Accepted]:
                      return    
                  self.last_executed_price = order.executed.price
                  
                  if order.status in [order.Completed]:
                      
                      if order.isbuy():
                              
                              self.log('%s: BUY EXECUTED, Price: %.2f, Cost: %.2f, Size: %.2f, Comm %.2f' %
                                  (order.data._name,
                                   order.executed.price,
                                   order.executed.value,
                                   order.executed.size,
                                   order.executed.comm))
              
                              self.buyprice[d] = order.executed.price
                              self.buycomm[d] = order.executed.comm
                              self.last_executed_price = order.executed.price
                              self.order[d] = None
                              self.bar_executed[d] = len(self)
                      else:
      
                          # Sell
                          self.log('%s: SELL EXECUTED, Price: %.2f, Cost: %.2f, Size: %.2f, Comm %.2f' %
                                   (order.data._name,
                                    order.executed.price,
                                    order.executed.value,
                                    order.executed.size,
                                    order.executed.comm))
                          
                          self.last_executed_price = order.executed.price
                          self.order[d] = None           
                          self.bar_executed[d] = len(self)
          
                      self.bar_executed[d] = len(self)
              
                  elif order.status in [order.Canceled, order.Margin, order.Rejected]:
                      self.log('%s Order Canceled/Margin/Rejected' % (order.executed._name))
          
                  # Write down: no pending order[order.data._name]
                  self.order[d] = None
      
      
          def notify_trade(self, trade):
              if not trade.isclosed:
                  return
      
              self.log('OPERATION PROFIT, GROSS %.2f, NET %.2f' %
                       (trade.pnl, trade.pnlcomm))
      
          def next(self):
              for i, d in enumerate(self.datas):
                  pv = self.broker.get_value() * prop
                  self.stakes = abs(rounddown(pv/d.close[0]))
                  target = csh * prop    # Ideal total value of the position
                  price = d.close[0]
                  shares_ideal = target / price    # How many shares are needed to get target
                  batches = int(shares_ideal / batch)    # How many batches is this trade?
                  shares = batches * batch         
      
                  if not self.getposition(d).size and not self.order[d]:
                      
                      if (pv >= target*(1+TP)):
                          return
                      
                      if (pv <= target*(1-SL)):
                          return
          
                      if (self.data.datetime.time(0) >= exittime):
                          return
                      
                      if ((self.inds[d]['rsi'][0] <= lwbnd)and(pv > target*(1-SL))and(self.data.datetime.time(0) >= entrytime)):
                          print('%s pv: %.2f, rsi: %.2f'% (d._name, pv, self.inds[d]['rsi'][0]))
                          self.log('%s: BUY CREATE, %.2f, VLM BOUGHT: %.2f' % (d._name, d.close[0], shares))
                          self.order[d] = self.buy(data=d, size=shares)
                          
                  else:
                      
                      if (self.inds[d]['rsi'][0] >= upbnd):
                          print('%s pv: %.2f, rsi: %.2f'% (d._name, pv, self.inds[d]['rsi'][0]))
                          self.log('%s: SELL CREATE (RSI>Upbnd), %.2f, VLM BOUGHT: %.2f' % (d._name, d.close[0], self.position.size))
                          self.order[d] = self.close(data=d, size=abs(self.position.size))       
                          
                      else:
                          if (pv >= target*(1+TP)):
                              print('%s pv: %.2f, rsi: %.2f'% (d._name, pv, self.inds[d]['rsi'][0]))
                              self.log('%s: TAKE PROFIT VAL CREATE (>%.2fpct), %.2f, VLM BOUGHT: %.2f' % (d._name, TPpct, d.close[0], self.position.size))
                              self.order[d] = self.sell(data=d, size=abs(self.position.size))
                          else:
                              if (pv <= target*(1-SL)):
                                  print('%s pv: %.2f, rsi: %.2f'% (d._name, pv, self.inds[d]['rsi'][0]))
                                  self.log('%s: STOPLOSS VAL CREATE (<%.2fpct), %.2f, VLM BOUGHT: %.2f' % (d._name, SLpct, d.close[0], self.position.size))
                                  self.order[d] = self.sell(data=d, size=abs(self.position.size))
                                  return
                              else:
                                  if (self.data.datetime.time(0) >= exittime):
                                      print('%s pv: %.2f, rsi: %.2f'% (d._name, pv, self.inds[d]['rsi'][0]))
                                      self.log('%s: EOD STOP, %.2f, VLM BOUGHT: %.2f' % (d._name, d.close[0], self.position.size))
                                      self.order[d] = self.close(data=d, exectype=bt.Order.Stop, size=abs(self.position.size))  
      
      def runstrat():
      
          
          # Get a pandas dataframe
          cerebro = bt.Cerebro()
          ibstore = bt.stores.IBStore(port=7497, host='127.0.0.1', clientId=12345)
          #create our data list
          datalist = [(cn1,'XXXX'),(cn2,'YYYY')]
          is_first = True
          #Loop through the list adding to cerebro.
          for i in datalist:
              data = ibstore.getdata(dataname=i[0],fromdate=stdt, historical =True, useRTH=True, tz = pytz.timezone('US/Eastern'),
                                   todate=enddt, timeframe=bt.TimeFrame.Seconds, compression=15)
              if i in datalist:
                  if is_first:
                      data_main_plot = data
                      is_first = False
                  else:
                      data.plotinfo.plotmaster = data_main_plot
              else:
                  data.plotinfo.plot = False
              cerebro.adddata(data, name=i[1])
              
          cerebro.broker.setcash(csh)    
          comminfo = IBCommission(commission=commis)
          cerebro.broker.addcommissioninfo(comminfo)
          cerebro.addwriter(bt.WriterFile, csv=True, rounding=2, out="C:\\Users\\User\\Desktop\\Backtest Library\\TestResults.csv")
          
          start_value = cerebro.broker.getvalue()
      
          cerebro.addstrategy(MainSt)
          cerebro.addsizer(PropSizer)
          # Run over everything
          cerebro.run()  
          
          # Plot the result
          cerebro.plot(volume=False)
          
          # Print out the starting conditions
          print(' ')
          print('--','Summary','--')
          print('Start capital: %.2f' % start_value)
          # Print out the final result
          print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())
          print('Final PnL Value: %.2f' % (cerebro.broker.getvalue()-start_value))
      
      if __name__ == '__main__':
      
          runstrat()
          
      

      the problematic results:

      Server Version: 76
      TWS Time at connection:20190704 20:50:32 SGT
      XXXX pv: 25000.00, rsi: 39.81
      65) 2019-06-28T09:46:00, XXXX: BUY CREATE, 53.66, VLM BOUGHT: 465.00
      66) 2019-06-28T09:46:15, XXXX: BUY EXECUTED, Price: 53.66, Cost: 24951.90, Size: 465.00, Comm 0.05
      66) 2019-06-28T09:46:15, XXXX: BUY EXECUTED, Price: 53.66, Cost: 24951.90, Size: 465.00, Comm 0.05
      YYYY pv: 24998.83, rsi: 33.98
      108) 2019-06-28T09:56:45, YYYY: BUY CREATE, 31.86, VLM BOUGHT: 784.00
      109) 2019-06-28T09:57:00, YYYY: BUY EXECUTED, Price: 31.84, Cost: 24962.56, Size: 784.00, Comm 0.05
      109) 2019-06-28T09:57:00, YYYY: BUY EXECUTED, Price: 31.84, Cost: 24962.56, Size: 784.00, Comm 0.05
      YYYY pv: 25028.35, rsi: 75.65
      251) 2019-06-28T10:32:30, YYYY: SELL CREATE (RSI>Upbnd), 32.05, VLM BOUGHT: 465.00
      252) 2019-06-28T10:32:45, YYYY: SELL EXECUTED, Price: 32.05, Cost: 14805.60, Size: -465.00, Comm 0.05
      252) 2019-06-28T10:32:45, YYYY: SELL EXECUTED, Price: 32.05, Cost: 14805.60, Size: -465.00, Comm 0.05
      XXXX pv: 25025.31, rsi: 77.52
      290) 2019-06-28T10:42:15, XXXX: SELL CREATE (RSI>Upbnd), 53.62, VLM BOUGHT: 465.00
      291) 2019-06-28T10:42:30, XXXX: SELL EXECUTED, Price: 53.62, Cost: 24951.90, Size: -465.00, Comm 0.05
      291) 2019-06-28T10:42:30, XXXX: SELL EXECUTED, Price: 53.62, Cost: 24951.90, Size: -465.00, Comm 0.05
      291) 2019-06-28T10:42:30, OPERATION PROFIT, GROSS -18.60, NET -18.70
      

      P/S: I intentionally not using the bracket order on this and try to find a workaround for it.

      Thanks again.

      posted in General Discussion
      J
      jabbarabdullah
    • 1 / 1