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/

    Noob questions on RSI trading strategies from multiple datafeeds and close orders

    General Code/Help
    2
    5
    1236
    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.
    • B
      BernardLin last edited by BernardLin

      Hi I am a noob on Python and I just started learning about backtrader, I would appreciate some help greatly if someone can take a look at my code and give me some advice.

      I want to backtest a very simple strategy, that is, if there is no open position, then place buy orders when both RSIm30 and RSIm60 are below 30, place sell orders when they are both above 70; while there are open positions, close the long positions when RSIm30 and RSIm60 are above 70, close the short positions when they are below 30.

      I want to realize this simple logic in backtrader so that I can backtest more complicated ones in future, however I am having problems with it now. Below is my code:

      # -*- coding: utf-8 -*-
      """
      Created on Tue Aug 28 21:06:23 2018
      
      @author: lenovo
      """
      
      import backtrader as bt
      import backtrader.feeds as btfeeds
      import os
      import datetime
      import sys  # To find out the script name (in argv[0])
      
      class TestStrategy(bt.Strategy):
      
          def log(self, txt, dt=None):
              dt = dt or self.datas[0].datetime.date(0)
              print('%s, %s' % (dt.isoformat(), txt))
      
          def __init__(self):
              self.dataclose = self.datas[0].close
              self.order = None
              self.buyprice = None
              self.buycomm = None
      
              self.rsim30=bt.indicators.RSI(self.data.close, period=14)
              self.rsim60=bt.indicators.RSI(self.data1.close, period=14)
      
          def notify_order(self, order):
              if order.status in [order.Submitted, order.Accepted]:
                  # Buy/Sell order submitted/accepted to/by broker - Nothing to do
                  return
      
              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
                  else:
                      self.log('SELL EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' %
                               (order.executed.price,
                                order.executed.value,
                                order.executed.comm))
      
                  self.bar_executed = len(self)
      
              elif order.status in [order.Canceled, order.Margin, order.Rejected]:
                  self.log('Order Canceled/Margin/Rejected')
      
              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): # input trade logid in this function
              self.log('Close, %.2f' % self.dataclose[0])
      
              if self.order:
                  return
      
              if not self.position:
      
                  if self.rsim30<30 and self.rsim60<30:
      
                      self.log('BUY CREATE, %.2f' % self.dataclose[0])
                      self.order = self.buy()
      
                  elif self.rsim30>70 and self.rsim60>70:
                      self.log('SELL CREATE, %.2f' % self.dataclose[0])
                      self.order = self.sell()
              
              if self.position:
                  if self.rsim30>70 and self.rsim60>70:
                      self.p.exectype == 'Close'
                      self.buy(exectype=bt.Order.Close)
                      self.log('BUY CREATE, exectype Close, price %.2f' %
                               self.data.close[0])
                  if self.rsim30<30 and self.rsim60<30:
                      self.p.exectype == 'Close'
                      self.sell(exectype=bt.Order.Close)
      
                      self.log('SELL CREATE, exectype Close, price %.2f' %
                               self.data.close[0])
      
      
      
      if __name__ == '__main__':
          cerebro = bt.Cerebro()
          cerebro.addstrategy(TestStrategy)
          modpath = os.path.dirname(os.path.abspath(sys.argv[0]))
          datapath = os.path.join(modpath, 'EURUSD30.csv')
          datapath1 = os.path.join(modpath, 'EURUSD60.csv')
          # Create a Data Feed
          data = btfeeds.GenericCSVData(
              dataname=datapath,
              fromdate=datetime.datetime(2018, 1, 1),
              dtformat=('%Y.%m.%d'),
              tmformat=('%H:%M'),
              datetime=0,
              time=1,
              high=3,
              low=4,
              open=2,
              close=5,
              volume=6,
              timeframe= bt.TimeFrame.Minutes,
              compression= 30
          )
          data1 = btfeeds.GenericCSVData(
              dataname=datapath1,
              fromdate=datetime.datetime(2018, 1, 1),
              dtformat=('%Y.%m.%d'),
              tmformat=('%H:%M'),
              datetime=0,
              time=1,
              high=3,
              low=4,
              open=2,
              close=5,
              volume=6,
              timeframe= bt.TimeFrame.Minutes,
              compression= 30
          )
      
          cerebro.adddata(data)
      
          cerebro.broker.setcash(10000.0)
      
          cerebro.addsizer(bt.sizers.FixedSize, stake=0.05)
      
          cerebro.broker.setcommission(commission=0.00)
      
          print('Starting Balance: %.2f' % cerebro.broker.getvalue())
      
          cerebro.run()
      
          print('Final Balance: %.2f' % cerebro.broker.getvalue())
      
          cerebro.plot()
      

      When I run it, needless to say it went terribly wrong, here is the error message I got :

      runfile('C:/Users/lenovo/Desktop/python_work/backtest1.py', wdir='C:/Users/lenovo/Desktop/python_work')
      Starting Balance: 10000.00
      Traceback (most recent call last):
      
        File "<ipython-input-3-140e68c3c26b>", line 1, in <module>
          runfile('C:/Users/lenovo/Desktop/python_work/backtest1.py', wdir='C:/Users/lenovo/Desktop/python_work')
      
        File "D:\Anaconda3\lib\site-packages\spyder\utils\site\sitecustomize.py", line 705, in runfile
          execfile(filename, namespace)
      
        File "D:\Anaconda3\lib\site-packages\spyder\utils\site\sitecustomize.py", line 102, in execfile
          exec(compile(f.read(), filename, 'exec'), namespace)
      
        File "C:/Users/lenovo/Desktop/python_work/backtest1.py", line 144, in <module>
          cerebro.run()
      
        File "D:\Anaconda3\lib\site-packages\backtrader\cerebro.py", line 1127, in run
          runstrat = self.runstrategies(iterstrat)
      
        File "D:\Anaconda3\lib\site-packages\backtrader\cerebro.py", line 1217, in runstrategies
          strat = stratcls(*sargs, **skwargs)
      
        File "D:\Anaconda3\lib\site-packages\backtrader\metabase.py", line 88, in __call__
          _obj, args, kwargs = cls.doinit(_obj, *args, **kwargs)
      
        File "D:\Anaconda3\lib\site-packages\backtrader\metabase.py", line 78, in doinit
          _obj.__init__(*args, **kwargs)
      
        File "C:/Users/lenovo/Desktop/python_work/backtest1.py", line 27, in __init__
          self.rsim60=bt.indicators.RSI(self.data1.close, period=14)
      
        File "D:\Anaconda3\lib\site-packages\backtrader\lineseries.py", line 461, in __getattr__
          return getattr(self.lines, name)
      
      AttributeError: 'Lines_LineSeries_LineIterator_DataAccessor_Strateg' object has no attribute 'data1'
      

      Can someone just take a look at it and let me know how I should change it to make the backtest go through? Thanks immensely!

      1 Reply Last reply Reply Quote 0
      • A
        ab_trader last edited by

        Please format code and outputs. Really hard to read.

        • If my answer helped, hit reputation up arrow at lower right corner of the post.
        • Python Debugging With Pdb
        • New to python and bt - check this out
        1 Reply Last reply Reply Quote 0
        • B
          BernardLin last edited by

          Hi, sorry about that, new to this community, still trying to get the hang of it, I just edited my question and I think it looks better now.

          1 Reply Last reply Reply Quote 0
          • A
            ab_trader last edited by

            You didin't add data1 into the system but try to get it's values. Need to add one more adddata statement.

            • If my answer helped, hit reputation up arrow at lower right corner of the post.
            • Python Debugging With Pdb
            • New to python and bt - check this out
            1 Reply Last reply Reply Quote 0
            • B
              BernardLin last edited by BernardLin

              Thanks a lot! I will try that! Meanwhile, are my RSI definitions and positions-close syntax correct in the code? I am terribly worried that there may be some other mistakes in my code, for instance, I don't think I used this line

                  def __init__(self):
                      self.dataclose = self.datas[0].close
              

              anywhere in the file (it comes from the template), not even in the RSI definitions, this line seems to have been used in defining the SMA in the original template, I hope I am not making a cock-up here by ignoring it.

              1 Reply Last reply Reply Quote 0
              • 1 / 1
              • First post
                Last post
              Copyright © 2016, 2017, 2018, 2019, 2020, 2021 NodeBB Forums | Contributors