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/

    Full example of custom indicator

    Indicators/Strategies/Analyzers
    3
    7
    1577
    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.
    • Roger Bos
      Roger Bos last edited by

      I am trying to learn how to create a custom indicator based on the Indicator Development help page, but I am getting the following error:

      ---> 84 params = dict(period=20, movav=btind.MovAv.Simple)
      85 def init(self):
      86 movav = self.p.movav(self.data, period=self.p.period)

      AttributeError: module 'backtrader.indicator' has no attribute 'MovAv'

      creating the indicator class seems straightforward enough, but I do not understand how to make it available to the rest of the program. My full code is below if anyone is able to point me in the correct direction. Thanks in advance.

      from __future__ import (absolute_import, division, print_function,
                              unicode_literals)
      
      import datetime  # For datetime objects
      import os.path  # To manage paths
      import sys  # To find out the script name (in argv[0])
      
      # Import the backtrader platform
      import backtrader as bt
      import backtrader.indicator as btind
      
      # Create a Stratey
      class TestStrategy(bt.Strategy):
          params = (
              ('period', 15),
          )
      
          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):
              # Keep a reference to the "close" line in the data[0] dataseries
              self.dataclose = self.datas[0].close
      
              self.signal = OverUnderMovAv(
                  self.datas[0], period = self.p.period)
      
              # To keep track of pending orders and buy price/commission
              self.order = None
              self.buyprice = None
              self.buycomm = None
      
          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 enough 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')
      
              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):
              # Simply log the closing price of the series from the reference
              self.log('Close, %.2f' % self.dataclose[0])
      
              # Check if an order is pending ... if yes, we cannot send a 2nd one
              if self.order:
                  return
      
              # Check if we are in the market
              if not self.position:
      
                  # Not yet ... we MIGHT BUY if ...
                  if self.signal > 0:
                      # BUY, BUY, BUY!!! (with default parameters)
                      self.log('BUY CREATE, %.2f' % self.dataclose[0])
      
                      # Keep track of the created order to avoid a 2nd order
                      self.order = self.buy()
      
              else:
      
                  # Already in the market ... we might sell
                  if self.signal < 0:
                      # SELL, SELL, SELL!!! (with all possible default parameters)
                      self.log('SELL CREATE, %.2f' % self.dataclose[0])
      
                      # Keep track of the created order to avoid a 2nd order
                      self.order = self.sell()
      
      # Add custom indicator
      class OverUnderMovAv(bt.Indicator):
          lines = ('overunder',)
          params = dict(period=20, movav=btind.MovAv.Simple)
      
          def __init__(self):
              movav = self.p.movav(self.data, period=self.p.period)
              self.l.overunder = bt.Cmp(movav, self.data)    
      
      
      if __name__ == '__main__':
          # Create a cerebro entity
          cerebro = bt.Cerebro()
      
          # Add a strategy
          cerebro.addstrategy(TestStrategy)
      
          # Datas are in a subfolder of the samples. Need to find where the script is
          # because it could have been called from anywhere
          # modpath = os.path.dirname(os.path.abspath(sys.argv[0]))
          datapath = '/Users/rjbos2/backtrader/datas/orcl-1995-2014.txt'
      
          # Create a Data Feed
          data = bt.feeds.YahooFinanceCSVData(
              dataname=datapath,
              # Do not pass values before this date
              fromdate=datetime.datetime(2000, 1, 1),
              # Do not pass values before this date
              todate=datetime.datetime(2000, 12, 31),
              # Do not pass values after this date
              reverse=False)
      
          # Add the Data Feed to Cerebro
          cerebro.adddata(data)
      
          # Set our desired cash start
          cerebro.broker.setcash(100000.0)
      
          # Set the commission - 0.1% ... divide by 100 to remove the %
          cerebro.broker.setcommission(commission=0.001)
      
          # Print out the starting conditions
          print('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue())
      
          # Run over everything
          cerebro.run()
      
          # Print out the final result
          print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())
          
      
      B 1 Reply Last reply Reply Quote 0
      • A
        ab_trader last edited by

        Actually it is true, there is no attribute MovAv in bt.indicator. You may want to use

        movav = btind.SimpleMovingAverage
        
        Roger Bos 1 Reply Last reply Reply Quote 0
        • Roger Bos
          Roger Bos @ab_trader last edited by

          @ab_trader said in Full example of custom indicator:

          movav = btind.SimpleMovingAverage

          Thanks for the suggestion. I did notice in the indicators folder that that function was not there, but I was following an example. Unfortunately, SimpleMovingAverage does not work either :(.

          ---> 86 params = dict(period=20, movav = btind.SimpleMovingAverage)
          87 def init(self):
          88 movav = self.p.movav(self.data, period=self.p.period)

          AttributeError: module 'backtrader.indicator' has no attribute 'SimpleMovingAverage'

          Do you think there is something wrong with my installation? All of the "built in" indicator's work fine. I have used backtrader for a few weeks now with no other problems.

          Roger Bos 1 Reply Last reply Reply Quote 0
          • Roger Bos
            Roger Bos @Roger Bos last edited by

            And for good measure I also tried MovingAverageSimple:

            ---> 86 params = dict(period=20, movav=btind.MovingAverageSimple)
            87 def init(self):
            88 movav = self.p.movav(self.data, period=self.p.period)

            AttributeError: module 'backtrader.indicator' has no attribute 'MovingAverageSimple'

            class MovingAverageSimple(MovingAverageBase):
                '''
                Non-weighted average of the last n periods
            
                Formula:
                  - movav = Sum(data, period) / period
            
                See also:
                  - http://en.wikipedia.org/wiki/Moving_average#Simple_moving_average
                '''
                alias = ('SMA', 'SimpleMovingAverage',)
                lines = ('sma',)
            
                def __init__(self):
                    # Before super to ensure mixins (right-hand side in subclassing)
                    # can see the assignment operation and operate on the line
                    self.lines[0] = Average(self.data, period=self.p.period)
            
                    super(MovingAverageSimple, self).__init__()
            
            
            1 Reply Last reply Reply Quote 0
            • A
              ab_trader last edited by

              I confused you. I think this need to be changed so your original script:

              import backtrader.indicators as btind
              
              Roger Bos 1 Reply Last reply Reply Quote 2
              • Roger Bos
                Roger Bos @ab_trader last edited by

                @ab_trader Thank you.

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

                  @Roger-Bos said in Full example of custom indicator:

                  import backtrader.indicator as btind
                  

                  Notice that the original problem is the lack on an s. The code is importing backtrader.indicator and not backtrader.indicators

                  And yes, MovAv.Simple and all other aliases aforementioned, do exist.

                  1 Reply Last reply Reply Quote 1
                  • 1 / 1
                  • First post
                    Last post
                  Copyright © 2016, 2017, 2018 NodeBB Forums | Contributors
                  $(document).ready(function () { app.coldLoad(); }); }