Overall Statistics
Total Trades
21
Average Win
0.01%
Average Loss
-0.02%
Compounding Annual Return
-0.255%
Drawdown
0.100%
Expectancy
-0.210
Net Profit
-0.042%
Sharpe Ratio
-1.503
Probabilistic Sharpe Ratio
15.372%
Loss Rate
50%
Win Rate
50%
Profit-Loss Ratio
0.58
Alpha
-0.002
Beta
0.001
Annual Standard Deviation
0.002
Annual Variance
0
Information Ratio
1.612
Tracking Error
0.246
Treynor Ratio
-2.574
Total Fees
$21.00
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
        
        self.daysInvested = {}
        

    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
        '''
        
        if not self.spyMomentum.IsReady or not self.spySD.IsReady:
            return
        
        # 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 - 10*self.noOfSDForSL*self.spySD.Current.Value
        self.shortStopLoss = self.Securities["SPY"].Close + 10*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 not self.Portfolio.Invested: 
            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.LimitOrder("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.LimitOrder("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 OnEndOfDay(self):
        for symbol in self.Portfolio.Keys:
            holding = self.Portfolio[symbol]
            
            if not holding.Invested:
                continue
            
            if symbol not in self.daysInvested:
                self.daysInvested[symbol] = 1
            else:
                self.daysInvested[symbol] += 1
                
            if self.daysInvested[symbol] >= 5:
                self.Liquidate(symbol)
            
        
    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
            
            self.longtakeProfitTicket.Cancel()
            
        if self.shortstopLossTicket is not None and self.shortstopLossTicket.OrderId == orderEvent.OrderId:
            self.noOfSL += 1
            self.shorttakeProfitTicket.Cancel()
            
        if self.shorttakeProfitTicket is not None and self.shorttakeProfitTicket.OrderId == orderEvent.OrderId:
            self.noOfTP += 1
            self.shortstopLossTicket.Cancel()
            
        if self.longtakeProfitTicket is not None and self.longtakeProfitTicket.OrderId == orderEvent.OrderId:
            self.noOfTP += 1
            self.longstopLossTicket.Cancel()