Overall Statistics
Total Trades
204
Average Win
0.26%
Average Loss
-0.22%
Compounding Annual Return
1.451%
Drawdown
1.400%
Expectancy
0.360
Net Profit
8.491%
Sharpe Ratio
0.991
Probabilistic Sharpe Ratio
48.373%
Loss Rate
37%
Win Rate
63%
Profit-Loss Ratio
1.17
Alpha
0.014
Beta
0.004
Annual Standard Deviation
0.015
Annual Variance
0
Information Ratio
-0.669
Tracking Error
0.185
Treynor Ratio
3.351
Total Fees
$4271.17
# Research question: Is there a bias after a significant close in a bull market?
# Sourced from https://www.youtube.com/watch?v=HdOgW8YobCE

class BullMarketGapDownReboundAlgorithm(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2015, 1, 1)
        self.SetCash(1000000)
        
        self.symbol = self.AddEquity("SPY", Resolution.Minute).Symbol
        self.sma_short = SimpleMovingAverage(50)
        self.sma_long = SimpleMovingAverage(200)
        self.max = Maximum(50)
        
        closes = self.History(self.symbol, 200, Resolution.Daily).loc[self.symbol].close
        for time, close in closes.iteritems():
            self.sma_short.Update(time, close)
            self.sma_long.Update(time, close)
            self.max.Update(time, close)
        
        self.last_close = None
        self.quantity = 0
        
        self.Schedule.On(self.DateRules.EveryDay(self.symbol), self.TimeRules.AfterMarketOpen(self.symbol, 1), self.Open)
        self.Schedule.On(self.DateRules.EveryDay(self.symbol), self.TimeRules.BeforeMarketClose(self.symbol, 15), self.Close)
        
    def Open(self):
        if self.last_close is None:
            return
        
        # Enter if:
        # - Gapped down this morning
        # - Yesterday closed at the highest close in the last 50 bars
        # - Short MA > Long MA
        if self.Securities[self.symbol].Open < self.last_close and \
            self.max.Current.Value == self.last_close and \
            self.sma_short > self.sma_long:
            self.quantity = self.CalculateOrderQuantity(self.symbol, 1)
            self.MarketOrder(self.symbol, self.quantity)
        
    def Close(self):
        if self.quantity > 0:
            self.MarketOrder(self.symbol, -self.quantity)
            self.quantity = 0
        
    def OnEndOfDay(self):
        self.last_close = self.Securities[self.symbol].Price
        
        self.sma_short.Update(self.Time, self.last_close)
        self.sma_long.Update(self.Time, self.last_close)
        self.max.Update(self.Time, self.last_close)