# Black and Normal Model for Caplet using Python

I am able to Price Caplet using Black 76 model in Python. However, I am unable to price the same with Normal Model. Can anyone suggest what is missing ?

I am valuing caplet that caps interest rate on 10000 loan at 8% p.a. quarterly compounding for three months starting in one year.

The zero curve is flat at 6.9394% p.a. one year volatility is 20% p.a.

Also, If you can suggest best place to see practical SABR model implementation using python that would be great.

Code for Black in Python:

from scipy.stats import norm
import math

def black(F_0,y,expiry,vol,rfr,expiry_1,isCall):
option_value = 0
if expiry * vol == 0.0:
if isCall:
option_value = max(F_0 - y, 0.0)
else:
option_value = max(y - F_0 , 0.0)
else:
d1 = dPlusBlack(F_0 = F_0 , y = y, expiry = expiry ,vol = vol)
d2 = dMinusBlack(F_0 = F_0 , y = y, expiry = expiry ,vol = vol)
if isCall:
option_value = (math.exp((-rfr)*expiry_1))*(F_0 * norm.cdf(d1) - y *norm.cdf(d2))
else:
option_value = (math.exp((-rfr)*expiry_1))*(y * norm.cdf(-d2) - F_0 *norm.cdf(-d1))
return option_value
def dPlusBlack(F_0 , y, expiry , vol):
d_plus = ((math.log(F_0 / y) + 0.5 * vol * vol * expiry)/ vol / math.sqrt(expiry))
return d_plus
def dMinusBlack(F_0 , y, expiry , vol):
d_minus = (dPlusBlack(F_0 = F_0 , y = y, expiry = expiry ,vol = vol ) - vol * math.sqrt(expiry))
return d_minus
a = black(0.07,0.08,1,0.20,0.069394,1.25,"isCall")
a = 0.0020646470930435683


Code for bachelier

from scipy.stats import norm
import math

def bachelier(F_0,y,expiry,vol,rfr,expiry_1,isCall):
option_value = 0
if expiry * vol == 0.0:
if isCall:
option_value = max(F_0 - y, 0.0)
else:
option_value = max(y - F_0 , 0.0)
else:
d1 = dPlusBachelier(F_0 = F_0 , y = y, expiry = expiry ,vol = vol)
if isCall:
option_value = (math.exp((-rfr)*expiry_1))*((F_0 - y)* norm.cdf(d1) + vol * math.sqrt(expiry) * norm.cdf(d1))
else:
option_value = (math.exp((-rfr)*expiry_1))*((y-F_0) * norm.cdf(-d1) + vol * math.sqrt(expiry) * norm.cdf(-d1))
return option_value

def dPlusBachelier(F_0 , y, expiry , vol):
d_plus = (F_0 - y)/ (vol * math.sqrt(expiry))
return d_plus

a = bachelier(0.07,0.08,1,0.20,0.069394,1.25,"isCall")

• Shouldn't the second part of your option_value in the bachelier code be norm.pdf(d1)? Jan 9, 2019 at 16:15

are you using the same volatility 20% for both black76 and Bachelier?

The black76 is a lognormal model, where volatilities are quoted as relative price changes. The bachelier/normal model quotes volatilities as absolute changes.

That might be what you're missing?

Kind regards

Sorry I am bit late to the party. Just saw your post while trying to write my own black model. I am going to the mistake is a typo in dplus

d_plus = ((math.log(F_0 / y) + 0.5 * vol * vol * expiry)/ vol / math.sqrt(expiry))


Should be:

d_plus = ((math.log(F_0 / y) + 0.5 * vol * vol * expiry)/( vol * math.sqrt(expiry)))


Warm Regards, Varun