Overall Statistics |
Total Trades 475 Average Win 1.21% Average Loss -1.11% Compounding Annual Return -100% Drawdown 89.000% Expectancy -0.732 Net Profit -88.952% Sharpe Ratio -0.233 Probabilistic Sharpe Ratio 0.009% Loss Rate 87% Win Rate 13% Profit-Loss Ratio 1.09 Alpha -4.351 Beta 8.767 Annual Standard Deviation 4.285 Annual Variance 18.359 Information Ratio -0.325 Tracking Error 4.254 Treynor Ratio -0.114 Total Fees $85170.23 Estimated Strategy Capacity $62000.00 Lowest Capacity Asset BMJ TDP0JIUCTNJ9 |
class QuantumHorizontalRegulators(QCAlgorithm): def Initialize(self): self.SetStartDate(2020, 7, 1) # Set Start Date self.SetEndDate(2020, 8, 31) self.SetCash(333333) # Set Strategy Cash self.backtestSymbolsPerDay = {} self.current_universe = [] self.UniverseSettings.Resolution = Resolution.Second self.SetUniverseSelection(ScheduledUniverseSelectionModel( self.DateRules.Every(DayOfWeek.Monday, DayOfWeek.Tuesday, DayOfWeek.Wednesday, DayOfWeek.Thursday, DayOfWeek.Friday), self.TimeRules.Every(timedelta(minutes = 15)), self.SelectSymbols )) self.AddAlpha(ShortSqueezeModel(self)) self.SetExecution(ImmediateExecutionModel()) self.SetPortfolioConstruction(AccumulativeInsightPortfolioConstructionModel(lambda time: None)) self.SetRiskManagement(TrailingStopRiskManagementModel(0.02)) def SelectSymbols(self, dateTime): # handle live mode file format if self.LiveMode: # fetch the file from dropbox str = self.Download("https://www.dropbox.com/s/x4ptyv396uv0ezu/Watchlist%202.csv?dl=1") # if we have a file for today, return symbols, else leave universe unchanged self.current_universe = str.split(',') if len(str) > 0 else self.current_universe return self.current_universe # backtest - first cache the entire file if len(self.backtestSymbolsPerDay) == 0: # No need for headers for authorization with dropbox, these two lines are for example purposes #byteKey = base64.b64encode("UserName:Password".encode('ASCII')) # The headers must be passed to the Download method as dictionary #headers = { 'Authorization' : f'Basic ({byteKey.decode("ASCII")})' } #str = self.Download("https://www.dropbox.com/s/x4ptyv396uv0ezu/Watchlist%202.csv?dl=1", headers) csv_data = self.Download("https://www.dropbox.com/s/x4ptyv396uv0ezu/Watchlist%202.csv?dl=1") for line in csv_data.splitlines(): data = line.split(',') self.backtestSymbolsPerDay[data[0]] = data[1:] index = dateTime.date().strftime("%Y%m%d") if index in self.backtestSymbolsPerDay.keys(): tickers = self.backtestSymbolsPerDay[index] self.current_universe = [Symbol.Create(ticker, SecurityType.Equity, Market.USA) for ticker in tickers] return self.current_universe class ShortSqueezeModel(AlphaModel): symbolData = {} def __init__(self, algo): self.algo = algo def Update(self, algorithm, slice): insights = [] # Create insights for symbols up at least 40% on the day for symbol, symbol_data in self.symbolData.items(): # If already invested, continue to next symbol if algorithm.Securities[symbol].Invested or symbol not in slice.Bars or not symbol_data.max.IsReady: continue # Calculate return sign yesterday's close yest_close = symbol_data.yest_close close = slice[symbol].Close ret = (close - yest_close) / yest_close high_of_day_break = close > symbol_data.max.Current.Value if ret >= 0.4 and high_of_day_break: # Up 20% on the day & breaks high of day hours = algorithm.Securities[symbol].Exchange.Hours closeTime = hours.GetNextMarketClose(algorithm.Time, False) - timedelta(minutes=2) # exit 1-minute before the close insights.append(Insight.Price(symbol, closeTime, InsightDirection.Up)) return insights def OnSecuritiesChanged(self, algorithm, changes): if len(changes.AddedSecurities) > 0: # Get history of symbols over lookback window added_symbols = [x.Symbol for x in changes.AddedSecurities] history = algorithm.History(added_symbols, 1, Resolution.Daily) if history.empty: return history = history['close'] for added in changes.AddedSecurities: # Save yesterday's close closes = history.loc[[str(added.Symbol.ID)]].values if len(closes) < 1: continue self.symbolData[added.Symbol] = SymbolData(closes[0], algorithm, added.Symbol) for removed in changes.RemovedSecurities: # Delete yesterday's close tracker symbol_data = self.symbolData.pop(removed.Symbol, None) if symbol_data: symbol_data.dispose() class SymbolData: def __init__(self, yest_close, algo, symbol): self.yest_close = yest_close self.algo = algo self.symbol = symbol self.event = algo.Schedule.On(algo.DateRules.EveryDay(symbol), algo.TimeRules.AfterMarketOpen(symbol, 375), self.reset) self.internal_max = Maximum(45) # 45 minutes self.max = Delay(1) self.daily_consolidator = TradeBarConsolidator(timedelta(days = 1)) ## 1 Day TradeBar Consolidator self.daily_consolidator.DataConsolidated += self.DailyConsolidator ## Add fuction to do what you want every day with your data self.algo.SubscriptionManager.AddConsolidator(self.symbol, self.daily_consolidator) self.minute_consolidator = TradeBarConsolidator(timedelta(minutes = 1)) ## 1 Day TradeBar Consolidator self.minute_consolidator.DataConsolidated += self.MinuteConsolidator ## Add fuction to do what you want every day with your data self.algo.SubscriptionManager.AddConsolidator(self.symbol, self.minute_consolidator) def MinuteConsolidator(self, sender, bar): self.internal_max.Update(bar.Time,bar.High) self.max.Update(bar.Time, self.internal_max.Current.Value) def DailyConsolidator(self, sender, bar): self.yest_close = bar.Close def reset(self): self.internal_max.Reset() self.max.Reset() def dispose(self): self.algo.Schedule.Remove(self.event) # Remove consolidators self.algo.SubscriptionManager.RemoveConsolidator(self.symbol, self.daily_consolidator) self.algo.SubscriptionManager.RemoveConsolidator(self.symbol, self.minute_consolidator)