Heston
rl.SwitchingHestonModel(chain, S0, r, q, v0, kappa, theta, sigma, rho) is QuantLib’s HestonModel with the
long-run variance theta allowed to switch.
The model
With \(S_T = F e^{X_T}\),
Reduction
Try \(\phi_i = e^{D(t)v}a_i(t)\) in the equation for the characteristic function. The terms in \(v\) cancel when
which involves \(\kappa\), \(\xi\) and \(\rho\) and not \(\theta\), so one \(D\) serves both regimes:
Closed form
The forcing is a multiple of \(D\), so two integrals are needed. With \(L = \log\big((1 - \gamma e^{-dT})/(1 - \gamma)\big)\),
with \(\alpha = (\gamma^2 - 1)/\gamma\) and \(\beta = 2\gamma - 2 - \alpha\). Then, with \(\bar\theta, \tilde\theta = \tfrac12(\theta_1 \pm \theta_2)\),
Python
S0, r, q, v0, kappa, theta, xi, rho, lam, T = 100.0, 0.0, 0.0, 0.04, 2.0, [0.09, 0.02], 0.4, -0.6, 10.0, 1.0
def heston_D(u):
"""D(T), D'(T) and the integrals of D and D^2 over [0, T]."""
b = kappa - rho * xi * 1j * u
d = np.sqrt(b * b + xi * xi * (u * u + 1j * u))
gam, E = (b - d) / (b + d), np.exp(-d * T)
D = (b - d) / xi ** 2 * (1 - E) / (1 - gam * E)
dD = -0.5 * (u * u + 1j * u) - b * D + 0.5 * xi * xi * D * D
L = np.log((1 - gam * E) / (1 - gam))
al = (gam * gam - 1) / gam
be = 2 * gam - 2 - al
I1 = ((b - d) * T - 2 * L) / xi ** 2
I2 = ((b - d) / xi ** 2) ** 2 * (T + al * L / (gam * d) - be / (gam * d) * (1 / (1 - gam * E) - 1 / (1 - gam)))
return D, dD, I1, I2
thbar, tht = half(theta)
def phi(u):
D, dD, I1, I2 = heston_D(u)
return np.exp(D * v0) * second_order(kappa * thbar * I1, kappa ** 2 * tht ** 2 * I2,
kappa * tht * D, 0.0, kappa * tht * dD, lam)
model = rl.SwitchingHestonModel(rl.RegimeChain.twoState(lam, lam), S0, r, q, v0, kappa, theta, xi, rho)
for K in (80.0, 100.0, 120.0):
print(f"K = {K:5.0f} closed form, second order {lewis_call(phi, S0, K, r, q, T, U=40.0):.5f}"
f" library {library_call(model, K, T):.5f}")
K = 80 closed form, second order 22.13388 library 22.13369
K = 100 closed form, second order 8.40289 library 8.40279
K = 120 closed form, second order 1.83003 library 1.82993
The difference is the third-order term. rl.FastSwitchingEngine(model, order=4) carries the same expansion
further.