| Overall Statistics |
|
Total Trades 5 Average Win 0.54% Average Loss 0% Compounding Annual Return 128.221% Drawdown 3.100% Expectancy 0 Net Profit 8.234% Sharpe Ratio 8.613 Probabilistic Sharpe Ratio 95.161% Loss Rate 0% Win Rate 100% Profit-Loss Ratio 0 Alpha 0.603 Beta 0.193 Annual Standard Deviation 0.135 Annual Variance 0.018 Information Ratio -6.021 Tracking Error 0.289 Treynor Ratio 6.023 Total Fees $0.00 |
class UniverseRollingAlgorithm(QCAlgorithm):
def Initialize(self): #Initialize Dates, Cash, Equities, Fees, Allocation, Parameters, Indicators, Charts
# Set Start Date, End Date, and Cash
#-------------------------------------------------------
self.SetTimeZone(TimeZones.NewYork) #EDIT: Added Timezon
self.SetStartDate(2020, 4, 1) # Set Start Date
self.SetEndDate(2020, 5, 5) # Set End Date
self.SetCash(100000) # Set Strategy Cash
#-------------------------------------------------------
# Set Custom Universe
#-------------------------------------------------------
self.AddUniverse(self.CoarseSelectionFilter, self.FineSelectionFilter)
self.UniverseSettings.Resolution = Resolution.Minute #Needs to change to Resolution.Minute once code works, leaving Daily for now to minimize data
self.UniverseSettings.SetDataNormalizationMode = DataNormalizationMode.SplitAdjusted
self.UniverseSettings.FeeModel = ConstantFeeModel(0.0)
self.UniverseSettings.Leverage = 1
#-------------------------------------------------------
self.SetBrokerageModel(BrokerageName.Alpaca, AccountType.Cash) #EDIT: Added Brokerage, appears to have set fees to zero
self.Schedule.On(self.DateRules.EveryDay(), self.TimeRules.At(0, 0), self.UniEquityPicks) #EDIT: Added scheduled event to prevent universe from triggering at minute intervals
self.init_uni_picks = True #Initialize flag only true once
self.uni_picks = False #second flag to switch on/off
self.EMA_Period_Fast = 20
self.EMA_Period_Slow = 50
self.__numberOfSymbols = 100
self.__numberOfSymbolsFine = 10
self.indicators = {}
# Define Percentage Allocation
#-------------------------------------------------------
self.percentagebuy = 0.1
#-------------------------------------------------------
def CoarseSelectionFilter(self, coarse):
if self.uni_picks or self.init_uni_picks:
sortedByDollarVolume = sorted(coarse, key=lambda x: x.DollarVolume, reverse=True) # sort descending by daily dollar volume
return [ x.Symbol for x in sortedByDollarVolume[:self.__numberOfSymbols] ] # return the symbol objects of the top entries from our sorted collection
else:
return Universe.Unchanged
def FineSelectionFilter(self, fine): # sort the data by P/E ratio and take the top 'NumberOfSymbolsFine'
if self.uni_picks or self.init_uni_picks:
self.init_uni_picks = False #False for the rest of program operation
self.uni_picks = False
sortedByPeRatio = sorted(fine, key=lambda x: x.OperationRatios.OperationMargin.Value, reverse=False) # sort descending by P/E ratio
self.universe = [ x.Symbol for x in sortedByPeRatio[:self.__numberOfSymbolsFine] ] # take the top entries from our sorted collection
return self.universe
else:
return Universe.Unchanged
def OnSecuritiesChanged(self, changes):
# Create indicator for each new security
for security in changes.AddedSecurities:
self.indicators[security.Symbol] = SymbolData(security.Symbol, self, self.EMA_Period_Fast, self.EMA_Period_Slow)
for security in changes.RemovedSecurities:
if security.Invested:
self.Liquidate(security.Symbol, "Universe Removed Security")
if security in self.indicators:
del self.indicators[security.Symbol] # UNVERIFIED EDIT - Shifted del command outside of if statement, need to test
def UniEquityPicks(self):
self.uni_picks = True
def OnData(self, data): #Entry Point for Data and algorithm - Check Data, Define Buy Quantity, Process Volume, Check Portfolio, Check RSI, Execute Buy/Sell orders, Chart Plots
for symbol in self.universe:
if not data.ContainsKey(symbol): #Tested and Valid/Necessary
continue
if data[symbol] is None: #Tested and Valid/Necessary
continue
if not symbol in self.indicators: #Tested and Valid/Necessary
continue
# Check for Indicator Readiness within Rolling Window
#-------------------------------------------------------
if not (self.indicators[symbol].fast_ema_window.IsReady and self.indicators[symbol].slow_ema_window.IsReady):
continue #return #EDIT
#self.Debug("Get Fast EMA = " + str(self.indicators[symbol].get_fast_EMA()) + " window[0] = " + str(self.indicators[symbol].fast_ema_window[0]))
'''
if self.Time.hour == 10 and self.Time.minute == 0 and self.Time.minute < 2:
self.Debug("Rolling Fast Index[0] = " + str(symbol) + "-EMA : " + str(self.indicators[symbol].fast_ema_window[0]))
self.Debug("Rolling Slow Index[0] = " + str(symbol) + "-EMA : " + str(self.indicators[symbol].fast_ema_window[1]))
self.Debug("Rolling Fast Index[4] = " + str(symbol) + "-EMA : " + str(self.indicators[symbol].fast_ema_window[2]))
self.Debug("Rolling Slow Index[4] = " + str(symbol) + "-EMA : " + str(self.indicators[symbol].fast_ema_window[3]))
self.Debug("Rolling Slow Index[4] = " + str(symbol) + "-EMA : " + str(self.indicators[symbol].fast_ema_window[4]))
self.Debug(" ")
'''
#Check time for live debugging
checkhour = self.Time.hour
checkminute = self.Time.minute
#EXECUTE TRADING LOGIC HERE -
self.buyquantity = round((self.percentagebuy*self.Portfolio.TotalPortfolioValue)/data[symbol].Close)
if (not self.Portfolio[symbol].Invested) and (self.Portfolio.MarginRemaining > 0.9*self.percentagebuy*self.Portfolio.TotalPortfolioValue):
if (self.indicators[symbol].fast_ema_window[1] >= self.indicators[symbol].slow_ema_window[1]) and (self.indicators[symbol].fast_ema_window[4] < self.indicators[symbol].slow_ema_window[4]):
self.MarketOrder(symbol, self.buyquantity)
#if self.Portfolio[symbol].Invested: #Remove if implementing Short Strategies
if self.indicators[symbol].fast_ema_window[1] <= self.indicators[symbol].slow_ema_window[1] and (self.indicators[symbol].fast_ema_window[4] > self.indicators[symbol].slow_ema_window[4]):
self.Liquidate(symbol) #self.MarketOrder(symbol, self.buyquantity)
#elif self.EMA_FastWin[0] < self.EMA_SlowWin[0] and self.EMA_FastWin[1] > self.EMA_SlowWin[1]:
# self.Liquidate(security.Key7
class SymbolData(object):
rolling_window_length = 5
def __init__(self, symbol, context, fast_ema_period, slow_ema_period):
self.symbol = symbol
self.fast_ema_period = fast_ema_period
self.slow_ema_period = slow_ema_period
self.fast_ema = context.EMA(symbol, self.fast_ema_period, Resolution.Minute) #, fillDataForward = True, leverage = 1, extendedMarketHours = False)
self.slow_ema = context.EMA(symbol, self.slow_ema_period, Resolution.Minute) #, fillDataForward = True, leverage = 1, extendedMarketHours = False)
self.fast_ema_window = RollingWindow[float](self.rolling_window_length)
self.slow_ema_window = RollingWindow[float](self.rolling_window_length)
# Warm up EMA indicators
history = context.History([symbol], slow_ema_period + self.rolling_window_length, Resolution.Minute)
for time, row in history.loc[symbol].iterrows():
self.fast_ema.Update(time, row["close"])
self.slow_ema.Update(time, row["close"])
# Warm up rolling windows
if self.fast_ema.IsReady:
self.fast_ema_window.Add(self.fast_ema.Current.Value)
if self.slow_ema.IsReady:
self.slow_ema_window.Add(self.slow_ema.Current.Value)
def get_fast_EMA(self):
return self.fast_ema.Current.Value
def get_slow_EMA(self):
return self.slow_ema.Current.Value