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

build indicator by taking another indicator as input



  • I meat problem when I try to build an indicator upon another indicator. I don't know how to access input data properly. Below is the code

    import backtrader as bt
    import datetime
    
    class A(bt.Indicator):
        lines = ('a',)
        params = (('period1', 5),('period2', 10))
    
        def __init__(self):
            self.addminperiod(self.p.period1 + self.p.period2)
            super(A, self).__init__()
    
        def next(self):
            print(self.data0.get(size=self.p.period1).tolist())
    
    class TestStrategy(bt.Strategy):
    
        def __init__(self):
            self.ind1 = bt.indicators.MovingAverageSimple(period = 10)
            self.ind2 = A(self.ind1, period1 = 5, period2 = 10)
    
        def next(self):
            print(self.ind1.sma[0])
    
    cerebro = bt.Cerebro()
    cerebro.addstrategy(TestStrategy)
    data = bt.feeds.YahooFinanceCSVData(
        dataname='orcl-1995-2014.txt',
        fromdate=datetime.datetime(2000, 1, 1),
        todate=datetime.datetime(2000, 3, 1),
        reverse=False)
    cerebro.adddata(data)
    cerebro.run()
    

    I try to get self.ind1 value in Indicator class A, method next(self). But unfortunately I failed. May I know what's wrong, and how to do it properly? Thanks!

    Below is the printing message.

    []
    []
    []
    []
    []
    []
    []
    []
    []
    []
    []
    []
    []
    []
    []
    []
    []
    26.82
    26.648000000000003
    26.812
    27.224
    27.808
    27.933
    27.861
    27.805
    27.755000000000003
    27.497000000000003
    27.325
    27.244
    27.104000000000003
    26.976
    26.883
    27.171
    27.326999999999998
    27.570999999999998
    28.095999999999997
    28.711000000000002
    29.322000000000003
    29.691000000000003
    30.037
    30.284
    30.320999999999998
    30.29
    30.464999999999996
    30.564999999999998
    30.98
    31.427
    32.03


  • I would also like to ask whether the line below is written in a good way?

    self.addminperiod(self.p.period1 + self.p.period2)


  • All of sudden, I found how to fix it. To close my question, this is the code. :-) (BTW, I tried to delete this post, but failed....)

    import backtrader as bt
    import datetime
    
    class A(bt.Indicator):
        lines = ('a',)
        params = (('period', 5),)
    
        def __init__(self):
            self.addminperiod(self.p.period)
            super(A, self).__init__()
    
        def next(self):
            print(self.data0.get(size=self.p.period).tolist())
    
    class TestStrategy(bt.Strategy):
    
        def __init__(self):
            self.ind1 = bt.indicators.MovingAverageSimple(period = 10)
            self.ind2 = A(self.ind1.sma, period = 5)
    
        # def next(self):
        #     print(self.ind1.sma[0])
    
    cerebro = bt.Cerebro()
    cerebro.addstrategy(TestStrategy)
    data = bt.feeds.YahooFinanceCSVData(
        dataname='orcl-1995-2014.txt',
        fromdate=datetime.datetime(2000, 1, 1),
        todate=datetime.datetime(2000, 3, 1),
        reverse=False)
    cerebro.adddata(data)
    cerebro.run()


  • @hobart-liu said in build indicator by taking another indicator as input:

    class A(bt.Indicator):
        lines = ('a',)
        params = (('period', 5),)
    
        def __init__(self):
            self.addminperiod(self.p.period)
            super(A, self).__init__()
    
        def next(self):
            print(self.data0.get(size=self.p.period).tolist())
    

    May I ask what's the point about self.addminperiod

    Your indicator A is receiving something (it may be a data feed, but in your example is another indicator which already carries a minperiod payload:

     self.ind1 = bt.indicators.MovingAverageSimple(period = 10)
     self.ind2 = A(self.ind1.sma, period = 5)
    

    And that's why it seems superfluous to add an extra self.addminperiod to A, which will already learn the dependency from MovingAverageSimple.

    Seeing some of your other questions, it seems you have seen the usage of self.addminperiod in some example and you may be abusing it.



  • The reason in behind is simple, I am using StochasticFull(period70) > 80, and want to use slope to detect downtrend of %K. I know TALib and BT both support slope, but I want to build "weighted" slope. The period is slope period.



  • The point is that you probably don't need addminperiod at all. If we want the average defined as

    • Total Value_Change / Number_of_Periods

    An indicator that calculates that would be:

    class Slope(bt.Indicator):
        line = ('slope',)
        params = dict(period=5)
    
        def __init__(self):
            self.lines.slope = (self.data - self.data(-self.p.period)) / self.p.period
    

    Edited: to calculate the actual slope.



  • Many thanks Paska :-)
    It seems next time I have to show I can not directly use existing functions.

    Again, thanks for your information. It helps.