use serde::{Deserialize, Serialize};
use crate::{
cashflows::cashflow::{Cashflow, Side},
core::traits::HasCurrency,
currencies::enums::Currency,
rates::interestrate::RateDefinition,
time::{date::Date, enums::Frequency},
utils::errors::{AtlasError, Result},
visitors::traits::HasCashflows,
};
use super::{
fixedrateinstrument::FixedRateInstrument, floatingrateinstrument::FloatingRateInstrument,
traits::Structure,
};
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum RateType {
Fixed,
Floating,
FixedThenFloating,
FloatingThenFixed,
FixedThenFixed,
Suffled,
}
impl TryFrom<String> for RateType {
type Error = AtlasError;
fn try_from(s: String) -> Result<Self> {
match s.as_str() {
"Fixed" => Ok(Self::Fixed),
"Floating" => Ok(Self::Floating),
"FixedThenFloating" => Ok(Self::FixedThenFloating),
"FloatingThenFixed" => Ok(Self::FloatingThenFixed),
"FixedThenFixed" => Ok(Self::FixedThenFixed),
"Suffled" => Ok(Self::Suffled),
_ => Err(AtlasError::InvalidValueErr(format!(
"Invalid rate type: {s}"
))),
}
}
}
impl From<RateType> for String {
fn from(rate_type: RateType) -> Self {
match rate_type {
RateType::Fixed => "Fixed".to_string(),
RateType::Floating => "Floating".to_string(),
RateType::FixedThenFloating => "FixedThenFloating".to_string(),
RateType::FloatingThenFixed => "FloatingThenFixed".to_string(),
RateType::FixedThenFixed => "FixedThenFixed".to_string(),
RateType::Suffled => "Suffled".to_string(),
}
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum Instrument {
FixedRateInstrument(FixedRateInstrument),
FloatingRateInstrument(FloatingRateInstrument),
}
impl HasCashflows for Instrument {
fn cashflows(&self) -> &[Cashflow] {
match self {
Self::FixedRateInstrument(fri) => fri.cashflows(),
Self::FloatingRateInstrument(fri) => fri.cashflows(),
}
}
fn mut_cashflows(&mut self) -> &mut [Cashflow] {
match self {
Self::FixedRateInstrument(fri) => fri.mut_cashflows(),
Self::FloatingRateInstrument(fri) => fri.mut_cashflows(),
}
}
}
impl Instrument {
#[must_use]
pub const fn notional(&self) -> f64 {
match self {
Self::FixedRateInstrument(fri) => fri.notional(),
Self::FloatingRateInstrument(fri) => fri.notional(),
}
}
#[must_use]
pub const fn start_date(&self) -> Date {
match self {
Self::FixedRateInstrument(fri) => fri.start_date(),
Self::FloatingRateInstrument(fri) => fri.start_date(),
}
}
#[must_use]
pub const fn end_date(&self) -> Date {
match self {
Self::FixedRateInstrument(fri) => fri.end_date(),
Self::FloatingRateInstrument(fri) => fri.end_date(),
}
}
#[must_use]
pub fn id(&self) -> Option<String> {
match self {
Self::FixedRateInstrument(fri) => fri.id(),
Self::FloatingRateInstrument(fri) => fri.id(),
}
}
#[must_use]
pub fn structure(&self) -> Structure {
match self {
Self::FixedRateInstrument(fri) => fri.structure(),
Self::FloatingRateInstrument(fri) => fri.structure(),
}
}
#[must_use]
pub const fn payment_frequency(&self) -> Frequency {
match self {
Self::FixedRateInstrument(fri) => fri.payment_frequency(),
Self::FloatingRateInstrument(fri) => fri.payment_frequency(),
}
}
#[must_use]
pub const fn side(&self) -> Option<Side> {
match self {
Self::FixedRateInstrument(fri) => Some(fri.side()),
Self::FloatingRateInstrument(fri) => Some(fri.side()),
}
}
#[must_use]
pub const fn issue_date(&self) -> Option<Date> {
match self {
Self::FixedRateInstrument(fri) => fri.issue_date(),
Self::FloatingRateInstrument(fri) => fri.issue_date(),
}
}
#[must_use]
pub const fn rate_type(&self) -> RateType {
match self {
Self::FixedRateInstrument(_) => RateType::Fixed,
Self::FloatingRateInstrument(_) => RateType::Floating,
}
}
#[must_use]
pub fn rate(&self) -> Option<f64> {
match self {
Self::FixedRateInstrument(fri) => Some(fri.rate().rate()),
Self::FloatingRateInstrument(_) => None,
}
}
#[must_use]
pub fn spread(&self) -> Option<f64> {
match self {
Self::FixedRateInstrument(_) => None,
Self::FloatingRateInstrument(fri) => Some(fri.spread()),
}
}
#[must_use]
pub const fn forecast_curve_id(&self) -> Option<usize> {
match self {
Self::FixedRateInstrument(_) => None,
Self::FloatingRateInstrument(fri) => fri.forecast_curve_id(),
}
}
#[must_use]
pub const fn discount_curve_id(&self) -> Option<usize> {
match self {
Self::FixedRateInstrument(fri) => fri.discount_curve_id(),
Self::FloatingRateInstrument(fri) => fri.discount_curve_id(),
}
}
pub fn set_discount_curve_id(&mut self, id: usize) {
match self {
Self::FixedRateInstrument(fri) => fri.set_discount_curve_id(id),
Self::FloatingRateInstrument(fri) => fri.set_discount_curve_id(id),
}
}
pub fn set_forecast_curve_id(&mut self, id: usize) {
match self {
Self::FloatingRateInstrument(fri) => fri.set_forecast_curve_id(id),
Self::FixedRateInstrument(_) => {}
}
}
#[must_use]
pub const fn first_rate_definition(&self) -> Option<RateDefinition> {
match self {
Self::FixedRateInstrument(fri) => Some(fri.rate().rate_definition()),
Self::FloatingRateInstrument(fri) => Some(fri.rate_definition()),
}
}
#[must_use]
pub const fn second_rate_definition(&self) -> Option<RateDefinition> {
match self {
Self::FixedRateInstrument(_) | Self::FloatingRateInstrument(_) => None,
}
}
}
impl HasCurrency for Instrument {
fn currency(&self) -> Result<Currency> {
match self {
Self::FixedRateInstrument(fri) => fri.currency(),
Self::FloatingRateInstrument(fri) => fri.currency(),
}
}
}