Overall Statistics
class HorizontalMultidimensionalThrustAssembly(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2018, 11, 1)
        self.SetEndDate(2019, 1, 1)
        self.SetCash(50000)
        
        self.AddEquity("SPY", Resolution.Minute)
        
        # Measures the change in SPY prices between 2 minutes
        self.spyMomentum = self.MOMP("SPY", 2, Resolution.Minute)
        
        # Measures the standard deviation in SPY prices in 24 hours
        self.spySD = self.STD("SPY", 10080, Resolution.Minute)
        
        # Measures the mean SPY momentum in 24 hours
        self.spyMomentumMean = SimpleMovingAverage(10080)
        
        # Performs the operation to update the SPY momentum mean indicator by piping spyMomentum into it
        self.spyMomentum.Updated += self.OnSpyMomentum
        
        # For tracking stats
        self.longstopLossTicket = None
        self.shortstopLossTicket = None
        self.shorttakeProfitTicket = None
        self.longtakeProfitTicket = None
        self.noOfTrades = 0
        self.noOfSL = 0
        self.noOfTP = 0

    def OnData(self, data):
        '''OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.
            Arguments:
                data: Slice object keyed by symbol containing the stock data
        '''
        
        # Putting 1 percent of the portfolio in a trade
        self.percentageOfPortfolioPerTrade = 0.01
        self.noOfSDForSL = 0.1
        self.noOfSDForTP = 10
        
        # Purchasing quantities
        self.price = self.Securities["SPY"].Close
        self.quantity = self.percentageOfPortfolioPerTrade * self.Portfolio.TotalPortfolioValue / self.price
        self.lotSize = self.Securities["SPY"].SymbolProperties.LotSize
        self.quantity = round(self.quantity/self.lotSize) * self.lotSize
        
        # Stop losses
        self.longStopLoss = self.Securities["SPY"].Close - self.noOfSDForSL*self.spySD.Current.Value
        self.shortStopLoss = self.Securities["SPY"].Close + self.noOfSDForSL*self.spySD.Current.Value
        
        # Take Profits
        self.longTakeProfit = self.Securities["SPY"].Close + self.noOfSDForTP*self.spySD.Current.Value
        self.shortTakeProfit = self.Securities["SPY"].Close - self.noOfSDForTP*self.spySD.Current.Value

        # The current change in price is greater than the mean change in price over 24 hours
        if self.spyMomentum.Current.Value > self.spyMomentumMean.Current.Value:
            self.MarketOrder("SPY", self.quantity)
            self.longstopLossTicket = self.StopMarketOrder("SPY", -self.quantity, self.longStopLoss)
            self.longtakeProfitTicket = self.StopMarketOrder("SPY", -self.quantity, self.longTakeProfit)
            self.noOfTrades += 1
            
        elif self.spyMomentum.Current.Value < self.spyMomentumMean.Current.Value:
            self.MarketOrder("SPY", -self.quantity)
            self.shortstopLossTicket = self.StopMarketOrder("SPY", self.quantity, self.shortStopLoss)
            self.shorttakeProfitTicket = self.StopMarketOrder("SPY", self.quantity, self.shortTakeProfit)
            self.noOfTrades += 1
            
        if self.noOfTrades > 0:    
            self.Debug(f"Number of trades so far: {self.noOfTrades}\n\
                         Percentage of trades stopped out: {round(self.noOfSL/self.noOfTrades, 5)}\n\
                         Percent of trades profitted out: {round(self.noOfTP/self.noOfTrades, 5)}\n\n")
        
    def OnSpyMomentum(self, sender, updated):
        if self.spyMomentum.IsReady:
            self.spyMomentumMean.Update(self.Time, updated.Value)
            
    def OnOrderEvent(self, orderEvent):
        
        if orderEvent.Status != OrderStatus.Filled:
            return
        
        #2. Check if we hit our stop loss (Compare the orderEvent.Id with the stopMarketTicket.OrderId)
        #   It's important to first check if the ticket isn't null (i.e. making sure it has been submitted)
        if self.longstopLossTicket is not None and self.longstopLossTicket.OrderId == orderEvent.OrderId:
            self.noOfSL += 1
            
        if self.shortstopLossTicket is not None and self.shortstopLossTicket.OrderId == orderEvent.OrderId:
            self.noOfSL += 1
            
        if self.shorttakeProfitTicket is not None and self.shorttakeProfitTicket.OrderId == orderEvent.OrderId:
            self.noOfTP += 1
        
        if self.longtakeProfitTicket is not None and self.longtakeProfitTicket.OrderId == orderEvent.OrderId:
            self.noOfTP += 1