| Overall Statistics |
|
Total Trades 234 Average Win 5.18% Average Loss -2.15% Compounding Annual Return 18.995% Drawdown 37.800% Expectancy 1.206 Net Profit 2419.574% Sharpe Ratio 0.969 Probabilistic Sharpe Ratio 29.722% Loss Rate 35% Win Rate 65% Profit-Loss Ratio 2.41 Alpha 0.129 Beta 0.731 Annual Standard Deviation 0.229 Annual Variance 0.053 Information Ratio 0.503 Tracking Error 0.189 Treynor Ratio 0.304 Total Fees $3938.51 |
# Pick 5 ETFs with strongest 3 month momentum into your portfolio and weight them equally.
# Hold for 1 month and then rebalance at the satrt of a month
import pandas as pd
from datetime import datetime
class AssetClassMomentumAlgorithm(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2002, 7, 28)
self.SetEndDate(datetime.now())
self.SetCash(100000)
# create a dictionary to store momentum indicators for all symbols
self.data = {}
period = 3*22*24 # period of the momentum indicator is 3 months and average 22 business day for each month
self.symbols = ["SPY", "IWF", "QQQ", "IBB", "XLV", "EEM", "IWD", "TLT", "IEF", "IGOV", "GLD", "IYR", "DBC"]
# warm up the MOM indicator
self.SetWarmUp(period)
for symbol in self.symbols:
self.AddEquity(symbol, Resolution.Hour)
self.data[symbol] = self.MOM(symbol, period, Resolution.Hour)
# schedule the function to fire at the month start, 30 min from a market open
self.Schedule.On(self.DateRules.MonthStart("SPY"), self.TimeRules.AfterMarketOpen("SPY", 30), self.Rebalance)
def OnData(self, data):
pass
def Rebalance(self):
if self.IsWarmingUp: return
top5 = pd.Series(self.data).sort_values(ascending = False)[:5]
for kvp in self.Portfolio:
security_hold = kvp.Value
# liquidate the security which is no longer in the top5 momentum list
if security_hold.Invested and (security_hold.Symbol.Value not in top5.index):
self.Liquidate(security_hold.Symbol)
added_symbols = []
for symbol in top5.index:
if not self.Portfolio[symbol].Invested:
added_symbols.append(symbol)
# 0.9 is to have some cushion and enough capital for order execution
for added in added_symbols:
self.SetHoldings(added, 0.9/len(added_symbols))