| Overall Statistics |
|
Total Trades 544 Average Win 1.42% Average Loss -1.06% Compounding Annual Return 0.532% Drawdown 18.000% Expectancy 0.054 Net Profit 9.785% Sharpe Ratio 0.136 Loss Rate 55% Win Rate 45% Profit-Loss Ratio 1.35 Alpha 0.005 Beta 0.02 Annual Standard Deviation 0.047 Annual Variance 0.002 Information Ratio -0.385 Tracking Error 0.189 Treynor Ratio 0.322 Total Fees $1255.21 |
# https://www.quantconnect.com/tutorials/strategy-library/momentum-and-style-rotation-effect
# https://quantpedia.com/Screener/Details/91
class MomentumAndStyleRotationAlgorithm(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2001, 1, 1)
self.SetEndDate(2018, 8, 1)
self.SetCash(100000)
tickers = ["IJJ", # iShares S&P Mid-Cap 400 Value Index ETF
"IJK", # iShares S&P Mid-Cap 400 Growth ETF
"IJS", # iShares S&P Small-Cap 600 Value ETF
"IJT", # iShares S&P Small-Cap 600 Growth ETF
"IVE", # iShares S&P 500 Value Index ETF
"IVW"] # iShares S&P 500 Growth ETF
lookback = 12*20
# Save all momentum indicator into the dictionary
self.mom = dict()
for ticker in tickers:
symbol = self.AddEquity(ticker, Resolution.Daily).Symbol
self.mom[symbol] = self.MOM(symbol, lookback)
self.SetWarmUp(lookback)
# Portfolio monthly rebalance
self.Schedule.On(self.DateRules.MonthStart("IJJ"), self.TimeRules.At(0, 0), self.Rebalance)
def Rebalance(self):
'''Sort securities by momentum.
Short the one with the lowest momentum.
Long the one with the highest momentum.
Liquidate positions of other securities'''
# Order the MOM dictionary by value
sorted_mom = sorted(self.mom, key = lambda x: self.mom[x].Current.Value)
# Liquidate the ETFs that are no longer selected
for symbol in sorted_mom[1:-1]:
if self.Portfolio[symbol].Invested:
self.Liquidate(symbol, 'No longer selected')
self.SetHoldings(sorted_mom[-1], -0.5) # Short the ETF with lowest MOM
self.SetHoldings(sorted_mom[0], 0.5) # Long the ETF with highest MOM