# Bisection method for implied volatility not working for European Put Options

I am trying to implement a Bisection method for implied volatility calculation. I use an algorithm from Haug (page 455).

def GBlackScholesImpVolBisection(CallPutFlag, S, X, T, r, cm):
vLow = 0.01
vHigh = 100
eps = 1e-7
cLow = BlackScholes(CallPutFlag, S, X, T, r, vLow)
cHigh = BlackScholes(CallPutFlag, S, X, T, r, vHigh)
counter = 0

vi = vLow + (cm - cLow) * (vHigh - vLow)/(cHigh - cLow)
while abs(cm - BlackScholes(CallPutFlag, S, X, T, r, vi)) > eps:
counter = counter + 1
if counter == 500:
GBlackScholesImpVolBisection = 'NA'
return GBlackScholesImpVolBisection
if BlackScholes(CallPutFlag, S, X, T, r, vi) < cm:
vLow = vi
else:
vHigh = vi
cLow = BlackScholes(CallPutFlag, S, X, T, r, vLow)
cHigh = BlackScholes(CallPutFlag, S, X, T, r, vHigh)
vi = vLow + (cm - cLow) * (vHigh - vLow) / (cHigh - cLow)
GBlackScholesImpVolBisection = vi
return GBlackScholesImpVolBisection


Basically, it works just fine for Call options but gives a mistake (zero division) if I use Put options. I tried with different low and high estimations but nothing helps.

My BlackScholes function looks like this

def BlackScholes(CallPutFlag, S, X, T, r, sigma):
d1 = (math.log(S/X) + (r + sigma**2 / 2) * T) / (sigma * math.sqrt(T))
d2 = d1 - sigma * math.sqrt(T)
if CallPutFlag == "C":
price = S * stats.norm.cdf(d1) - X * math.exp(-r * T) * stats.norm.cdf(d2)
elif CallPutFlag == "P":
price = X * math.exp(-r * T) * stats.norm.cdf(-d2) - S * stats.norm.cdf(-d1)
return price


And the variables I use are

S = 91.1 # Stock price
r = 7.2/100 # Risk-free interest rate
X = 60 # strike
T = 70/365 # Time to expiration in years
spot_price = 90.2

• When you try to solve for implied volatility, what market price for the option are you using? Commented Aug 25, 2023 at 15:12
• Market price is the same thing as the spot price, so, 90.2, like my code says. Commented Aug 25, 2023 at 15:21

## 1 Answer

There's a few ways to look at what's happening here.

From the perspective of just analyzing the code as it runs, your values with "high vol" and "low vol" are too close together. Financially, this is common if vega is near-zero, as is often the case with a deep OTM option.

From a higher level, the vol you're trying to solve for does not exist. To see why intuitively, imagine somehow we knew the stock would go to 0 -- the "best case scenario" for whoever owns the put. On expiration day, the putholder would get $$(K - S_T)^+ = 60$$. So we can never have anything worth more than $$60$$, meaning we shouldn't be able to find an implied vol making prices match.

• Thank you for the answer. Am I right, that using implied vol approximation formulas, such as Corrado-Miller, would give incorrect answer? I tried using it for my case and got volatility equal to 802% Commented Aug 25, 2023 at 15:52
• I'm not familiar with Corrado-Miller, but hopefully you'll agree that any procedure that purports to get a vol that makes this example work has to be flawed, based on the "upper bound" reasoning I gave that the option can't be worth more than \$60. Commented Aug 26, 2023 at 12:41
• Also potentially worth noting: all approximations will be wrong anyway (even a successful bisection method like in your implementation finds a vol up to a certain precision, not an exact value). A fair question is how much error is OK, and this depends on the user/application. Commented Aug 26, 2023 at 12:51