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

Indicators for datas with less periods than the indicator requires

  • I am trying to get an indicator for IPO stocks. The trouble is that the indicators require a certain amount of periods to have passed for the indicator to work and sometimes there are less periods in the whole data set than the indicator requires.

    I would like to write something like:

    if len(self.datas) < 14:
        period = len(self.datas)

    The trouble is that I dont know how to get the length of the data within the def init_(self): of the bt.strategy class.

    Any idea how to do this?


    Actually the period would have to be a rolling for some and static for others. If the indicator I wanted to make was all time highs, and its the 3rd period of a data then that number would have a rolling period always referencing the first day. Is this something that is possible to do with a custom indicator?

    However if the indicator was ATR for example, I would want the ATR of the last 3 periods until it hits 14 periods and then be 14 after that.

  • If you would be more specific, than the answer can be more specific also. But I'll try.

    I would do all calculations in the next() using slices taken from data feed. Length of the slice can be calculated based on the rules. Say if I want rolling value up to period of 10, than if length of delivered data is smaller than 10, I use length of delivered data, otherwise I use 10. Make a slice and do all the calculations to get indicator value.

    Slicing is shown in the docs Platform Concepts - Slicing

    For All Time High I would put indicator calculations in the next() also: every next I will just compare current bar High with the current indicator value and update indicator value if current High is bigger.

    For ATR - create two ATR's for periods of 3 and 14 in the __init()__. Then in the next() check the length of delivered data: shorter than 14, use ATR3; longer than 14 - use ATR14.

  • @ab_trader Thanks for the reply. I really appriciate it.

    I have indeed made such indicators within next(), but it makes back testing go much much slower.

    What specifics would you like so I can provide some more color? I think you have a good idea of what I am trying to do.

    A specific example might be trying to get year highs for the ticker BRY. I am using daily data as the feed for the stock. The stock had its IPO on July 26. This is my indicator for year highs.

     for i, elm in enumerate(self.datas):  
         Symbol = self.datas[i]._name
         High   = self.datas[i].high
         self.Year_highs[Symbol] = btind.Highest(High, period = 
         abs(Inputs.params['Year_bars']),plot = False)

    Since the stock has been around for less than 250 days(periods) the code throws an error. I could do what you suggested and make the indicator in the next() method, but when processing many stocks it can take a while to complete a backtest.

  • The only way I can possibly think to work around this is to record the len() of my data before i put it into cerebro. I would record it into a dictionary and then write something like:

    if lendic['BRY'] < 250:
        period = lendic['BRY']

    This seems messy though and I prefer not to do it if I dont have to.

    but now that I think of it, this doesnt solve the rolling period issue.

  • administrators

    @rstrong said in Indicators for datas with less periods than the indicator requires:

    However if the indicator was ATR for example, I would want the ATR of the last 3 periods until it hits 14 periods and then be 14 after that.

    The only way to do that as pointed out by @ab_trader is to do the calculations manually in next and the declared period of your indicator has to be 3 (without taking into account that the value should be a parameter a not a fixed value)

    If you use internally the built-in ATR, the platform will know there is an ATR with period 14 (which actually ends up with a higher effective period due to the internal constraints of the indicator) and that will be the period of your indicator.

    To overcome this you need to:

    • Send each prenext call to next
    • Check the actual len(self) > 14 or even better the length of the longer ATR if len(atr_14) > 0
    • If the comparison succeeds deliver the value of the longer indicator
    • If not, deliver the value of the smaller ATR of period 3.

    In any case there will be an initial period in which you cannot deliver anything, because the ATR of period 3 cannot also deliver until its minimum constraints have been met.

Log in to reply