## From Research To Production -- Mean Reversion

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)):

# 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 = {}

for i in range(len(self.assets)):

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!

The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by QuantConnect. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. QuantConnect makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances. All investments involve risk, including loss of principal. You should consult with an investment professional before making any investment decisions.

0

The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by QuantConnect. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. QuantConnect makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances. All investments involve risk, including loss of principal. You should consult with an investment professional before making any investment decisions.

AWESOME!

0

hi all, bloody amazing!

I am just in awe! about what quantconnect is doing!!

Jack Simonson

Is the universe selection function available in the research enviroment?

Best,

Andrew

0

Cool, thank you Jack for sharing!
0

Thanks for sharing Jack.
When I modify this a bit--
2. VWAP execution
It gives an Order Error

Backtest Handled Error: Order Error: id: 8363, Insufficient buying power to complete order (Value:42279.1594), Reason: Id: 8363, Initial Margin: 38438.774485818181818181818182, Free Margin: 20213.1599005897999605090909

How can this be handled given that I want to use the LiquidETFUniverse, with no changes to initial capital.

Bala

0

Hello!

Just wanted to say a big thank you and your colleagues for the "From Research To Production" series!

Best Regards,

Bjorn

0

0

The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by QuantConnect. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. QuantConnect makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances. All investments involve risk, including loss of principal. You should consult with an investment professional before making any investment decisions.