Overall Statistics
Total Trades
146
Average Win
0.03%
Average Loss
-0.04%
Compounding Annual Return
-2.187%
Drawdown
1.300%
Expectancy
-0.117
Net Profit
-0.375%
Sharpe Ratio
-0.574
Probabilistic Sharpe Ratio
20.842%
Loss Rate
54%
Win Rate
46%
Profit-Loss Ratio
0.90
Alpha
-0.027
Beta
0.049
Annual Standard Deviation
0.026
Annual Variance
0.001
Information Ratio
-2.485
Tracking Error
0.103
Treynor Ratio
-0.306
Total Fees
$146.00
Estimated Strategy Capacity
$13000000.00
Lowest Capacity Asset
SMID XJLTRYSI6U79
Portfolio Turnover
2.71%
# region imports
from AlgorithmImports import *
# endregion

class EarningsContinuation(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2021, 9, 12)  # Set Start Date
        self.SetEndDate(2021, 11, 12)
        self.SetCash(100000)  # Set Strategy Cash
        

        self.UniverseSettings.Resolution = Resolution.Daily
        self.AddUniverse(self.CoarseSelectionFunction, self.FineSelectionFunction)
        #self.UniverseSettings.DataNormalizationMode = DataNormalizationMode.Raw

        self.entryTime = datetime.min
        self.gaps= {}
        self.strongclose = 0 
        self.openPositions ={}
        self.finalfilter = []
        self.longs = []
        self.tickets = []

        self.AddEquity("SPY", Resolution.Daily)
        self.SetBenchmark("SPY")
   
        self.Schedule.On(self.DateRules.EveryDay("SPY"),self.TimeRules.AfterMarketOpen("SPY", 5),self.EveryMarketOpen)


    def CoarseSelectionFunction(self,coarse):
        
        sortedByDollarVolume = sorted(coarse, key=lambda x: x.DollarVolume, reverse=True)
        byprice = [x for x in sortedByDollarVolume if x.DollarVolume > 1000000 and x.Price > 5 and x.HasFundamentalData]
        
        byprice = [x.Symbol for x in byprice]
        
        return byprice

    def FineSelectionFunction(self,fine):
        fineUniverse = []
        yesterday = self.Time - timedelta(days=1)
        for x in fine:
            if x.EarningReports.FileDate == yesterday and  x.MarketCap > 5e7:
                self.Log(f'stock{x.Symbol.Value} has earnings on {x.EarningReports.FileDate}')
                fineUniverse.append(x)
       
        symbols = [x.Symbol for x in fineUniverse]
        
        #if self.IsWarmingUp: return
        price = self.History(symbols, timedelta(days=2), Resolution.Daily) # two days index - 0 is yesterday
        #price = self.History(Tradebar, symbols, start_time = yesterday, end_time = self.Time, Resolution.Daily)
        #dataNormalizationMode=DataNormalizationMode.Raw
        #Strong earnings close, then buy the next day

        #ex. ORCL 9/13/2021 reported earnings after the market closed
        for sec in symbols:

            try:
                earningsdayopen = price.loc[sec]['open'][0]
                earningsdayclose = price.loc[sec]['close'][0]
                earningsdayhigh = price.loc[sec]['high'][0]
                afterearningsopen = price.loc[sec]['open'][-1]
     
            except:
                self.Debug(f"History data unavailable for {sec}")
                continue
            
            closestrength= (earningsdayclose-earningsdayopen)/(earningsdayhigh-earningsdayopen)
            
            percentGap = (afterearningsopen / earningsdayclose) - 1
            
            if closestrength >=0.8 and percentGap > 0.01:
                    self.longs.append(sec)
                    self.Log(f"adding {sec} to long list with strength close{closestrength} and gap up of {percentGap}")
            
        return self.longs
        
            
    def OnSecuritiesChanged(self, changes):
        for security in changes.AddedSecurities:
            if security != 'SPY':
                self.Log(f'about to trade {security}')
                
                self.MarketOrder(security,10)
                self.entryTime = self.Time
                self.openPositions[security] = self.entryTime
            
    
    
    def EveryMarketOpen(self):
        

        for position in list(self.openPositions.keys()):
            if self.openPositions[position] + timedelta(days=5) <= self.Time :
                self.Liquidate(position.Symbol)
                self.openPositions.pop(position)
            else:
                continue