| Overall Statistics |
|
Total Trades 21 Average Win 0.11% Average Loss -0.10% Compounding Annual Return -0.509% Drawdown 0.500% Expectancy -0.007 Net Profit -0.045% Sharpe Ratio -0.198 Loss Rate 53% Win Rate 47% Profit-Loss Ratio 1.13 Alpha 0.057 Beta -3.19 Annual Standard Deviation 0.023 Annual Variance 0.001 Information Ratio -1.011 Tracking Error 0.024 Treynor Ratio 0.001 Total Fees $0.00 |
from clr import AddReference
AddReference("QuantConnect.Common")
AddReference("QuantConnect.Algorithm")
AddReference("QuantConnect.Algorithm.Framework")
AddReference("QuantConnect.Indicators")
from QuantConnect import *
from QuantConnect.Indicators import *
from QuantConnect.Algorithm import *
from QuantConnect.Algorithm.Framework import *
from QuantConnect.Algorithm.Framework.Alphas import *
from Risk.NullRiskManagementModel import NullRiskManagementModel
import datetime
import pandas as pd
class MomentumAndStyleRotationAlgorithm(QCAlgorithmFramework):
def Initialize(self):
self.SetStartDate(2018, 1, 1) # Set Start Date
self.SetEndDate(2018, 2, 1) # Set End Date
self.SetCash(100000) # Set Strategy Cash
self.SetSecurityInitializer(lambda security: security.SetFeeModel(ConstantFeeModel(0)))
self.tickers = [
"IJJ", # iShares S&P MidCap 400 Value Index ETF
"IJS", # iShares S&P SmallCap 600 Value ETF
"IVE", # iShares S&P 500 Value Index ETF
"IVW", # iShares S&P 500 Growth ETF
"IJK", # iShares S&P Mid-Cap 400 Growth ETF
"IJT", # iShares S&P Small-Cap 600 Growth ETF
]
self.UniverseSettings.Resolution = Resolution.Daily
symbols = [ Symbol.Create(ticker, SecurityType.Equity, Market.USA) for ticker in self.tickers ]
self.SetUniverseSelection( ManualUniverseSelectionModel(symbols) )
self.SetAlpha(MomentumAndStyleRotationAlphaModel())
self.SetPortfolioConstruction(EqualWeightingPortfolioConstructionModel())
self.SetExecution(ImmediateExecutionModel())
self.SetRiskManagement(NullRiskManagementModel())
class MomentumAndStyleRotationAlphaModel(AlphaModel):
'''Alpha model that uses an SMA and security price to create insights'''
def __init__(self,
period = 12*20,
resolution = Resolution.Daily,
datetime = datetime,
pd = pd):
'''
Initializes a new instance of the MomentumAndStyleRotationAlphaModel class
Args:
period: The SMA period
'''
self.period = period
self.resolution = resolution
self.predictionInterval = Time.Multiply(Extensions.ToTimeSpan(resolution), period)
self.symbolDataBySymbol = {}
resolutionString = Extensions.GetEnumString(resolution, Resolution)
self.Name = '{}({},{})'.format(self.__class__.__name__, period, resolutionString)
self.lastMonth = -1
self.longSymbol = None
self.shortSymbol = None
self.monthStart = False
self.longStockList = []
self.shortStockList = []
def Update(self, algorithm, data):
'''
Updates this alpha model with the latest data from the algorithm.
This is called each time the algorithm receives data for subscribed securities
Args:
algorithm: The algorithm instance
data: The new data available
Returns:
The new insights generated
'''
insights = []
month = algorithm.Time.month
if month == self.lastMonth:
return insights
self.lastMonth = algorithm.Time.month
mom = {}
for symbol, symbolData in self.symbolDataBySymbol.items():
if symbolData.mom.IsReady:
mom.update({symbol : symbolData.momValue})
sortedMomentum = list(dict(sorted(mom.items(), key=lambda kv: kv[1],reverse=True)))
self.longSymbol = list(sortedMomentum)[0]
self.shortSymbol = list(sortedMomentum)[-1]
predictionInterval = Time.Multiply(Extensions.ToTimeSpan(self.resolution), self.daysLeftInMonth(year = algorithm.Time.year,month = algorithm.Time.month,day = algorithm.Time.day))
# EMIT INSIGHTS
insights.append(Insight.Price(self.longSymbol, predictionInterval, InsightDirection.Up))
insights.append(Insight.Price(self.shortSymbol, predictionInterval, InsightDirection.Down))
return insights
# Calculates number of days left in month
def daysLeftInMonth(self,year,month,day):
date = datetime.date(year,month,day)
if date.month == 12:
return abs(datetime.date(year,month,day)-date.replace(day=31)).days
return abs(datetime.date(year,month,day)-date.replace(month=date.month+1, day=1) - datetime.timedelta(days=1)).days
def OnSecuritiesChanged(self, algorithm, changes):
'''
Event fired each time the we add securities from the data feed
Args:
algorithm: The algorithm instance that experienced the change in securities
changes: The security additions and removals from the algorithm
'''
# initialize data for added securities
addedSymbols = [ x.Symbol for x in changes.AddedSecurities ]
history = algorithm.History(addedSymbols, self.period, self.resolution)
for added in changes.AddedSecurities:
algorithm.Log(added)
symbolData = self.symbolDataBySymbol.get(added.Symbol)
if symbolData is None:
# Create SymbolData objects
symbolData = SymbolData(symbol = str(added.Symbol),period = self.period,resolution = self.resolution,algorithm = algorithm)
# Warmup indicators
ticker = SymbolCache.GetTicker(added.Symbol)
symbolData.WarmUpIndicators(history.loc[ticker])
# Add object to dictionary
self.symbolDataBySymbol[added.Symbol] = symbolData
class SymbolData:
'''
Contains data specific to a symbol required by this model
'''
def __init__(self,symbol, period,resolution,algorithm):
self.symbol = symbol
self.mom = algorithm.MOM(symbol, period, resolution)
def WarmUpIndicators(self, history):
for tuple in history.itertuples():
self.mom.Update(tuple.Index, tuple.close)
@property
def momValue(self):
return float(self.mom.Current.Value)