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"