Self Models SM
Self Models SM
January 8, 2025
1
Adjusted Characteristic function for Merton '76 model: Only jump component
"""
* T
)
return char_func_value
def B96_char_func(u, T, r, kappa_v, theta_v, sigma_v, rho, v0, lamb, mu, delta):
"""
Bates (1996) characteristic function
"""
H93 = H93_char_func(u, T, r, kappa_v, theta_v, sigma_v, rho, v0)
M76J = M76J_char_func(u, T, lamb, mu, delta)
return H93 * M76J
def B96_int_func(u, S0, K, T, r, kappa_v, theta_v, sigma_v, rho, v0, lamb, mu,␣
↪delta):
"""
Lewis (2001) integral value for Bates (1996) characteristic function
"""
char_func_value = B96_char_func(
u - 1j * 0.5, T, r, kappa_v, theta_v, sigma_v, rho, v0, lamb, mu, delta
)
int_func_value = (
1 / (u**2 + 0.25) * (np.exp(1j * u * np.log(S0 / K)) * char_func_value).
↪real
)
return int_func_value
"""
Valuation of European call option in B96 Model via Lewis (2001)
Parameters:
==========
S0: float
initial stock/index level
K: float
strike price
T: float
time-to-maturity (for t=0)
2
r: float
constant risk-free short rate
kappa_v: float
mean-reversion factor
theta_v: float
long-run mean of variance
sigma_v: float
volatility of variance
rho: float
correlation between variance and stock/index level
v0: float
initial level of variance
lamb: float
jump intensity
mu: float
expected jump size
delta: float
standard deviation of jump
==========
"""
int_value = quad(
lambda u: B96_int_func(
u, S0, K, T, r, kappa_v, theta_v, sigma_v, rho, v0, lamb, mu, delta
),
0,
np.inf,
limit=250,
)[0]
call_value = max(0, S0 - np.exp(-r * T) * np.sqrt(S0 * K) / np.pi *␣
↪int_value)
return call_value
#---------------------------------------------------------------------------------------------
S0 = 10.65
K = 22
T = 265/365
r = 0.00
# Heston'93 Parameters
kappa_v = 0.85
theta_v = 0.16
sigma_v = 0.15
rho = -0.95
v0 = 0.016
# Merton'76 Parameters
lamb = 0.1
3
mu = -0.05
delta = 0.9
sigma = np.sqrt(v0)
#---------------------------------------------------------------------------------------------
print(
"B96 Call option price via Lewis(2001): $%10.4f"
% B96_call_value(S0, K, T, r, kappa_v, theta_v, sigma_v, rho, v0, lamb, mu,␣
↪delta)
* T
)
4
return char_func_value
def B96_char_func(u, T, r, kappa_v, theta_v, sigma_v, rho, v0, lamb, mu, delta):
"""
Bates (1996) characteristic function
"""
H93 = H93_char_func(u, T, r, kappa_v, theta_v, sigma_v, rho, v0)
M76J = M76J_char_func(u, T, lamb, mu, delta)
return H93 * M76J
def B96_int_func(u, S0, K, T, r, kappa_v, theta_v, sigma_v, rho, v0, lamb, mu,␣
↪delta):
"""
Lewis (2001) integral value for Bates (1996) characteristic function
"""
char_func_value = B96_char_func(
u - 1j * 0.5, T, r, kappa_v, theta_v, sigma_v, rho, v0, lamb, mu, delta
)
int_func_value = (
1 / (u**2 + 0.25) * (np.exp(1j * u * np.log(S0 / K)) * char_func_value).
↪real
)
return int_func_value
"""
Valuation of European call option in B96 Model via Lewis (2001)
Parameters:
==========
S0: float
initial stock/index level
K: float
strike price
T: float
time-to-maturity (for t=0)
r: float
constant risk-free short rate
kappa_v: float
mean-reversion factor
theta_v: float
long-run mean of variance
sigma_v: float
volatility of variance
rho: float
5
correlation between variance and stock/index level
v0: float
initial level of variance
lamb: float
jump intensity
mu: float
expected jump size
delta: float
standard deviation of jump
==========
"""
int_value = quad(
lambda u: B96_int_func(
u, S0, K, T, r, kappa_v, theta_v, sigma_v, rho, v0, lamb, mu, delta
),
0,
np.inf,
limit=250,
)[0]
call_value = max(0, S0 - np.exp(-r * T) * np.sqrt(S0 * K) / np.pi *␣
↪int_value)
return call_value
"""
Valuation of European put option in B96 Model using Put-Call Parity.
Parameters:
==========
(Same as B96_call_value)
"""
# Call value using existing function
call_value = B96_call_value(S0, K, T, r, kappa_v, theta_v, sigma_v, rho,␣
↪v0, lamb, mu, delta)
# Put-Call Parity
put_value = call_value + K * np.exp(-r * T) - S0
return put_value
#---------------------------------------------------------------------------------------------
S0 = 100
K = 100
T = 1
r = 0.05
# Heston'93 Parameters
6
kappa_v = 1.5
theta_v = 0.02
sigma_v = 0.15
rho = 0.1
v0 = 0.01
# Merton'76 Parameters
lamb = 0.25
mu = -0.2
delta = 0.1
sigma = np.sqrt(v0)
#---------------------------------------------------------------------------------------------
print(
"B96 Put option price via Lewis(2001) using Put-Call Parity: $%10.4f"
% B96_put_value(S0, K, T, r, kappa_v, theta_v, sigma_v, rho, v0, lamb, mu,␣
↪delta)
B96 Put option price via Lewis(2001) using Put-Call Parity: $ 4.0277
Pricing a European Call Option | Merton (Lewis) Model
return value
7
def M76_call_value(S0, K, T, r, sigma, lamb, mu, delta):
"""
Value of the Call option under Lewis (2001) for Merton'76 jump diffusion␣
↪model
"""
int_value = quad(
lambda u: M76_integration_function(u, S0, K, T, r, sigma, lamb, mu,␣
↪delta),
0,
50,
limit=250,
)[0]
return call_value
#---------------------------------------------------------------------------------------------
S0 = 305.39
K = 305
T = 5/365
r = 0.08
sigma = 0.65
lamb = 2
mu = -0.05
delta = 0.75
#---------------------------------------------------------------------------------------------
print(
"Value of the Call option under Merton (1976) is: $",
np.round(M76_call_value(S0, K, T, r, sigma, lamb, mu, delta),4),
)
8
- 0.5 * u**2 * sigma**2
+ lamb * (np.exp(1j * u * mu - u**2 * delta**2 * 0.5) - 1)
)
* T
)
return char_func_value
return value
"""
int_value = quad(
lambda u: M76_integration_function(u, S0, K, T, r, sigma, lamb, mu,␣
↪delta),
0,
50,
limit=250,
)[0]
return call_value
#---------------------------------------------------------------------------------------------
# Example usage:
9
S0 = 8.75
K = 10
T = 35/365
r = 0.00
sigma = 0.65
lamb = 2
mu = -0.65
delta = 0.1
#---------------------------------------------------------------------------------------------
call_price = M76_call_value(S0, K, T, r, sigma, lamb, mu, delta)
put_price = M76_put_value(S0, K, T, r, sigma, lamb, mu, delta)
#---------------------------------------------------------------------------------------------
#print("Value of the Call option under Merton (1976) is: $", np.
↪round(call_price,4))
print("Value of the Put option under Merton (1976) is: $", np.
↪round(put_price,4))
10
omega = -lamb * (np.exp(mu + 0.5 * delta**2) - 1)
char_func_value = np.exp(
(1j * u * omega + lamb * (np.exp(1j * u * mu - u**2 * delta**2 * 0.5) -␣
↪1))
* T
)
return char_func_value
def B96_char_func(u, T, r, kappa_v, theta_v, sigma_v, rho, v0, lamb, mu, delta):
"""
Bates (1996) characteristic function
"""
H93 = H93_char_func(u, T, r, kappa_v, theta_v, sigma_v, rho, v0)
M76J = M76J_char_func(u, T, lamb, mu, delta)
return H93 * M76J
"""
Call option price in Bates (1996) under FFT
"""
k = np.log(K / S0)
g = 1 # Factor to increase accuracy
N = g * 4096
eps = (g * 150) ** -1
eta = 2 * np.pi / (N * eps)
b = 0.5 * N * eps - k
u = np.arange(1, N + 1, 1)
vo = eta * (u - 1)
else:
alpha = 1.1
v = (vo - 1j * alpha) - 1j
modcharFunc1 = np.exp(-r * T) * (
1 / (1 + 1j * (vo - 1j * alpha))
11
- np.exp(r * T) / (1j * (vo - 1j * alpha))
- B96_char_func(
v, T, r, kappa_v, theta_v, sigma_v, rho, v0, lamb, mu, delta
)
/ ((vo - 1j * alpha) ** 2 - 1j * (vo - 1j * alpha))
)
v = (vo + 1j * alpha) - 1j
modcharFunc2 = np.exp(-r * T) * (
1 / (1 + 1j * (vo + 1j * alpha))
- np.exp(r * T) / (1j * (vo + 1j * alpha))
- B96_char_func(
v, T, r, kappa_v, theta_v, sigma_v, rho, v0, lamb, mu, delta
)
/ ((vo + 1j * alpha) ** 2 - 1j * (vo + 1j * alpha))
)
)
payoff = (np.fft.fft(FFTFunc)).real
CallValueM = payoff / (np.sinh(alpha * k) * np.pi)
return CallValue
#---------------------------------------------------------------------------------------------
S0 = 2247.5
K = 2250
T = 190/365
r = 0.025
# Heston'93 Parameters
kappa_v = 1.85
12
theta_v = 0.06
sigma_v = 0.45
rho = -0.75
v0 = 0.21
# Merton'76 Parameters
lamb = 0.13
mu = -0.4
delta = 0.3
sigma = np.sqrt(v0)
#---------------------------------------------------------------------------------------------
print(
"B96 Call option price via FFT: $%10.4f"
% B96_call_FFT(S0, K, T, r, kappa_v, theta_v, sigma_v, rho, v0, lamb, mu,␣
↪delta)
13
omega = -lamb * (np.exp(mu + 0.5 * delta**2) - 1)
char_func_value = np.exp(
(1j * u * omega + lamb * (np.exp(1j * u * mu - u**2 * delta**2 * 0.5) -␣
↪1))
* T
)
return char_func_value
def B96_char_func(u, T, r, kappa_v, theta_v, sigma_v, rho, v0, lamb, mu, delta):
"""
Bates (1996) characteristic function
"""
H93 = H93_char_func(u, T, r, kappa_v, theta_v, sigma_v, rho, v0)
M76J = M76J_char_func(u, T, lamb, mu, delta)
return H93 * M76J
"""
Call option price in Bates (1996) under FFT
"""
k = np.log(K / S0)
g = 1 # Factor to increase accuracy
N = g * 4096
eps = (g * 150) ** -1
eta = 2 * np.pi / (N * eps)
b = 0.5 * N * eps - k
u = np.arange(1, N + 1, 1)
vo = eta * (u - 1)
else:
alpha = 1.1
v = (vo - 1j * alpha) - 1j
modcharFunc1 = np.exp(-r * T) * (
1 / (1 + 1j * (vo - 1j * alpha))
14
- np.exp(r * T) / (1j * (vo - 1j * alpha))
- B96_char_func(
v, T, r, kappa_v, theta_v, sigma_v, rho, v0, lamb, mu, delta
)
/ ((vo - 1j * alpha) ** 2 - 1j * (vo - 1j * alpha))
)
v = (vo + 1j * alpha) - 1j
modcharFunc2 = np.exp(-r * T) * (
1 / (1 + 1j * (vo + 1j * alpha))
- np.exp(r * T) / (1j * (vo + 1j * alpha))
- B96_char_func(
v, T, r, kappa_v, theta_v, sigma_v, rho, v0, lamb, mu, delta
)
/ ((vo + 1j * alpha) ** 2 - 1j * (vo + 1j * alpha))
)
)
payoff = (np.fft.fft(FFTFunc)).real
CallValueM = payoff / (np.sinh(alpha * k) * np.pi)
return CallValue
"""
Put option price in Bates (1996) via Put-Call Parity using FFT
"""
call_price = B96_call_FFT(S0, K, T, r, kappa_v, theta_v, sigma_v, rho, v0,␣
↪lamb, mu, delta)
15
put_price = call_price + K * np.exp(-r * T) - S0
return put_price
#---------------------------------------------------------------------------------------------
S0 = 10.65
K = 22
T = 5/365
r = 0.00
# Heston'93 Parameters
kappa_v = 0.85
theta_v = 0.16
sigma_v = 0.15
rho = -0.95
v0 = 0.016
# Merton'76 Parameters
lamb = 0.1
mu = -0.05
delta = 0.9
sigma = np.sqrt(v0)
#---------------------------------------------------------------------------------------------
#print(
# "B96 Call option price via FFT: $%10.4f"
# % B96_call_FFT(S0, K, T, r, kappa_v, theta_v, sigma_v, rho, v0, lamb, mu,␣
↪delta)
#)
print(
"B96 Put option price via FFT: $%10.4f"
% B96_put_FFT(S0, K, T, r, kappa_v, theta_v, sigma_v, rho, v0, lamb, mu,␣
↪delta)
[ ]:
[ ]:
16