Overall Statistics |
Total Orders 1688 Average Win 0.55% Average Loss -0.59% Compounding Annual Return 1.827% Drawdown 10.200% Expectancy 0.096 Start Equity 100000 End Equity 156393.35 Net Profit 56.393% Sharpe Ratio -0.215 Sortino Ratio -0.128 Probabilistic Sharpe Ratio 0.003% Loss Rate 43% Win Rate 57% Profit-Loss Ratio 0.93 Alpha -0.012 Beta 0.081 Annual Standard Deviation 0.04 Annual Variance 0.002 Information Ratio -0.336 Tracking Error 0.151 Treynor Ratio -0.106 Total Fees $8532.84 Estimated Strategy Capacity $130000000.00 Lowest Capacity Asset SPY R735QTJ8XC9X Portfolio Turnover 18.66% |
from AlgorithmImports import * class SPYBreakoutStrategy(QCAlgorithm): ## Initialize the algorithm, set up data feeds, and schedule functions. def Initialize(self): self.SetStartDate(2000, 1, 1) # Set start date self.SetCash(100000) # Set initial capital # Add SPY data self.spy = self.AddEquity("SPY", Resolution.Hour).Symbol # Create a RollingWindow to store the last 2 daily bars self.dailyBars = RollingWindow[TradeBar](2) # Schedule the daily check function self.Schedule.On(self.DateRules.EveryDay(self.spy), self.TimeRules.AfterMarketOpen(self.spy, 2), self.DailyCheck) # Initialize flags and variables self.checkForEntry = False self.previousDayHigh = 0 # Schedule the function to exit positions at the beginning or end of the day self.Schedule.On(self.DateRules.EveryDay(self.spy), # self.TimeRules.BeforeMarketClose(self.spy, 1), self.TimeRules.AfterMarketOpen(self.spy, 1), self.ExitPositions) ## Event handler called for each new data point. def OnData(self, data): if not self.dailyBars.IsReady \ or (self.spy not in data) \ or (data[self.spy] is None): return if self.checkForEntry and not self.Portfolio.Invested: if data[self.spy].Close > self.previousDayHigh: self.SetHoldings(self.spy, 1) self.Debug(f"Entered long position in SPY at {data[self.spy].Close}") ## Get yesterday's candle def GetYesterdaysCandle(self): history = self.History(self.spy, 1, Resolution.Daily) if history.empty or 'close' not in history.columns: return None for index, row in history.loc[self.spy].iterrows(): tradeBar = TradeBar() tradeBar.Close = row['close'] tradeBar.Open = row['open'] tradeBar.High = row['high'] tradeBar.Low = row['low'] tradeBar.Volume = row['volume'] tradeBar.Time = index tradeBar.Period = timedelta(1) return tradeBar ## Perform daily check for entry conditions. def DailyCheck(self): lastBar = self.GetYesterdaysCandle() if lastBar is None: return self.dailyBars.Add(lastBar) if not self.dailyBars.IsReady: return yesterday = self.dailyBars[0] previousDay = self.dailyBars[1] if yesterday.Low < previousDay.Low and yesterday.High < previousDay.High: self.checkForEntry = True self.previousDayHigh = yesterday.High self.Debug(f"Set checkForEntry to True. Previous day's high: {self.previousDayHigh}") else: self.checkForEntry = False ## Exit all positions - Called at the end or begining of the trading day. def ExitPositions(self): if self.Portfolio.Invested: self.Liquidate(self.spy) self.Debug("Exited all positions at end of day")