Overall Statistics
Total Trades
70
Average Win
2.16%
Average Loss
-0.32%
Compounding Annual Return
10.703%
Drawdown
14.200%
Expectancy
0.760
Net Profit
10.058%
Sharpe Ratio
0.81
Probabilistic Sharpe Ratio
41.974%
Loss Rate
77%
Win Rate
23%
Profit-Loss Ratio
6.70
Alpha
0.089
Beta
-0.005
Annual Standard Deviation
0.11
Annual Variance
0.012
Information Ratio
0.422
Tracking Error
0.181
Treynor Ratio
-16.923
Total Fees
$175.00
class BootCampTask(QCAlgorithm):
    
    # Order ticket for our stop order, Datetime when stop order was last hit
    stopMarketTicket = None
    stopMarketOrderFillTime = datetime.min
    highestSPYPrice = -1
    lowestSPYPrice = 9999999
    stopLossTicket = None
    
    def Initialize(self):
        self.SetStartDate(2018, 1, 1)
        self.SetEndDate(2018, 12, 10)
        self.SetCash(100000)
        spy = self.AddEquity("SPY", Resolution.Minute)
        spy.SetDataNormalizationMode(DataNormalizationMode.Raw)
    
    def OnData(self, data): 
        close = self.Securities["SPY"].Close
        if not self.Portfolio["SPY"].Invested:
            #placing your time restriction here ensures we can still update our Order Tickets
            if (self.Time - self.stopMarketOrderFillTime).days < 1:
                return
            #Our Entry Stop Market Order, We want to enter with only 1 trade
            if self.stopMarketTicket is None:
                self.stopMarketTicket = self.StopMarketOrder("SPY", 500, 1.002 * close)
            #As long as we are not filled in our entry order, we must update our stop entry price if necessary
            if self.Securities["SPY"].Close < self.lowestSPYPrice:
                self.lowestSPYPrice = close
                self.stopMarketTicket.UpdateStopPrice(self.lowestSPYPrice * 1.002) 
        else:
            #If we have shares of SPY it means we have also opened a stop loss order in  OnOrderEvent
            #so we must update our stop loss update to trail
            if close > self.highestSPYPrice:
                self.highestSPYPrice = close
                self.stopLossTicket.UpdateStopPrice(self.highestSPYPrice * 0.998)
                
    def OnOrderEvent(self, orderEvent):
        if orderEvent.Status != OrderStatus.Filled:
            return
        #if our market entry order is filled, we must open a stop loss 
        if self.stopMarketTicket is not None and self.stopMarketTicket.OrderId == orderEvent.OrderId: 
            self.stopMarketOrderFillTime = self.Time
            self.stopLossTicket = self.StopMarketOrder("SPY", -500, 0.998 * self.Securities["SPY"].Close)
        #if our stop loss is filled, we should reset our stopMarketTicket
        if self.stopLossTicket is not None and self.stopLossTicket.OrderId == orderEvent.OrderId: 
            self.stopMarketTicket = None