use serde::{Deserialize, Serialize};
use std::fmt::{self, Display, Formatter};
use crate::currencies::currency::Currency;
use crate::indices::rateindex::RateIndexDetails;
use crate::indices::{
quotetype::QuoteType,
rateindices::{
aonia::AONIAIndex,
corra::CORRAIndex,
estr::ESTRIndex,
euribor::{Euribor12mIndex, Euribor1mIndex, Euribor3mIndex, Euribor6mIndex},
nowa::NOWAIndex,
nzonia::NZONIAIndex,
saron::SARONIndex,
sofr::{
SOFRCompoundedIndex, SOFRIndex, TermSOFR12mIndex, TermSOFR1mIndex, TermSOFR3mIndex,
TermSOFR6mIndex,
},
sonia::SONIAIndex,
swestr::SWESTRIndex,
tibor::{Tibor3mIndex, Tibor6mIndex},
tonar::TONARIndex,
},
};
use crate::utils::errors::{QSError, Result};
#[derive(Serialize, Deserialize, Debug, Hash, PartialEq, Eq, Clone)]
pub enum MarketIndex {
SOFR,
SOFRCompounded,
TermSOFR1m,
TermSOFR3m,
TermSOFR6m,
TermSOFR12m,
ESTR,
EURIBOR1m,
EURIBOR3m,
EURIBOR6m,
EURIBOR12m,
SONIA,
TONAR,
TIBOR3m,
TIBOR6m,
SARON,
CORRA,
AONIA,
NZONIA,
NOWA,
SWESTR,
ICP,
VIX,
Equity(String),
Collateral(Currency, Currency),
Other(String),
}
impl Display for MarketIndex {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
Self::SOFR => write!(f, "SOFR"),
Self::SOFRCompounded => write!(f, "SOFRCompounded"),
Self::TermSOFR1m => write!(f, "TermSOFR1m"),
Self::TermSOFR3m => write!(f, "TermSOFR3m"),
Self::TermSOFR6m => write!(f, "TermSOFR6m"),
Self::TermSOFR12m => write!(f, "TermSOFR12m"),
Self::ESTR => write!(f, "ESTR"),
Self::EURIBOR1m => write!(f, "EURIBOR1m"),
Self::EURIBOR3m => write!(f, "EURIBOR3m"),
Self::EURIBOR6m => write!(f, "EURIBOR6m"),
Self::EURIBOR12m => write!(f, "EURIBOR12m"),
Self::SONIA => write!(f, "SONIA"),
Self::TONAR => write!(f, "TONAR"),
Self::TIBOR3m => write!(f, "TIBOR3m"),
Self::TIBOR6m => write!(f, "TIBOR6m"),
Self::SARON => write!(f, "SARON"),
Self::CORRA => write!(f, "CORRA"),
Self::AONIA => write!(f, "AONIA"),
Self::NZONIA => write!(f, "NZONIA"),
Self::NOWA => write!(f, "NOWA"),
Self::SWESTR => write!(f, "SWESTR"),
Self::ICP => write!(f, "ICP"),
Self::VIX => write!(f, "VIX"),
Self::Equity(name) => write!(f, "{name}"),
Self::Collateral(ccy, coll) => write!(f, "Collateral({ccy}/{coll})"),
Self::Other(s) => write!(f, "{s}"),
}
}
}
impl std::str::FromStr for MarketIndex {
type Err = std::convert::Infallible;
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
let resutls = match s {
"SOFR" => Self::SOFR,
"SOFRCompounded" => Self::SOFRCompounded,
"TermSOFR1m" => Self::TermSOFR1m,
"TermSOFR3m" => Self::TermSOFR3m,
"TermSOFR6m" => Self::TermSOFR6m,
"TermSOFR12m" => Self::TermSOFR12m,
"ESTR" | "€STR" => Self::ESTR,
"EURIBOR1m" => Self::EURIBOR1m,
"EURIBOR3m" => Self::EURIBOR3m,
"EURIBOR6m" => Self::EURIBOR6m,
"EURIBOR12m" => Self::EURIBOR12m,
"SONIA" => Self::SONIA,
"TONAR" => Self::TONAR,
"TIBOR3m" => Self::TIBOR3m,
"TIBOR6m" => Self::TIBOR6m,
"SARON" => Self::SARON,
"CORRA" => Self::CORRA,
"AONIA" => Self::AONIA,
"NZONIA" => Self::NZONIA,
"NOWA" => Self::NOWA,
"SWESTR" => Self::SWESTR,
"ICP" => Self::ICP,
"VIX" => Self::VIX,
other if other.starts_with("Collateral(") && other.ends_with(')') => {
let inner = &other["Collateral(".len()..other.len() - 1];
if let Some((a, b)) = inner.split_once('/') {
if let (Ok(c1), Ok(c2)) =
(a.trim().parse::<Currency>(), b.trim().parse::<Currency>())
{
Self::Collateral(c1, c2)
} else {
Self::Other(other.to_string())
}
} else {
Self::Other(other.to_string())
}
}
other => Self::Other(other.to_string()), };
Ok(resutls)
}
}
impl Default for MarketIndex {
fn default() -> Self {
Self::Other("UNKNOWN".to_string())
}
}
pub trait MarketIndexDetails {
fn name(&self) -> &'static str;
fn quote_type(&self) -> QuoteType;
}
impl MarketIndex {
pub fn details(&self) -> Result<Box<dyn MarketIndexDetails>> {
match self {
Self::SOFR => Ok(Box::new(SOFRIndex)),
Self::SOFRCompounded => Ok(Box::new(SOFRCompoundedIndex)),
Self::TermSOFR1m => Ok(Box::new(TermSOFR1mIndex)),
Self::TermSOFR3m => Ok(Box::new(TermSOFR3mIndex)),
Self::TermSOFR6m => Ok(Box::new(TermSOFR6mIndex)),
Self::TermSOFR12m => Ok(Box::new(TermSOFR12mIndex)),
Self::ESTR => Ok(Box::new(ESTRIndex)),
Self::EURIBOR1m => Ok(Box::new(Euribor1mIndex)),
Self::EURIBOR3m => Ok(Box::new(Euribor3mIndex)),
Self::EURIBOR6m => Ok(Box::new(Euribor6mIndex)),
Self::EURIBOR12m => Ok(Box::new(Euribor12mIndex)),
Self::SONIA => Ok(Box::new(SONIAIndex)),
Self::TONAR => Ok(Box::new(TONARIndex)),
Self::TIBOR3m => Ok(Box::new(Tibor3mIndex)),
Self::TIBOR6m => Ok(Box::new(Tibor6mIndex)),
Self::SARON => Ok(Box::new(SARONIndex)),
Self::CORRA => Ok(Box::new(CORRAIndex)),
Self::AONIA => Ok(Box::new(AONIAIndex)),
Self::NZONIA => Ok(Box::new(NZONIAIndex)),
Self::NOWA => Ok(Box::new(NOWAIndex)),
Self::SWESTR => Ok(Box::new(SWESTRIndex)),
_ => Err(QSError::InvalidValueErr(
"Index does not contain market details".into(),
)),
}
}
pub fn rate_index_details(&self) -> Result<Box<dyn RateIndexDetails>> {
match self {
Self::SOFR => Ok(Box::new(SOFRIndex)),
Self::SOFRCompounded => Ok(Box::new(SOFRCompoundedIndex)),
Self::TermSOFR1m => Ok(Box::new(TermSOFR1mIndex)),
Self::TermSOFR3m => Ok(Box::new(TermSOFR3mIndex)),
Self::TermSOFR6m => Ok(Box::new(TermSOFR6mIndex)),
Self::TermSOFR12m => Ok(Box::new(TermSOFR12mIndex)),
Self::ESTR => Ok(Box::new(ESTRIndex)),
Self::EURIBOR1m => Ok(Box::new(Euribor1mIndex)),
Self::EURIBOR3m => Ok(Box::new(Euribor3mIndex)),
Self::EURIBOR6m => Ok(Box::new(Euribor6mIndex)),
Self::EURIBOR12m => Ok(Box::new(Euribor12mIndex)),
Self::SONIA => Ok(Box::new(SONIAIndex)),
Self::TONAR => Ok(Box::new(TONARIndex)),
Self::TIBOR3m => Ok(Box::new(Tibor3mIndex)),
Self::TIBOR6m => Ok(Box::new(Tibor6mIndex)),
Self::SARON => Ok(Box::new(SARONIndex)),
Self::CORRA => Ok(Box::new(CORRAIndex)),
Self::AONIA => Ok(Box::new(AONIAIndex)),
Self::NZONIA => Ok(Box::new(NZONIAIndex)),
Self::NOWA => Ok(Box::new(NOWAIndex)),
Self::SWESTR => Ok(Box::new(SWESTRIndex)),
_ => Err(QSError::InvalidValueErr("Index is not rate index".into())),
}
}
}