Equity with stochastic rates
rl.SwitchingEquityRates(equity, rates, rho=0.0): an equity (SwitchingBlackScholesProcess or
SwitchingHestonModel) discounted at a short rate (SwitchingVasicek or SwitchingHullWhite) on one chain.
The frozen limit is QuantLib’s AnalyticBSMHullWhiteEngine and AnalyticHestonHullWhiteEngine.
The model
For the Black–Scholes equity with Vasicek rates,
Even with \(\rho = 0\) the stock and the rate are dependent, through the regime.
Reduction
The discount factor cannot be taken outside the expectation, so the object is the discounted characteristic function
Since \(S_T = S_0\exp(\int_0^T(r - q) + X_T)\), the rate is integrated with the complex weight \(c = 1 - iw\): \(e^{-\int r}S_T^{\,iw} = S_0^{\,iw}e^{-iwqT}\exp(-c\int r + iwX_T)\). Trying \(e^{-cB(t)r}a_i(t)\) cancels the terms in \(r\) when \(B' = 1 - aB\), as for a bond, and leaves
Closed form
Collect the forcing by power of \(B\):
With bars and tildes the half-sums and half-differences, and \(I_n = \int_0^TB^n\),
At \(w = 0\) this is the Vasicek bond. At \(w = -i\) the weight is zero and \(\Psi = S_0e^{-qT}\) exactly.
Python
S0, q, sigma, rho, lam, T = 100.0, 0.0, [0.30, 0.15], -0.3, 25.0, 1.0
r0, a, b, eta = 0.03, 0.5, [0.05, 0.02], [0.015, 0.008]
E, B, I1, I2, I3, I4 = powers_of_B(a, T)
def Psi(w):
c = 1 - 1j * w
(alb, alt) = half([-c * (a * b[i] + 1j * w * rho * sigma[i] * eta[i]) for i in range(2)])
(beb, bet) = half([0.5 * c * c * eta[i] ** 2 for i in range(2)])
(gab, gat) = half([-0.5 * sigma[i] ** 2 * (w * w + 1j * w) for i in range(2)])
return S0 ** (1j * w) * np.exp(-1j * w * q * T - c * B * r0) * second_order(
int_gbar=alb * I1 + beb * I2 + gab * T,
int_gt2=(alt ** 2 * I2 + 2 * alt * bet * I3 + bet ** 2 * I4
+ 2 * alt * gat * I1 + 2 * bet * gat * I2 + gat ** 2 * T),
gt_T=alt * B + bet * B * B + gat,
gt_0=gat,
dgt_T=(alt + 2 * bet * B) * E,
lam=lam)
def discounted_lewis_call(K, U=40.0, n=400):
x, wts = np.polynomial.legendre.leggauss(n)
u, wts = (x + 1) * U / 2, wts * U / 2
integral = np.sum(wts * (K ** (-1j * u) * Psi(u - 0.5j)).real / (u * u + 0.25))
return S0 * np.exp(-q * T) - np.sqrt(K) / np.pi * integral
chain = rl.RegimeChain.twoState(lam, lam)
model = rl.SwitchingEquityRates(rl.SwitchingBlackScholesProcess(chain, S0, 0.0, q, sigma),
rl.SwitchingVasicek(chain, r0, a, b, eta), rho=rho)
for K in (90.0, 110.0):
print(f"K = {K:5.0f} closed form, second order {discounted_lewis_call(K):.6f}"
f" library {library_call(model, K, T):.6f}")
print(f"bond closed form, second order {Psi(0.0).real:.6f}"
f" library {library_bond(rl.SwitchingVasicek(chain, r0, a, b, eta), T):.6f}")
K = 90 closed form, second order 16.621954 library 16.621952
K = 110 closed form, second order 6.774836 library 6.774838
bond closed form, second order 0.969317 library 0.969317
Other pairs
With Hull–White rates the level term drops, \(\alpha_i = -c\,iw\,\rho\,\sigma_i\eta_i\), and the prefactor \(e^{-cBr_0}\) becomes \(\exp(-c\int_0^T\varphi)\). With a Heston equity and \(\rho = 0\) the equity part of the forcing is \(\kappa\theta_iD(t; w)\) and the prefactor gains \(e^{D(T; w)v_0}\). A correlation between a Heston equity and the rate adds a term \(\rho\,\eta_i\sqrt v\,\partial_x\partial_r\) that no exponential-affine form absorbs.