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
2.371
Tracking Error
0.192
Treynor Ratio
0
Total Fees
$0.00
Estimated Strategy Capacity
$0
Lowest Capacity Asset
class SwimmingOrangeAlpaca(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2022, 2, 1)  # Set Start Date
        self.SetCash(100000)  # Set Strategy Cash
        
        self.UniverseSettings.Resolution = Resolution.Minute
        self.UniverseSettings.DataNormalizationMode = DataNormalizationMode.Raw
        self.AddUniverse(self.Universe.DollarVolume.Top(3))
        
        self.SetSecurityInitializer(self.OptionContractSecurityInitializer)
        self.optionsByEquity = {}

    def OptionContractSecurityInitializer(self, security):
        if security.Type == SecurityType.Equity:
            symbol = security.Symbol
            security.VolatilityModel = StandardDeviationOfReturnsVolatilityModel(30, Resolution.Daily)
            for index, row in self.History(symbol, 30, Resolution.Daily).iterrows():
                security.SetMarketPrice(IndicatorDataPoint(index[1], row.close))
                
        if security.Type == SecurityType.Option:
            security.PriceModel = OptionPriceModels.CrankNicolsonFD()

    def CoarseContractSelection(self, security):
            
        symbol = security.Symbol
        price = security.Price
        contracts = self.OptionChainProvider.GetOptionContractList(symbol, self.Time)
            
        strikes = set([x.ID.StrikePrice for x in contracts])
        strikes = sorted(strikes, key=lambda x: abs(price-x))[:10]
            
        return [x for x in contracts if (x.ID.Date - self.Time).days < 15 and
                                          x.ID.OptionRight == OptionRight.Put and
                                          x.ID.StrikePrice in strikes]

    def OnSecuritiesChanged(self, changes):
        
        # When the Underlying is added, add the contracts
        for security in changes.AddedSecurities:
            if security.Type != SecurityType.Equity:
                continue
    
            symbol = security.Symbol
            contracts = self.CoarseContractSelection(security)         

            if not contracts:
                continue
            
            msg = ', '.join([x.Value for x in contracts])
            self.Log(f'Adding {len(contracts)} for {symbol} on {self.Time}')

            self.optionsByEquity[symbol] = list()
            for contract in contracts:
                contractSymbol = self.AddOptionContract(contract).Symbol
                self.optionsByEquity[symbol].append(contractSymbol)


        # When the Underlying is removed, remove the contracts
        for security in changes.RemovedSecurities:
            symbol = security.Symbol
            if security.Type == SecurityType.Equity:
                contractSymbols = self.optionsByEquity.pop(symbol, [])
                for contractSymbol in contractSymbols:
                    self.Log(f'Removing {contractSymbol} on {self.Time}')
                    self.RemoveOptionContract(contractSymbol)

    def OnData(self, data):
        
        for kvp in data.OptionChains:
            underlyingSymbol = kvp.Key.Underlying
            if not self.IsMarketOpen(underlyingSymbol):
                return
            contracts = kvp.Value.Contracts.Values

            zero_delta = 0
            for contract in contracts:
                delta = contract.Greeks.Delta
                if delta == 0:
                    zero_delta += 1

            if zero_delta > 0:
                self.Debug(f'Zero delta in {100 * zero_delta / len(contracts)}% of contracts on {self.Time}')