Source code for merton.core.term_structure

"""PD term-structure generation.

Given a fitted Merton model (asset value, asset volatility, default point,
risk-free rate), return PDs across an array of horizons in one call. The
helper here is exposed via :meth:`MertonResult.pd_term_structure` for
convenience.
"""

from __future__ import annotations

from collections.abc import Iterable
from typing import TYPE_CHECKING

import numpy as np

from .._typing import ArrayLike
from .distance import distance_to_default, prob_of_default

if TYPE_CHECKING:
    import pandas as pd

[docs] DEFAULT_HORIZONS: tuple[float, ...] = (1 / 12, 3 / 12, 6 / 12, 1.0, 3.0, 5.0)
[docs] def term_structure_pd( asset_value: ArrayLike, asset_vol: ArrayLike, debt: ArrayLike, rf: ArrayLike, *, horizons: Iterable[float] = DEFAULT_HORIZONS, dividend_yield: ArrayLike = 0.0, ) -> pd.DataFrame: """Compute PDs for several horizons in one shot. Returns ------- pandas.DataFrame Columns: ``horizon_years`` (the input grid), ``dd`` (distance to default at that horizon), ``pd`` (risk-neutral PD). """ import pandas as pd # lazy: pandas costs ~160 ms to import horizon_arr = np.asarray(list(horizons), dtype=np.float64) dd = distance_to_default( asset_value, asset_vol, debt, rf, horizon_arr, dividend_yield=dividend_yield ) pd_vals = prob_of_default(dd) return pd.DataFrame( { "horizon_years": horizon_arr, "dd": np.asarray(dd, dtype=np.float64), "pd": np.asarray(pd_vals, dtype=np.float64), } )
__all__ = ["DEFAULT_HORIZONS", "term_structure_pd"]