Overall Statistics
Total Trades
0
Average Win
0%
Average Loss
0%
Compounding Annual Return
0%
Drawdown
0%
Expectancy
0
Net Profit
0%
Sharpe Ratio
0
Probabilistic Sharpe Ratio
0%
Loss Rate
0%
Win Rate
0%
Profit-Loss Ratio
0
Alpha
0
Beta
0
Annual Standard Deviation
0
Annual Variance
0
Information Ratio
0
Tracking Error
0
Treynor Ratio
0
Total Fees
$0.00
Estimated Strategy Capacity
$0
Lowest Capacity Asset
from AlgorithmImports import *

# Goal:
#   - Option chain selection

class TSLAOptionChainFilter(QCAlgorithm): 
    def Initialize(self):
        self.SetStartDate(2023, 1, 1)
        self.SetEndDate(2023, 1, 10)
        self.SetCash(5000)

        # Time Resolution controller 
        self.timeResolution = Resolution.Hour

        # Set TSLA equity 
        equity = self.AddEquity("TSLA", self.timeResolution)
        self.underlyingSymbol = equity.Symbol

        # Set the RAW price 
        equity.SetDataNormalizationMode(DataNormalizationMode.Raw)

        # Set TSLA options in the Universe 
        option = self.AddOption("TSLA", self.timeResolution)
        self.symbol = option.Symbol

        # Set the model for better pricing model
        option.PriceModel = OptionPriceModels.BjerksundStensland()

        # Set broker 
        self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, AccountType.Cash)

        ## Set the security initializer to call SetMarketPrice
        self.SetSecurityInitializer(lambda x: x.SetMarketPrice(self.GetLastKnownPrice(x)))
        
        # Point of interest contracts 
        self.contractStrikes = []


    def OnData(self, slice: Slice) -> None:
        if not self.Portfolio.Invested:
            atm_strike = int(slice[self.underlyingSymbol].Price)
            min_strike = atm_strike - 22
            max_strike = atm_strike + 22
            min_expiry = self.Time + timedelta(days=20)
            max_expiry = self.Time + timedelta(days=25)

            options = self.GetOption(slice, self.underlyingSymbol, OptionRight.Call, min_expiry, max_expiry, min_strike, max_strike)
            
            expiry = min([symbol.ID.Date for symbol in options])
            filtered_options = [symbol for symbol in options if symbol.ID.Date == expiry]

            strikes = [x.ID.StrikePrice for x in filtered_options]
            self.Log( "Price: " + str(atm_strike) + " | " + " Expiry: " + str(expiry.date()) + " | " + str(strikes))

    def GetOption(self, slice, underlying, option_right, min_expiry, max_expiry, min_strike, max_strike):

        ## Get list of Options Contracts for a specific time
        chainProvider = self.OptionChainProvider 
        contracts = chainProvider.GetOptionContractList(underlying, self.Time)  
        
        if len(contracts) == 0: return
       
        filtered_options = [x for x in contracts if x.ID.OptionRight == option_right and \
                                                     x.ID.StrikePrice >= min_strike and \
                                                     x.ID.StrikePrice <= max_strike and \
                                                     x.ID.Date >= min_expiry and \
                                                     x.ID.Date <= max_expiry]
           
        if len(filtered_options) == 0: 
            return
        
        sorted_options = sorted(filtered_options, key = lambda x: x.ID.StrikePrice)

        return sorted_options        


        # filtered = [x for x in chain if x.ID.Date.date() >= (self.Time.date() + timedelta(days = min_expiration)) ]

        # # Pick the closest expiration day
        # expiry = min([symbol.ID.Date for symbol in filtered])

        # # Get current equity price and round it 
        # atm_strike = int(self.Securities[self.underlyingSymbol].Price)

        # # Filter based on 
        # filtered_symbols = [symbol for symbol in filtered if symbol.ID.Date == expiry and 
        #                     symbol.ID.StrikePrice >= atm_strike + min_strike and 
        #                     symbol.ID.StrikePrice <= atm_strike + max_strike]
        
        # contract_symbol = sorted(filtered_symbols, key=lambda symbol: symbol.ID.StrikePrice)

        # option_strikes = sorted([x.ID.StrikePrice for x in contract_symbol])

        # if self.contractStrikes != option_strikes:
        #     self.contractStrikes = option_strikes
        #     self.Log("price: " + str(atm_strike) + " | " + str(option_strikes))

    def OnOrderEvent(self, orderEvent):
        if not orderEvent.Status == OrderStatus.Filled:
            return 
        message = f"Symbol {orderEvent.Symbol} |" + \
                    f"Fill Price {orderEvent.FillPrice} "+ \
                    f"Action {str(orderEvent.Direction)}"
        self.Log(f"{self.Time} {message}")