Overall Statistics
Total Orders
30
Average Win
4.81%
Average Loss
-10.16%
Compounding Annual Return
4.180%
Drawdown
11.900%
Expectancy
0.327
Start Equity
1000000
End Equity
1368889.26
Net Profit
36.889%
Sharpe Ratio
0.104
Sortino Ratio
0.026
Probabilistic Sharpe Ratio
3.304%
Loss Rate
10%
Win Rate
90%
Profit-Loss Ratio
0.47
Alpha
0.004
Beta
0.031
Annual Standard Deviation
0.067
Annual Variance
0.005
Information Ratio
-0.498
Tracking Error
0.164
Treynor Ratio
0.224
Total Fees
$4231.68
Estimated Strategy Capacity
$920000.00
Lowest Capacity Asset
CROX TG0PJGXPBS6D
Portfolio Turnover
0.71%
'''
a. Enter: If Close >Open on Earnings Date, Enter position Next Day Open if open < high
b. Exit: Price >= High of ED [can be High*(1+r%)]
c. Stoploss: -10% of Entry Price

Req Data: ED_Open, ED_Close, ED_High
Orders: ENTER:MKT(AED_OPEN), EXIT:LIMIT(ED_HIGH), STOPLOSS: STOP(-10% of EntryPrice)
'''

# region imports
from AlgorithmImports import *
# endregion


# Strategy Class
class PowerEarninggap(QCAlgorithm):
    
    # Variables
    stopMarketTicket = None
    limitTicket = None


    # Initialize strategy
    def initialize(self):
        self.SetStartDate(2017, 1, 1)
        self.SetEndDate(2024,8,30)
        self.SetCash(1000000)

        # self.AddUniverse(self.CoarseFilter, self.FineFilter)

        # self.SPY = self.AddEquity('SPY', Resolution.Minute).Symbol
        # self.Schedule.On(self.DateRules.EveryDay("SPY"), self.TimeRules.AfterMarketOpen("SPY", 1), self.AfterMarketOpen)
        self.CROX = self.AddEquity('CROX', Resolution.Minute).Symbol
        self.Schedule.On(self.DateRules.EveryDay("CROX"), self.TimeRules.AfterMarketOpen("CROX", 1), self.AfterMarketOpen)


    def AfterMarketOpen(self):
        req_securities = [sec.Symbol.Value for sec in self.ActiveSecurities.Values]

        for security in self.ActiveSecurities.Values:
            # Add check for yesterday
            yesterday = self.Time - timedelta(days=1)

            # Check yesterday is ED
            if security.Fundamentals.EarningReports.FileDate.ThreeMonths.date() == yesterday.date():
                symbol = security.Symbol
                historyData = self.History(symbol, 3, Resolution.Daily)
                try:
                    openED = historyData['open'][-1]
                    closeED = historyData['close'][-1]
                    highED = historyData['high'][-1]
                    openAED = security.Open
                except:
                    self.Debug(f"History data unavailable for {symbol.Value}")
                    continue

                # Trading Logic    
                if closeED>openED and openAED<highED and security.Fundamentals.EarningReports.FileDate.ThreeMonths:
                    # Enter Position if not invested
                    if not self.Portfolio.Invested:
                        # Enter Market Order
                        self.qty = int((self.Portfolio.Cash/security.AskPrice)*0.99)
                        
                        self.MarketOrder(symbol,self.qty)
                        
                        # Enter Stoploss Order, return OrderTicket
                        self.stopMarketTicket = self.StopMarketOrder(symbol, -self.qty, 0.9*openAED)
                        
                        # Exit Market Order
                        self.limitTicket = self.LimitOrder(symbol,-self.qty,highED)


    # Triggered when any event related to order happens
    def OnOrderEvent(self, orderEvent):
        # Check if limit order is filled
        if self.limitTicket is not None and self.limitTicket.OrderId == orderEvent.OrderId:
            self.Debug("Limit Order Filled Time:" + str(self.Time))
            self.Debug("Limit Order Filled :(")
            response = self.stopMarketTicket.Cancel()
            if response.is_success:
                self.debug("StopLoss Order successfully cancelled")
            else:
                self.debug("StopLoss Order not cancelled :(")
        
        # If stopMarketTicket is filled, cancel the limit order
        if self.stopMarketTicket is not None and self.stopMarketTicket.OrderId == orderEvent.OrderId:
            # store time
            self.stopMarketFillTime = self.time
            self.Debug("Cancel Limit Order Time:" + str(self.stopMarketFillTime))
            response = self.limitTicket.Cancel()
            if response.is_success:
                self.debug("Order successfully cancelled")
            else:
                self.debug("Order not cancelled :(")