merton.calibration.duan_mle

Duan (1994) transformed-data maximum-likelihood calibration.

The Duan MLE jointly estimates the asset drift μ and asset volatility σ_A directly from an equity time series. Unlike Vassalou-Xing’s iterative substitution, it writes the likelihood of the equity observations as a function of the parameters and maximises that likelihood with a generic optimiser.

Mathematics

Suppose we observe E_0, E_1, …, E_n at intervals Δt = 1/252 and the firm has a single zero-coupon liability D maturing at T years out. The Black-Scholes-Merton equity-value map E = h(A; σ_A, D, r, T) is strictly increasing in A; let A_t = h^{-1}(E_t; σ_A, D, r, T_t) with T_t = T - t·Δt. A_t is then geometric Brownian motion with drift μ and volatility σ_A under the physical measure. The transformed-data log-likelihood is

\[\ell(\mu, \sigma_A) = \sum_{t=1}^n \log f(r_t; \mu - \sigma_A^2/2, \sigma_A^2 \Delta t) - \sum_{t=1}^n \log \!\bigl[A_t \Phi(d_1^t)\bigr]\]

where r_t = log(A_t / A_{t-1}) and the second sum is the Jacobian of the E A transformation. Maximising \ell over (μ, σ_A) gives the MLE.

Survivorship-bias correction

For samples that only include firms surviving to T_obs = n·Δt, Duan-Gauthier-Simonato-Zaanoun (2004) recommend dividing the likelihood by the survival probability:

\[\ell_{corr}(\mu, \sigma_A) = \ell(\mu, \sigma_A) - \log P\!\bigl(\min_{0 \le t \le T_{obs}} A_t > D\bigr).\]

The survival probability has a closed-form via the reflection principle for geometric Brownian motion (see merton._backend._survival).

References

Duan, J.-C. (1994). Maximum Likelihood Estimation Using Price Data of the Derivative Contract. Mathematical Finance 4 (2), 155-167.

Duan, J.-C., Gauthier, G., Simonato, J.-G., Zaanoun, S. (2004). Estimating Merton’s Model by Maximum Likelihood with Survivorship Consideration. HEC Montreal Working Paper.

Classes

DuanMLECalibrator

OO wrapper around duan_mle().

Functions

duan_mle(→ merton.calibration.base.CalibrationResult)

Run the Duan transformed-data MLE on an equity time series.

Module Contents

merton.calibration.duan_mle.duan_mle(*, equity_series: merton._typing.FloatArray, debt: float, rf: float, T: float, dt: float = 1.0 / ANNUALIZATION, dividend_yield: float = 0.0, survivor_bias_correction: bool = True, initial_sigma: float | None = None, initial_mu: float | None = None, tol: float = 1e-06, max_iter: int = 200) merton.calibration.base.CalibrationResult[source]

Run the Duan transformed-data MLE on an equity time series.

Parameters:
  • equity_series – 1-D array of equity values at uniform time steps.

  • debt – Default threshold (single liability at maturity T).

  • rf – Risk-free rate and time-to-maturity (constant maturity convention).

  • T – Risk-free rate and time-to-maturity (constant maturity convention).

  • dt – Sampling interval in years. Default 1/252 (daily).

  • dividend_yield – Continuous dividend yield q.

  • survivor_bias_correction – If True, add -log P(survive) to the negative log-likelihood per Duan-Gauthier-Simonato-Zaanoun (2004). Default True.

  • initial_sigma – Optional warm-starts for the optimiser. If omitted, σ_A is initialised from the naive equity-vol proxy and μ from the sample mean of equity log-returns annualised.

  • initial_mu – Optional warm-starts for the optimiser. If omitted, σ_A is initialised from the naive equity-vol proxy and μ from the sample mean of equity log-returns annualised.

  • tol – Optimiser stopping criteria.

  • max_iter – Optimiser stopping criteria.

class merton.calibration.duan_mle.DuanMLECalibrator(*, survivor_bias_correction: bool = True, tol: float = 1e-06, max_iter: int = 200)[source]

Bases: merton.calibration.base.Calibrator

OO wrapper around duan_mle().

method = 'duan_mle'[source]
survivor_bias_correction = True[source]
tol = 1e-06[source]
max_iter = 200[source]
fit(firm: merton.core.firm.Firm) merton.calibration.base.CalibrationResult[source]

Infer asset value & volatility for firm.