| Overall Statistics |
|
Total Trades 118 Average Win 6.83% Average Loss -1.02% Compounding Annual Return 29.039% Drawdown 15.700% Expectancy 5.792 Net Profit 2680.576% Sharpe Ratio 1.519 Probabilistic Sharpe Ratio 95.224% Loss Rate 12% Win Rate 88% Profit-Loss Ratio 6.72 Alpha 0.145 Beta 0.501 Annual Standard Deviation 0.134 Annual Variance 0.018 Information Ratio 0.653 Tracking Error 0.133 Treynor Ratio 0.405 Total Fees $340.86 Estimated Strategy Capacity $4600000.00 Lowest Capacity Asset XLK RGRPZX100F39 |
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("4ctnjerqtjyCDxPpCrdv")
self.SetStartDate(2009,1,1) #Set Start Date
#self.SetEndDate(datetime.today() - timedelta(1)) #Set End Date
self.SetCash(10000) #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
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
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, .50)
self.SetHoldings(self.XLY, .50)
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, .33)
# self.SetHoldings(self.XLK, .20)
# self.SetHoldings(self.XLB, .10)
# self.SetHoldings(self.XLY, .25)
self.SetHoldings(self.XLF, .33)
self.SetHoldings(self.XLE, .33)
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.XLU, .50)
self.SetHoldings(self.XLK, .50)
# self.SetHoldings(self.XLB, .10)
# self.SetHoldings(self.XLF, .10)
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, .34)
self.SetHoldings(self.XLK, .33)
self.SetHoldings(self.XLF, .33)
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.bond, .50)
self.SetHoldings(self.XLP, .50)
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, .50)
self.SetHoldings(self.XLK, .50)
# self.SetHoldings(self.XLY, .30)
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.bond, .50)
self.SetHoldings(self.XLP, .50)
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.bond, .50)
self.SetHoldings(self.XLP, .50)
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"