Overall Statistics
# Monthly ETF Rollover Strategy
# Use 11 Sector ETFs (XLB, XLC, XLE, XLF, XLI, XLK, XLP, XLRE, XLU, XLV, and XLY), equal weight the TOP3 ETF’s on 1st Day of the Month. Hold asset class Sector ETF’s for 1 month.
# If ETF is still in the TOP3 at month end, Keep It

import numpy as np
import pandas as pd
from datetime import datetime

class EmmausAlgorithm(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2019, 5, 1)
        self.SetCash(100000) 

        # choose 11 sector ETFs
        tickers = [ "XLB",  # Materials
                    "XLC",  # Communication Services
                    "XLE",  # Energy
                    "XLF",  # Financials
                    "XLI",  # Industrials
                    "XLK",  # Technology
                    "XLP",  # Staples
                    "XLRE", # Real Estate
                    "XLU",  # Utilities
                    "XLV",  # Health Care
                    "XLY"]  # Discretionary 

        self.data = {}

        for ticker in tickers:
            symbol = self.AddEquity(ticker, Resolution.Daily).Symbol
            self.data[symbol] = RateOfChangePercent(1)
            consolidator = TradeBarConsolidator(CalendarType.Monthly)
            self.RegisterIndicator(symbol, self.data[symbol], consolidator)

        self.SetWarmUp(30)

        # shcedule the function to fire at the month start 
        self.Schedule.On(
            self.DateRules.MonthStart("XLB"),
            self.TimeRules.AfterMarketOpen("XLB", 10),
            self.Rebalance)


    def Rebalance(self):
        if self.IsWarmingUp:
            return
        
        func = lambda x: x[1].Current.Value

        top3 = {x[0]: x[1].Current.Value
            for x in sorted(self.data.items(), key=func, reverse=True)[:3]}

        for kvp in self.Portfolio:
            symbol = kvp.Key
            if symbol in top3:
                continue
            # liquidate the security which is no longer in the top3 momentum list
            if kvp.Value.Invested:
                self.Liquidate(symbol, 'Not selected')

        for symbol, value in top3.items():
            self.SetHoldings(symbol, 1/3)