Struct Slice
struct Slice {
expiry: f64,
forward: f64,
strikes: Vec<f64>,
quotes: Vec<f64>,
slopes: Vec<f64>,
weights: Vec<f64>,
atm: Atm,
}Expand description
One slice’s market data in the formula’s convention.
Fields§
§expiry: f64§forward: f64§strikes: Vec<f64>§quotes: Vec<f64>§slopes: Vec<f64>d(restated quote)/d(grid quote): one where the conventions agree.
weights: Vec<f64>§atm: AtmImplementations§
§impl Slice
impl Slice
fn read(
grid: &RateVolSurface,
node: usize,
expiry: f64,
tenor: f64,
forward: f64,
held: Option<f64>,
spec: &SabrSpec,
) -> Result<Self, SabrCalibrationError>
fn read( grid: &RateVolSurface, node: usize, expiry: f64, tenor: f64, forward: f64, held: Option<f64>, spec: &SabrSpec, ) -> Result<Self, SabrCalibrationError>
The slice at grid node node: its strikes, its quotes restated in the
spec’s convention, the ATM quote where the grid has one, and the
normalised vega weights.
fn vega<R: Scalar>(&self, i: usize, vol: R, spec: &SabrSpec) -> R
fn vega<R: Scalar>(&self, i: usize, vol: R, spec: &SabrSpec) -> R
The undiscounted vega of quote i read at vol vol — the weight a
vol error carries in price terms — in mode R, so the fit’s quote
Jacobian can see the weights move with the quotes.
fn vols<R: Scalar>(
&self,
spec: &SabrSpec,
theta: [R; 3],
) -> Result<Vec<R>, SabrError>
fn vols<R: Scalar>( &self, spec: &SabrSpec, theta: [R; 3], ) -> Result<Vec<R>, SabrError>
The SABR vols at the slice’s strikes for natural parameters
(σ_ATM, ρ, ν) in mode R.
fn natural_derivatives(
&self,
spec: &SabrSpec,
theta: [f64; 3],
) -> Option<(Vec<[f64; 3]>, Vec<[[f64; 3]; 3]>)>
fn natural_derivatives( &self, spec: &SabrSpec, theta: [f64; 3], ) -> Option<(Vec<[f64; 3]>, Vec<[[f64; 3]; 3]>)>
∂σᵢ/∂θₐ and ∂²σᵢ/∂θₐ∂θ_b at natural parameters theta: a Jet2
pass along each axis and along each pair’s sum, the mixed partials by
polarisation.
fn natural(&self, u: &[f64], atm: f64) -> [f64; 3]
fn natural(&self, u: &[f64], atm: f64) -> [f64; 3]
Natural parameters from the unconstrained vector over the free set.
fn unconstrained(&self, theta: [f64; 3]) -> Vec<f64>
fn unconstrained(&self, theta: [f64; 3]) -> Vec<f64>
The unconstrained vector over the free set at natural theta.
fn evaluate(
&self,
spec: &SabrSpec,
u: &[f64],
atm: f64,
) -> (Vec<f64>, Vec<Vec<f64>>)
fn evaluate( &self, spec: &SabrSpec, u: &[f64], atm: f64, ) -> (Vec<f64>, Vec<Vec<f64>>)
Weighted residuals and their Jacobian in the unconstrained parameters.
fn errors(&self, spec: &SabrSpec, theta: [f64; 3]) -> Option<(f64, f64)>
fn errors(&self, spec: &SabrSpec, theta: [f64; 3]) -> Option<(f64, f64)>
The weighted RMS error and the largest absolute error at theta.
fn guess(&self, spec: &SabrSpec) -> [f64; 3]
fn guess(&self, spec: &SabrSpec) -> [f64; 3]
The three-point explicit guess off Hagan’s small-moneyness expansion
of the Black vol, σ(K) ≈ σ₀(1 + s₁x + s₂x²) at x = ln(K/F) with
s₁ = −½(1 − β − ρλ) and s₂ = [(1 − β)² + (2 − 3ρ²)λ²]/12: a
quadratic through the three strikes nearest the forward, solved for
ρλ and λ², and ν = λσ₀. A slice the expansion cannot read (a
non-positive shifted forward, fewer than three strikes) starts flat.
fn butterfly_ok(&self, spec: &SabrSpec, theta: [f64; 3]) -> bool
fn butterfly_ok(&self, spec: &SabrSpec, theta: [f64; 3]) -> bool
The butterfly check: undiscounted calls on 41 strikes over ±4 ATM standard deviations, their second strike differences non-negative. The strikes are spaced in the formula’s own domain — arithmetically where it reads any strike (β = 0), geometrically in the shifted strike otherwise, at the ATM vol’s Black equivalent — so none falls where the formula is undefined.
fn fit(&self, spec: &SabrSpec) -> Option<([f64; 3], usize, f64, f64, bool)>
fn fit(&self, spec: &SabrSpec) -> Option<([f64; 3], usize, f64, f64, bool)>
The fit: natural parameters, restarts spent, RMS and largest error,
and whether the acceptance bound was met. None when no start
converged to a point the expansion reads.
fn polish(&self, spec: &SabrSpec, theta: [f64; 3]) -> [f64; 3]
fn polish(&self, spec: &SabrSpec, theta: [f64; 3]) -> [f64; 3]
Newton on the first-order condition g = 0 from a converged
Levenberg–Marquardt point: LM stops on a gradient test, a few exact
steps finish what it leaves, so the implicit-function Jacobian reads
a point that is stationary to the last digit. A step that leaves the
parameters’ domain or does not shrink the gradient is not taken.
fn condition(
&self,
spec: &SabrSpec,
theta: [f64; 3],
) -> Option<(Vec<f64>, Vec<Vec<f64>>)>
fn condition( &self, spec: &SabrSpec, theta: [f64; 3], ) -> Option<(Vec<f64>, Vec<Vec<f64>>)>
The first-order condition over the free parameters at theta:
gₐ = Σᵢ wᵢ(σᵢ − qᵢ)∂ₐσᵢ and its exact slope
Aₐ_b = Σᵢ wᵢ(∂ₐσᵢ∂_bσᵢ + (σᵢ − qᵢ)∂ₐ∂_bσᵢ).
fn quote_jacobian(
&self,
spec: &SabrSpec,
theta: [f64; 3],
) -> (Vec<[f64; 3]>, [f64; 3])
fn quote_jacobian( &self, spec: &SabrSpec, theta: [f64; 3], ) -> (Vec<[f64; 3]>, [f64; 3])
d(σ_ATM, ρ, ν)/d(quote) on the converged slice, by the implicit
function theorem on the first-order condition over the free
parameters, the weights held.
With gₐ = Σᵢ wᵢ(σᵢ − qᵢ)∂ₐσᵢ = 0 over the free a, and
Aₐ_b = Σᵢ wᵢ(∂ₐσᵢ∂_bσᵢ + (σᵢ − qᵢ)∂ₐ∂_bσᵢ) its slope in every θ_b:
a quote moves g by −w_q∂ₐσ_q directly and, where it is the held
ATM vol, by Aₐ₀ through σ_ATM; the free parameters answer with
−A_ff⁻¹ of that. A quote also moves the weights, its own vega being
read at it, which moves g by Σᵢ ∂wᵢ/∂q·(σᵢ − qᵢ)∂ₐσᵢ. With that and
the residual-curvature term kept the result is exact off a perfect
fit — it is what bumping a quote and refitting converges to.
Each row is against the grid’s own quote: the restatement’s slope is
applied last. Beside the rows comes the response to a σ_ATM held from
an ATM matrix, d(σ_ATM, ρ, ν)/dσ_ATM, zero where σ_ATM is fitted.