Overall Statistics
Total Trades
158
Average Win
1.02%
Average Loss
-2.34%
Compounding Annual Return
-7.944%
Drawdown
53.300%
Expectancy
-0.062
Net Profit
-20.482%
Sharpe Ratio
-0.103
Probabilistic Sharpe Ratio
1.340%
Loss Rate
35%
Win Rate
65%
Profit-Loss Ratio
0.44
Alpha
-0.06
Beta
0.537
Annual Standard Deviation
0.249
Annual Variance
0.062
Information Ratio
-0.372
Tracking Error
0.243
Treynor Ratio
-0.048
Total Fees
$223.96
Estimated Strategy Capacity
$0
Lowest Capacity Asset
DVYA V4DT5T986VDX
#region imports
from AlgorithmImports import *
#endregion
## SIMON LesFlex June 2021 ##
## Modified by Vladimir, Frank, and Tom Penrose

### Key Short—Term Economic Indicators. The Key Economic Indicators (KEI) database contains monthly and quarterly statistics 
### (and associated statistical methodological information) for the 33 OECD member and for a selection of non—member countries 
### on a wide variety of economic indicators, namely: quarterly national accounts, industrial production, composite leading indicators, 
### business tendency and consumer opinion surveys, retail trade, consumer and producer prices, hourly earnings, employment/unemployment,
### interest rates, monetary aggregates, exchange rates, international trade and balance of payments. Indicators have been prepared by national statistical 
### agencies primarily to meet the requirements of users within their own country. In most instances, the indicators are compiled in accordance with 
### international statistical guidelines and recommendations. However, national practices may depart from these guidelines, and these departures may 
### impact on comparability between countries. There is an on—going process of review and revision of the contents of the database in order to maximise 
### the relevance of the database for short—term economic analysis.
### For more information see: http://stats.oecd.org/OECDStat_Metadata/ShowMetadata.ashx?Dataset=KEI&Lang=en
### Reference Data Set: https://www.quandl.com/data/OECD/KEI_LOLITOAA_OECDE_ST_M-Leading-indicator-amplitude-adjusted-OECD-Europe-Level-ratio-or-index-Monthly

# Further links:
# https://app.hedgeye.com/insights/77156-chart-of-the-day-what-works-in-which-quad?type=macro
# https://stockcharts.com/freecharts/rrg/
# https://seekingalpha.com/article/4434713-sector-rotation-strategy-using-the-high-yield-spread


import numpy as np
from QuantConnect.Python import PythonQuandl

