Hey all,

We're producing a few posts on how you can quickly take your ideas from the research notebook and implement them in an algorithm. In this one, we've used the research notebook to calculate the spread between an asset's price and its historical mean (past 30 days). Then, we calculate the standard deviation and determine which assets have moved more than one standard deviation below their average price. The theory is that they are due to revert back towards the mean, and so we can take advantage of this by taking long positions. In the research notebook, we do this as follows:

import numpy as np qb = QuantBook() qb symbols = {} assets = ["SHY", "TLT", "SHV", "TLH", "EDV", "BIL", "SPTL", "TBT", "TMF", "TMV", "TBF", "VGSH", "VGIT", "VGLT", "SCHO", "SCHR", "SPTS", "GOVT"] for i in range(len(assets)): symbols[assets[i]] = qb.AddEquity(assets[i],Resolution.Minute).Symbol # Fetch history on our universe df = qb.History(qb.Securities.Keys, 30, Resolution.Daily) # Make all of them into a single time index. df = df.close.unstack(level=0) # Calculate the truth value of the most recent price being less than 1 std away from the mean classifier = df.le(df.mean().subtract(df.std())).tail(1) # Get indexes of the True values classifier_indexes = np.where(classifier)[1] # Get the Symbols for the True values classifier = classifier.transpose().iloc[classifier_indexes].index.values # Get the std values for the True values (used for magnitude) magnitude = df.std().transpose()[classifier_indexes].values # Zip together to iterate over later selected = zip(classifier, magnitude)

It's great to have this kind of power in the research environment, and thankfully it is easily transferrable into an algorithm! We set up a quick algorithm using the US Treasuries ETF basket, an Equal Weighting Portfolio Construction Model, and an Immediate Execution Model. We also used a Scheduled Event to trigger every Monday just after Market Open.

def Initialize(self): #1. Required: Five years of backtest history self.SetStartDate(2014, 1, 1) #2. Required: Alpha Streams Models: self.SetBrokerageModel(BrokerageName.AlphaStreams) #3. Required: Significant AUM Capacity self.SetCash(1000000) #4. Required: Benchmark to SPY self.SetBenchmark("SPY") self.SetPortfolioConstruction(EqualWeightingPortfolioConstructionModel()) self.SetExecution(ImmediateExecutionModel()) self.assets = ["IEF", "SHY", "TLT", "IEI", "SHV", "TLH", "EDV", "BIL", "SPTL", "TBT", "TMF", "TMV", "TBF", "VGSH", "VGIT", "VGLT", "SCHO", "SCHR", "SPTS", "GOVT"] self.symbols = {} # Add Equity ------------------------------------------------ for i in range(len(self.assets)): self.symbols[self.assets[i]] = self.AddEquity(self.assets[i],Resolution.Minute).Symbol self.Schedule.On(self.DateRules.Every(DayOfWeek.Monday), self.TimeRules.AfterMarketOpen("IEF", 1), self.EveryDayAfterMarketOpen)

In the event "EveryDayAfterMarketOpen" we can copy and paste our research notebook code, and by setting qb = self, we don't even need to change any of the code we've imported.

def EveryDayAfterMarketOpen(self): qb = self # Fetch history on our universe df = qb.History(qb.Securities.Keys, 5, Resolution.Daily) # Make all of them into a single time index. df = df.close.unstack(level=0) # Calculate the truth value of the most recent price being less than 1 std away from the mean classifier = df.le(df.mean().subtract(df.std())).tail(1) # Get indexes of the True values classifier_indexes = np.where(classifier)[1] # Get the Symbols for the True values classifier = classifier.transpose().iloc[classifier_indexes].index.values # Get the std values for the True values (used for magnitude) magnitude = df.std().transpose()[classifier_indexes].values # Zip together to iterate over later selected = zip(classifier, magnitude) # ============================== insights = [] for symbol, magnitude in selected: insights.append( Insight.Price(symbol, timedelta(days=5), InsightDirection.Up, magnitude) ) self.EmitInsights(insights)

 

At the bottom of the method, we generate Insights for the symbols we've selected and use their calculated standard deviation as the magnitude of the price change we expect over the next five days. These Insights will be used as inputs to the Portfolio Construction model and this will tell the execution model how much weight to assign to each position (in our case, equal weight).

This is just a quick example of how you can move between your research and an algorithm without too much hassle. Hope you find it helpful!