Overall Statistics
Total Trades
2167
Average Win
0.72%
Average Loss
-0.73%
Compounding Annual Return
10.620%
Drawdown
25.500%
Expectancy
0.238
Net Profit
550.864%
Sharpe Ratio
0.899
Probabilistic Sharpe Ratio
26.258%
Loss Rate
38%
Win Rate
62%
Profit-Loss Ratio
0.99
Alpha
0
Beta
0
Annual Standard Deviation
0.129
Annual Variance
0.017
Information Ratio
0.899
Tracking Error
0.129
Treynor Ratio
0
Total Fees
$9614.23
# 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
# Why invalid orders in backtest
# https://www.quantconnect.com/forum/discussion/10611/why-invalid-orders-in-backtest/p1
import pandas as pd
from datetime import datetime

class AssetClassMomentumAlgorithm(QCAlgorithm):

    def Initialize(self):

        self.SetStartDate(2002, 7, 28)  
        self.SetEndDate(datetime.now())  
        self.InitCash = 100000
        self.SetCash(self.InitCash)  
        self.MKT = self.AddEquity("SPY", Resolution.Hour).Symbol
        self.mkt = []
        self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, AccountType.Margin)

        # create a dictionary to store momentum indicators for all symbols 
        self.data = {}
        period = int(3*21) # period of the momentum indicator is 3 months, average 21 business day for each month and 6.5 hours trading session
        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.Minute)
            if self.Securities[symbol].IsTradable == True:
                self.data[symbol] = self.MOM(symbol, period, Resolution.Daily)
            else:
                continue   

        self.Schedule.On(self.DateRules.MonthStart("SPY"), self.TimeRules.AfterMarketOpen("SPY", 30), 
            self.Rebalance)
            

    def Rebalance(self):
        if self.IsWarmingUp: return
    
        for sec in self.data:
            if self.Securities[sec].IsTradable == False:
                self.data.remove(sec)
        
        top5 = pd.Series(self.data).sort_values(ascending = False)[:5]

        for sec in self.Portfolio.Keys:
            if sec not in top5.index:                
                self.Liquidate(sec)               
                
        for sec in top5.index:        
            self.SetHoldings(sec, 1.0 / len(top5))
        
            
    def OnEndOfDay(self): 
        
        mkt_price = self.Securities[self.MKT].Close
        self.mkt.append(mkt_price)
        mkt_perf = self.InitCash * self.mkt[-1] / self.mkt[0] 
        self.Plot('Strategy Equity', self.MKT, mkt_perf)     
        
        account_leverage = self.Portfolio.TotalHoldingsValue / self.Portfolio.TotalPortfolioValue
        
        self.Plot('Holdings', 'leverage', round(account_leverage, 2))
        self.Plot('Holdings', 'Target Leverage', 1)