Overall Statistics |
Total Orders 518 Average Win 2.06% Average Loss -2.17% Compounding Annual Return 7.143% Drawdown 35.400% Expectancy 0.346 Start Equity 10000 End Equity 62407.06 Net Profit 524.071% Sharpe Ratio 0.311 Sortino Ratio 0.156 Probabilistic Sharpe Ratio 0.080% Loss Rate 31% Win Rate 69% Profit-Loss Ratio 0.95 Alpha 0.016 Beta 0.239 Annual Standard Deviation 0.106 Annual Variance 0.011 Information Ratio -0.193 Tracking Error 0.191 Treynor Ratio 0.138 Total Fees $1239.88 Estimated Strategy Capacity $99000000.00 Lowest Capacity Asset QQQ RIWIV7K5Z9LX Portfolio Turnover 5.33% |
#region imports from AlgorithmImports import * #endregion class SimpleSpyClimber(QCAlgorithm): """ Inspired by quantitativo : https://www.quantitativo.com/p/turnaround-tuesdays-on-steroids Entry rules: ----------------------- - Today is Tuesday - Yesterday's close (Monday) was lower than Friday's - Friday's close was lower than Thursday's; - Go long at the opening. Exit rules ----------------------- - Exit the trade when the close is higher than yesterday's high. """ # Entry Point for the algo. # =========================== def Initialize(self): ## Init backtest params, etc self.ticker = "QQQ" # Ticker symbol to trade self.SetBenchmark(self.ticker) # Benchmark for reporting (buy and hold) self.SetStartDate(1998, 1, 1) # Backtest start date self.SetEndDate(2024, 7, 9) # Backtest end date self.SetCash(10000) # Starting portfolio balance ## Subscrbe to an hourly data feed (hour bars) self.symbol = self.AddEquity(self.ticker, Resolution.Hour).symbol ## Set up a daily bar consolidator self.dailyConsolidator = TradeBarConsolidator(timedelta(days=1)) self.dailyConsolidator.DataConsolidated += lambda _, dailyBar: self.barsWindow.add(dailyBar) self.SubscriptionManager.AddConsolidator(self.symbol, self.dailyConsolidator) ## Set up a rollingwindow to store recent bars self.barsWindow = RollingWindow[TradeBar](3) ## Schedule a weekly chron job to run on tuesday after the first hour of trading self.Schedule.On(self.DateRules.Every(DayOfWeek.Tuesday), self.TimeRules.AfterMarketOpen(self.ticker, 60), \ self.CheckForEntry) # self.barsWindow.add(dailyBar) ## Register our technical indicators w/the ticker so they are updated automatically # self.MA_66 = self.SMA(self.ticker, 66, Resolution.Daily) # track moving average of past 66 days # self.LOW_3 = self.MIN(self.ticker, 3, Resolution.Daily) # track min price of past 3 days # self.HIGH_19 = self.MAX(self.ticker, 19, Resolution.Daily) # track max price of past 19 days # def DailyBarHandler(self, sender: object, dailyBar: TradeBar): # self.barsWindow.add(dailyBar) def CheckForEntry(self): """ - Yesterday's close (Monday) was lower than Friday's - Friday's close was lower than Thursday's; - Go long at the opening. """ if self.barsWindow.IsReady: if not self.Portfolio.Invested: monBar, friBar, thursBar = self.barsWindow[0],self.barsWindow[1],self.barsWindow[2] if( monBar.close < friBar.close < thursBar.close ): self.SetHoldings(self.ticker, 1) # A handler that's called every time there is a new bar # (ie candlestick) of data. The 'dataSlice' holds all the data. # ============================================================== def OnData(self, dataSlice): ## Make sure we have data for this ticker before we check for our entry conditions if( dataSlice.ContainsKey(self.ticker)) and (dataSlice[self.ticker] is not None ): ## The price that the last bar closed at closePrice = dataSlice[self.ticker].Close if self.Portfolio.Invested: # Exit the trade when the close is higher than yesterday's high. if (self.barsWindow[0].close > self.barsWindow[1].high): self.Liquidate(tag=f"Exit @ last close > prev high: {self.barsWindow[0].close} > {self.barsWindow[1].high}") # Exit the trade when the close is higher than yesterday's high. # ## If we're not hodling any positions, check for a signal # if not self.Portfolio.Invested: # ## If closing price > 66 day Moving average && is the lowest in past 3 days, take a position. # if(closePrice > self.MA_66.Current.Value) and (closePrice < self.LOW_3.Current.Value): # self.SetHoldings(self.ticker, 1) # allocate 100% of portfolio to ticker # else: # # If we're holding, and the day's close price is the highest of the last 19 days, then exit. # if(closePrice > self.HIGH_19.Current.Value): # self.Liquidate()