use crate::{
core::{
collateral::Discountable,
instrument::{AssetClass, Instrument},
trade::{Side, Trade},
},
currencies::currency::Currency,
indices::marketindex::MarketIndex,
time::{date::Date, daycounter::DayCounter, enums::Frequency},
utils::errors::{QSError, Result},
};
#[derive(Clone, Debug)]
pub struct CreditDefaultSwap {
identifier: String,
credit_index: MarketIndex,
discount_index: MarketIndex,
currency: Currency,
start_date: Date,
maturity_date: Date,
spread: f64,
recovery: f64,
premium_frequency: Frequency,
day_counter: DayCounter,
}
impl CreditDefaultSwap {
#[allow(clippy::too_many_arguments)]
pub fn new(
identifier: String,
credit_index: MarketIndex,
discount_index: MarketIndex,
currency: Currency,
start_date: Date,
maturity_date: Date,
spread: f64,
recovery: f64,
premium_frequency: Frequency,
day_counter: DayCounter,
) -> Result<Self> {
if !matches!(credit_index, MarketIndex::Credit(_)) {
return Err(QSError::InvalidValueErr(format!(
"CDS credit index must be MarketIndex::Credit, got {credit_index}"
)));
}
if maturity_date <= start_date {
return Err(QSError::InvalidValueErr(
"CDS maturity date must be after start date".into(),
));
}
if !(0.0..1.0).contains(&recovery) {
return Err(QSError::InvalidValueErr(format!(
"CDS recovery must be in [0, 1), got {recovery}"
)));
}
Ok(Self {
identifier,
credit_index,
discount_index,
currency,
start_date,
maturity_date,
spread,
recovery,
premium_frequency,
day_counter,
})
}
#[must_use]
pub const fn credit_index(&self) -> &MarketIndex {
&self.credit_index
}
#[must_use]
pub const fn discount_index(&self) -> &MarketIndex {
&self.discount_index
}
#[must_use]
pub const fn currency(&self) -> Currency {
self.currency
}
#[must_use]
pub const fn start_date(&self) -> Date {
self.start_date
}
#[must_use]
pub const fn maturity_date(&self) -> Date {
self.maturity_date
}
#[must_use]
pub const fn spread(&self) -> f64 {
self.spread
}
#[must_use]
pub const fn recovery(&self) -> f64 {
self.recovery
}
#[must_use]
pub const fn premium_frequency(&self) -> Frequency {
self.premium_frequency
}
#[must_use]
pub const fn day_counter(&self) -> DayCounter {
self.day_counter
}
}
impl Instrument for CreditDefaultSwap {
fn identifier(&self) -> String {
self.identifier.clone()
}
}
impl Discountable for CreditDefaultSwap {
fn asset_class(&self) -> AssetClass {
AssetClass::Credit
}
fn discount_index(&self) -> Option<MarketIndex> {
Some(self.discount_index.clone())
}
fn currency(&self) -> Currency {
self.currency
}
}
pub struct CdsTrade {
instrument: CreditDefaultSwap,
trade_date: Date,
notional: f64,
side: Side,
}
impl CdsTrade {
#[must_use]
pub const fn new(
instrument: CreditDefaultSwap,
trade_date: Date,
notional: f64,
side: Side,
) -> Self {
Self {
instrument,
trade_date,
notional,
side,
}
}
#[must_use]
pub const fn notional(&self) -> f64 {
self.notional
}
}
impl Trade<CreditDefaultSwap> for CdsTrade {
fn instrument(&self) -> &CreditDefaultSwap {
&self.instrument
}
fn trade_date(&self) -> Date {
self.trade_date
}
fn side(&self) -> Side {
self.side
}
}