| Overall Statistics |
|
Total Trades 12 Average Win 0.27% Average Loss -0.13% Compounding Annual Return 19.023% Drawdown 1.100% Expectancy 0.231 Net Profit 0.143% Sharpe Ratio 3.55 Probabilistic Sharpe Ratio 0% Loss Rate 60% Win Rate 40% Profit-Loss Ratio 2.08 Alpha 0.424 Beta -1.26 Annual Standard Deviation 0.036 Annual Variance 0.001 Information Ratio -2.244 Tracking Error 0.047 Treynor Ratio -0.102 Total Fees $12.00 Estimated Strategy Capacity $15000000.00 Lowest Capacity Asset OSH XGSEQC44B4O5 |
'''
Gap and Go Strategy
Shorts stocks gapping down >2%
1/1 Risk-to-Reward
-change the support levels from close to low?
'''
class MeasuredRedSalmon(QCAlgorithm):
success_count = 1
loss_count = 1
success_countt = 1
loss_countt = 1
def Initialize(self):
self.SetStartDate(2021, 5, 25) # Set Start Date
self.SetEndDate(2021, 5,27)
self.SetCash(50000) # Set Strategy Cash
self.spy = self.AddEquity("SPY", Resolution.Minute, Market.USA, True, 1.0, True)
self.UniverseSettings.Resolution = Resolution.Second
self.UniverseSettings.ExtendedMarketHours = True
self.AddUniverse(self.Coarse, self.Fine)
self.SetRiskManagement(MaximumDrawdownPercentPerSecurity(0.05))
self.Schedule.On(self.DateRules.EveryDay("SPY"),
self.TimeRules.AfterMarketOpen("SPY", 0),
self.collectPreMarketData)
self.Schedule.On(self.DateRules.EveryDay("SPY"),
self.TimeRules.BeforeMarketClose("SPY", 0),
self.prevspyclose)
self.Schedule.On(self.DateRules.EveryDay("SPY"),
self.TimeRules.AfterMarketOpen("SPY", 1),
self.trackMarket)
self.Schedule.On(self.DateRules.EveryDay("SPY"),
self.TimeRules.AfterMarketOpen("SPY", 90),
self.endMarket)
self.Schedule.On(self.DateRules.EveryDay("SPY"),
self.TimeRules.AfterMarketOpen("SPY", 100),
self.LiquidatePositions)
self.isMarket = False
self.spyisred = False
self.lastPrePrice = -1
self.yesterday = -1
self.isGapped = False
self.maxTraded = 4
self.securityWeight = .2
self.lastMonth = -1
self.activeSecurities = {}
self.todaysSecurities = {}
self.tradedToday = []
self.tradingSecurities = {}
self.oneMinuteHigh = {}
self.quarterPositions = {}
self.oneMinuteLow = {}
self.lastMinute = {}
self.prevoneminutelow = {}
self.prevoneminutehigh = {}
self.SetWarmUp(timedelta(days = 2))
def endMarket(self):
remove =[]
self.isMarket = False
self.tradedToday = []
for symbol, symbolData in self.todaysSecurities.items():
remove.append(symbol)
for symbol in remove:
self.todaysSecurities.pop(symbol, None)
self.tradingSecurities.pop(symbol, None)
self.Liquidate(symbol, "End of Trading")
self.RemoveSecurity(symbol)
self.oneMinuteHigh
self.oneMinuteLow
self.lastMinute
def collectPreMarketData(self):
remove = []
for symbol, symbolData in self.activeSecurities.items():
symbolData.Open = self.Securities[symbol].Price
symbolData.Logged = False
historyMinute = self.History(symbol, 300, Resolution.Minute)
historyDay = self.History(symbol, 1, Resolution.Daily)
if symbol.Value == 'JWN':
self.Log("JWN in activeSecurities")
try:
symbolData.YesterdayClose = float(historyDay["close"])
except:
remove.append(symbol)
continue
preMarketLow = 100000
resistance1 = 1
resistance2 = 1
resistance3 = 1
counter = 0
for tuple in historyMinute.itertuples():
symbolData.premarketavg.Update(tuple.Index[1], tuple.volume)
symbolData.premarketstd.Update(tuple.Index[1], tuple.volume)
symbolData.currentpremarketavg.Update(tuple.Index[1], tuple.volume)
symbolData.sum = symbolData.sum + tuple.volume
if tuple.close < preMarketLow:
if tuple.open < tuple.close:
preMarketLow = tuple.open
else:
preMarketLow = tuple.close
if tuple.close > resistance1:
if tuple.open > tuple.close:
resistance1 = tuple.open
else:
resistance1 = tuple.close
if counter >= 100:
if tuple.close > resistance2:
if tuple.open > tuple.close:
resistance2 = tuple.open
else:
resistance2 = tuple.close
if counter >= 240:
if tuple.close > resistance3:
if tuple.open > tuple.close:
resistance3 = tuple.open
else:
resistance3 = tuple.close
counter += 1
if resistance1 <= resistance2 and resistance1 <= resistance3:
lowest_resistance = resistance1
if resistance2 <= resistance3:
mid_resistance = resistance2
high_resistance = resistance3
else:
mid_resistance = resistance3
high_resistance = resistance2
if resistance2 < resistance1 and resistance2 <= resistance3:
lowest_resistance = resistance2
if resistance1 <= resistance3:
mid_resistance = resistance1
high_resistance = resistance3
else:
mid_resistance = resistance3
high_resistance = resistance1
if resistance3 < resistance1 and resistance3 < resistance2:
lowest_resistance = resistance3
if resistance1 <= resistance2:
mid_resistance = resistance1
high_resistance = resistance3
else:
mid_resistance= resistance3
high_resistance = resistance1
symbolData.resistance1 = round(lowest_resistance, 1)
symbolData.resistance2 = round(mid_resistance, 1)
symbolData.resistance3 = round(high_resistance, 1)
symbolData.firstresistanceBroke = False
symbolData.secondresistanceBroke = False
symbolData.thirdresistanceBroke = False
symbolData.AlreadyBrokeOut = False
symbolData.preMarketLow = preMarketLow
if symbolData.Open <= symbolData.YesterdayClose*0.98:
symbolData.isGap = True
else:
symbolData.isGap = False
symbolData.isGapPercent = (symbolData.YesterdayClose - symbolData.Open) / symbolData.YesterdayClose
symbolData.RVOL = symbolData.currentpremarketavg.Current.Value/(symbolData.premarketstd.Current.Value + symbolData.premarketavg.Current.Value + 0.01)
for symbol in remove:
self.activeSecurities.pop(symbol, None)
self.Liquidate(symbol, "End of Trading")
self.RemoveSecurity(symbol)
def trackMarket(self):
for symbol, symbolData in self.activeSecurities.items():
if symbolData.RVOL > 1 and symbolData.sum >= 50000:
if symbol.Value == 'JWN':
self.Log("JWN in todaysSecurities")
self.todaysSecurities[symbol] = self.activeSecurities[symbol]
sortedByGap = [x for x in self.todaysSecurities.keys()]
gapPercentBySymbol = {x.Symbol:x.isGapPercent for x in self.todaysSecurities.values()}
sortedByGap = sorted(sortedByGap, key = lambda x: self.todaysSecurities[x].isGapPercent, reverse = True)
finalGap = sortedByGap[:self.maxTraded]
for symbol in finalGap:
if symbol.Value == 'JWN':
self.Log("JWN in FinalGap")
self.tradingSecurities[symbol] = self.todaysSecurities[symbol]
# self.oneMinuteHigh[symbol] = self.Securities[symbol].High
# self.oneMinuteLow[symbol] = self.Securities[symbol].Low
for symbol, symbolData in self.tradingSecurities.items():
if symbol.Value == 'JWN':
self.Log("JWN in tradingSecurities")
self.isMarket = True
def LiquidatePositions(self):
self.spyisred = False
self.Liquidate()
def prevspyclose(self):
History = self.History(self.spy.Symbol, 1, Resolution.Daily)
Close = float(History["close"])
if self.Securities[self.spy.Symbol].Price <= Close:
self.spyisred = True
def OnData(self, data):
if self.isMarket == True:
# removed = []
# for symbol in removed:
# self.tradingSecurities.pop(symbol, None)
# self.Liquidate(symbol)
# self.RemoveSecurity(symbol)
for symbol, symbolData in self.tradingSecurities.items():
if symbolData.isGap == True:
if symbol.Value == 'JWN':
self.Log("JWN in tradingSecurities OnData")
if len([x for x in self.Portfolio if x.Value.Invested]) >= self.maxTraded:
break
if symbolData.Logged == False:
self.Log(str(symbol) + "tradingSecurities with gap")
self.Log(str(symbol) + "resistance1 = " + str(symbolData.resistance1))
self.Log(str(symbol) + "preMarketLow = " + str(symbolData.preMarketLow))
symbolData.Logged = True
# if symbolData.lastMinute == self.Time.minute:
# if symbolData.oneMinuteLow > self.Securities[symbol].Low:
# symbolData.oneMinuteLow = self.Securities[symbol].Low
# if symbolData.oneMinuteHigh < self.Securities[symbol].High:
# symbolData.oneMinuteHigh = self.Securities[symbol].High
#
# elif symbolData.prevoneminutelow == symbolData.oneMinuteLow:
# symbolData.prevoneminutelow = self.Securities[symbol].Low
# symbolData.prevoneminutehigh = self.Securities[symbol].High
# symbolData.lastMinute = self.Time.minute
#
# else:
# symbolData.prevoneminutelow = symbolData.oneMinuteLow
# symbolData.prevoneminutehigh = symbolData.oneMinuteHigh
# symbolData.oneMinuteLow = self.Securities[symbol].Low
# symbolData.oneMinuteHigh = self.Securities[symbol].High
# symbolData.lastMinute = self.Time.minute
if self.Portfolio[symbol].Invested:
if symbolData.AlreadyBrokeOut == False and self.Securities[symbol].Price <= symbolData.preMarketLow:
self.SetHoldings([PortfolioTarget(symbol, -self.securityWeight)])
symbolData.AlreadyBrokeOut = True
# self.Log(str(symbol) + "resistance1 = " + str(symbolData.resistance1))
# self.Log(str(symbol) + "preMarketLow = " + str(symbolData.preMarketLow))
if not self.Portfolio[symbol].Invested and symbol not in self.tradedToday:
if self.Securities[symbol].Price >= symbolData.resistance1:
symbolData.firstresistanceBroke = True
if self.Securities[symbol].Price >= symbolData.preMarketLow:
symbolData.secondresistanceBroke = True
if symbolData.firstresistanceBroke == True and self.Securities[symbol].Price <= symbolData.resistance1:
self.SetHoldings([PortfolioTarget(symbol, -self.securityWeight/2)])
self.tradedToday.append(symbol)
# self.Log(str(symbol) + "resistance1 = " + str(symbolData.resistance3))
# self.Log(str(symbol) + "preMarketLow = " + str(symbolData.preMarketLow))
if symbolData.secondresistanceBroke == True and self.Securities[symbol].Price <= symbolData.preMarketLow:
self.SetHoldings([PortfolioTarget(symbol, -self.securityWeight/2)])
self.tradedToday.append(symbol)
symbolData.AlreadyBrokeOut = True
self.Log(str(symbol) + " just traded")
# self.Log(str(symbol) + "resistance1 = " + str(symbolData.resistance1))
# self.Log(str(symbol) + "preMarketLow = " + str(symbolData.preMarketLow))
# if symbol in self.quarterPositions:
# self.quarterPositions.pop(symbol, None)
continue
# if symbol not in self.quarterPositions:
# self.quarterPositions[symbol] = self.securityWeight/4
# else:
# self.quarterPositions[symbol] += self.securityWeight/4
#
# if self.quarterPositions[symbol] >=1:
# continue
self.manageProfit()
def manageProfit(self):
investedSecurities = [x.Key for x in self.Portfolio if x.Value.Invested]
for symbol, symbolData in self.tradingSecurities.items():
if symbol.Value == 'JWN':
self.Log("JWN in manageprofit")
symbolData.takeprofit = (symbolData.resistance1 - symbolData.preMarketLow)
if self.Portfolio[symbol].Invested and symbolData.AlreadyBrokeOut == False and (self.Securities[symbol].Price <= (symbolData.resistance1 - symbolData.takeprofit)):
self.Liquidate(symbol, "PROFIT for resistance")
# self.Log("resistance success count = " + str(self.success_count))
# self.success_count = self.success_count + 1
elif self.Portfolio[symbol].Invested and symbolData.AlreadyBrokeOut == False and self.Securities[symbol].Price >= (symbolData.resistance1 + symbolData.takeprofit):
self.Liquidate(symbol, "Hit resistance Stop")
self.Log("resistance loss count = " + str(self.loss_count))
self.loss_count = self.loss_count + 1
continue
if self.Portfolio[symbol].Invested and symbolData.AlreadyBrokeOut == True and self.Securities[symbol].Price <= (symbolData.preMarketLow - symbolData.takeprofit):
self.Liquidate(symbol, "PROFIT for Breakout")
# self.Log("PMH success count = " + str(self.success_countt))
# self.success_countt = self.success_countt + 1
elif self.Portfolio[symbol].Invested and symbolData.AlreadyBrokeOut == True and self.Securities[symbol].Price >= (symbolData.preMarketLow + symbolData.takeprofit):
self.Liquidate(symbol, "Hit Breakout resistance")
# self.Log("PMH loss count = " + str(self.loss_countt))
# self.loss_countt = self.loss_countt + 1
def OnSecuritiesChanged(self, changes):
addedSecurities = [x.Symbol for x in changes.AddedSecurities]
removedSecurities = [x.Symbol for x in changes.RemovedSecurities]
for symbol in addedSecurities:
if symbol == self.spy.Symbol:
continue
sma = SimpleMovingAverage(960)
std = StandardDeviation(960)
currentavg = SimpleMovingAverage(120)
history = self.History(symbol, 6720, Resolution.Minute)
for tuple in history.itertuples():
CurrentHour = int(str(tuple.Index[1])[11:13])
if CurrentHour > 6 and CurrentHour < 9:
sma.Update(tuple.Index[1], tuple.volume)
std.Update(tuple.Index[1], tuple.volume)
currentavg.Update(tuple.Index[1], tuple.volume)
symbolData = SymbolData(symbol, sma, std, currentavg)
self.activeSecurities[symbol] = symbolData
for symbol in removedSecurities:
if symbol in self.tradingSecurities:
self.tradingSecurities.pop(symbol, None)
if self.Portfolio[symbol].Invested:
self.Liquidate(symbol, "Removed from Trading Securities")
def Coarse(self, coarse):
if self.lastMonth == self.Time.month:
return Universe.Unchanged
self.lastMonth = self.Time.month
selectedCoarse = [x for x in coarse if x.HasFundamentalData and x.Price > 30 and x.Volume > 1000000]
self.dollarVolumeBySymbol = {x.Symbol:x.Volume for x in selectedCoarse}
# If no security has met the QC500 criteria, the universe is unchanged.
# A new selection will be attempted on the next trading day as self.lastMonth is not updated
if len(self.dollarVolumeBySymbol) == 0:
return Universe.Unchanged
return [x.Symbol for x in selectedCoarse]
def Fine(self, fine):
hist = self.History([i.Symbol for i in fine], 1, Resolution.Daily)
sortedByVolume = sorted([x.Symbol for x in fine if x.CompanyReference.CountryId == "USA"
and x.CompanyReference.PrimaryExchangeID in ["NYS","NAS"]
and float(x.EarningReports.BasicAverageShares.ThreeMonths) * hist.loc[str(x.Symbol)]['close'][0] > 1e9],
key = lambda x: self.dollarVolumeBySymbol[x], reverse=True)
count = len(sortedByVolume)
if count == 0:
return Universe.Unchanged
return sortedByVolume[:400]
class SymbolData:
def __init__(self, symbol, sma, std, currentavg):
self.Open = -1
self.YesterdayClose = -1
self.preMarketLow = 10000
self.isGap = False
self.RVOL = 0
self.Symbol = symbol
self.isGapPercent = 0.0
self.resistance1 = 1
self.resistance2 = 1
self.resistance3 = 1
self.firstresistanceBroke = False
self.secondresistanceBroke = False
self.thirdresistanceBroke = False
self.AlreadyBrokeOut = False
self.premarketavg = sma
self.premarketstd = std
self.currentpremarketavg = currentavg
self.lastMinute = 30
self.prevoneminutelow = 0
self.prevoneminutehigh = 0
self.oneMinuteLow = 0
self.oneMinuteHigh = 0
self.takeprofit = 0
self.Logged = False
self.sum = 0