use chrono::NaiveDate;
use super::CurveProvider;
use super::coupon::Cashflow;
use super::leg::Leg;
use crate::calendar::DayCountConvention;
use crate::traits::FloatExt;
#[derive(Debug, Clone)]
pub struct CashflowSummary<T: FloatExt> {
pub dirty_npv: T,
pub accrued_interest: T,
pub clean_npv: T,
}
#[derive(Debug, Clone)]
pub struct CashflowPricer {
pub valuation_date: NaiveDate,
pub discount_day_count: DayCountConvention,
}
impl CashflowPricer {
pub fn new(valuation_date: NaiveDate, discount_day_count: DayCountConvention) -> Self {
Self {
valuation_date,
discount_day_count,
}
}
pub fn cashflow_npv<T: FloatExt>(
&self,
cashflow: &Cashflow<T>,
curves: &(impl CurveProvider<T> + ?Sized),
) -> T {
let payment_date = cashflow.payment_date();
if payment_date < self.valuation_date {
return T::zero();
}
let tau = self
.discount_day_count
.year_fraction(self.valuation_date, payment_date);
let df = curves.discount_curve().discount_factor(tau);
df * cashflow.amount(curves, self.valuation_date)
}
pub fn leg_npv<T: FloatExt>(&self, leg: &Leg<T>, curves: &(impl CurveProvider<T> + ?Sized)) -> T {
leg
.cashflows()
.iter()
.map(|cashflow| self.cashflow_npv(cashflow, curves))
.fold(T::zero(), |acc, value| acc + value)
}
pub fn leg_accrued_interest<T: FloatExt>(
&self,
leg: &Leg<T>,
curves: &(impl CurveProvider<T> + ?Sized),
) -> T {
leg
.cashflows()
.iter()
.map(|cashflow| cashflow.accrued_interest(curves, self.valuation_date, self.valuation_date))
.fold(T::zero(), |acc, value| acc + value)
}
pub fn summarize_leg<T: FloatExt>(
&self,
leg: &Leg<T>,
curves: &(impl CurveProvider<T> + ?Sized),
) -> CashflowSummary<T> {
let dirty_npv = self.leg_npv(leg, curves);
let accrued_interest = self.leg_accrued_interest(leg, curves);
CashflowSummary {
dirty_npv,
accrued_interest,
clean_npv: dirty_npv - accrued_interest,
}
}
}