Overall Statistics
Total Trades
5
Average Win
0%
Average Loss
-0.41%
Compounding Annual Return
-13.354%
Drawdown
2.600%
Expectancy
-1
Net Profit
-1.867%
Sharpe Ratio
-2.272
Probabilistic Sharpe Ratio
7.355%
Loss Rate
100%
Win Rate
0%
Profit-Loss Ratio
0
Alpha
-0.004
Beta
0.246
Annual Standard Deviation
0.042
Annual Variance
0.002
Information Ratio
2.198
Tracking Error
0.126
Treynor Ratio
-0.388
Total Fees
$5.00
Estimated Strategy Capacity
$160000000.00
Lowest Capacity Asset
GSG TKH7EPK7SRC5
# https://quantpedia.com/Screener/Details/2
# Use 5 ETFs (SPY - US stocks, EFA - foreign stocks, BND - bonds, VNQ - REITs, GSG - commodities).
# Pick 3 ETFs with strongest 12 month momentum into your portfolio and weight them equally. 
# Hold for 1 month and then rebalance.

import pandas as pd
from datetime import datetime

class AssetClassMomentumAlgorithm(QCAlgorithm):

    def Initialize(self):

        self.SetStartDate(2022, 1, 1)  
        self.SetEndDate(datetime.now())  
        self.SetCash(10000) 
        # create a dictionary to store momentum indicators for all symbols 
        self.data = {}
        period = 5*21
        self.symbols = ["SPY", "EFA", "BND", "VNQ", "GSG", "XLE", "ARKK", "EEM", "DBP"]
        # warm up the MOM indicator
        self.SetWarmUp(period)
        for symbol in self.symbols:
            self.AddEquity(symbol, Resolution.Daily)
            self.data[symbol] = self.MOM(symbol, period, Resolution.Daily)
        # shcedule the function to fire at the month start 
        self.Schedule.On(self.DateRules.MonthStart("SPY"), self.TimeRules.AfterMarketOpen("SPY"), self.Rebalance)
        self.Settings.FreePortfolioValuePercentage=0.2
            
    def OnData(self, data):
        stock = self.symbols[0]
        close = data[stock].Close
        #self.Debug("{} Symbol:{} Close:{:.2f}".format(self.Time, stock, close))
        self.value=close

    def Rebalance(self):
        if self.IsWarmingUp: return
        top3 = pd.Series(self.data).sort_values(ascending = False)[:3]
        for kvp in self.Portfolio:
            security_hold = kvp.Value
            # liquidate the security which is no longer in the top3 momentum list
            if security_hold.Invested and (security_hold.Symbol.Value not in top3.index):
                self.Liquidate(security_hold.Symbol)
        
        added_symbols = []        
        for symbol in top3.index:
            if not self.Portfolio[symbol].Invested:
                added_symbols.append(symbol)
                
        for added in added_symbols:
            lastPrice = self.value
            sharesToBuy= self.Portfolio.MarginRemaining*(1-self.Settings.FreePortfolioValuePercentage) // len(added_symbols) // lastPrice
            self.Debug("{} Shares to buy Symbol:{} Close:{} RemMargin:{:.2f} sharesToBuy:{}"
                    .format(self.Time, added, lastPrice , self.Portfolio.MarginRemaining, sharesToBuy))
            self.MarketOrder(added, sharesToBuy)