Symbolic
Formulas rather than procedures: sympy expressions for prices and greeks, checked against the engines to round-off
where the engine computes the same truncation and to the expected order otherwise. Every class has .terms (the
terms of log P, kept apart), .price, .greek(...) and .evaluate(expr, **values).
Class |
Chain |
Order |
Model page |
|---|---|---|---|
|
two regimes, equal rates |
second |
|
|
any finite chain |
first |
|
|
any finite chain |
first |
|
|
any finite chain |
first |
|
|
two regimes, any rates |
exact |
The other models have their closed forms written out, and evaluated in numpy, on their pages under Models: mathematics and Python; they are not yet sympy classes.
Two regimes, second order
- class rl.symbolic.VasicekTwoStateBond(regime=0)
The two-state Vasicek bond to second order in \(\varepsilon = 1/\lambda\):
.terms holds the five terms as state, averaged, green_kubo, second_order and memory;
.greek("r0"), .greek("theta1"), .greek("lam") differentiate the price; .delta(), .gamma(),
.theta() are QuantLib’s names.
from regimelib.symbolic import VasicekTwoStateBond
f = VasicekTwoStateBond(regime=0)
f.greek("r0")
f.evaluate(f.delta(), r0=0.03, kappa=0.5, theta1=0.06, theta2=0.02, sigma1=0.015, sigma2=0.008, lam=8.0, T=5.0)
Any chain, first order
For a chain with any number of regimes the first-order bond depends on the chain only through numbers: the
stationary averages, the Green–Kubo integrals \(K\) of the switched coefficients, and the memory coefficients
\(m\) of the starting regime. coefficients(chain, ...) computes them from the generator, and the formula is
symbolic in them.
- class rl.symbolic.VasicekBondFirstOrder
Vasicek, with \(g_i = c_iB + d_iB^2\), \(c_i = -\kappa\theta_i\), \(d_i = \tfrac12\sigma_i^2\) and \(I_n = \int_0^TB^n\):
from regimelib.symbolic import VasicekBondFirstOrder
f = VasicekBondFirstOrder()
numbers = f.coefficients(chain, kappa_=0.5, thetas=[0.08, 0.05, 0.01], sigmas=[0.015, 0.01, 0.006], regime=0)
f.evaluate(f.price, r0=0.03, kappa=0.5, T=4.0, **numbers)
- class rl.symbolic.CIRBondFirstOrder
Cox–Ingersoll–Ross with a switching mean level, \(g_i = c_iB\) with \(c_i = -k\theta_i\) and \(B\) the CIR Riccati solution:
\(I_1\) is the logarithm in the classical CIR bond, and the Riccati equation closes \(I_2\) with no further
integration. coefficients(chain, k, thetas, regime=0).
- class rl.symbolic.VasicekJumpsBondFirstOrder
Vasicek with exponential jumps of mean \(m\) at a switching intensity, \(g_i = c_iB + d_iB^2 + \ell_iJ\) with \(J(t) = 1/(1 + mB) - 1\):
The jump integrals are closed by the substitution \(u = e^{-\kappa t}\). Building the formula takes about half
a minute of sympy. coefficients(chain, kappa_, thetas, sigmas, intensities, regime=0).
Greeks in the model’s parameters
- parameterGreek(chain, wrt, regime=0, **params)
A method of the three first-order classes. wrt = ("theta", i), ("sigma", i), ("intensity", i) for a
per-regime parameter or ("q", a, b) for the switching rate out of regime a into b. The chain rule runs
through the coefficients, whose derivatives are exact: the Green–Kubo matrix is bilinear in the forcing, and the
group inverse and the stationary distribution vary with the generator as
Checked against finite differences of the engine at order 1.
params = dict(r0=0.03, kappa=0.5, T=4.0, thetas=[0.08, 0.05, 0.01], sigmas=[0.015, 0.01, 0.006])
f.parameterGreek(chain, ("theta", 2), regime=1, **params) # dP / d theta_2
f.parameterGreek(chain, ("q", 0, 1), regime=1, **params) # dP / d Q_01
Two regimes, constant forcing
- class rl.symbolic.TwoStateConstantForcing
The exact solution of the two-regime reduced system with constant forcing, a 2 × 2 matrix exponential written with its eigenvalues \(\mu_\pm\):
This is the closed-form characteristic function of every two-regime Black–Scholes, Merton or variance-gamma model.
.a(regime) in q12, q21, g1, g2, T; .blackScholes(regime) in u, sigma1, sigma2.