use serde::{Deserialize, Serialize};
use crate::{
core::collateral::SingleCurveCSADiscountPolicy,
currencies::currency::Currency,
indices::marketindex::MarketIndex,
time::date::Date,
utils::errors::{QSError, Result},
};
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct FundingSpreadCurve {
pub dates: Vec<Date>,
pub spreads: Vec<f64>,
}
impl FundingSpreadCurve {
pub fn validate(&self) -> Result<()> {
if self.dates.is_empty() {
return Err(QSError::InvalidValueErr(
"Funding spread curve must have at least one pillar".into(),
));
}
if self.dates.len() != self.spreads.len() {
return Err(QSError::InvalidValueErr(format!(
"Funding spread curve has {} dates but {} spreads",
self.dates.len(),
self.spreads.len()
)));
}
if self.dates.windows(2).any(|w| w[1] <= w[0]) {
return Err(QSError::InvalidValueErr(
"Funding spread curve dates must be strictly increasing".into(),
));
}
Ok(())
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct CsaTerms {
pub collateral_index: MarketIndex,
pub collateral_currency: Currency,
pub credit_spread: f64,
pub recovery: f64,
#[serde(default)]
pub funding_spread: f64,
#[serde(default)]
pub funding_spread_curve: Option<FundingSpreadCurve>,
#[serde(default)]
pub funding_index: Option<MarketIndex>,
#[serde(default)]
pub credit_index: Option<MarketIndex>,
}
impl CsaTerms {
#[must_use]
pub fn discount_policy(&self) -> SingleCurveCSADiscountPolicy {
SingleCurveCSADiscountPolicy::new(self.collateral_index.clone(), self.collateral_currency)
}
}