Full example of custom indicator
-
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())
-
Actually it is true, there is no attribute
MovAv
inbt.indicator
. You may want to usemovav = btind.SimpleMovingAverage
-
@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.
-
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__()
-
I confused you. I think this need to be changed so your original script:
import backtrader.indicators as btind
-
@ab_trader Thank you.
-
@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 importingbacktrader.indicator
and notbacktrader.indicators
And yes,
MovAv.Simple
and all other aliases aforementioned, do exist.