Function coupon_bond_option_from
pub(crate) fn coupon_bond_option_from<R: Scalar>(
params: &HullWhiteParameters<R>,
curve: &dyn YieldCurve<R>,
expiry: NaiveDate,
start: NaiveDate,
pay_dates: &[NaiveDate],
coupons: &[R],
strike: f64,
kind: OptionKind,
) -> Result<R, CurveError>Expand description
A European option, exercised at expiry, to exchange strike paid on
start for the coupon bond Σ c_i paid on pay_dates — Jamshidian’s
decomposition in mode R, with the strike leg forward-starting as a
swaption’s is: the swap delivered at expiry starts a spot lag later.
At expiry the exchange is worth P(T,S)·(Σ c_i X_i − K) with
X_i = P(T, t_i)/P(T, S), each X_i monotone in the short rate, so the
option exercises on one side of the r* that solves Σ c_i X_i(r*) = K
and is the sum of options on the forward bonds X_i struck at
K_i = X_i(r*). Under the S-forward measure each X_i is lognormal
with volatility σ_p(T, t_i) − σ_p(T, S), so each piece is the zero-bond
formula with P(0, S) in place of P(0, T) — which it is exactly when
S = T, the bond options running from the swap’s first reset.
r* is solved passively — on the projection — and the strikes enter
as constants: by the envelope argument, the decomposition is exact at the
solved r*, so its own derivative is not needed and a Newton recorded in
the mode would only put statements on the tape for a term that is
identically zero. A test pins that claim against a full bump.
coupons are per unit face and include the redemption on the last date;
strike is in the same units. The coupons are in the mode — a swaption’s
carry its basis spread, which reads the curve — and by the same envelope
argument only the final sum needs them active.
§Errors
Whatever the curve reports; CurveError::Malformed for an empty or
mismatched schedule, a start before the expiry or after the first payment,
or a critical-rate solve that does not converge.