Overall Statistics
Total Trades
38
Average Win
0.34%
Average Loss
-0.09%
Compounding Annual Return
4.037%
Drawdown
0.900%
Expectancy
0.681
Net Profit
1.024%
Sharpe Ratio
1.573
Probabilistic Sharpe Ratio
63.653%
Loss Rate
65%
Win Rate
35%
Profit-Loss Ratio
3.76
Alpha
0.041
Beta
-0.018
Annual Standard Deviation
0.021
Annual Variance
0
Information Ratio
-2.963
Tracking Error
0.124
Treynor Ratio
-1.831
Total Fees
$38.10
Estimated Strategy Capacity
$25000000.00
Lowest Capacity Asset
KMB R735QTJ8XC9X
'''
Gap and Go Strategy 
-calculate best resistance options and weight for each
    -make sure resistances are different
-take profit:
    -New 1 min candle to make new low
        -Add a buffer (.03?)
    -at a certain level
'''
class MeasuredRedSalmon(QCAlgorithm):
    
    success_count = 1
    loss_count = 1
    success_countt = 1
    loss_countt = 1
        
    def Initialize(self):
        self.SetStartDate(2021, 2, 3)  # Set Start Date
        self.SetEndDate(2021, 5, 7)
        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.tradedToday = []
        self.tradingSecurities = {}
        self.oneMinuteHigh = {}
        self.quarterPositions = {}
        self.oneMinuteLow = {}
        self.lastMinute = {}
        self.prevoneminutelow = {}
        self.prevoneminutehigh = {}

        
        
        self.SetWarmUp(timedelta(days = 2))
        
    def endMarket(self):
        self.isMarket = False
        self.tradedToday = []
        self.tradingSecurities = {}
        self.oneMinuteHigh
        self.oneMinuteLow
        self.lastMinute

    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.oneMinuteLow[symbol] = self.Securities[symbol].Low
            
        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
            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)
                    
                if tuple.close < preMarketLow:
                    preMarketLow = tuple.close
                if tuple.close > resistance1:
                    resistance1 = tuple.close
                if counter >= 100:
                    if tuple.close > resistance2:
                        resistance2 = tuple.close
                if counter >= 240:
                    if tuple.close > resistance3:
                        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


        for symbol in remove:
            self.activeSecurities.pop(symbol, None)
            self.Liquidate(symbol)
            self.RemoveSecurity(symbol)
            
    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, symbolData in self.tradingSecurities.items():
                if symbolData.currentpremarketavg.Current.Value <= (symbolData.premarketstd.Current.Value + symbolData.premarketavg.Current.Value):
                    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 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) + "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.activeSecurities.items():
            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 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.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[:200]
        
class SymbolData:
    def __init__(self, symbol, sma, std, currentavg):
        
        self.Open = -1
        self.YesterdayClose = -1
        self.preMarketLow = 10000
        self.isGap = False
        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