Backtrader Community

    • 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/

    Strategy inheritance

    General Code/Help
    2
    10
    3853
    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.
    • Maxim Korobov
      Maxim Korobov last edited by

      I made 3 simple strategies, now I want to move shared code into BaseStrategy with 3 subclasses.

      class BaseStrategy(bt.Strategy):
      	def __init__(self):
      		self.xz = "test"
      		self.data = "test"
      ...
      class RSISimple(BaseStrategy):
      	def next(self):
      		print(self.xz)
      

      Error appeared:

      Traceback (most recent call last):
        File "D:/Projects/trading-bot/main/lab/backtrader/netflix.py", line 74, in <module>
      	strategies = back_trader.run()
        File "C:\Users\Home\AppData\Local\Programs\Python\Python35-32\lib\site-packages\backtrader\cerebro.py", line 809, in run
      	runstrat = self.runstrategies(iterstrat)
        File "C:\Users\Home\AppData\Local\Programs\Python\Python35-32\lib\site-packages\backtrader\cerebro.py", line 926, in runstrategies
      	self._runonce(runstrats)
        File "C:\Users\Home\AppData\Local\Programs\Python\Python35-32\lib\site-packages\backtrader\cerebro.py", line 1276, in _runonce
      	strat._oncepost(dt0)
        File "C:\Users\Home\AppData\Local\Programs\Python\Python35-32\lib\site-packages\backtrader\strategy.py", line 269, in _oncepost
      	self.nextstart()  # only called for the 1st value
        File "C:\Users\Home\AppData\Local\Programs\Python\Python35-32\lib\site-packages\backtrader\lineiterator.py", line 324, in nextstart
      	self.next()
        File "D:\Projects\trading-bot\main\lab\strategy\rsi_simple.py", line 54, in next
      	print(self.xz)
        File "C:\Users\Home\AppData\Local\Programs\Python\Python35-32\lib\site-packages\backtrader\lineseries.py", line 429, in __getattr__
      	return getattr(self.lines, name)
      AttributeError: 'Lines_LineSeries_LineIterator_DataAccessor_Strateg' object has no attribute 'xz'
      

      Indeed debugger shows that there is no xz or data attributes in RSISimple instance. Even more

      print(self.__class__)
      

      shows MetaStrategy, not my BaseStrategy.

      How to inherit strategies right?

      1 Reply Last reply Reply Quote 0
      • B
        backtrader administrators last edited by

        Your code must be a lot more complicated than the snippet shown above which has been for sure typed manually, because inheritance for strategies is not being intercepted.

        The following code works 100% and is just like what you in theory have done above.

        class MACrossOver1(bt.Strategy):
            params = (
                # period for the fast Moving Average
                ('fast', 10),
                # period for the slow moving average
                ('slow', 30),
                # moving average to use
                ('_movav', bt.ind.MovAv.SMA)
            )
        
            def __init__(self):
                sma_fast = self.p._movav(period=self.p.fast)
                sma_slow = self.p._movav(period=self.p.slow)
        
                self.buysig = bt.ind.CrossOver(sma_fast, sma_slow)
                self.xz = 1
        
            def next(self):
                if self.position.size:
                    if self.buysig < 0:
                        self.sell()
        
                elif self.buysig > 0:
                    self.buy()
        
        
        class MACrossOver(MACrossOver1):
            def next(self):
                if self.xz:
                    pass
        
                super(MACrossOver, self).next()
        
        1 Reply Last reply Reply Quote 0
        • Maxim Korobov
          Maxim Korobov last edited by Maxim Korobov

          Seems like the problem appears when two init methods we have - in base and subclassed strategy:

          import backtrader as bt
          
          
          class MACrossOver1(bt.Strategy):
          	params = (
          		# period for the fast Moving Average
          		('fast', 10),
          		# period for the slow moving average
          		('slow', 30),
          		# moving average to use
          		('_movav', bt.ind.MovAv.SMA)
          	)
          
          	def __init__(self):
          		self.xz = 1
          
          	def next(self):
          		if self.position.size:
          			if self.buysig < 0:
          				self.sell()
          
          		elif self.buysig > 0:
          			self.buy()
          
          
          class MACrossOver(MACrossOver1):
          
          	def __init__(self):
          		sma_fast = self.p._movav(period=self.p.fast)
          		sma_slow = self.p._movav(period=self.p.slow)
          
          		self.buysig = bt.ind.CrossOver(sma_fast, sma_slow)
          
          	def next(self):
          		if self.xz:
          			pass
          
          		super(MACrossOver, self).next()
          
          
          if __name__ == '__main__':
          	back_trader = bt.Cerebro()
          	back_trader.adddata(
          		bt.feeds.YahooFinanceData(dataname='NFLX', period='h', reverse=True,
          								  fromdate=bt.datetime.datetime(2016, 1, 1), todate=bt.datetime.datetime(2016, 12, 31)
          								  )
          	)
          	back_trader.addstrategy(MACrossOver)
          	back_trader.run()
          

          Traceback:

          Traceback (most recent call last):
            File "D:/Projects/trading-bot/main/lab/strategy/xz_test.py", line 53, in <module>
          	back_trader.run()
            File "C:\Users\Home\AppData\Local\Programs\Python\Python35-32\lib\site-packages\backtrader\cerebro.py", line 809, in run
          	runstrat = self.runstrategies(iterstrat)
            File "C:\Users\Home\AppData\Local\Programs\Python\Python35-32\lib\site-packages\backtrader\cerebro.py", line 928, in runstrategies
          	self._runonce(runstrats)
            File "C:\Users\Home\AppData\Local\Programs\Python\Python35-32\lib\site-packages\backtrader\cerebro.py", line 1278, in _runonce
          	strat._oncepost(dt0)
            File "C:\Users\Home\AppData\Local\Programs\Python\Python35-32\lib\site-packages\backtrader\strategy.py", line 269, in _oncepost
          	self.nextstart()  # only called for the 1st value
            File "C:\Users\Home\AppData\Local\Programs\Python\Python35-32\lib\site-packages\backtrader\lineiterator.py", line 324, in nextstart
          	self.next()
            File "D:/Projects/trading-bot/main/lab/strategy/xz_test.py", line 39, in next
          	if self.xz:
            File "C:\Users\Home\AppData\Local\Programs\Python\Python35-32\lib\site-packages\backtrader\lineseries.py", line 429, in __getattr__
          	return getattr(self.lines, name)
          AttributeError: 'Lines_LineSeries_LineIterator_DataAccessor_Strateg' object has no attribute 'xz'
          
          1 Reply Last reply Reply Quote 0
          • Maxim Korobov
            Maxim Korobov last edited by Maxim Korobov

            Sorry, I forgot to init base class:

            ...
            class MACrossOver(MACrossOver1):

            	def __init__(self):
            		MACrossOver1.__init__(self)
            		sma_fast = self.p._movav(period=self.p.fast)
            		sma_slow = self.p._movav(period=self.p.slow)
            
            		self.buysig = bt.ind.CrossOver(sma_fast, sma_slow)
            

            ...

            Same for the first example:

            BaseStrategy.__init__(self)
            
            1 Reply Last reply Reply Quote 0
            • B
              backtrader administrators last edited by

              It's good to know there is no problem.

              The base hierarchy in backtrader is designed to avoid having to call __init__ from the subclasses. That means that subclassing from Strategy doesn't need to call any base class __init__.

              Background processing is done by means of controlling the __call__ method of metaclasses.

              You may want to have a look at this python package:

              • pypy - metaframe
              • github - metaframe
              • documentation - metaframe

              If your own hierarchy defines __init__ there is no workaround to avoid calling it from subclasses.

              Note: there actually is by scanning the classes and automagically invoking the methods without user intervention, but that would also require user cooperation, because the user must not call it. And it breaks some patterns like when some work has to be done before invoking the base class __init__

              1 Reply Last reply Reply Quote 1
              • Maxim Korobov
                Maxim Korobov last edited by

                Now I have to implement abstract strategy using ABC module:

                According to some recepies in Python to define Abstract class we should declare that it's abcmeta like this:

                class BaseStrategy(metaclass=ABCMeta):
                

                But what if this class is already subclassed from other class?

                class BaseStrategy(bt.Strategy):
                

                Use other options (interfaces, exception in base class) instead?

                Note that I tried:

                class BaseStrategy(bt.Strategy, metaclass=ABCMeta):
                

                With such traceback:

                Traceback (most recent call last):
                  File "D:/Projects/trading-bot/main/lab/backtrader/netflix.py", line 13, in <module>
                	from main.lab.strategy import RSISimple, RSIBuySell, SMACross, SMA_RSI, HolyGrail, MACD_ADX, BBands
                  File "D:\Projects\trading-bot\main\lab\strategy\__init__.py", line 1, in <module>
                	from .rsi_simple import *
                  File "D:\Projects\trading-bot\main\lab\strategy\rsi_simple.py", line 3, in <module>
                	from main.lab.strategy.base_strategy import BaseStrategy
                  File "D:\Projects\trading-bot\main\lab\strategy\base_strategy.py", line 6, in <module>
                	class BaseStrategy(bt.Strategy, metaclass=ABCMeta):
                TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases
                

                Possible that bt.Strategy uses abstract classes too.

                Asked on SO too: http://stackoverflow.com/questions/41659630/abstract-class-which-is-subclass-of-something-else/41659690#41659690

                1 Reply Last reply Reply Quote 0
                • B
                  backtrader administrators last edited by

                  backtrader doesn't use abstract classes but it relies heavily on metaclasses and metaprogramming

                  You are trying to simply replace the entire metaclass hierarchy and python is complaining you cannot replace an existing metaclass hierarchy suddenly at will.

                  1 Reply Last reply Reply Quote 0
                  • Maxim Korobov
                    Maxim Korobov last edited by

                    Roger. Any way to solve it?

                    1 Reply Last reply Reply Quote 0
                    • B
                      backtrader administrators last edited by

                      Don't apply abstract classes.

                      1 Reply Last reply Reply Quote 0
                      • Maxim Korobov
                        Maxim Korobov last edited by

                        Hopefully solved from the python side, not backtrader library. See answer in SO about one more stub class.
                        Overall abstract classes makes me a little bit of pain in python. Maybe sometimes I'll master metaclasses :)
                        Thanks!

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