For code/output blocks: Use ``` (aka backtick or grave accent) in a single line before and after the block. See: http://commonmark.org/help/

Adding custom indicator



  • I have developed my first custom backtrader indicator class (in a separate file) which calculates resistance values. The first thing I do in the next() method of this indicator class is to get the previous 8 values of self.data and store them in an array named 'ltp', like so:

    class supres(bt.Indicator):
    
        lines = ('support','resistance')
        params = (('n', 8),)
        
        def __init__(self):
    
            #converting n to a nearest even number
            if self.p.n%2 != 0:
                self.p.n += 1
    
        def next(self):
    
            ltp = self.data.get(ago=0, size=self.p.n)
            print(ltp)
    

    When I come to call the indicator in the init of my strategy, I pass in self.data[0]. But the self.data[0] doesn't seem to be available in the the indicator class. When I print out 'ltp' from the indicator class the array is empty.

    Here is my strategy code for the init and main that isolates the problem:

    import backtrader as bt
    import datetime
    from backtrader import indicators as ind
    import numpy as np
    
    from supres_ind import supres
    
    # Create strategy
    class TestStrategy(bt.Strategy):
            
        def __init__(self):
            # Keep a reference to the "close" line in the data[0] dataseries
            self.dataclose = self.datas[0].close
            
            #calls the indicator
            self.support = supres(self.datas[0])
    

    and

    if __name__ == '__main__':
        
        datapath = '../../data/raw_bitcoin_data_copy.csv'
        data = bt.feeds.BacktraderCSVData(
            dataname=datapath,
            fromdate=datetime.datetime(2017, 1, 1),
            todate=datetime.datetime(2017, 7, 1),
            adjclose=False)
        
        cerebro = bt.Cerebro()
        cerebro.adddata(data)
        cerebro.addstrategy(TestStrategy)
        
        cerebro.broker.setcash(100000.0)
        cerebro.addsizer(bt.sizers.SizerFix, stake=10)
        cerebro.broker.setcommission(0.001) #0.1%
        print('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue())
        cerebro.run()
        print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())
    

    Do I have to add the indicator class to the cerebro engine somehow? And does the indicator have to be called with bt.ind prefix?

    Here is the form of the data:

    timestamp	open	high	low	close	volume	adj close
    2017-01-01	973.37	1000	964.37	992.95	4421.502883	992.95
    2017-01-02	992.96	1034.39	990.52	1011.45	7723.635752	1011.45
    2017-01-03	1011.52	1036.99	1006.71	1020.67	8614.250058	1020.67
    2017-01-04	1020.69	1147	1018	1130.3	16222.23027	1130.3
    2017-01-05	1131.1	1175	880	1007	20438.58193	1007
    2017-01-06	1007	1033.85	875.01	895.71	14262.50427	895.71
    

    Cheers


  • administrators

    @maxpaton said in Adding custom indicator:

    When I come to call the indicator in the init of my strategy, I pass in self.data[0]. But the self.data[0] doesn't seem to be available in the the indicator class. When I print out 'ltp' from the indicator class the array is empty.

    There is nothing telling the framework how many bars make up the lookback period. Neither you nor additional elements in your indicator (like a Moving Average) what the period will be. It cannot as such provide you with n bars of information in advance.

    Subclass your indicator from: PeriodN which already provides a period parameter and will do it for you.



  • @backtrader Got it now, thanks