'''
Gap and Go Strategy
-calculate best support options and weight for each
-make sure supports are different
-take profit:
-New 1 min candle to make new low
-Add a buffer (.03?)
-at a certain level
-Stop loss
-Change from trailing to next support level below
-Liquidate after 90 min
-Relative vol filter?
'''
class MeasuredRedSalmon(QCAlgorithm):
success_count = 1
loss_count = 1
success_countt = 1
loss_countt = 1
SPY_Close = 1
def Initialize(self):
self.SetStartDate(2021, 3, 10) # Set Start Date
self.SetEndDate(2021, 3, 12)
self.SetCash(100000) # Set Strategy Cash
#self.nvx = self.AddEquity("NVAX", Resolution.Minute, Market.USA, True, 1.0, True)
self.spy = self.AddEquity("SPY", Resolution.Minute, Market.USA, True, 1.0, True)
self.spyisgreen = False
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.isPreMarket = False
self.isMarket = False
self.lastPrePrice = -1
self.highestPreMarket = 0
self.yesterday = -1
self.isGapped = False
self.maxTraded = 5
self.securityWeight = .2
self.lastMonth = -1
self.activeSecurities = {}
self.tradedToday = []
self.tradingSecurities = {}
self.oneMinuteHigh = {}
self.quarterPositions = {}
self.oneMinuteLow = {}
self.SetWarmUp(timedelta(days = 2))
def endMarket(self):
self.isMarket = False
self.tradedToday = []
self.tradingSecurities = {}
self.oneMinuteHigh
def trackMarket(self):
sortedByGap = [x for x in self.activeSecurities.keys()]
gapPercentBySymbol = {x.Symbol:x.isGapPercent for x in self.activeSecurities.values()}
sortedByGap = sorted(sortedByGap, key = lambda x: self.activeSecurities[x].isGapPercent, reverse = True)
finalGap = sortedByGap[:self.maxTraded]
for symbol in finalGap:
self.tradingSecurities[symbol] = self.activeSecurities[symbol]
self.oneMinuteHigh[symbol] = self.Securities[symbol].High
self.isMarket = True
def collectPreMarketData(self):
remove = []
for symbol, symbolData in self.activeSecurities.items():
symbolData.Open = self.Securities[symbol].Price
historyMinute = self.History(symbol, 300, Resolution.Minute)
historyDay = self.History(symbol, 1, Resolution.Daily)
try:
symbolData.YesterdayClose = float(historyDay["close"])
except:
remove.append(symbol)
continue
preMarketHigh = -1
support1 = 100000
support2 = 100000
support3 = 100000
counter = 0
for tuple in historyMinute.itertuples():
symbolData.premarketavg.Update(tuple.Index, tuple.volume)
symbolData.premarketstd.Update(tuple.Index, tuple.volume)
symbolData.currentprematketavg(tuple.Index, tuple.volume)
if tuple.close > preMarketHigh:
preMarketHigh = tuple.close
if tuple.close < support1:
support1 = tuple.close
if counter >= 100:
if tuple.close < support2:
support2 = tuple.close
if counter >= 200:
if tuple.close < support3:
support3 = tuple.close
counter += 1
if support1 <= support2 and support1 <= support3:
lowest_support = support1
if support2 <= support3:
mid_support = support2
high_support = support3
else:
mid_support = support3
high_support = support2
if support2 < support1 and support2 <= support3:
lowest_support = support2
if support1 <= support3:
mid_support = support1
high_support = support3
else:
mid_support = support3
mid_support = support1
if support3 < support1 and support3 < support2:
lowest_support = support3
if support1 <= support2:
mid_support = support1
high_support = support3
else:
mid_support= support3
high_support = support1
symbolData.support1 = lowest_support
symbolData.support2 = mid_support
symbolData.support3 = high_support
symbolData.firstSupportBroke = False
symbolData.secondSupportBroke = False
symbolData.thirdSupportBroke = False
symbolData.AlreadyBrokeOut = False
symbolData.preMarketHigh = preMarketHigh
if symbolData.Open >= symbolData.YesterdayClose*1.03:
symbolData.isGap = True
else:
symbolData.isGap = False
symbolData.isGapPercent = (symbolData.Open - symbolData.YesterdayClose) / symbolData.YesterdayClose
for symbol in remove:
self.activeSecurities.pop(symbol, None)
self.Liquidate(symbol)
self.RemoveSecurity(symbol)
def LiquidatePositions(self):
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.spyisgreen = True
def OnData(self, data):
if self.isMarket == True and self.spyisgreen == True:
removed = []
for symbol, symbolData in self.tradingSecurities.items():
if symbolData.premarketavg.Current.Value >= (symbolData.premarketstd + 1)*symbolData.currentpremarketavg:
removed.append(symbol)
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 len([x for x in self.Portfolio if x.Value.Invested]) >= self.maxTraded:
break
if self.Portfolio[symbol].Invested:
if symbolData.AlreadyBrokeOut == False and self.Securities[symbol].Price >= symbolData.preMarketHigh:
self.SetHoldings([PortfolioTarget(symbol, self.securityWeight)])
if self.lastMinute == self.Time.minute:
pass
else:
self.lastMinute = self.Time.minute
self.oneMinuteLow[symbol] = self.Securities[symbol].Low
symbolData.AlreadyBrokeOut = True
if not self.Portfolio[symbol].Invested and symbol not in self.tradedToday:
if self.Securities[symbol].Price <= symbolData.support1:
symbolData.firstSupportBroke = True
if self.Securities[symbol].Price <= symbolData.preMarketHigh:
symbolData.secondSupportBroke = True
if symbolData.firstSupportBroke == True and self.Securities[symbol].Price >= symbolData.support1:
self.SetHoldings([PortfolioTarget(symbol, self.securityWeight/2)])
self.oneMinuteLow[symbol] = self.Securities[symbol].Low
self.tradedToday.append(symbol)
self.Log(str(symbol) + "support1 = " + str(symbolData.support1))
self.Log(str(symbol) + "PreMarketHigh = " + str(symbolData.preMarketHigh))
if symbolData.secondSupportBroke == True and self.Securities[symbol].Price >= symbolData.preMarketHigh:
self.SetHoldings([PortfolioTarget(symbol, self.securityWeight/2)])
self.tradedToday.append(symbol)
self.oneMinuteLow[symbol] = self.Securities[symbol].Low
symbolData.AlreadyBrokeOut = True
# 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.oneMinuteHigh[symbol] = self.Securities[symbol].High
self.manageProfit()
self.oneMinuteLow[symbol] = self.Securities[symbol].Low
def manageProfit(self):
investedSecurities = [x.Key for x in self.Portfolio if x.Value.Invested]
for symbol, symbolData in self.activeSecurities.items():
if self.Portfolio[symbol].Invested and (self.Securities[symbol].Price <= symbolData.preMarketHigh) and (self.Securities[symbol].Price <= self.oneMinuteLow[symbol]) and (self.Securities[symbol].Price > symbolData.support1):
self.Liquidate(symbol, "PROFIT for Support 1")
self.Log("Support success count = " + str(self.success_count))
self.success_count = self.success_count + 1
elif self.Portfolio[symbol].Invested and self.Securities[symbol].Price <= symbolData.support1:
self.Liquidate(symbol, "Hit Support 1")
self.Log("Support loss count = " + str(self.loss_count))
self.loss_count = self.loss_count + 1
continue
if self.Portfolio[symbol].Invested and self.Securities[symbol].Price >= symbolData.preMarketHigh and (self.Securities[symbol].Price <= self.oneMinuteLow[symbol]):
self.Liquidate(symbol, "PROFIT High")
self.Log("PMH success count = " + str(self.success_countt))
self.success_countt = self.success_countt + 1
elif self.Portfolio[symbol].Invested and self.Securities[symbol].Price >= symbolData.preMarketHigh and (self.Securities[symbol].Price <= self.oneMinuteLow[symbol]):
self.Liquidate(symbol, "Hit High Support")
self.Log("PMH loss count = " + str(self.loss_countt))
self.loss_countt = self.loss_countt + 1
# if self.Portfolio[symbol].Invested and (self.Securities[symbol].Holdings.UnrealizedProfitPercent > 0.02):
# self.Liquidate(symbol, "PROFIT")
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(2400)
std = StandardDeviation(2400)
currentavg = SimpleMovingAverage(300)
history = self.History(symbol, 5600, Resolution.Minute)
for tuple in history.itertuples():
CurrentHour = int(str(tuple.Index[1])[11:13])
if CurrentHour < 9:
sma.Update(tuple.Index, tuple.volume)
std.Update(tuple.Index, tuple.volume)
currentavg.Update(tuple.Index, tuple.volume)
symbolData = SymbolData(symbol, sma, std, currentavg)
self.activeSecurities[symbol] = symbolData
for symbol in removedSecurities:
if symbol in self.activeSecurities:
self.activeSecurities.pop(symbol, None)
if self.Portfolio[symbol].Invested:
self.Liquidate(symbol)
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 > 40 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):
sortedByVolume = sorted([x.Symbol for x in fine if x.CompanyReference.CountryId == "USA"
and x.CompanyReference.PrimaryExchangeID in ["NYS","NAS"]],
key = lambda x: self.dollarVolumeBySymbol[x], reverse=True)
count = len(sortedByVolume)
if count == 0:
return Universe.Unchanged
return sortedByVolume[:500]
class SymbolData:
def __init__(self, symbol, sma, std, currentavg):
self.Open = -1
self.YesterdayClose = -1
self.preMarketHigh = -1
self.isGap = False
self.Symbol = symbol
self.isGapPercent = 0.0
self.support1 = 0
self.support2 = 0
self.support3 = 0
self.firstSupportBroke = False
self.secondSupportBroke = False
self.thirdSupportBroke = False
self.AlreadyBrokeOut = False
self.premarketavg = sma
self.premarketstd = std
self.currentpremarketavg = currentavg