Navigation

    Backtrader Community

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

    J T

    @J T

    2
    Reputation
    47
    Profile views
    31
    Posts
    0
    Followers
    0
    Following
    Joined Last Online

    J T Unfollow Follow

    Best posts made by J T

    • RE: ZigZag indicator for live trading.

      Thanks alot. I will do some reading into these articles. Also will be diving into connection with IB.

      Pls stay safe in the meantime. And really appreciate your help.

      posted in Indicators/Strategies/Analyzers
      J T
      J T
    • 2 timeframes, but trade observer and buy/sell affected

      sorry, misclicked. I really want the old trade observer back. Where the profits are in blue dots, losses in red dots. Now I only get blue dots even though they are negative pnl.

      class BaseStrategy(bt.Strategy):  # Strategy is a lines object
          params = dict(order_percentage=0.25, ticker='eurusd', fast=10, slow=30)
          parent_order = None  # default value for a potential order
          stoploss = None
      
          def __init__(self):
              self.order = None  # To keep track of pending orders, init with None
              self.buyprice = None
              self.buycomm = None
              self.bar_executed = None
              self.size = None
              self.lendata1 = 0
              self.data = self.datas[0]
              self.data1 = self.datas[1]
              self.fast_sma = bt.indicators.SMA(self.data.close, period=self.params.fast)
              self.slow_sma = bt.indicators.SMA(self.data.close, period=self.params.slow)
              self.crossover = bt.indicators.CrossOver(self.fast_sma, self.slow_sma)
      
              self.fast1_sma = bt.indicators.SMA(self.data1.close, period=self.params.fast)
              self.slow1_sma = bt.indicators.SMA(self.data1.close, period=self.params.slow)
              self.crossover1 = bt.indicators.CrossOver(self.fast1_sma, self.slow1_sma)
      
              self.data1.plotinfo.plot = False
              self.fast1_sma.plotinfo.plot = False
              self.slow1_sma.plotinfo.plot = False
              self.crossover1.plotinfo.plot = False
           
          def notify_order(self, order):  # called when a buy or sell is requested
      
              if order.status in [order.Submitted]:  # status 1
                  # Buy/Sell order submitted/accepted to/by broker - Nothing to do
                  print('Order Submitted...', order.ref)
                  return
      
              if order.status in [order.Accepted]:  # status 2
                  # Buy/Sell order submitted/accepted to/by broker - Nothing to do
                  print('Order Accepted...', order.ref)
                  return
      
              if order.status in [order.Margin, order.Rejected]:
                  print('Order Margin/Rejected', order.ref)
                  return
      
              # Check if an order has been completed, Attention: broker could reject order if not enough cash
              if order.status in [order.Completed]:  # status 4
                  print('-'*50, 'EXECUTED ORDER', '-'*50)
                  print('{} EXE-D, REF {}, AT {}: {:d} shares of {}, Price: {}, Value: {:.2f}, Comm: {:.2f}, PNL: {}'.format(
                        order.info['name'], order.ref, bt.num2date(order.executed.dt), order.executed.size, self.p.ticker,
                        order.executed.price, order.executed.value, order.executed.comm, order.executed.pnl))
                  print('-' * 116)
      
          def nextstart(self):
              self.lendata1 = len(self.data1)  # if this a 240min timeframe, len of self.data1 is 2.
              # super(BaseStrategy, self).nextstart() -->do i even need this?
              # print(len(self.data1))
      
          def next(self):
              # print('len self.datas:', len(self.datas))
              # print('len self.data1, lendata1', len(self.data1), self.lendata1)
              txt = list()
              txt.append('Data0')
              txt.append('{}'.format(len(self.data)))
              txt.append('{}'.format(self.data.datetime.datetime(0)))
              txt.append('{:.5f}'.format(self.data.open[0]))
              txt.append('{:.5f}'.format(self.data.high[0]))
              txt.append('{:.5f}'.format(self.data.low[0]))
              txt.append('{:.5f}'.format(self.data.close[0])
              # print(', '.join(txt))
      
              if len(self.data1) > self.lendata1:
                  self.lendata1 += 1
                  print('new higher TF bar')
      
                  if len(self.datas) > 1 and len(self.data1):  # len datas is always at 2 becasue i got min and 240 min data, len data1 is increasing from 2 to ...
                      txt = list()
                      txt.append('Data1')
                      txt.append('{}'.format(len(self.data1)))
                      txt.append('{}'.format(self.data1.datetime.datetime(0)))
                      txt.append('{:.5f}'.format(self.data1.open[0]))
                      txt.append('{:.5f}'.format(self.data1.high[0]))
                      txt.append('{:.5f}'.format(self.data1.low[0]))
                      txt.append('{:.5f}'.format(self.data1.close[0])
                      # print(', '.join(txt))
      
              can_trade = check_timefx(self.data.datetime.date(0), self.data.datetime.time(0))
      
              if self.crossover > 0 and self.crossover1 > 0:
                  action = 'long'
              elif self.crossover < 0 and self.crossover1 < 0:
                  action = 'short'
              else:
                  action = 'not sure yet'
       
              # Check if we are in the market
              if can_trade:
      
                  if action == 'long' or action == 'short':
                      if self.position:
                          self.cancel(self.stoploss)
                          print('{} {} canceled.'.format(self.stoploss.info['name'], self.stoploss.ref))
                          self.close(name='Trend Change - take profit...')
                          self.stoploss = None
      
                      if self.parent_order:  # something was pending, cancelling parent cancels stoploss too
                          self.cancel(self.parent_order)
                          print('{} {} canceled.'.format(self.parent_order.info['name'], self.parent_order.ref))
                          self.parent_order = None
                          self.stoploss = None
      
                      # Now I am no more in a position
                      amount_to_invest = (self.p.order_percentage * self.broker.cash)
                      self.size = math.floor(amount_to_invest / self.data.close)
      
                      if action == 'long':
                          self.parent_order = self.buy(size=self.size, exectype=bt.Order.Market, transmit=False, valid=None)
                          self.stoploss = self.sell(price=self.data.close, exectype=bt.Order.Stop, size=self.parent_order.size,
                                                    parent=self.parent_order, transmit=True, valid=None)
                          self.parent_order.addinfo(name='Parent Long Order')
                          self.stoploss.addinfo(name='Child Long Stop Loss Order')
      
                      elif action == 'short':
                          self.parent_order = self.sell(size=self.size, exectype=bt.Order.Market, transmit=False, valid=None)
                          self.stoploss = self.buy(price=self.data.close, exectype=bt.Order.Stop, size=self.parent_order.size,
                                                   parent=self.parent_order, transmit=True, valid=None) 
                          self.parent_order.addinfo(name='Parent Short Order')
                          self.stoploss.addinfo(name='Child Short Stop Loss Order')
      
                      print('=' * 50, 'CREATE ORDER', '=' * 50)
                      print('{} CREATE, REF {}, CURRENT PX: {:.5f}, {} AT {:.5f}, STOPLOSS AT {:.5f}'.format(
                            self.parent_order.info['name'], self.parent_order.ref, self.data.close[0],
                            'LONG' if 'Long' in self.parent_order.info['name'] else 'SHORT',
                            self.data.close[0], self.data.close[-1]))
                      print('=' * 114)
      
                  elif action == 'not sure yet':
                      print('not sure what action to take')
                  else:
                      print('no action2 - meaning regular trading')
      
              else:  # past time 3pm, not trading anymore, look to close position
                  # print('Last hour or Closed....')
                  if self.position:
                      if times_upfx(self.data.datetime.time(0)):  # 15:46 times up look to just close.
                          self.cancel(self.stoploss)
                          print('{} {} canceled.'.format(self.stoploss.info['name'], self.stoploss.ref))
                          self.close(name='Times Up, Close final position')
                          self.stoploss = None
                          self.parent_order = None
                      else:  # 15:01 to 15:46 look for next turning point to sell so maximise profit
                          if action == 'long' or action == 'short':
                              self.cancel(self.stoploss)
                              print('{} {} canceled.'.format(self.stoploss.info['name'], self.stoploss.ref))
                              self.close(name='Trend Change, Take profit')
                              self.stoploss = None
                              self.parent_order = None
      def main():
          cerebro = bt.Cerebro(stdstats=True)  
          # Add a strategy
          cerebro.addstrategy(BaseStrategy)
      
          df = pd.read_csv('datas\\EURUSD2019Jan.csv', sep=',', header=0, index_col=0, parse_dates=True)
         
          # Create a Data Feed and add to cerebro
          data = bt.feeds.PandasData(dataname=df, timeframe=bt.TimeFrame.Minutes, compression=1)
          cerebro.adddata(data, name='data')
          # cerebro.resampledata(data, timeframe=bt.TimeFrame.Minutes, compression=1)
          cerebro.resampledata(data, timeframe=bt.TimeFrame.Minutes, compression=240, name='data1')
      
          cerebro.broker.setcash(10000.0)  
          cerebro.broker.setcommission(commission=0.0001) 
      
          strat = cerebro.run(maxcpus=3)  
          print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())  
      
          cerebro.plot(style='candlestick', barup='green', bardown='red', fmt_x_ticks='%d-%b %H:%M', fmt_x_data='%d-%b %H:%M', volume=False)  # Plot the result
      
      
      if __name__ == '__main__':
          main()
      
      

      This is what I get. I only need the smaller timeframe plotted with its indicators. Hope a kind soul can help me out here. Thanks.

      Figure_0.png

      posted in General Code/Help
      J T
      J T

    Latest posts made by J T

    • Oandav20 separate trail order

      Hi

      I like to ask if anyone has experience with creating a single trail order in oanda. I tried the below but got the following error:

      self.long_trailstop = self.sell(price=trail_stop_px, exectype=bt.Order.StopTrail, size=stop_size, trailamount=self.ATR_at_exe * 1.5, id='888')
      but the above does not work.
      

      I got an error which bascially is an error when issuing stoptrail orders without brackets.

      okwargs['type'] = self._ORDEREXECS[order.exectype]
      KeyError: 5
      

      Will some kind souls help me out with this?

      Thanks alot!

      posted in General Code/Help
      J T
      J T
    • RE: btoandav20 sizers

      Re: btoandav20 sizers

      changed to this:

      self.exe_size = btoandav20.sizers.OandaV20Risk(risk_percents=2, stoploss=sl_pips).getsizing(data=self.data0.close[0], isbuy=True)
      

      which returns error:

      comminfo = self.broker.getcommissioninfo(data)
      AttributeError: 'NoneType' object has no attribute 'getcommissioninfo'
      

      and added this in runstrat:

      comminfo = forexSpreadCommisionScheme(spread=3, acc_counter_currency=False)
      cerebro.broker.addcommissioninfo(comminfo)
      

      Error is still the same.

      comminfo = self.broker.getcommissioninfo(data)
      AttributeError: 'NoneType' object has no attribute 'getcommissioninfo'
      
      posted in Indicators/Strategies/Analyzers
      J T
      J T
    • btoandav20 sizers

      Hi !
      Does anyone have experience using the btoandav20.sizers.OandaV20Risk ?

      I think it needs to run in strategy class, next method and not in the run strat right?
      I say this because this sizer requires stoploss pips which is dynamic.

      I tried this which probably is rubbish.

      # in Strategy class I have params dict(sizer = None)
      # and in initi the below. I am just following bt docs. 
      def __init__(self):
       if self.p.sizer is not None:
                  self.sizer = self.p.sizer
      
      def next(self):
              if self.one_test_trade:
                  globe.action = 'long'
                  self.one_test_trade = False
                  price = self.data0.close[0] - 0.0001
                  sl_px = price - self.atr[0] * 1.5
                  sl_pips = abs(sl_px - price) / 0.0001
                  limit_px = price + self.atr[0]
                  self.ATR_at_exe = self.atr[0]
      
      self.exe_size = self.sizer.getsizing(btoandav20.sizers.OandaV20Risk, risk_percents=2, stoploss=sl_pips) 
      

      the above returns error although risk_percents is a valid param for this sizer:

      TypeError: getsizing() got an unexpected keyword argument 'risk_percents'
      

      Would some kind souls pls help me with some sample code how this is to be used?

      source code of the sizer is here: https://github.com/ftomassetti/backtrader-oandav20/blob/master/btoandav20/sizers/oandav20sizer.py

      Thanks a miliion!

      posted in Indicators/Strategies/Analyzers
      J T
      J T
    • Oanda setcommision and size

      Hi ! Hoping everyone is keeping safe in these times.

      Need some help with forex oanda commision. I cannot fully understand the docs.
      The commission is in the spread, but under a million shares traded, the commision is $50. Lets say $5 per trade for easy calculation.
      Margin for my country is 5% and so I believe leverage is 20x.

      Can I ask how do you set cerebro broker is this case?

      #This code cannot work... meaning no orders executed, beleive commtype=bt.CommInfo.COMM_FIXED is the issue?
      cerebro.broker.setcommission(leverage=20, mult=1.0, stocklike=False, automargin=0.05, commtype=bt.CommInfoBase.COMM_FIXED, commission=5.0)
      

      a few more questions

      1. whats the difference between mult and leverage?
      2. how do you set the size to buy. Should size include the 20x leverage?
        as objective is to trade live on oanda, hence hoping to get this right
      amount_to_invest = (0.5 * self.broker.cash)
      self.size_to_exe = math.floor(amount_to_invest / self.data0.close)
      

      Thanks a million!

      posted in General Code/Help
      J T
      J T
    • both buy and sell orders executed on same bar

      Hi Guys,
      I like some advice from more experienced guys. Trying to see how to avoid this.

      Testing a breakout strategy.
      at min 10, I place a stop order to buy at 2.00, place a stoploss at A
      at min 15 I place a stop order to sell at 1.50, place a stoploss at B
      at min 17, both stop orders got triggered on the same bar (when the price movement is this big) and they close out the position.

      Earlier, I experienced both orders triggered, but on different bar. I am able to
      add code in if order.status in [order completed], if I have gone into 1 position, I just cancel the other pending. But happening on the same bar left me scratching my head.

      Any ideas or suggestions to workaround this?

      posted in General Discussion
      J T
      J T
    • RE: Questions on tradeid

      Re: Questions on tradeid

      this is the docs: What I want to do is to tag the new stop loss to the open position. If there are other ways of implementation, kindly share with me! Thanks!

      IBBroker - Trading Live
      Note

      Following a request a tradeid functionality was implemented in the broker simulation available in backtrader. This allows to keep track of trades being executed in paralled on the same asset correctly allocating commissions to the appropriate tradeid

      Such notion is not supported in this live broker because commissions are reported by the broker at times at which it would be impossible to separate them for the different tradeid values.

      tradeid can still be specified but it makes no longer sense.

      posted in General Discussion
      J T
      J T
    • Questions on tradeid

      Hi
      I have read the tradeid mentioned in live trading but I do not fully understand.
      The aim is to trade live using IB. And I am trying to implement a dynamic change of stop loss.
      I sent the order in using a parent order with stop loss and limit. Then I want to change the stoploss and limit later as the trade goes on.

      I have not been able to successfully do this as cancelling the old stoploss and then adding a new one, does not tag it to the open trade. The stop loss is like a whole new order on its own.

      I have searched through the forum and find maybe I can do a tradeid = tradeid in:

      self.cancel(self.long_stoploss)
      self.long_stoploss = self.sell(tradeid=tradeid, exectype=bt.Order.StopTrail, size=self.position.size, trailpercent=0.0005, transmit=False, valid=None)
      
      self.long_stoplimit = self.sell(exectype=bt.Order.StopTrailLimit, size=self.position.size, trailpercent=0.0005, plimit=plimit, parent=self.long_stoploss, transmit=True, valid=None)
      

      But can this be taken to live trading in IB as something that was mentioned in the docs about tradeid?

      posted in General Discussion
      J T
      J T
    • indicator on resampled data

      Hi
      I am having some trouble on resampled data and custom indicator.

      class BaseStrategy(bt.Strategy): 
          def __init__(self):
              self.zz = ZigZag(self.data0, period=2, retrace=0.05, minbars=2)
          
          def next(self):
              print('{},{:.5f},{:.5f},{:.5f}'.format(self.data0.datetime.datetime(0),
                     self.zz.l.zigzag[0], self.zz.l.last_high[0], self.zz.l.last_low[0]))    
      
      def main():
          cerebro = bt.Cerebro(oldtrades=True)
          cerebro.addstrategy(BaseStrategy)
          df = pd.read_csv('datas\\EURUSD.csv', sep=',', header=0, index_col=0, parse_dates=True)
          data0 = bt.feeds.PandasData(dataname=df, timeframe=bt.TimeFrame.Minutes)
          cerebro.adddata(data0)
          cerebro.resampledata(data0, timeframe=bt.TimeFrame.Minutes, compression=240)
          cerebro.run(maxcpus=3, stdstats=False, runonce=True)
      
      if __name__ == '__main__':
          main()
      

      Simple enough code that passes in 2 datas. Run an indicator on init and run it on data0 and print out the line values in the next() method. However, the above code does not work. The zz.l.zigzag[0] are always nan. If I remove resampleddata() line, it works and it works with only this single change.
      Code of the indicator is below, courtesy of Nikolai. https://community.backtrader.com/topic/1771/zigzag-indicator-for-live-trading/25

      class ZigZag(bt.ind.PeriodN):  # periodN controls number lines to skip i think, so period is 2 so curr_idx start at 2
          lines = ('trend', 'last_high', 'last_low', 'zigzag',)
      
          plotinfo = dict(
              subplot=False,
              plotlinelabels=True, plotlinevalues=True, plotvaluetags=True,
          )
      
          plotlines = dict(
              trend=dict(_plotskip=True),
              last_high=dict(color='green', ls='-', _plotskip=True),
              last_low=dict(color='black', ls='-', _plotskip=True),
              zigzag=dict(_name='zz', color='lightblue', ls='-', _skipnan=True),  # linewidth=2.0, ls='-',
          )
      
          params = (dict(period=2, retrace=0.25, minbars=2, _autoplot=True))
      
          def __init__(self):
              super(ZigZag, self).__init__()
      
              assert self.p.retrace > 0, 'Retracement should be above zero.'
              assert self.p.minbars >= 0, 'Minimal bars should be >= zero.'
      
              self.ret = self.data.close * self.p.retrace / 100
              self.minbars = self.p.minbars
              self.count_bars = 0
              self.last_pivot_t = 0
              self.last_pivot_ago = 0
      
          def prenext(self):  # prenext called before the minimum period required for the indicator, this case 2. So called just once.
              self.l.trend[0] = 0
              self.l.last_high[0] = self.data.high[0]
              self.l.last_low[0] = self.data.low[0]
              self.l.zigzag[0] = (self.data.high[0] + self.data.low[0]) / 2
              # print('prenext: ', self.l.trend[0], self.l.last_high[0], self.l.last_low[0], self.l.zigzag[0] )
      
          def next(self):  # this starts at 2nd line of data
      
              curr_idx = len(self.data)
              self.ret = self.data.close[0] * self.p.retrace / 100
              self.last_pivot_ago = curr_idx - self.last_pivot_t
              self.l.trend[0] = self.l.trend[-1]
              self.l.last_high[0] = self.l.last_high[-1]
              self.l.last_low[0] = self.l.last_low[-1]
              self.l.zigzag[0] = float('nan')
              # print('next1:',curr_idx,self.data.close[0], self.ret, self.last_pivot_t,self.last_pivot_ago,self.l.trend[0],self.l.last_high[0],self.l.last_low[0])
      
              # Search for trend
              if self.l.trend[-1] == 0:
                  if self.l.last_low[0] < self.data.low[0] and self.l.last_high[0] < self.data.high[0]:  # if current bar is higher than last high and last low
                      self.l.trend[0] = 1
                      self.l.last_high[0] = self.data.high[0]
                      self.last_pivot_t = curr_idx
      
                  elif self.l.last_low[0] > self.data.low[0] and self.l.last_high[0] > self.data.high[0]:  # if current bar is higher than last high and last low
                      self.l.trend[0] = -1
                      self.l.last_low[0] = self.data.low[0]
                      self.last_pivot_t = curr_idx
      
              # Up trend
              elif self.l.trend[-1] == 1:
                  if self.data.high[0] > self.l.last_high[-1]:
                      self.l.last_high[0] = self.data.high[0]
                      self.count_bars = self.minbars
                      self.last_pivot_t = curr_idx
      
                  elif self.count_bars <= 0 and self.l.last_high[0] - self.data.low[0] > self.ret and self.data.high[0] < self.l.last_high[0]:
                      self.l.trend[0] = -1
                      self.count_bars = self.minbars
                      self.l.last_low[0] = self.data.low[0]
                      self.l.zigzag[-self.last_pivot_ago] = self.l.last_high[0]
                      self.last_pivot_t = curr_idx
      
                  elif self.count_bars < self.minbars and self.data.close[0] < self.l.last_low[0]:
                      self.l.trend[0] = -1
                      self.count_bars = self.minbars
                      self.l.last_low[0] = self.data.low[0]
                      self.l.zigzag[-self.last_pivot_ago] = self.l.last_high[0]
                      self.last_pivot_t = curr_idx
      
              # Down trend
              elif self.l.trend[-1] == -1:
                  if self.data.low[0] < self.l.last_low[-1]:
                      self.l.last_low[0] = self.data.low[0]
                      self.count_bars = self.minbars
                      self.last_pivot_t = curr_idx
      
                  elif self.count_bars <= 0 and self.data.high[0] - self.l.last_low[0] > self.ret and self.data.low[0] > self.l.last_low[0]:
                      self.l.trend[0] = 1
                      self.count_bars = self.minbars
                      self.l.last_high[0] = self.data.high[0]
                      self.l.zigzag[-self.last_pivot_ago] = self.l.last_low[0]
                      self.last_pivot_t = curr_idx
      
                  elif self.count_bars < self.minbars and self.data.close[0] > self.l.last_high[-1]:
                      self.l.trend[0] = 1
                      self.count_bars = self.minbars
                      self.l.last_high[0] = self.data.high[0]
                      self.l.zigzag[-self.last_pivot_ago] = self.l.last_low[0]
                      self.last_pivot_t = curr_idx
      
              # Decrease minbars counter
              self.count_bars -= 1
      

      Need some advice why this is happening, even though I have specified that the indicator run on data0. And how can I change the indicator code so that it can run even if resampled data is passed (no need to run on resampled data, but even just running on lower timeframe data would be great!) ?

      Thanks

      posted in Indicators/Strategies/Analyzers
      J T
      J T
    • RE: Flipping from long to short on the same bar

      @ab_trader i am in a dilema on this too. With the way backtrader is designed its not possible to do it right? Next() has to go to notify_order().

      I mean i can close my position and then jump straight to a new buy. But my cash available is less because the trade that was closed have not been 'processed'.

      posted in General Discussion
      J T
      J T
    • RE: How to create as sell order @ high price

      Self.data.high?

      posted in General Discussion
      J T
      J T