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
            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 
  • $\begingroup$ When you try to solve for implied volatility, what market price for the option are you using? $\endgroup$
    – Rylan
    Commented Aug 25, 2023 at 15:12
  • $\begingroup$ Market price is the same thing as the spot price, so, 90.2, like my code says. $\endgroup$
    – mclord
    Commented Aug 25, 2023 at 15:21

1 Answer 1


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.

  • $\begingroup$ 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% $\endgroup$
    – mclord
    Commented Aug 25, 2023 at 15:52
  • $\begingroup$ 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. $\endgroup$
    – Rylan
    Commented Aug 26, 2023 at 12:41
  • $\begingroup$ 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. $\endgroup$
    – Rylan
    Commented Aug 26, 2023 at 12:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.