#src\quantmetrics\price_calculators\dejd_pricing\dejd_characteristic_function.py
import numpy as np
from typing import TYPE_CHECKING
from quantmetrics.risk_calculators.martingale_equation import RiskPremium
from quantmetrics.utils.exceptions import FeatureNotImplementedError, UnsupportedEMMTypeError
if TYPE_CHECKING:
from quantmetrics.levy_models import LevyModel
from quantmetrics.option_pricing import Option
[docs]
class DEJDCharacteristicFunction:
"""
Implements the characteristic function for a lognormal jump-diffusion (LJD) model.
Parameters
----------
model : LevyModel
A LevyModel object specifying the underlying asset's model and its parameters.
option : Option
An Option object specifying the option parameters: interest rate, strike price, time to maturity, dividend yield and the equivalent martingale measure.
"""
[docs]
def __init__(self, model: "LevyModel", option: "Option"):
self.model = model
self.option = option
[docs]
def calculate(self, u: np.ndarray) -> np.ndarray:
"""
Calculate the characteristic function for the DEJD model.
Parameters
----------
u : np.ndarray
Input array for the characteristic function.
Returns
-------
np.ndarray
The characteristic function values.
Notes
-------
The characteristic function of the DEJD under the risk-neutral measure is defined as follows:
- If ``emm = "mean-correcting"``:
.. math::
\\Phi^{\\mathbb{Q}}(u) = \\exp\\left\{T \\left[i u b^\\mathbb{Q} -\\frac{u^2}{2}c + \\lambda \\left( \\frac{p\\eta_1}{\\eta_1 - iu} + \\frac{q \\eta_2}{\\eta_2 + iu} - 1 \\right) \\right]\\right\},
where
.. math::
b^\\mathbb{Q}= r - \\frac{\\sigma^2}{2} -\\lambda \\kappa \\quad c = \\sigma^2
.. math::
\\kappa = \\frac{p\\eta_1}{\\eta_1 -1} + \\frac{q\\eta_2}{\\eta_2+1} - 1, \\quad q = 1-p
- If ``emm = "Esscher"`` and ``psi = 0``:
.. math::
\\Phi^{\\mathbb{Q}}(u) = \\exp\\left\{T \\left[i u b^\\mathbb{Q} -\\frac{u^2}{2}c + \\lambda^\\mathbb{Q} \\left( \\frac{\\frac{p\\eta_1}{\\eta_1 - (\\theta +iu)} + \\frac{q\\eta_2}{\\eta_2 + (\\theta + iu)}}{\\frac{p\\eta_1}{\\eta_1 - \\theta} + \\frac{q\\eta_2}{\\eta_2 + \\theta}} - 1 \\right) \\right]\\right\},
where
.. math::
b^\\mathbb{Q}= r - \\frac{\\sigma^2}{2} -\\lambda \\kappa + \\theta \\sigma^2 \\quad c = \\sigma^2
.. math::
\\lambda^\\mathbb{Q} = \\lambda \\left( \\frac{p\\eta_1}{\\eta_1 - \\theta} + \\frac{q\\eta_2}{\\eta_2 + \\theta} \\right)
- If ``emm = "Esscher"`` and ``psi != 0``:
.. math::
\\Phi^{\\mathbb{Q}}(u) = \\exp\\left\{T \\left[i u b^\\mathbb{Q} -\\frac{u^2}{2}c + \\lambda^\\mathbb{Q} \\left(\\frac{p\\eta_1 I(\\theta+iu, \\eta_1, \\psi) + q\\eta_2 I(\\theta +iu, -\\eta_2, \\psi)}{p\\eta_1 I(\\theta, \\eta_1, \\psi) + q\\eta_2 I(\\theta, -\\eta_2, \\psi)} - 1 \\right)\\right] \\right\},
where
.. math::
b^\\mathbb{Q}= r - \\frac{\\sigma^2}{2} -\\lambda \\kappa + \\theta(\\psi) \\sigma^2 \\quad c = \\sigma^2
.. math::
\\lambda^\\mathbb{Q} = \\lambda \\frac{1}{2}\\sqrt{\\frac{\\pi}{|\\psi|}} \\left[p\\eta_1 I(\\theta, \\eta_1, \\psi) + q\\eta_2 I(\\theta, -\\eta_2, \\psi) \\right],
.. math::
I(a,b,\\psi):= \\exp \\left[-\\psi \\left(\\frac{a-b}{2\\psi} \\right)^2 \\right] \\left\{1 - erf\\left[\\sqrt{|\\psi|} \\left(\\frac{a-b}{2\\psi} \\right) \\right] \\right\}
with
.. math::
\\psi < 0.
The first-order Esscher parameter :math:`\\theta` is the risk premium (market price of risk) and which is the unique solution to the martingale equation for each :math:`\\psi` which is the second-order Esscher parameter. See the documentation of the ``RiskPremium`` class for the martingale equation and refer to [1]_ for more details.
- :math:`\\mathbb{Q}` is the risk-neutral measure.
- :math:`T` is the time to maturity.
- :math:`i` is the imaginary unit.
- :math:`u` is the input variable.
- :math:`r` is the risk-free interest rate.
- :math:`\\sigma` is the volatility of the underlying asset.
- :math:`p,q\\geq 0, p+q =1` are the probabilities of upward and downward jumps.
- The upward jump sizes are exponentially distributed with mean :math:`1/\\eta_1` with :math:`\\eta_1>1`.
- The downward jump sizes are exponentially distributed with mean :math:`1/\\eta_2` with :math:`\\eta_2 >0`.
- :math:`\\lambda` is the jump intensity rate.
References
----------
.. [1] Choulli, T., Elazkany, E., & Vanmaele, M. (2024). Applications of the Second-Order Esscher Pricing in Risk Management. arXiv preprint arXiv:2410.21649.
.. [2] Jeanblanc, M., Yor, M., & Chesney, M. (2009). Mathematical methods for financial markets. Springer Science & Business Media.
.. [3] Kou, S. G. (2002). A jump-diffusion model for option pricing. Management science, 48(8), 1086-1101.
"""
return self._dejd_characteristic_function(u)
def _dejd_characteristic_function(self, u: np.ndarray) -> np.ndarray:
"""
Calculate the characteristic function for the DEJD model.
Parameters
----------
u : np.ndarray
Input array for the characteristic function.
Returns
-------
np.ndarray
The characteristic function values.
"""
mu = self.model.mu
sigma = self.model.sigma
lambda_ = self.model.lambda_
eta1 = self.model.eta1
eta2 = self.model.eta2
p = self.model.p
r = self.option.r
T = self.option.T
emm = self.option.emm
psi = self.option.psi
if emm == "mean-correcting":
b = (
r
- sigma**2 / 2
- lambda_ * (p * eta1 / (eta1 - 1) + (1 - p) * eta2 / (eta2 + 1) - 1)
)
char_func = np.exp(
T
* (
1j * u * b
- sigma**2 * u**2 / 2
+ lambda_
* (
p * eta1 / (eta1 - 1j * u)
+ (1 - p) * eta2 / (eta2 + 1j * u)
- 1
)
)
)
elif (emm == "Esscher") & (psi == 0.0):
theta = RiskPremium(self.model, self.option).calculate()
b = (
mu
- 0.5 * sigma**2
- lambda_ * (p / (eta1 - 1) - (1 - p) / (eta2 + 1) + theta * sigma**2)
)
char_func = np.exp(
T
* (
1j * u * b
- 0.5 * sigma**2 * u**2
+ lambda_
* (
(
p * eta1 / (eta1 - (theta + 1j * u))
+ (1 - p) * eta2 / (eta2 + (theta + 1j * u))
)
- (p * eta1 / (eta1 - theta) + (1 - p) * eta2 / (eta2 + theta))
)
)
)
elif (emm == "Esscher") & (psi != 0.0):
raise FeatureNotImplementedError("Esscher")
else:
raise UnsupportedEMMTypeError(emm)
return char_func