Create UncorrelatedToSpyUniverseSelectionModel.py

This commit is contained in:
HalldorAndersen
2019-03-25 14:40:53 -07:00
committed by GitHub
parent a873493364
commit d702aa5def
@@ -0,0 +1,117 @@
# QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
# Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from clr import AddReference
AddReference("QuantConnect.Algorithm")
AddReference("QuantConnect.Algorithm.Framework")
AddReference("QuantConnect.Common")
from QuantConnect import *
from QuantConnect.Algorithm import *
from QuantConnect.Algorithm.Framework import *
from Selection.FundamentalUniverseSelectionModel import FundamentalUniverseSelectionModel
class UncorrelatedToSPYUniverseSelectionModel(FundamentalUniverseSelectionModel):
'''
This universe selection model picks stocks that currently have their correlation to SPY deviated from the mean.
'''
def __init__(self, filterFineData = False, universeSettings = None, securityInitializer = None):
'''Initializes a new default instance of the OnTheMoveUniverseSelectionModel'''
super().__init__(filterFineData, universeSettings, securityInitializer)
# Add SPY to the universe
self.spySymbol = Symbol.Create("SPY", SecurityType.Equity, Market.USA)
# Number of coarse symbols
self.numberOfSymbolsCoarse = 400
# Number of symbols selected by the universe model
self.numberOfSymbols = 10
# Rolling window length period for correlation calculation
self.windowLength = 5
# History length period
self.historyLength = 25
# Symbols in universe
self.symbols = []
# Initial history not retrieved
self.initialHistory = False
self.coarseSymbols = []
self.cor = None
def SelectCoarse(self, algorithm, coarse):
if not self.coarseSymbols:
# The stocks must have fundamental data
# The stock must have positive previous-day close price
# The stock must have positive volume on the previous trading day
filtered = [x for x in coarse if x.HasFundamentalData and x.Volume ¨ 0 and x.Price > 0]
sortedByDollarVolume = sorted(filtered, key = lambda x: x.DollarVolume, reverse=True)[:self.numberOfSymbolsCoarse]
self.coarseSymbols = [x.Symbol for x in sortedByDollarVolume]
# return the symbol objects our sorted collection
self.symbols = self.corRanked(algorithm,self.coarseSymbols)
return self.symbols
def corRanked(self, algorithm, symbols):
# Not enough symbols to filter
if len(symbols) <= self.numberOfSymbols:
return symbols
# Retrieve history of prices
hist = algorithm.History(symbols + [self.spySymbol], self.historyLength, Resolution.Daily)
# # Calculate returns
returns=hist.close.unstack(level=0).pct_change()
# Retrieve rolling correlation to calculate stdev(correlation)
if not self.initialHistory:
corMat=returns.rolling(self.windowLength,min_periods = self.windowLength).corr().dropna()
# Correlation of all securities against SPY
self.cor = corMat[str(self.spySymbol)].unstack()
self.initialHistory = True
if self.initialHistory:
corRow=returns.tail(self.windowLength).corr()[str(self.spySymbol)]
# Correlation of all securities against SPY
self.cor = self.cor.append(corRow).tail(self.historyLength)
# Calculate the mean of correlation
corMu = self.cor.mean()
# Calculate the standard deviation of correlation
corStd = self.cor.std()
# Calculate absolute value of Z-Score for stocks in the Coarse Universe. Only include stocks with significantly positive or negative correlation to SPY.
zScore = {}
for symbol in corStd.index:
if not symbol == "SPY":
if abs(corMu[symbol]) > 0.5:
zScore.update({symbol : abs((self.cor[symbol].tail(1).values-corMu[symbol])/corStd[symbol])})
# Rank stocks on Z-Score
symbols=sorted(zScore, key=lambda symbol: zScore[symbol],reverse=True)[:self.numberOfSymbols]
return symbols