Overall Statistics
Total Trades
4
Average Win
0.21%
Average Loss
-1.55%
Compounding Annual Return
-1.144%
Drawdown
9.300%
Expectancy
-0.433
Net Profit
-0.572%
Sharpe Ratio
-0.043
Probabilistic Sharpe Ratio
23.147%
Loss Rate
50%
Win Rate
50%
Profit-Loss Ratio
0.13
Alpha
0.036
Beta
-0.257
Annual Standard Deviation
0.115
Annual Variance
0.013
Information Ratio
-0.294
Tracking Error
0.557
Treynor Ratio
0.019
Total Fees
$2.00
class MultidimensionalResistanceAutosequencers(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2019, 12, 7)  # Set Start Date
        self.SetCash(100000)  # Set Strategy Cash
        
        spy_security = self.AddEquity("SPY", Resolution.Minute)
        spy_security.SetDataNormalizationMode(DataNormalizationMode.Raw)
        self.spy = spy_security.Symbol
        
        self.ema_slow = self.EMA(self.spy, 200, Resolution.Minute)
        self.ema_fast = self.EMA(self.spy, 50, Resolution.Minute)
        
        # set custom security intializer
        self.SetSecurityInitializer(self.custom_security_initializer)
        
        self.SetWarmUp(200)

    def OnData(self, data):
        
        # if data available and indicators ready
        if not data.Bars.ContainsKey(self.spy) or not (self.ema_slow.IsReady and self.ema_fast.IsReady):
            return
        
        # current price of underlying
        price = data.Bars[self.spy].Close
        
        
        # if not in a position
        if not self.Portfolio.Invested:
            
            # if EMA short crossover
            if self.ema_fast.Current.Value < self.ema_slow.Current.Value:
                
                # calculate strikes and expiry
                long_strike = price * 1.05
                short_strike = price 
                expiry = self.Time + timedelta(days=7)
                
                # retrive closest contracts
                short_put, long_put = self.bear_put_spread(self.spy, short_strike, long_strike, expiry)
                
                # subscribe to data for those contracts
                self.AddOptionContract(short_put, Resolution.Minute)
                self.AddOptionContract(long_put, Resolution.Minute)
                
                # enter spread
                self.MarketOrder(short_put, -1)
                self.MarketOrder(long_put, 1)
    
    
    
    def bear_put_spread(self, symbol, low_strike, high_strike, expiry):
        
        contracts = self.OptionChainProvider.GetOptionContractList(symbol, self.Time)
        
        # get puts
        puts = [symbol for symbol in contracts if symbol.ID.OptionRight == OptionRight.Put]
        
        # get expiry closest to desired expiry
        puts_expiry_sorted = sorted(puts, key=lambda p: abs(p.ID.Date - expiry), reverse=False)
        closest_expiry = puts_expiry_sorted[0].ID.Date
        
        # get all contracts with closest expiry
        puts_expiry_filtered = [contract for contract in puts_expiry_sorted if contract.ID.Date == closest_expiry]
        
        # sort contracts to find ones near our desired strikes
        puts_low_sorted = sorted(puts_expiry_filtered, key=lambda p: abs(p.ID.StrikePrice - low_strike), reverse=False)
        puts_high_sorted = sorted(puts_expiry_filtered, key=lambda p: abs(p.ID.StrikePrice - high_strike), reverse=False)
        
        # pick contracts closest to desired strike and expiry
        put_low = puts_low_sorted[0]
        put_high = puts_high_sorted[0]
        
        return put_low, put_high
        
    
    def custom_security_initializer(self, security):
        # intialize securities with last known price, so that we can immediately trade the security
        bar = self.GetLastKnownPrice(security)
        security.SetMarketPrice(bar)