Overall Statistics
Total Trades
63
Average Win
5.97%
Average Loss
-2.22%
Compounding Annual Return
62.514%
Drawdown
35.800%
Expectancy
1.182
Net Profit
70.941%
Sharpe Ratio
1.179
Probabilistic Sharpe Ratio
58.321%
Loss Rate
41%
Win Rate
59%
Profit-Loss Ratio
2.68
Alpha
0.438
Beta
0.182
Annual Standard Deviation
0.407
Annual Variance
0.166
Information Ratio
0.598
Tracking Error
0.417
Treynor Ratio
2.632
Total Fees
$579.04
# Speculation Rollover Strategy
# Use 12 Speculative ETFs (DWT, UWT, DGAZ, UGAZ, TZA, TNA, ERY, ERX, FAZ, FAS, TLT, and TBT), 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 TOPX 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, 1, 1)
        self.SetEndDate(datetime.now())
        self.SetCash(100000) 

        # choose 13 speculative ETF 
        tickers = [ "SPY",  # S&P500 ETF 
                    "DWT",  # Triple Oil Down
                    "UWT",  # Triple Oil Up
                    "DGAZ",  # Triple Natural Gas Down
                    "UGAZ",  # Triple Natural Gas Up
                    "TZA",  # Triple Small Cap Down
                    "TNA",  # Triple Small Cap Up
                    "ERY",  # Triple Energy Down
                    "ERX",  # Triple Energy Up
                    "FAZ",  # Triple Financials Down
                    "FAS",  # Triple Financials Up
                    "TBT",  # 20 Treasury Bond Down
                    "TLT"]  # 20 Treasury Bond Up 

        self.data = {}
        
        for ticker in tickers:
            symbol = self.AddEquity(ticker, Resolution.Daily).Symbol
            self.data[symbol] = SymbolData(self, symbol)

        self.SetWarmUp(30)
        
        
        # shcedule the function to fire on Tuesday, after 30 minutes 
        self.Schedule.On(
            self.DateRules.MonthStart("TBT"),
            self.TimeRules.AfterMarketOpen("TBT", 30),
            self.Rebalance)
            
    def OnData(self, data):
        for symbol, symbolData in self.data.items():
            if symbolData.IsOverBought:
                self.Debug("Overbought Signal")
                self.Liquidate(symbol)
            else:
                self.Debug("Not Overbought") 

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

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

        # liquidate the security which is no longer in the top3 momentum list
        for symbol in self.data:
            if symbol not in selected:
                if self.Portfolio[symbol].Invested:
                   self.Liquidate(symbol, 'Not selected')

        for symbol in selected:
            self.SetHoldings(symbol, 1/len(selected))
           
            
class SymbolData:
    
    def __init__(self, algorithm, symbol):
        self.algorithm = algorithm
        self.symbol = symbol
        self.TRIX_Period = 10
        self.TRIX_OB = 60   # Overbought is above 60
        self.TRIX_OS = 40   # Oversold is below 40  
        self.roc = RateOfChangePercent(1)
        self.trix = algorithm.TRIX(symbol, self.TRIX_Period, Resolution.Daily)
        
        consolidator = TradeBarConsolidator(CalendarType.Monthly)
        algorithm.RegisterIndicator(symbol, self.roc, consolidator)
        
    @property    
    def IsOverBought(self):
        if self.trix.Current.Value > self.TRIX_OB:
            return True
        else:
            return False
    @property
    def IsOverSold(self):
        if self.trix.Current.Value < self.TRIX_OS:
            return True
        else:
            return False