use std::fmt;
#[derive(Debug, Clone)]
pub enum IVError {
NoPriceAvailable,
SpreadTooWide {
spread_bps: f64,
threshold_bps: f64,
},
ConvergenceFailure {
iterations: u32,
last_iv: f64,
},
InvalidParams {
message: String,
},
PriceBelowIntrinsic {
price: f64,
intrinsic: f64,
},
TimeToExpiryTooSmall {
time_to_expiry: f64,
min_time: f64,
},
VolatilityOutOfBounds {
volatility: f64,
min_bound: f64,
max_bound: f64,
},
}
impl fmt::Display for IVError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
IVError::NoPriceAvailable => {
write!(f, "no valid price available from order book")
}
IVError::SpreadTooWide {
spread_bps,
threshold_bps,
} => {
write!(
f,
"spread too wide: {spread_bps:.1} bps exceeds threshold of {threshold_bps:.1} bps"
)
}
IVError::ConvergenceFailure {
iterations,
last_iv,
} => {
write!(
f,
"solver did not converge after {iterations} iterations, last IV: {last_iv:.4}"
)
}
IVError::InvalidParams { message } => {
write!(f, "invalid parameters: {message}")
}
IVError::PriceBelowIntrinsic { price, intrinsic } => {
write!(
f,
"price {price:.4} is below intrinsic value {intrinsic:.4}"
)
}
IVError::TimeToExpiryTooSmall {
time_to_expiry,
min_time,
} => {
write!(
f,
"time to expiry {time_to_expiry:.6} years is below minimum {min_time:.6} years"
)
}
IVError::VolatilityOutOfBounds {
volatility,
min_bound,
max_bound,
} => {
write!(
f,
"volatility {volatility:.4} is outside bounds [{min_bound:.4}, {max_bound:.4}]"
)
}
}
}
}
impl std::error::Error for IVError {}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_error_display() {
let err = IVError::NoPriceAvailable;
assert_eq!(err.to_string(), "no valid price available from order book");
let err = IVError::SpreadTooWide {
spread_bps: 600.0,
threshold_bps: 500.0,
};
assert!(err.to_string().contains("600.0 bps"));
let err = IVError::ConvergenceFailure {
iterations: 100,
last_iv: 0.25,
};
assert!(err.to_string().contains("100 iterations"));
let err = IVError::InvalidParams {
message: "negative spot price".to_string(),
};
assert!(err.to_string().contains("negative spot price"));
let err = IVError::PriceBelowIntrinsic {
price: 5.0,
intrinsic: 10.0,
};
assert!(err.to_string().contains("below intrinsic"));
let err = IVError::TimeToExpiryTooSmall {
time_to_expiry: 0.0001,
min_time: 0.001,
};
assert!(err.to_string().contains("time to expiry"));
let err = IVError::VolatilityOutOfBounds {
volatility: 6.0,
min_bound: 0.001,
max_bound: 5.0,
};
assert!(err.to_string().contains("outside bounds"));
}
}