| 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")