use crate::calibration::calibrationpricer::CalibrationInstrumentPricer;
use crate::quotes::calibrationinstrument::CalibrationInstrument;
use crate::quotes::quote::CalibrationInstrumentType;
use crate::utils::errors::{QSError, Result};
pub trait CalibrationProcess: CalibrationInstrumentPricer {
fn residual(&self, instruments: &[CalibrationInstrument]) -> Result<Vec<f64>> {
let mut residuals = Vec::new();
for inst in instruments {
let res = match inst.built() {
CalibrationInstrumentType::Swap(_)
| CalibrationInstrumentType::BasisSwap(_)
| CalibrationInstrumentType::FixFloatCrossCurrencySwap(_)
| CalibrationInstrumentType::FloatFloatCrossCurrencySwap(_) => self.price(inst)?,
CalibrationInstrumentType::FixedRateDeposit(_) => {
let implied = self.price(inst)?;
implied - inst.quote_value()
}
CalibrationInstrumentType::RateFutures(rf) => {
let implied = self.price(inst)?;
implied - rf.implied_rate()
}
CalibrationInstrumentType::FxForward(fxf) => {
let market_fwd = if let Some(price) = fxf.forward_price() {
price
} else if let Some(points) = fxf.forward_points() {
points
} else {
return Err(QSError::ValueNotSetErr(
"FX forward: neither price nor points set".into(),
));
};
let implied = self.price(inst)?;
implied - market_fwd
}
CalibrationInstrumentType::CapletFloorlet(_)
| CalibrationInstrumentType::CapFloor(_)
| CalibrationInstrumentType::EuropeanSwaption(_) => {
return Err(QSError::InvalidValueErr(
"Vol-quoted instruments require an overridden residual() implementation"
.into(),
))
}
_ => {
return Err(QSError::InvalidValueErr(
"Unsupported instrument type for calibration residual".into(),
))
}
};
residuals.push(res);
}
Ok(residuals)
}
}