#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(default))]
#[non_exhaustive]
pub struct SolverConfig {
pub nr_max_iterations: u32,
pub price_tolerance: f64,
pub iv_tolerance: f64,
pub vega_floor: f64,
pub iv_min: f64,
pub iv_max: f64,
pub brent_max_iterations: u32,
pub near_expiry_cutoff_hours: f64,
}
impl Default for SolverConfig {
fn default() -> Self {
Self {
nr_max_iterations: 50,
price_tolerance: 1e-8,
iv_tolerance: 1e-7,
vega_floor: 1e-10,
iv_min: 0.01,
iv_max: 5.0,
brent_max_iterations: 100,
near_expiry_cutoff_hours: 2.0,
}
}
}
impl SolverConfig {
pub fn builder() -> SolverConfigBuilder {
SolverConfigBuilder {
inner: SolverConfig::default(),
}
}
}
#[derive(Debug, Clone)]
#[must_use = "a builder does nothing unless you call `.build()`"]
pub struct SolverConfigBuilder {
inner: SolverConfig,
}
impl SolverConfigBuilder {
pub const fn nr_max_iterations(mut self, value: u32) -> Self {
self.inner.nr_max_iterations = value;
self
}
pub const fn price_tolerance(mut self, value: f64) -> Self {
self.inner.price_tolerance = value;
self
}
pub const fn iv_tolerance(mut self, value: f64) -> Self {
self.inner.iv_tolerance = value;
self
}
pub const fn vega_floor(mut self, value: f64) -> Self {
self.inner.vega_floor = value;
self
}
pub const fn iv_min(mut self, value: f64) -> Self {
self.inner.iv_min = value;
self
}
pub const fn iv_max(mut self, value: f64) -> Self {
self.inner.iv_max = value;
self
}
pub const fn brent_max_iterations(mut self, value: u32) -> Self {
self.inner.brent_max_iterations = value;
self
}
pub const fn near_expiry_cutoff_hours(mut self, value: f64) -> Self {
self.inner.near_expiry_cutoff_hours = value;
self
}
#[must_use]
pub const fn build(self) -> SolverConfig {
self.inner
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn default_values() {
let cfg = SolverConfig::default();
assert_eq!(cfg.nr_max_iterations, 50);
assert_eq!(cfg.iv_min, 0.01);
assert_eq!(cfg.iv_max, 5.0);
}
#[test]
fn builder_overrides() {
let cfg = SolverConfig::builder()
.iv_min(0.005)
.iv_max(8.0)
.price_tolerance(1e-10)
.build();
assert_eq!(cfg.iv_min, 0.005);
assert_eq!(cfg.iv_max, 8.0);
assert_eq!(cfg.price_tolerance, 1e-10);
assert_eq!(cfg.nr_max_iterations, 50);
}
}