| Overall Statistics |
|
Total Trades
571
Average Win
3.07%
Average Loss
-3.07%
Compounding Annual Return
-1.218%
Drawdown
53.700%
Expectancy
0.045
Net Profit
-25.184%
Sharpe Ratio
-0.035
Probabilistic Sharpe Ratio
0.000%
Loss Rate
48%
Win Rate
52%
Profit-Loss Ratio
1.00
Alpha
-0.001
Beta
-0.041
Annual Standard Deviation
0.1
Annual Variance
0.01
Information Ratio
-0.326
Tracking Error
0.195
Treynor Ratio
0.086
Total Fees
$1221.34
Estimated Strategy Capacity
$3500000.00
Lowest Capacity Asset
IVE RV0PWMLXVHPH
Portfolio Turnover
3.03%
|
#region imports
from AlgorithmImports import *
#endregion
# https://quantpedia.com/strategies/momentum-factor-and-style-rotation-effect/
#
# Russell’s ETFs for six equity styles are used
# (small-cap value, mid-cap value, large-cap value, small-cap growth, mid-cap growth, large-cap growth).
# Each month, the investor calculates 12-month momentum for each style and goes long on the winner and short on the loser.
# The portfolio is rebalanced each month.
#
# QC Implementation:
# - Trading IVW in 10/2020 is skipped due to data error.
class MomentumFactorAndStyleRotationEffect(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2000, 1, 1)
self.SetCash(100000)
self.tickers = [
'IWS', # iShares Russell Midcap Value ETF
'IWP', # iShares Russell Midcap Growth ETF
'IWN', # iShares Russell 2000 Value ETF
'IWO', # iShares Russell 2000 Growth ETF
'IVE', # iShares S&P 500 Value ETF
'IVW' # iShares S&P 500 Growth ETF
]
self.mom = {}
self.period = 12 * 21
self.SetWarmUp(self.period)
for ticker in self.tickers:
security = self.AddEquity(ticker, Resolution.Daily)
security.SetFeeModel(CustomFeeModel())
security.SetLeverage(10)
self.mom[security.Symbol] = self.MOM(security.Symbol, self.period)
self.recent_month = -1
def OnData(self, data):
if self.recent_month == self.Time.month:
return
self.recent_month = self.Time.month
mom_ready = [ s for s in self.mom if self.mom[s].IsReady and s in data]
if mom_ready:
sorted_mom = sorted(mom_ready, key = lambda x: self.mom[x].Current.Value, reverse=True)
for symbol in sorted_mom[1:-1]:
if self.Portfolio[symbol].Invested:
self.Liquidate(symbol)
winner = sorted_mom[0]
loser = sorted_mom[-1]
if self.Securities[winner].Price != 0 and self.Securities[winner].IsTradable:
if (self.Time.month == 10 and self.Time.year == 2020) and winner.Value == 'IVW': # prevent data error
self.Liquidate(winner)
else:
self.SetHoldings(winner, 1)
if self.Securities[loser].Price != 0 and self.Securities[loser].IsTradable:
if (self.Time.month == 10 and self.Time.year == 2020) and loser.Value == 'IVW': # prevent data error
self.Liquidate(loser)
else:
self.SetHoldings(loser, -1)
# Custom fee model.
class CustomFeeModel(FeeModel):
def GetOrderFee(self, parameters):
fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.00005
return OrderFee(CashAmount(fee, "USD"))