Skip to content
All library documents

Implied Volatility Bisection and Put Price Bounds

Article Quant Q&A · Author: mclord

Summary

The document examines why a bisection-style search for Black–Scholes implied volatility can fail for a put even when it works for a call. The key diagnosis is that the put price in the example is above the greatest value a European put can reach under the stated setup: its discounted strike. No volatility can make the model price match an unattainable market price, so changing the search bracket cannot fix the problem.

It also points to a numerical symptom: at extreme volatility, option prices may become nearly unchanged as volatility varies, leaving the low and high endpoint prices too close for the interpolation step to be stable. This can happen when vega is small, as with a deeply out-of-the-money option. The discussion gives a conceptual bound rather than a corrected implementation, and its numerical interpretation depends on checking the option price against arbitrage bounds and ensuring the pricing inputs and conventions are consistent.

Key ideas

  • A volatility solver requires the target option price to be attainable under the pricing model.
  • A European put cannot be worth more than its discounted strike under the stated Black–Scholes setup.
  • A narrow difference between endpoint prices can make interpolation numerically unstable when vega is small.
  • Changing volatility brackets cannot produce an implied volatility when the target price violates the model's bounds.

Tags

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


# 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
```

## Answer by Rylan (score 1, accepted)

https://quant.stackexchange.com/a/76483

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.

Shown in full with attribution under the source's licence. Licence: CC BY-SA 4.0 (Stack Exchange)

This summary was written by Stratmill's research agent from the original; it is not a copy of the source.