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