use crate::no_arb::evidence::ArbitrageAssessment;
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct RawParameterMargins {
slope: f64,
correlation: f64,
sigma: f64,
minimum_variance: f64,
arbitrage: f64,
}
impl RawParameterMargins {
pub(crate) const fn new(
slope: f64,
correlation: f64,
sigma: f64,
minimum_variance: f64,
arbitrage: f64,
) -> Self {
Self {
slope,
correlation,
sigma,
minimum_variance,
arbitrage,
}
}
#[must_use]
pub const fn slope(self) -> f64 {
self.slope
}
#[must_use]
pub const fn correlation(self) -> f64 {
self.correlation
}
#[must_use]
pub const fn sigma(self) -> f64 {
self.sigma
}
#[must_use]
pub const fn minimum_variance(self) -> f64 {
self.minimum_variance
}
#[must_use]
pub const fn arbitrage(self) -> f64 {
self.arbitrage
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct SurfaceParameterMargins {
correlation: f64,
phi_scale: f64,
phi_shape: f64,
butterfly: f64,
calendar: f64,
}
impl SurfaceParameterMargins {
pub(crate) const fn new(
correlation: f64,
phi_scale: f64,
phi_shape: f64,
butterfly: f64,
calendar: f64,
) -> Self {
Self {
correlation,
phi_scale,
phi_shape,
butterfly,
calendar,
}
}
#[must_use]
pub const fn correlation(self) -> f64 {
self.correlation
}
#[must_use]
pub const fn phi_scale(self) -> f64 {
self.phi_scale
}
#[must_use]
pub const fn phi_shape(self) -> f64 {
self.phi_shape
}
#[must_use]
pub const fn butterfly(self) -> f64 {
self.butterfly
}
#[must_use]
pub const fn calendar(self) -> f64 {
self.calendar
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ParameterizationEvidence {
transform: &'static str,
repair: &'static str,
}
impl ParameterizationEvidence {
pub(crate) const fn new(transform: &'static str, repair: &'static str) -> Self {
Self { transform, repair }
}
#[must_use]
pub const fn transform(self) -> &'static str {
self.transform
}
#[must_use]
pub const fn repair(self) -> &'static str {
self.repair
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TerminationReason {
ObjectiveConverged,
GradientConverged,
StepConverged,
Stagnated,
SingularModel,
NonFiniteEvaluation,
MaximumIterations,
}
impl From<crate::numerics::OptimizerTermination> for TerminationReason {
fn from(reason: crate::numerics::OptimizerTermination) -> Self {
use crate::numerics::OptimizerTermination;
match reason {
OptimizerTermination::ObjectiveConverged => Self::ObjectiveConverged,
OptimizerTermination::GradientConverged => Self::GradientConverged,
OptimizerTermination::StepConverged => Self::StepConverged,
OptimizerTermination::Stagnated => Self::Stagnated,
OptimizerTermination::SingularModel => Self::SingularModel,
OptimizerTermination::NonFiniteEvaluation => Self::NonFiniteEvaluation,
OptimizerTermination::IterationLimit => Self::MaximumIterations,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct ResidualDiagnostics {
objective: f64,
rmse: f64,
max_absolute: f64,
positive_weight_quotes: usize,
distinct_strikes: usize,
omitted_quotes: usize,
total_weight: f64,
}
impl ResidualDiagnostics {
pub(crate) const fn new(
objective: f64,
rmse: f64,
max_absolute: f64,
positive_weight_quotes: usize,
distinct_strikes: usize,
omitted_quotes: usize,
total_weight: f64,
) -> Self {
Self {
objective,
rmse,
max_absolute,
positive_weight_quotes,
distinct_strikes,
omitted_quotes,
total_weight,
}
}
#[must_use]
pub const fn objective(self) -> f64 {
self.objective
}
#[must_use]
pub const fn rmse(self) -> f64 {
self.rmse
}
#[must_use]
pub const fn max_absolute(self) -> f64 {
self.max_absolute
}
#[must_use]
pub const fn positive_weight_quotes(self) -> usize {
self.positive_weight_quotes
}
#[must_use]
pub const fn distinct_strikes(self) -> usize {
self.distinct_strikes
}
#[must_use]
pub const fn omitted_quotes(self) -> usize {
self.omitted_quotes
}
#[must_use]
pub const fn total_weight(self) -> f64 {
self.total_weight
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct CalibrationReport {
algorithm: &'static str,
starts: usize,
selected_start: Option<usize>,
tolerance: f64,
condition_estimate: Option<f64>,
parameterization: ParameterizationEvidence,
margins: RawParameterMargins,
iterations: usize,
evaluations: usize,
termination: TerminationReason,
residuals: ResidualDiagnostics,
arbitrage: ArbitrageAssessment,
}
impl CalibrationReport {
#[allow(clippy::too_many_arguments, clippy::large_types_passed_by_value)]
pub(crate) const fn new(
iterations: usize,
evaluations: usize,
termination: TerminationReason,
residuals: ResidualDiagnostics,
arbitrage: ArbitrageAssessment,
algorithm: &'static str,
starts: usize,
selected_start: Option<usize>,
tolerance: f64,
condition_estimate: Option<f64>,
parameterization: ParameterizationEvidence,
margins: RawParameterMargins,
) -> Self {
Self {
algorithm,
starts,
selected_start,
tolerance,
condition_estimate,
parameterization,
margins,
iterations,
evaluations,
termination,
residuals,
arbitrage,
}
}
#[must_use]
pub const fn algorithm(self) -> &'static str {
self.algorithm
}
#[must_use]
pub const fn starts(self) -> usize {
self.starts
}
#[must_use]
pub const fn selected_start(self) -> Option<usize> {
self.selected_start
}
#[must_use]
pub const fn tolerance(self) -> f64 {
self.tolerance
}
#[must_use]
pub const fn condition_estimate(self) -> Option<f64> {
self.condition_estimate
}
#[must_use]
pub const fn parameterization(self) -> ParameterizationEvidence {
self.parameterization
}
#[must_use]
pub const fn margins(self) -> RawParameterMargins {
self.margins
}
#[must_use]
pub const fn iterations(self) -> usize {
self.iterations
}
#[must_use]
pub const fn evaluations(self) -> usize {
self.evaluations
}
#[must_use]
pub const fn termination(self) -> TerminationReason {
self.termination
}
#[must_use]
pub const fn residuals(self) -> ResidualDiagnostics {
self.residuals
}
#[must_use]
pub const fn arbitrage_assessment(self) -> ArbitrageAssessment {
self.arbitrage
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct SurfaceCalibrationReport {
algorithm: &'static str,
starts: usize,
selected_start: Option<usize>,
tolerance: f64,
parameterization: ParameterizationEvidence,
margins: SurfaceParameterMargins,
iterations: usize,
evaluations: usize,
termination: TerminationReason,
residuals: ResidualDiagnostics,
butterfly: ArbitrageAssessment,
calendar: ArbitrageAssessment,
}
impl SurfaceCalibrationReport {
#[allow(clippy::too_many_arguments, clippy::large_types_passed_by_value)]
pub(crate) const fn new(
iterations: usize,
evaluations: usize,
termination: TerminationReason,
residuals: ResidualDiagnostics,
butterfly: ArbitrageAssessment,
calendar: ArbitrageAssessment,
algorithm: &'static str,
starts: usize,
selected_start: Option<usize>,
tolerance: f64,
parameterization: ParameterizationEvidence,
margins: SurfaceParameterMargins,
) -> Self {
Self {
algorithm,
starts,
selected_start,
tolerance,
parameterization,
margins,
iterations,
evaluations,
termination,
residuals,
butterfly,
calendar,
}
}
#[must_use]
pub const fn algorithm(self) -> &'static str {
self.algorithm
}
#[must_use]
pub const fn starts(self) -> usize {
self.starts
}
#[must_use]
pub const fn selected_start(self) -> Option<usize> {
self.selected_start
}
#[must_use]
pub const fn tolerance(self) -> f64 {
self.tolerance
}
#[must_use]
pub const fn parameterization(self) -> ParameterizationEvidence {
self.parameterization
}
#[must_use]
pub const fn margins(self) -> SurfaceParameterMargins {
self.margins
}
#[must_use]
pub const fn iterations(self) -> usize {
self.iterations
}
#[must_use]
pub const fn evaluations(self) -> usize {
self.evaluations
}
#[must_use]
pub const fn termination(self) -> TerminationReason {
self.termination
}
#[must_use]
pub const fn residuals(self) -> ResidualDiagnostics {
self.residuals
}
#[must_use]
pub const fn butterfly_assessment(self) -> ArbitrageAssessment {
self.butterfly
}
#[must_use]
pub const fn calendar_assessment(self) -> ArbitrageAssessment {
self.calendar
}
}