Hello everyone, I'm trying to implement an implied volatility rank which I can use for decision to trade the option. I've been unable to imlement the IV rank for multiple reasons, as the IV is often calculated to be 0, and an error for list index out of range often appears.

What I'm trying to do is to choose the 5 most liquid stocks and then create a dictionary for them that holds their indicators and other values which I might access later. The first indicator I want to hold is a historical volatility indicator that will be used to normalize the implied volatility. Then, I want to store the Normalized IV back into the dictionary so I can rank the dictionary by the stocks with the highest IV and make trades off them.


import pandas as pd

class ParticleCalibratedCoil(QCAlgorithm):

def Initialize(self):

Parameters for adjusting
self.numberOfLiquidStocks = 5 # Controls the number of stocks in play

Backtesting variables
self.SetStartDate(2019, 11, 18)
self.SetEndDate(2019, 12, 18)

Algorithm variables
self.UniverseSettings.Resolution = Resolution.Minute
self.SetSecurityInitializer(lambda x: x.SetDataNormalizationMode(DataNormalizationMode.Raw))

self.dictOfUnderlyingIndicators = {}

def CoarseSelectionFilter(self, coarse):
1. Sorts each element of the coarse object by dollar volume
2. Returns a list of coarse object, limited to top 100 highest volume
3. Returns a list of symbols we want to initialise into the algorithm

self.sortedByDollarVolume = sorted(coarse, key=lambda c: c.DollarVolume, reverse=True)
self.topHundredMostLiquid = self.sortedByDollarVolume[:self.numberOfLiquidStocks]

return [stock.Symbol for stock in self.topHundredMostLiquid]

def OnSecuritiesChanged (self, changes):
For any new securities added into the universe
If the security is an underlying
Subscribe to the option chains

For any securities we want removed from the universe
Remove the underlying and then remove the options

For each new secury added into the universe
If there is not yet one
Create a standard deviation indicator
for underlying in changes.AddedSecurities:
if underlying.Symbol.SecurityType != SecurityType.Equity: continue
option = self.AddOption(underlying.Symbol.Value, Resolution.Minute)
option.SetFilter(-5, +2, timedelta(30), timedelta(60))

if not underlying.Symbol in self.dictOfUnderlyingIndicators:
self.dictOfUnderlyingIndicators[underlying.Symbol] = \
{"Volatility": self.RSI(underlying.Symbol, 1, Resolution.Minute)}

for underlying in changes.RemovedSecurities:
for symbol in self.Securities.Keys:
if symbol.SecurityType == SecurityType.Option and symbol.Underlying == underlying.Symbol:

def OnData(self, slice):

For each OptionChain, the key is the underlying symbol object, while the
value is the option chain.
For each chain in OptionChains, each chain represents the entire chain of option contracts
for the underlying security.

for chain in slice.OptionChains.Values:

# Filter for the first ATM contract
atmContract = sorted(chain, key = lambda x: abs(x.UnderlyingLastPrice - x.Strike))[0]

impliedVolatility = atmContract.ImpliedVolatility
underlyingSymbol = atmContract.UnderlyingSymbol

if underlyingSymbol in self.dictOfUnderlyingIndicators and \
"Volatility" in self.dictOfUnderlyingIndicators[underlyingSymbol]:
self.dictOfUnderlyingIndicators[underlyingSymbol] = {'NormalizedIV':
impliedVolatility / self.dictOfUnderlyingIndicators[underlyingSymbol]["Volatility"].Current.Value

self.Debug(f"Implied volatility of {underlyingSymbol} is {impliedVolatility}")
self.Debug(f"The normalized implied volatility is {self.dictOfUnderlyingIndicators[underlyingSymbol]['NormalizedIV']}")