I'm solving the following problem as a part of Interest Rate Models class on Coursera

calibration of 1-factor Gaussian HJM

I'm having a hard time using nonlinear root solver to invert the Black formula for Cap price in order to obtain a Black implied volatility that will be used further for calibration purposes. My Python code is attached below.

import numpy as np
import math
import scipy
from scipy import optimize
from scipy import stats

Time = [0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4]
ForwardRates = [0.06, 0.08, 0.09, 0.10, 0.10, 0.10, 0.09, 0.09]
CapPrices = [0.20, 0.80, 1.20, 1.60]
SimpleRates = []
DiscountFactors = []


for i in range(1, len(Time)):

SwapRates = []
for k in range(1, len(Time)):
    s = sum(DiscountFactors[i] for i in range(1, k + 1))
    SwapRates.append((DiscountFactors[0] - DiscountFactors[k])/(0.5*s))

def d1(i, sigma):
    return (np.log(ForwardRates[i]/SwapRates[i])+0.5*math.pow(sigma, 2)*Time[i-1])/(sigma*math.sqrt(Time[i-1]))

def d2(i, sigma):
    return (np.log(ForwardRates[i]/SwapRates[i])+math.pow(sigma, 2)*Time[i-1])/(sigma*math.sqrt(Time[i-1])) - sigma*math.sqrt(Time[i-1])

def caplet(begin, end, sigma):
    return 0.5*DiscountFactors[end]*(ForwardRates[end]*scipy.stats.norm.cdf(d1(end, sigma))-SwapRates[end]*scipy.stats.norm.cdf(d2(end, sigma)))

def cap(end, sigma):
    price = 0
    for j in range(1, end + 1):
        price += caplet(j - 1, j, sigma)
    return price

s = scipy.optimize.bisect(lambda sigma: cap(1, sigma) - CapPrices[0], 0.0005, 0.5)

I'm getting an error that f(a) and f(b) must have different signs regardless of my interval choice. What particular root solving method should I use in Python to get around that? Is there anything else that I'm doing wrong?


1 Answer 1


Notice that cap prices are given as %, therefore your vector of cap prices should be

CapPrices = [0.002, 0.008, 0.012, 0.016]

while you have

CapPrices = [0.20, 0.80, 1.20, 1.60]

The code should find solution without problem for these cap prices.

Notice that for your incorrectly given CapPrices there is no solution. Notice:

${Caplet(F,\sigma,t) \to F} $ as $\sigma \to \infty$. Therefore the highest caplet value is $F$, but you are trying to find solution for roughly $2.5F$ i.e. (0.20 / 0.08 = 2.5), therefore the solver fails.

I have also noticed that you have error in your formula in d2, it should be equal to:

return (np.log(ForwardRates[i]/SwapRates[i])+0.5*math.pow(sigma, 2)*Time[i-1])/(sigma*math.sqrt(Time[i-1])) - sigma*math.sqrt(Time[i-1])

while you have (missing multiplication by 0.5)

return (np.log(ForwardRates[i]/SwapRates[i])+math.pow(sigma, 2)*Time[i-1])/(sigma*math.sqrt(Time[i-1])) - sigma*math.sqrt(Time[i-1])

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.