Source code for merton.greeks.equity

"""Closed-form Greeks of the BSM equity-as-call-option pricing."""

from __future__ import annotations

from dataclasses import dataclass
from typing import TYPE_CHECKING

import numpy as np

from .._backend._numpy import d1_d2, norm_cdf, norm_pdf
from .._typing import ArrayLike, FloatArray

if TYPE_CHECKING:
    import pandas as pd


[docs] def equity_delta( asset_value: ArrayLike, asset_vol: ArrayLike, debt: ArrayLike, rf: ArrayLike, T: ArrayLike, *, dividend_yield: ArrayLike = 0.0, ) -> FloatArray: """∂E/∂A = e^(-qT)·Φ(d₁) — equity sensitivity to firm asset value.""" d1, _ = d1_d2(asset_value, asset_vol, debt, rf, T, dividend_yield) q = np.asarray(dividend_yield, dtype=np.float64) T_ = np.asarray(T, dtype=np.float64) return np.exp(-q * T_) * norm_cdf(d1)
[docs] def equity_gamma( asset_value: ArrayLike, asset_vol: ArrayLike, debt: ArrayLike, rf: ArrayLike, T: ArrayLike, *, dividend_yield: ArrayLike = 0.0, ) -> FloatArray: """∂²E/∂A² = e^(-qT)·φ(d₁) / (A·σ_A·√T).""" d1, _ = d1_d2(asset_value, asset_vol, debt, rf, T, dividend_yield) A = np.asarray(asset_value, dtype=np.float64) s = np.asarray(asset_vol, dtype=np.float64) q = np.asarray(dividend_yield, dtype=np.float64) T_ = np.asarray(T, dtype=np.float64) return np.exp(-q * T_) * norm_pdf(d1) / (A * s * np.sqrt(T_))
[docs] def equity_vega( asset_value: ArrayLike, asset_vol: ArrayLike, debt: ArrayLike, rf: ArrayLike, T: ArrayLike, *, dividend_yield: ArrayLike = 0.0, ) -> FloatArray: """∂E/∂σ_A = A·e^(-qT)·φ(d₁)·√T.""" d1, _ = d1_d2(asset_value, asset_vol, debt, rf, T, dividend_yield) A = np.asarray(asset_value, dtype=np.float64) q = np.asarray(dividend_yield, dtype=np.float64) T_ = np.asarray(T, dtype=np.float64) return A * np.exp(-q * T_) * norm_pdf(d1) * np.sqrt(T_)
[docs] def equity_theta( asset_value: ArrayLike, asset_vol: ArrayLike, debt: ArrayLike, rf: ArrayLike, T: ArrayLike, *, dividend_yield: ArrayLike = 0.0, ) -> FloatArray: """∂E/∂T — time decay of equity.""" d1, d2 = d1_d2(asset_value, asset_vol, debt, rf, T, dividend_yield) A = np.asarray(asset_value, dtype=np.float64) D = np.asarray(debt, dtype=np.float64) s = np.asarray(asset_vol, dtype=np.float64) r = np.asarray(rf, dtype=np.float64) q = np.asarray(dividend_yield, dtype=np.float64) T_ = np.asarray(T, dtype=np.float64) term1 = -A * np.exp(-q * T_) * norm_pdf(d1) * s / (2.0 * np.sqrt(T_)) term2 = -r * D * np.exp(-r * T_) * norm_cdf(d2) term3 = q * A * np.exp(-q * T_) * norm_cdf(d1) return term1 + term2 + term3
[docs] def equity_rho( asset_value: ArrayLike, asset_vol: ArrayLike, debt: ArrayLike, rf: ArrayLike, T: ArrayLike, *, dividend_yield: ArrayLike = 0.0, ) -> FloatArray: """∂E/∂r = D·T·e^(-rT)·Φ(d₂).""" _, d2 = d1_d2(asset_value, asset_vol, debt, rf, T, dividend_yield) D = np.asarray(debt, dtype=np.float64) r = np.asarray(rf, dtype=np.float64) T_ = np.asarray(T, dtype=np.float64) return D * T_ * np.exp(-r * T_) * norm_cdf(d2)
@dataclass(slots=True, frozen=True)
[docs] class GreeksResult: """Container for all equity / PD Greeks returned by :func:`greeks`."""
[docs] equity_delta: FloatArray
[docs] equity_gamma: FloatArray
[docs] equity_vega: FloatArray
[docs] equity_theta: FloatArray
[docs] equity_rho: FloatArray
[docs] pd_dleverage: FloatArray
[docs] pd_dvol: FloatArray
[docs] pd_drate: FloatArray
[docs] def to_dict(self) -> dict[str, FloatArray]: return { "equity_delta": self.equity_delta, "equity_gamma": self.equity_gamma, "equity_vega": self.equity_vega, "equity_theta": self.equity_theta, "equity_rho": self.equity_rho, "pd_dleverage": self.pd_dleverage, "pd_dvol": self.pd_dvol, "pd_drate": self.pd_drate, }
[docs] def to_pandas(self) -> pd.DataFrame: import pandas as pd return pd.DataFrame({k: np.atleast_1d(v) for k, v in self.to_dict().items()})
[docs] def greeks( asset_value: ArrayLike, asset_vol: ArrayLike, debt: ArrayLike, rf: ArrayLike, T: ArrayLike, *, dividend_yield: ArrayLike = 0.0, ) -> GreeksResult: """Compute all equity + PD Greeks in one call.""" from .pd_sensitivity import ( pd_leverage_sensitivity, pd_rate_sensitivity, pd_vol_sensitivity, ) return GreeksResult( equity_delta=equity_delta( asset_value, asset_vol, debt, rf, T, dividend_yield=dividend_yield ), equity_gamma=equity_gamma( asset_value, asset_vol, debt, rf, T, dividend_yield=dividend_yield ), equity_vega=equity_vega(asset_value, asset_vol, debt, rf, T, dividend_yield=dividend_yield), equity_theta=equity_theta( asset_value, asset_vol, debt, rf, T, dividend_yield=dividend_yield ), equity_rho=equity_rho(asset_value, asset_vol, debt, rf, T, dividend_yield=dividend_yield), pd_dleverage=pd_leverage_sensitivity( asset_value, asset_vol, debt, rf, T, dividend_yield=dividend_yield ), pd_dvol=pd_vol_sensitivity( asset_value, asset_vol, debt, rf, T, dividend_yield=dividend_yield ), pd_drate=pd_rate_sensitivity( asset_value, asset_vol, debt, rf, T, dividend_yield=dividend_yield ), )
__all__ = [ "GreeksResult", "equity_delta", "equity_gamma", "equity_rho", "equity_theta", "equity_vega", "greeks", ]