use std::collections::HashMap;
use crate::{currencies::currency::Currency, indices::marketindex::MarketIndex};
use crate::{
instruments::fixedincome::fixedratedeposit::FixedRateDeposit,
utils::errors::{QSError, Result},
};
pub trait HasCurrency {
#[must_use]
fn currency(&self) -> Currency;
}
pub trait DiscountPolicy<T: HasCurrency>: Send + Sync {
fn accept(&self, target: &T) -> Result<MarketIndex>;
fn discount_indices(&self) -> Vec<MarketIndex>;
}
pub struct FixedIncomeDiscountPolicy {
risk_free_by_currency: HashMap<Currency, MarketIndex>,
prefer_instrument_index: bool,
}
impl FixedIncomeDiscountPolicy {
#[must_use]
pub fn new(prefer_instrument_index: bool) -> Self {
Self {
risk_free_by_currency: HashMap::new(),
prefer_instrument_index,
}
}
#[must_use]
pub fn with_risk_free_index(mut self, currency: Currency, market_index: MarketIndex) -> Self {
self.risk_free_by_currency.insert(currency, market_index);
self
}
fn risk_free_index(&self, currency: Currency) -> Option<MarketIndex> {
self.risk_free_by_currency.get(¤cy).cloned()
}
}
impl DiscountPolicy<FixedRateDeposit> for FixedIncomeDiscountPolicy {
fn accept(&self, target: &FixedRateDeposit) -> Result<MarketIndex> {
if self.prefer_instrument_index {
return Ok(target.market_index());
}
self.risk_free_index(target.currency()).ok_or_else(|| {
QSError::NotFoundErr(format!(
"No risk-free discount index configured for currency {}",
target.currency()
))
})
}
fn discount_indices(&self) -> Vec<MarketIndex> {
self.risk_free_by_currency.values().cloned().collect()
}
}
pub struct SingleCurveCSADiscountPolicy {
discount_index: MarketIndex,
currency: Currency,
}
impl SingleCurveCSADiscountPolicy {
#[must_use]
pub const fn new(discount_index: MarketIndex, currency: Currency) -> Self {
Self {
discount_index,
currency,
}
}
}
impl<T> DiscountPolicy<T> for SingleCurveCSADiscountPolicy
where
T: HasCurrency,
{
fn accept(&self, target: &T) -> Result<MarketIndex> {
if target.currency() == self.currency {
Ok(self.discount_index.clone())
} else {
Ok(MarketIndex::Collateral(target.currency(), self.currency))
}
}
fn discount_indices(&self) -> Vec<MarketIndex> {
vec![self.discount_index.clone()]
}
}