Overall Statistics |
Total Trades 3210 Average Win 0.65% Average Loss -0.34% Compounding Annual Return 61.333% Drawdown 13.500% Expectancy 0.336 Net Profit 424.702% Sharpe Ratio 2.336 Probabilistic Sharpe Ratio 98.228% Loss Rate 54% Win Rate 46% Profit-Loss Ratio 1.90 Alpha 0.475 Beta 0.256 Annual Standard Deviation 0.221 Annual Variance 0.049 Information Ratio 1.362 Tracking Error 0.26 Treynor Ratio 2.017 Total Fees $4249.59 Estimated Strategy Capacity $190000000.00 Lowest Capacity Asset SQ W5OUXC7GJYAT |
# VXX version - best length 22 # VIX hour version - best length 11 # VIX daily version - best length 22 import numpy as np from datetime import datetime class BasicTemplateAlgorithm(QCAlgorithm): def Initialize(self): self.SetStartDate(2018, 3, 17) #self.SetEndDate(2019, 3, 17) self.SetEndDate(datetime.now()) self.SetCash(25000) self.Settings.FreePortfolioValuePercentage = 0.00 self.data = {} self.SetBenchmark("SPY") #period = 10*21 self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, AccountType.Margin) self.trailing_stop = self.GetParameter("trailing-stop") self.trailing_stop = float(self.trailing_stop) if self.trailing_stop else 0.06 self.moving_average = self.GetParameter("moving-average") self.moving_average = float(self.moving_average) if self.moving_average else 13 self.rsi_value = self.GetParameter("rsi-value") self.rsi_value = float(self.rsi_value) if self.rsi_value else 51 self.sma_tolerance = self.GetParameter("sma-tolerance") self.sma_tolerance = float(self.sma_tolerance) if self.sma_tolerance else 0.0063 self.vix_length = self.GetParameter("vix-length") self.vix_length = float(self.vix_length) if self.vix_length else 11 self.rsi_upper = self.GetParameter("rsi-upper") self.rsi_upper = float(self.rsi_upper) if self.rsi_upper else 88 self.screener_price = self.GetParameter("screener-price") self.screener_price = float(self.screener_price) if self.screener_price else 60 self.AddRiskManagement(TrailingStopRiskManagementModel(self.trailing_stop)) self.SPY = self.AddEquity("SPY", Resolution.Hour).Symbol self.Schedule.On(self.DateRules.EveryDay("SPY"), self.TimeRules.BeforeMarketClose(self.SPY,20), self.StopTrading) self.Schedule.On(self.DateRules.EveryDay("SPY"), self.TimeRules.AfterMarketOpen(self.SPY, 0), self.StartTrading) self.SPY = self.AddEquity("SPY", Resolution.Hour).Symbol self.vix = self.AddEquity("VXX", Resolution.Minute).Symbol self.staticAssets = [self.SPY, self.vix] self.vixSma = self.SMA(self.vix, self.vix_length, Resolution.Hour) vixHistory = self.History(self.vix, 11, Resolution.Hour) for tuple in vixHistory.loc[self.vix].itertuples(): self.vixSma.Update(tuple.Index, tuple.close) self.Log(". VIX SMA INITIALIZED: " + str(self.vixSma.Current.Value)) # + ". VIX INITIALIZED: " + str(self.vix.Current.Value)) self.Schedule.On(self.DateRules.EveryDay("SPY"), self.TimeRules.BeforeMarketClose(self.SPY,20), self.StopTrading) self.Schedule.On(self.DateRules.EveryDay("SPY"), self.TimeRules.AfterMarketOpen(self.SPY, 0), self.StartTrading) self.Schedule.On(self.DateRules.EveryDay("SPY"), self.TimeRules.AfterMarketOpen(self.SPY, 30), self.SafetySwitch) self.AddUniverse(self.CoarseFilter, self.FineFilter) ''' If VVIX > 50 day SMA, Sell all current assets Switch to vxx and IEF (50/50) ''' self.UniverseSettings.Resolution = Resolution.Hour self.lastMonth = -1 self.lastHour = -1 self.allowTrades = True self.switchSafety = False self.Log("Initialized") def StartTrading(self): if self.Securities[self.vix].Price > self.vixSma.Current.Value: self.switchSafety = True self.allowTrades = False self.Log("StartTrading: allowtrades = False, switchSafety = True") else: self.switchSafety = False self.allowTrades = True self.Log("StartTrading: allowtrades = True, switchSafety = False") # def SafetySwitch(self): # if self.switchSafety == False: # self.Liquidate(self.vxx) # self.Liquidate(self.ief) # self.Log("switchSafety is False, liquidating vxx and ief") # elif self.switchSafety == True: # self.Log("switchSafety is True now liquidating") # if not self.Portfolio[self.vxx].Invested and not self.Portfolio[self.ief].Invested: # self.Liquidate() # #self.SetHoldings(self.vxx, 0.1) # #lf.SetHoldings(self.ief, 0.5) def SafetySwitch(self): if 1==1: self.Liquidate() def StopTrading(self): self.Log("Stopping Trading") self.allowTrades = False def CoarseFilter(self, coarse): if self.lastMonth == self.Time.month: return Universe.Unchanged self.lastMonth = self.Time.month topStocksByVolume = sorted([x for x in coarse if x.Price > self.screener_price and x.Volume > 0], key = lambda x: x.DollarVolume, reverse=True)[:6] return [x.Symbol for x in topStocksByVolume] def FineFilter(self, fine): topFiveMarketCap = sorted([x for x in fine], key = lambda x: x.MarketCap, reverse = True)[:5] ''' Manually exclude companies ''' filteredSymbols = [x.Symbol for x in topFiveMarketCap if x.Symbol.Value not in ["GME", "AMC", "GOOG"]] ''' Filter out high volatile stocks ''' preSdSymbols = [x for x in filteredSymbols] history = self.History(preSdSymbols, 50, Resolution.Daily) standardDeviations = {} for symbol in preSdSymbols: sd = StandardDeviation(50) for tuple in history.loc[symbol].itertuples(): sd.Update(tuple.Index, tuple.close) standardDeviations[symbol] = sd.Current.Value finalSymbols = [x for x in preSdSymbols if standardDeviations[x] < 1000]#5] self.Log("Picked number of symbols in universe: " + str(len(finalSymbols))) return finalSymbols def PlaceTrades(self, data): isUptrend = [] for symbol, symbolData in self.data.items(): self.Debug(str(symbol.Value) + " at " + str(self.Time) + ". RSI: " + str(symbolData.Rsi.Current.Value) + ". SMA: " + str(symbolData.Sma.Current.Value) + ". PRICE: " + str(self.Securities[symbol].Price)) if not data.ContainsKey(symbol): self.Log("Does not contain data for " + str(symbol)) continue if self.Securities[symbol].Price > (symbolData.Sma.Current.Value * (1 + self.sma_tolerance)) and not symbolData.Rsi.Current.Value < self.rsi_value and not symbolData.Rsi.Current.Value > self.rsi_upper and not self.Securities[self.vix].Price > self.vixSma.Current.Value: isUptrend.append(symbol) elif self.Portfolio[symbol].Invested: self.Log("Liquidating: " + str(symbol)) self.Liquidate(symbol, "SMA: " + str(self.data[symbol].Sma.Current.Value) + ". RSI: " + str(self.data[symbol].Rsi.Current.Value)) for symbol in isUptrend: self.Debug("Buying: " + str(symbol)) self.SetHoldings(symbol, 1.20/len(isUptrend), False, "SMA: " + str(self.data[symbol].Sma.Current.Value) + ". RSI: " + str(self.data[symbol].Rsi.Current.Value)) def OnData(self, data): if self.IsWarmingUp: return self.Log(". VIX: " + str(self.Securities[self.vix].Price) + ". VIX SMA: " + str(self.vixSma.Current.Value)) # self.Log(". Symbols: " + str(self.data.keys)) if self.allowTrades == False: return if self.lastHour == self.Time.hour or self.Time.hour < 10: return self.lastHour = self.Time.hour self.PlaceTrades(data) def OnSecuritiesChanged(self, changes): for added in changes.AddedSecurities: symbol = added.Symbol if symbol in self.staticAssets: continue added.MarginModel = PatternDayTradingMarginModel() sma = self.SMA(symbol, self.moving_average, Resolution.Hour) rsi = self.RSI(symbol, 14, MovingAverageType.Simple, Resolution.Hour) # sto = self.STO(symbol) history = self.History(symbol, 15, Resolution.Hour) for tuple in history.loc[symbol].itertuples(): sma.Update(tuple.Index, tuple.close) rsi.Update(tuple.Index, tuple.close) # sto.Update(TradeBar) self.Log(f'New Securities Added: {[security.Symbol.Value for security in changes.AddedSecurities]}') symbolData = SymbolData(sma, rsi) self.data[symbol] = symbolData #self.data[symbol].Sma.Current.Value for removed in changes.RemovedSecurities: symbol = removed.Symbol self.Liquidate(symbol) self.data.pop(symbol, None) self.Log(f'Securities Removed{[security.Symbol.Value for security in changes.RemovedSecurities]}') class SymbolData: def __init__(self, sma, rsi): self.Sma = sma self.Rsi = rsi # self.Sto = sto # FOR JOVAD: Need 2 versions 1 with a universe that only trades top 5 market cap stocks and 1 with Dropbox spreadsheet # Need to add STO, RSI, AND HAVE 3 SMA HERE (fast, medium, slow) # Need minute support with bars, 60 minutes consolidated for now # Need to understand how I can add more indicators if I want - struggled with warming up onData. Tried adding more indicators using for symbol, sma in self.data.items(): but it didn't work # FOR JOVAD NEW SESSION: HOW TO PICK STOCKS WITH HIGHEST # FOR JOVAD 6/29- NEW STRATEGY TO TEST: IF RSI PREVIOUS CLOSE < RSI CURRENT CLOSE ENTER TRADE ELSE EXIT TRADE, TRAILING STOP 5% HOURLY CHART # STOCK PICKING HOUR SMA NEEDS TO BE ADJUSTED TO CRYPTO AS WELL WITHOUT UNIVERSE SELECTION + FIX EXCHANGE IS CLOSED ERROR # ALSO FOR STOCK PICKING - WE NEED TO ADD FUNCTIONALITY TO REMOVE MANUALLY SELECTED TICKERS LIKE GOOG AND GME # ASK FOR ADVISE IF WE CAN FIND A LOGIC TO EXCLUDE DANGEROUS TICKERS LIKE AMC AND GME