| 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"