use std::collections::HashMap;
use crate::{currencies::currency::Currency, time::date::Date};
#[derive(Clone, Debug)]
pub struct CashflowsTable {
payment_dates: Vec<Date>,
cashflow_types: Vec<String>,
amount: Vec<f64>,
fixing: Vec<Option<f64>>,
accrual_periods: Vec<f64>,
currencies: Vec<Currency>,
floorlet_strike: Vec<Option<f64>>,
caplet_strike: Vec<Option<f64>>,
leg_indices: Vec<usize>,
}
impl CashflowsTable {
#[must_use]
pub const fn new() -> Self {
Self {
payment_dates: Vec::new(),
cashflow_types: Vec::new(),
amount: Vec::new(),
fixing: Vec::new(),
accrual_periods: Vec::new(),
currencies: Vec::new(),
floorlet_strike: Vec::new(),
caplet_strike: Vec::new(),
leg_indices: Vec::new(),
}
}
#[must_use]
pub fn payment_dates(&self) -> &[Date] {
&self.payment_dates
}
#[must_use]
pub fn cashflow_types(&self) -> &[String] {
&self.cashflow_types
}
#[must_use]
pub fn amounts(&self) -> &[f64] {
&self.amount
}
#[must_use]
pub fn fixing(&self) -> &[Option<f64>] {
&self.fixing
}
#[must_use]
pub fn accrual_periods(&self) -> &[f64] {
&self.accrual_periods
}
#[must_use]
pub fn currencies(&self) -> &[Currency] {
&self.currencies
}
#[must_use]
pub fn floorlet_strikes(&self) -> &[Option<f64>] {
&self.floorlet_strike
}
#[must_use]
pub fn caplet_strikes(&self) -> &[Option<f64>] {
&self.caplet_strike
}
#[must_use]
pub fn leg_indices(&self) -> &[usize] {
&self.leg_indices
}
#[allow(clippy::too_many_arguments)]
pub fn add_cashflow(
&mut self,
payment_date: Date,
cashflow_type: String,
amount: f64,
fixing: Option<f64>,
accrual_period: f64,
currency: Currency,
floorlet_strike: Option<f64>,
caplet_strike: Option<f64>,
leg_index: usize,
) {
self.payment_dates.push(payment_date);
self.cashflow_types.push(cashflow_type);
self.amount.push(amount);
self.fixing.push(fixing);
self.accrual_periods.push(accrual_period);
self.currencies.push(currency);
self.floorlet_strike.push(floorlet_strike);
self.caplet_strike.push(caplet_strike);
self.leg_indices.push(leg_index);
}
}
impl Default for CashflowsTable {
fn default() -> Self {
Self::new()
}
}
#[derive(Default, Debug)]
pub struct SensitivityMap {
instrument_key: Vec<String>,
exposure: Vec<f64>,
}
impl SensitivityMap {
#[must_use]
pub fn instrument_keys(&self) -> &[String] {
&self.instrument_key
}
#[must_use]
pub fn exposure(&self) -> &[f64] {
&self.exposure
}
#[must_use]
pub fn with_instrument_keys(mut self, instrument_keys: &[String]) -> Self {
instrument_keys.clone_into(&mut self.instrument_key);
self
}
#[must_use]
pub fn with_exposure(mut self, exposure: &[f64]) -> Self {
exposure.clone_into(&mut self.exposure);
self
}
#[must_use]
pub fn aggregate(self) -> Self {
let mut order: Vec<String> = Vec::new();
let mut sums: HashMap<String, f64> = HashMap::new();
for (key, exp) in self.instrument_key.iter().zip(self.exposure.iter()) {
if !sums.contains_key(key) {
order.push(key.clone());
}
*sums.entry(key.clone()).or_insert(0.0) += exp;
}
let exposure: Vec<f64> = order.iter().map(|k| sums[k]).collect();
Self {
instrument_key: order,
exposure,
}
}
}
pub struct EvaluationResults {
evaluation_date: Date,
identifier: String,
price: Option<f64>,
ytm: Option<f64>,
sensitivities: Option<SensitivityMap>,
cashflows: Option<CashflowsTable>,
fair_rate: Option<f64>,
}
impl EvaluationResults {
#[must_use]
pub const fn new(evaluation_date: Date, identifier: String) -> Self {
Self {
evaluation_date,
identifier,
price: None,
ytm: None,
sensitivities: None,
cashflows: None,
fair_rate: None,
}
}
#[must_use]
pub const fn with_price(mut self, price: f64) -> Self {
self.price = Some(price);
self
}
#[must_use]
pub const fn price(&self) -> Option<f64> {
self.price
}
#[must_use]
pub const fn sensitivities(&self) -> Option<&SensitivityMap> {
self.sensitivities.as_ref()
}
#[must_use]
pub fn with_sensitivities(mut self, sensitivities: SensitivityMap) -> Self {
self.sensitivities = Some(sensitivities);
self
}
#[must_use]
pub fn with_cashflows(mut self, cashflows: CashflowsTable) -> Self {
self.cashflows = Some(cashflows);
self
}
#[must_use]
pub const fn cashflows(&self) -> Option<&CashflowsTable> {
self.cashflows.as_ref()
}
#[must_use]
pub const fn with_evaluation_date(mut self, evaluation_date: Date) -> Self {
self.evaluation_date = evaluation_date;
self
}
#[must_use]
pub fn with_identifier(mut self, identifier: String) -> Self {
self.identifier = identifier;
self
}
#[must_use]
pub const fn with_ytm(mut self, ytm: f64) -> Self {
self.ytm = Some(ytm);
self
}
#[must_use]
pub const fn with_fair_rate(mut self, fair_rate: f64) -> Self {
self.fair_rate = Some(fair_rate);
self
}
#[must_use]
pub const fn fair_rate(&self) -> Option<f64> {
self.fair_rate
}
}