class QuandlImporterAlgorithm(QCAlgorithm):

    def Initialize(self):
        
        # Leading Indicator, Amplitude Adjusted, Oecd — EUROPE, Level, Ratio Or Index
        #self.quandlCode = "OECD/KEI_LOLITOAA_OECDE_ST_M"
        
        # Leading Indicator, Amplitude Adjusted, Oecd — TOTAL, Level, Ratio Or Index
        self.quandlCode = "OECD/KEI_LOLITOAA_OECD_ST_M"
        
        ## Optional argument - your personal token necessary for restricted dataset
        Quandl.SetAuthCode("ZYmz4yBbyvxrejZ44hKo")
        
        self.SetStartDate(2020,1,1)                                 #Set Start Date
        self.SetEndDate(datetime.today() - timedelta(1))            #Set End Date
        self.SetCash(100000)                                        #Set Strategy Cash
        
        # Benchmark using qqq & bond only?
        self.use_qqq_tlt_only = False
        
        # Tickers
        self.SetBenchmark("SPY")
        self.SPY = self.AddEquity('SPY', Resolution.Hour).Symbol
        self.stock = self.AddEquity('QQQ', Resolution.Hour).Symbol
        self.bond = self.AddEquity('TLT', Resolution.Hour).Symbol
        #US-Equity Indeces
        self.XLF = self.AddEquity('XLF', Resolution.Hour).Symbol
        self.XLE = self.AddEquity('XLE', Resolution.Hour).Symbol
        self.XLB = self.AddEquity('XLB', Resolution.Hour).Symbol
        self.XLI = self.AddEquity('XLI', Resolution.Hour).Symbol
        self.XLY = self.AddEquity('XLY', Resolution.Hour).Symbol
        self.XLP = self.AddEquity('XLP', Resolution.Hour).Symbol
        self.XLU = self.AddEquity('XLU', Resolution.Hour).Symbol
        self.XLK = self.AddEquity('XLK', Resolution.Hour).Symbol
        self.XLV = self.AddEquity('XLV', Resolution.Hour).Symbol
        self.XLC = self.AddEquity('XLC', Resolution.Hour).Symbol
        #International Indeces
        self.VEU = self.AddEquity('VEU', Resolution.Hour).Symbol
        self.VXUS = self.AddEquity('VXUS', Resolution.Hour).Symbol
        self.ACWI = self.AddEquity('ACWI', Resolution.Hour).Symbol
        #High-Yield Income ETF's
        self.SDIV = self.AddEquity('SDIV', Resolution.Hour).Symbol
        self.VNQ = self.AddEquity('VNQ', Resolution.Hour).Symbol
        self.HYD = self.AddEquity('HYD', Resolution.Hour).Symbol
        self.TIP = self.AddEquity('TIP', Resolution.Hour).Symbol
        #International Fixed Income
        self.DVYA = self.AddEquity('DVYA', Resolution.Hour).Symbol
        #Alt Investments
        self.GLD = self.AddEquity('GLD', Resolution.Hour).Symbol
        self.SLV = self.AddEquity('SLV', Resolution.Hour).Symbol
        
        symbols = ['QQQ', 'TLT', 'XLF', 'XLE', 'XLB', 'XLI', 'XLY', 'XLP', 'XLU', 'XLK', 'XLV', 'XLC']
        
        # Rate of Change for plotting
        self.sharpe_dict = {}
        for symbol in symbols:
            self.sharpe_dict[symbol] = SharpeRatio(symbol, 42, 0.)
            self.RegisterIndicator(symbol, self.sharpe_dict[symbol], Resolution.Daily)
        self.SetWarmup(42)
        
        # Vars
        self.init = True
        self.regime = 0
        self.kei = self.AddData(QuandlCustomColumns, self.quandlCode, Resolution.Daily, TimeZones.NewYork).Symbol
        self.sma = self.SMA(self.kei, 1)
        self.mom = self.MOMP(self.kei, 2)
        
        self.Schedule.On(self.DateRules.WeekStart(self.stock), self.TimeRules.AfterMarketOpen(self.stock, 31),
            self.Rebalance)
        
        
    def Rebalance(self):
        
        if self.IsWarmingUp or not self.mom.IsReady or not self.sma.IsReady: return
        initial_asset = self.stock if self.mom.Current.Value > 0 else self.bond
        
        if self.init:
            self.SetHoldings(initial_asset, 1)
            self.init = False
        
        # Return the historical data for custom 90 day period
        #keihist = self.History([self.kei],self.StartDate-timedelta(100),self.StartDate-timedelta(10))
        
        # Return the last 1400 bars of history
        keihist = self.History([self.kei], 6*220)
        #keihist = keihist['Value'].unstack(level=0).dropna()
        
        # Define adaptive tresholds
        keihistlowt = np.nanpercentile(keihist,  15.)
        keihistmidt = np.nanpercentile(keihist,  50.)
        keihisthight = np.nanpercentile(keihist, 90.)
        kei = self.sma.Current.Value
        keimom = self.mom.Current.Value
        
        if self.use_qqq_tlt_only == True:
            
            # KEI momentum
            if (keimom >= 0) and (not self.regime == 1):
                self.regime = 1
                self.Liquidate()
                self.SetHoldings(self.stock, 1.)
            elif (keimom < 0) and (not self.regime == 0):
                self.regime = 0
                self.Liquidate()
                self.SetHoldings(self.bond,  1.)

        else:
            
            if (keimom > 0 and kei <= keihistlowt) and (not self.regime == 1):
                # RECOVERY
                self.regime = 1
                self.Debug(f'{self.Time} 1 RECOVERY: INDUSTRIAL / MATERIALS / CUSTOMER DISCR / TECH')
                self.Liquidate()
                '''self.SetHoldings(self.XLI, .25)
                self.SetHoldings(self.XLK, .25)
                self.SetHoldings(self.XLB, .25)
                self.SetHoldings(self.XLY, .25)'''
                
                self.SetHoldings(self.XLI,  .05)
                self.SetHoldings(self.XLK,  .05)
                self.SetHoldings(self.XLB,  .05)
                self.SetHoldings(self.XLY,  .05)
                self.SetHoldings(self.XLF,  .05)
                self.SetHoldings(self.VEU, .04)
                self.SetHoldings(self.VXUS, .04)
                self.SetHoldings(self.ACWI, .04)
                self.SetHoldings(self.bond, .07)
                self.SetHoldings(self.SDIV, .07)
                self.SetHoldings(self.VNQ, .13)
                self.SetHoldings(self.HYD, .07)
                self.SetHoldings(self.TIP, .07)
                self.SetHoldings(self.DVYA, .06)
                self.SetHoldings(self.GLD, .06)
                self.SetHoldings(self.SLV, .06)
                
            elif (keimom > 0 and kei >= keihistlowt and kei < keihistmidt) and (not self.regime == 2):
                # EARLY EXPANSION - Technology, Transporation
                self.regime = 2
                self.Debug(f'{self.Time} 2 EARLY: INDUSTRIAL / CUSTOMER DISCR / FINANCIAL')
                '''self.SetHoldings(self.XLI,  .05)
                self.SetHoldings(self.XLK,  .05)
                self.SetHoldings(self.XLB,  .05)
                self.SetHoldings(self.XLY,  .05)
                self.SetHoldings(self.XLF,  .05)
                self.SetHoldings(self.VEU, .04)
                self.SetHoldings(self.VXUS, .04)
                self.SetHoldings(self.ACWI, .04)
                self.SetHoldings(self.bond, .07)
                self.SetHoldings(self.SDIV, .07)
                self.SetHoldings(self.VNQ, .13)
                self.SetHoldings(self.HYD, .07)
                self.SetHoldings(self.TIP, .07)
                self.SetHoldings(self.DVYA, .06)
                self.SetHoldings(self.GLD, .06)
                self.SetHoldings(self.SLV, .06)'''
                
                self.SetHoldings(self.XLI, .30)
                self.SetHoldings(self.XLK, .20)
                self.SetHoldings(self.XLB, .10)
                self.SetHoldings(self.XLY, .25)
                self.SetHoldings(self.XLF, .10)
                
            elif (keimom > 0 and kei >= keihistmidt and kei < keihisthight) and (not self.regime == 3):
                # REBOUND - Basic Materials, Metals, Energy, High Interest Finance
                self.regime = 3
                self.Debug(f'{self.Time} 3 REBOUND: INDUSTRIAL / TECH / MATERIALS')
                self.Liquidate()
                self.SetHoldings(self.XLI, .104)
                self.SetHoldings(self.XLK, .104)
                self.SetHoldings(self.XLB, .026)
                self.SetHoldings(self.XLF, .026)
                self.SetHoldings(self.VEU, .06)
                self.SetHoldings(self.VXUS, .06)
                self.SetHoldings(self.ACWI, .06)
                self.SetHoldings(self.bond, .058)
                self.SetHoldings(self.SDIV, .058)
                self.SetHoldings(self.VNQ, .12)
                self.SetHoldings(self.HYD, .058)
                self.SetHoldings(self.TIP, .058)
                self.SetHoldings(self.DVYA, .04)
                self.SetHoldings(self.GLD, .06)
                self.SetHoldings(self.SLV, .06)
                
            elif (keimom > 0 and kei >= keihisthight) and (not self.regime == 4):
                # TOP RISING - High Interest Finance, Real Estate, IT, Commodities, Precious Metals
                self.regime = 4
                self.Debug(f'{self.Time} 4 TOP RISING: INDUSTRIAL / TECH / FINANCIAL')
                self.Liquidate()
                self.SetHoldings(self.XLI, .17)
                self.SetHoldings(self.XLK, .17)
                self.SetHoldings(self.XLF, .17)
                self.SetHoldings(self.VEU, .06)
                self.SetHoldings(self.VXUS, .06)
                self.SetHoldings(self.ACWI, .06)
                self.SetHoldings(self.bond, .04)
                self.SetHoldings(self.SDIV, .04)
                self.SetHoldings(self.VNQ, .04)
                self.SetHoldings(self.HYD, .04)
                self.SetHoldings(self.TIP, .04)
                self.SetHoldings(self.GLD, .05)
                self.SetHoldings(self.SLV, .05)
                
                
            elif (keimom < 0 and kei >= keihisthight) and (not self.regime == 3.7):
                # TOP DECLINING - Utilities
                self.regime = 3.7
                self.Debug(f'{self.Time} 4 TOP DECLINING: BOND / UTILITIES')
                self.Liquidate()
                self.SetHoldings(self.XLU,  .26)
                self.SetHoldings(self.VEU, .06)
                self.SetHoldings(self.VXUS, .06)
                self.SetHoldings(self.ACWI, .06)
                self.SetHoldings(self.bond, .058)
                self.SetHoldings(self.SDIV, .058)
                self.SetHoldings(self.VNQ, .118)
                self.SetHoldings(self.HYD, .058)
                self.SetHoldings(self.TIP, .058)
                self.SetHoldings(self.DVYA, .04)
                self.SetHoldings(self.GLD, .065)
                self.SetHoldings(self.SLV, .065) 
                
                #self.SetHoldings(self.bond, .95)
                #self.SetHoldings(self.XLU,  .05)
                
            elif (keimom < 0 and kei <= keihisthight and kei > keihistmidt) and (not self.regime == 2.7):
                # LATE - 
                self.regime = 2.7
                self.Debug(f'{self.Time} 5 LATE: HEALTH / TECH / CUSTOMER DISCR') 
                self.Liquidate()
                self.SetHoldings(self.XLV,  .10)
                self.SetHoldings(self.XLK,  .8)
                self.SetHoldings(self.XLY,  .8)
                self.SetHoldings(self.VEU, .06)
                self.SetHoldings(self.VXUS, .06)
                self.SetHoldings(self.ACWI, .06)
                self.SetHoldings(self.bond, .058)
                self.SetHoldings(self.SDIV, .058)
                self.SetHoldings(self.VNQ, .118)
                self.SetHoldings(self.HYD, .058)
                self.SetHoldings(self.TIP, .058)
                self.SetHoldings(self.DVYA, .04)
                self.SetHoldings(self.GLD, .065)
                self.SetHoldings(self.SLV, .065)  
                
            elif (keimom < 0 and kei <= keihistmidt and kei > keihistlowt) and (not self.regime == 1.7):
                # DECLINE - Defensive Sectors, Utilities, Consumer Staples
                self.regime = 1.7
                self.Debug(f'{self.Time} 6 DECLINE: BOND / UTILITIES') 
                self.Liquidate()
                self.SetHoldings(self.XLU,  .24)
                self.SetHoldings(self.VEU, .04)
                self.SetHoldings(self.VXUS, .04)
                self.SetHoldings(self.ACWI, .04)
                self.SetHoldings(self.bond, .07)
                self.SetHoldings(self.SDIV, .07)
                self.SetHoldings(self.VNQ, .13)
                self.SetHoldings(self.HYD, .07)
                self.SetHoldings(self.TIP, .07)
                self.SetHoldings(self.DVYA, .06)
                self.SetHoldings(self.GLD, .06)
                self.SetHoldings(self.SLV, .06)
                
            elif (keimom < 0 and kei <= keihistlowt) and (not self.regime == 0.7):
                # BOTTOM DECLINING
                self.regime = 0.7
                self.Debug(f'{self.Time} 7 BOTTOM DECLINING: BOND / UTILITIES')
                self.Liquidate()
                self.SetHoldings(self.XLU,  .05)
                #self.SetHoldings(self.VEU, .02)
                #self.SetHoldings(self.VXUS, .02)
                #self.SetHoldings(self.ACWI, .02)
                self.SetHoldings(self.bond, .70)
                #self.SetHoldings(self.SDIV, .175)
                #self.SetHoldings(self.VNQ, .175)
                #self.SetHoldings(self.HYD, .175)
                #self.SetHoldings(self.TIP, .175)
                #self.SetHoldings(self.DVYA, .08)
                self.SetHoldings(self.GLD, .065)
                self.SetHoldings(self.SLV, .065)  
        
        self.Plot("LeadInd", "SMA(LeadInd)", 100. * self.sma.Current.Value)
        self.Plot("LeadInd", "keihistlowt",  100. * keihistlowt)
        self.Plot("LeadInd", "keihistmidt",  100. * keihistmidt)
        self.Plot("LeadInd", "keihisthight", 100. * keihisthight)
        self.Plot("MOMP", "MOMP(LeadInd)", min(2., max(-2., self.mom.Current.Value)))
        self.Plot("MOMP", "Regime", self.regime)
        
        #self.Plot("MOM", "XLF", self.sharpe_dict['XLF'].Current.Value)
        #self.Plot("MOM", "XLE", self.sharpe_dict['XLE'].Current.Value)
        #self.Plot("MOM", "XLB", self.sharpe_dict['XLB'].Current.Value)
        #self.Plot("MOM", "XLI", self.sharpe_dict['XLI'].Current.Value)
        #self.Plot("MOM", "XLY", self.sharpe_dict['XLY'].Current.Value)
        #self.Plot("MOM", "XLP", self.sharpe_dict['XLP'].Current.Value)
        #self.Plot("MOM", "XLU", self.sharpe_dict['XLU'].Current.Value)
        #self.Plot("MOM", "XLK", self.sharpe_dict['XLK'].Current.Value)
        #self.Plot("MOM", "XLV", self.sharpe_dict['XLV'].Current.Value)
        #self.Plot("MOM", "XLC", self.sharpe_dict['XLC'].Current.Value)


# Quandl often doesn't use close columns so need to tell LEAN which is the "value" column.
class QuandlCustomColumns(PythonQuandl):
    def __init__(self):
        # Define ValueColumnName: cannot be None, Empty or non-existant column name
        self.ValueColumnName = "Value"