'How to create an indicator extension with QuantConnect

I have created an indicator for the ratio between PEPSI (PEP) and Coca Cola (COKE) and am trying to create a 5 days simple moving average (sma) from this indicator using IndicatorExtension and then plot the result. The offending code is at the end of the script:

import numpy as np
class SquareLightBrownPanda(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2020, 1, 1)  # Set Start Date
        self.SetEndDate(2021,1,1) # Set End Date
        self.SetCash(100000)  # Set Strategy Cash
        self.pep = self.AddEquity("PEP", Resolution.Daily).Symbol # Add data for PEP
        self.coke = self.AddEquity("COKE", Resolution.Daily).Symbol # Add data for COKE
        self.log_ratio_spread=0
        
    
        self.sma_pep = self.SMA(self.pep,5,Resolution.Daily) #create 5 simple moving average indicator
        self.sma_coke = self.SMA(self.coke,5,Resolution.Daily) #create 5 simple moving average indicator
        
        closing_price_pep = self.History(self.pep,5,Resolution.Daily)["close"] #historic information for the past 5 bars.  
        closing_price_coke = self.History(self.coke,5,Resolution.Daily)["close"] #historic information for the past 5 bars.  
        
        for time, price in closing_price_pep.loc[self.pep].items(): #iterate over time and price information in the closing price dataframe
            self.sma_pep.Update(time, price) #update sma indicator is ready to use from the beginning
            
        for time, price in closing_price_coke.loc[self.coke].items(): #iterate over time and price information in the closing price dataframe
            self.sma_coke.Update(time, price) #update sma indicator is ready to use from the beginning    
    
    
    def OnData(self, data):
        if not self.sma_pep.IsReady and not self.sma_coke.IsReady:
            return
        
        #save the high and low price of the last year - not efficient use rolling window
        hist_pep = self.History(self.pep, timedelta(365),Resolution.Daily)
        hist_coke = self.History(self.coke, timedelta(365),Resolution.Daily)
    
        price_pep = self.Securities[self.pep].Price ##save PEP's most recent price to the price variable
        price_coke = self.Securities[self.coke].Price ##save COKE's most recent price to the price variable
            
        log_ratio_pep = np.log(price_pep/self.sma_pep.Current.Value)
        log_ratio_coke = np.log(price_coke/self.sma_coke.Current.Value)
        
        self.log_ratio_spread = log_ratio_pep - log_ratio_coke
        
        #TRYING TO CREATE 5 DAY MOVING AVERAGE OF log_ratio_spread HERE
    
        self.log_ratio_spread_sma = IndicatorExtensions.SMA(self.log_ratio_spread,5,Resolution.Daily)
            
        self.Plot("Spread","log_ratio_spread_sma",self.log_ratio_spread_sma) 

However when I run the code in QuantConnect I get the error:

Runtime Error: Trying to dynamically access a method that does not exist throws a TypeError exception. To prevent the exception, ensure each parameter type matches those required by the 'int'>) method. Please checkout the API documentation.
  at OnData
    ratio_spread = IndicatorExtensions.SMA(self.log_ratio_spread in main.py: line 53
     (Open Stacktrace)

which is associated with the flollowing line:

self.log_ratio_spread_sma = IndicatorExtensions.SMA(self.log_ratio_spread,5,Resolution.Daily)

What am I doing wrong?



Solution 1:[1]

The issue is that the IndicatorExtensions.SMA method expects an indicator object, but self.log_ratio_spread is a decimal.

To resolve the issue, create a SimpleMovingAverage indicator and manually update it with the log ratio spread.

log_ratio_pep = np.log(data[self.pep].Price / self.sma_pep.Current.Value)
log_ratio_coke = np.log(data[self.coke].Price / self.sma_coke.Current.Value)
log_ratio_spread = log_ratio_pep - log_ratio_coke        
self.log_ratio_spread_sma.Update(data.Time, log_ratio_spread)

For a full example, see this backtest.

Best,

Derek Melchin

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Derek