Overall Statistics
Total Trades
519
Average Win
1.72%
Average Loss
-0.35%
Compounding Annual Return
22.095%
Drawdown
17.200%
Expectancy
3.198
Net Profit
1418.329%
Sharpe Ratio
1.488
Probabilistic Sharpe Ratio
89.577%
Loss Rate
28%
Win Rate
72%
Profit-Loss Ratio
4.84
Alpha
0.193
Beta
0.305
Annual Standard Deviation
0.156
Annual Variance
0.024
Information Ratio
0.52
Tracking Error
0.2
Treynor Ratio
0.761
Total Fees
$2845.61
Estimated Strategy Capacity
$0
Lowest Capacity Asset
DVYA V4DT5T986VDX
## 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(2008,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"