I was able to get this working, but in a rather hacky way. I'm hoping someone will be kind enough to reply with a better solution than this.

Python is not my forte, and I'm not trained in data science, so probably this is not the best solution, and I wonder about the memory impact. All the example code I could find for rolling z-score, involved pandas, so I just imported it and used a pandas series object.

`import pandas as pd`

import math

asset_class = 'stocks'

pairs_list = {

'stocks': [

('CVX', 'XOM'),

('EGBN', 'FMBI')

],

'forex': [

('EURUSD', 'GBPUSD')

]

}

(symbol1, symbol2) = pairs_list[asset_class][0]

class MeanReversionResearch(QCAlgorithm):

def Initialize(self):

self.SetStartDate(2020, 12, 3)

self.SetEndDate(2020, 12, 5)

self.SetCash(100_000)

self.ZScoreSeries = Series("Z Score", SeriesType.Line, 0)

chart = Chart("Z Score")

chart.AddSeries(self.ZScoreSeries)

self.AddChart(chart)

self.Ratios = pd.Series()

if asset_class == 'stocks':

self.AddEquity(symbol1, Resolution.Minute)

self.AddEquity(symbol2, Resolution.Minute)

elif asset_class == 'forex':

self.AddForex(symbol1, Resolution.Minute)

self.AddForex(symbol2, Resolution.Minute)

def OnData(self, data):

if data.ContainsKey(symbol1) and data.ContainsKey(symbol2):

price1 = data[symbol1].Close

price2 = data[symbol2].Close

self.ZScore(price1 / price2)

def ZScore(self, ratio):

self.Debug(f'ratio: {ratio}')

self.Ratios = self.Ratios.append(pd.Series([ratio]))

x = self.Ratios.rolling(window = 1).mean()

w = self.Ratios.rolling(window = 20)

score = (x - w.mean()) / w.std()

if score.size > 0:

s = score.iat[-1]

if math.isnan(s):

return

else:

self.ZScoreSeries.AddPoint(self.Time, s)

Â