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/

    CCI on other indicator

    General Code/Help
    3
    10
    3731
    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.
    • H
      Horizion last edited by

      Hey guys,

      I'm trying to put a CCI on the +DI and -DI of an ADX indicator, and implement them in my strategy but I get an error with my code: "array out of range" here

      line 17, in init
      self.CCIplusDI = bt.indicators.CommodityChannelIndex(self.ADX.DIplus[0], period=20)

      My code is the following

      import backtrader as bt
      from  datetime import datetime
      
      class firstStrategy(bt.Strategy):
      
          def log(self, txt, dt=None):
              ''' Logging function fot this strategy'''
              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.rsi = bt.indicators.RSI_SMA(self.data.close, period=14)
              self.ADX = bt.indicators.DirectionalMovementIndex(self.data, period=12)
              self.CCIplusDI = bt.indicators.CommodityChannelIndex(self.ADX.DIplus[0], period=20)
              self.CCIminusDI = bt.indicators.CommodityChannelIndex(self.ADX.DIminus[0], period=20)
      
          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
      
              # Check if an order has been completed
              # Attention: broker could reject order if not enougth cash
              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:  # Sell
                      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')
      
              # 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):
              self.log('Close, %.2f' % self.dataclose[0])
              if self.order:
                  return
      
              # Check if we are in the market
              if not self.position:
      
                  # Not yet ... we MIGHT BUY if ...
                  if self.rsi < 30 and self.CCIplusDI[-1] > 100 and self.CCIminusDI[-1] < 100:
                      self.log('BUY CREATE, %.2f' % self.dataclose[0])
                      self.order = self.buy()
              else:
      
                  if self.rsi > 70 and self.CCIplusDI[-1] < 100 and self.CCIminusDI[-1] > 100:
                      self.log('SELL CREATE, %.2f' % self.dataclose[0])
                      self.order = self.sell()
      if __name__ == '__main__':
          # Create a cerebro entity
          cerebro = bt.Cerebro()
          startcash = 10000
      
          # Add a strategy
          cerebro.addstrategy(firstStrategy)
      
          # Create a Data Feed
          data = bt.feeds.YahooFinanceData(dataname='BNO', fromdate=datetime(2016, 1, 1), todate=datetime(2017, 11, 25))
      
           # Add the Data Feed to Cerebro
          cerebro.adddata(data)
      
          # Set our desired cash start
          cerebro.broker.setcash(startcash)
      
          # Set the commission
          cerebro.broker.setcommission(commission=0.0005)
      
          cerebro.run()
          # Print out the starting conditions
          print('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue())
      
          # Get final portfolio Value
          portvalue = cerebro.broker.getvalue()
          pnl = portvalue - startcash
      
          # Print out the final result
          print('Final Portfolio Value: ${}'.format(portvalue))
          print('P/L: ${}'.format(pnl))
      
          # Finally plot the end results
          cerebro.plot()
      
      P 1 Reply Last reply Reply Quote 0
      • A
        ab_trader last edited by ab_trader

        I assume it should with no [0] in the _init()':

                self.CCIplusDI = bt.indicators.CommodityChannelIndex(self.ADX.DIplus, period=20)
                self.CCIminusDI = bt.indicators.CommodityChannelIndex(self.ADX.DIminus, period=20)
        

        but it should be indexing in the next():

                if not self.position:
        
                    # Not yet ... we MIGHT BUY if ...
                    if self.rsi[whatever_index_you_need] < 30 and self.CCIplusDI[-1] > 100 and self.CCIminusDI[-1] < 100:
                        self.log('BUY CREATE, %.2f' % self.dataclose[0])
                        self.order = self.buy()
                else:
        
                    if self.rsi[whatever_index_you_need] > 70 and self.CCIplusDI[-1] < 100 and self.CCIminusDI[-1] > 100:
                        self.log('SELL CREATE, %.2f' % self.dataclose[0])
                        self.order = self.sell()
        
        • 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
        H 1 Reply Last reply Reply Quote 2
        • H
          Horizion @ab_trader last edited by

          @ab_trader Hey thanks for your answer

          I still get errors

          Traceback (most recent call last):
            File "C:/Users/mm/PycharmProjects/AlgoTrading/Algo09.py", line 97, in <module>
              cerebro.run()
            File "C:\Users\mm\AppData\Local\Programs\Python\Python36-32\lib\site-packages\backtrader\cerebro.py", line 1127, in run
              runstrat = self.runstrategies(iterstrat)
            File "C:\Users\mm\AppData\Local\Programs\Python\Python36-32\lib\site-packages\backtrader\cerebro.py", line 1214, in runstrategies
              strat = stratcls(*sargs, **skwargs)
            File "C:\Users\mm\AppData\Local\Programs\Python\Python36-32\lib\site-packages\backtrader\metabase.py", line 88, in __call__
              _obj, args, kwargs = cls.doinit(_obj, *args, **kwargs)
            File "C:\Users\mm\AppData\Local\Programs\Python\Python36-32\lib\site-packages\backtrader\metabase.py", line 78, in doinit
              _obj.__init__(*args, **kwargs)
            File "C:/Users/mm/PycharmProjects/AlgoTrading/Algo09.py", line 17, in __init__
              self.CCIplusDI = bt.indicators.CommodityChannelIndex(self.ADX.DIplus, period=20)
            File "C:\Users\mm\AppData\Local\Programs\Python\Python36-32\lib\site-packages\backtrader\indicator.py", line 53, in __call__
              return super(MetaIndicator, cls).__call__(*args, **kwargs)
            File "C:\Users\mm\AppData\Local\Programs\Python\Python36-32\lib\site-packages\backtrader\metabase.py", line 88, in __call__
              _obj, args, kwargs = cls.doinit(_obj, *args, **kwargs)
            File "C:\Users\mm\AppData\Local\Programs\Python\Python36-32\lib\site-packages\backtrader\metabase.py", line 78, in doinit
              _obj.__init__(*args, **kwargs)
            File "C:\Users\mm\AppData\Local\Programs\Python\Python36-32\lib\site-packages\backtrader\indicators\cci.py", line 62, in __init__
              tp = (self.data.high + self.data.low + self.data.close) / 3.0
            File "C:\Users\mm\AppData\Local\Programs\Python\Python36-32\lib\site-packages\backtrader\lineseries.py", line 461, in __getattr__
              return getattr(self.lines, name)
          AttributeError: 'Lines_LineSeries_LineSeriesStub' object has no attribute 'high'
          1 Reply Last reply Reply Quote 0
          • A
            ab_trader last edited by ab_trader

            As I know CCI calculates typical price which requires high, low and close prices. You calculate CCI on ADX indicator, which doesn't have values required. Probably this is a problem.

            You may need to re-write this indicator to be applicable in your case. The code is really simple - backtrader - CCI script

            • 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 1
            • P
              Paska Houso @Horizion last edited by

              @Horizion said in CCI on other indicator:

              I'm trying to put a CCI on the +DI and -DI of an ADX indicator,

              The problem is really here: a commodity channel for 2 values and the code shows attempts at using 1 value

              @ab_trader said in CCI on other indicator:

              As I know CCI calculates typical price which requires high, low and close prices

              Because as quoted here: 3 values are used to calculate the commodity channel

              If there were no mismatch between 1, 2 and 3, one could easily foresee a very small custom indicator which wraps the ADX and copies the needed values into custom lines high, low and close, which can be fed into the CCI

              H 1 Reply Last reply Reply Quote 2
              • H
                Horizion @Paska Houso last edited by

                @Paska-Houso @ab_trader Hey guys,

                Thanks for your answers. I have to admit that I am a little lost, as I don't know much about Python. I was trying to recreate what I used on an other Charting website (Tradingview) which allowed me to put a CCI on the +DI and -DI of the ADX.

                when you say "The problem is really here: a commodity channel for 2 values and the code shows attempts at using 1 value" what exactly do you mean ?

                What I was trying to do is get two CCI's on both the +DI and -DI. So I don't understand why the code shows attempts at using 1 value.

                Regarding the high, low and close: I don't know how to implement these, since the +DI has only one value, and same for the -DI...

                I don't know what to do... And where to look

                alt text

                1 Reply Last reply Reply Quote 0
                • P
                  Paska Houso last edited by Paska Houso

                  It's not a Python thing ... see

                  • https://en.wikipedia.org/wiki/Commodity_channel_index

                  0_1512137485782_17e9e6fb-5796-4113-aafb-9042a4e2bc81-image.png

                  0_1512137492600_d73886e6-6779-42ea-907b-5b7b2bb1894b-image.png

                  Typical Price == pt in the first formula.

                  The calculation is based on averaging the high, low and close as pointed out by @ab_trader, and the implementation in backtrader obviously followed that definition (i.e.: you need 3 components)

                  Because the calculation is made later exclusively based on the averaged price, one could do it (as you try in your code) by passing a single value. But with the current implementation, passing a single data feed (or line) is obviously doomed to fail.

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

                    First ADX indicators need to be improved a bit, hence write new indicator (shown ADXDIPlus only):

                    class ADXDIPlus3(bt.Indicator):
                    
                        lines = ('high', 'low', 'close')
                    
                        params = (('period', 20),)
                    
                        def __init__(self):
                    
                            self.ADX = bt.indicators.DirectionalMovementIndex(period=self.p.period)
                    
                            self.lines.high = self.ADX.DIplus
                            self.lines.low = self.ADX.DIplus
                            self.lines.close = self.ADX.DIplus
                    

                    Then call this indicator in your strategy __init__:

                        def __init__(self):
                    
                            self.ADXPlus3 = ADXDIPlus3(period=12)
                            self.CCI_ADXPlus = bt.indicators.CommodityChannelIndex(self.ADXPlus3, period=20)
                    

                    I didn't check the numbers, but the logic seems right. ADXMinus need to be treated the same way.

                    • 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 2
                    • P
                      Paska Houso last edited by

                      linealias as described in this blog post, could make things even simpler

                      • https://www.backtrader.com/blog/posts/2017-06-12-release-1.9.51.121/release-1.9.51.121.html

                      Something along the lines of

                      class For_CCI_On_DIplus(bt.indicators.DirectionalMovementIndex)
                          linealias = (('DIplus', 'high'), ('DIplus', 'low'), ('DIplus', 'close'),)
                      
                      H 1 Reply Last reply Reply Quote 2
                      • H
                        Horizion @Paska Houso last edited by

                        @Paska-Houso @ab_trader

                        Thanks a LOT guys, amazing community here...

                        I'll try to implement your solutions as soon as I have access to my PC

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