use serde::{Deserialize, Serialize};
use crate::{
ad::{dual::DualFwd, scalar::Scalar},
instruments::cashflows::{cashflow::Cashflow, coupons::LinearCoupon},
rates::interestrate::InterestRate,
time::date::Date,
utils::errors::Result,
};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FixedRateCoupon<T: Scalar> {
notional: f64,
rate: Box<InterestRate<T>>,
accrual_start_date: Date,
accrual_end_date: Date,
payment_date: Date,
}
impl<T: Scalar> FixedRateCoupon<T> {
#[must_use]
pub const fn new(
notional: f64,
rate: Box<InterestRate<T>>,
accrual_start_date: Date,
accrual_end_date: Date,
payment_date: Date,
) -> Self {
Self {
notional,
rate,
accrual_start_date,
accrual_end_date,
payment_date,
}
}
#[must_use]
pub fn rate(&self) -> &InterestRate<T> {
&self.rate
}
#[must_use]
pub const fn accrual_start_date(&self) -> Date {
self.accrual_start_date
}
#[must_use]
pub const fn accrual_end_date(&self) -> Date {
self.accrual_end_date
}
#[must_use]
pub const fn notional(&self) -> f64 {
self.notional
}
}
impl Cashflow<f64> for FixedRateCoupon<f64> {
fn amount(&self) -> Result<f64> {
let year_fraction = self
.rate
.day_counter()
.year_fraction(self.accrual_start_date, self.accrual_end_date);
Ok(self.rate.rate() * (year_fraction * self.notional))
}
fn payment_date(&self) -> Date {
self.payment_date
}
}
impl LinearCoupon<f64> for FixedRateCoupon<f64> {
fn accrued_amount(&self, start_date: Date, end_date: Date) -> Result<f64> {
let year_fraction = self.rate.day_counter().year_fraction(start_date, end_date);
Ok(self.rate.rate() * (year_fraction * self.notional))
}
fn accrual_start_date(&self) -> Date {
self.accrual_start_date
}
fn accrual_end_date(&self) -> Date {
self.accrual_end_date
}
fn notional(&self) -> f64 {
self.notional
}
}
impl Cashflow<DualFwd> for FixedRateCoupon<DualFwd> {
fn amount(&self) -> Result<DualFwd> {
let year_fraction = self
.rate
.day_counter()
.year_fraction(self.accrual_start_date, self.accrual_end_date);
Ok((self.rate.rate() * DualFwd::new(year_fraction * self.notional)).into())
}
fn payment_date(&self) -> Date {
self.payment_date
}
}
impl LinearCoupon<DualFwd> for FixedRateCoupon<DualFwd> {
fn accrued_amount(&self, start_date: Date, end_date: Date) -> Result<DualFwd> {
let year_fraction = self.rate.day_counter().year_fraction(start_date, end_date);
Ok((self.rate.rate() * DualFwd::new(year_fraction * self.notional)).into())
}
fn accrual_start_date(&self) -> Date {
self.accrual_start_date
}
fn accrual_end_date(&self) -> Date {
self.accrual_end_date
}
fn notional(&self) -> f64 {
self.notional
}
}
impl From<FixedRateCoupon<f64>> for FixedRateCoupon<DualFwd> {
fn from(value: FixedRateCoupon<f64>) -> Self {
Self::new(
value.notional,
Box::new((*value.rate).into()),
value.accrual_start_date,
value.accrual_end_date,
value.payment_date,
)
}
}
impl From<FixedRateCoupon<DualFwd>> for FixedRateCoupon<f64> {
fn from(value: FixedRateCoupon<DualFwd>) -> Self {
Self::new(
value.notional,
Box::new((*value.rate).into()),
value.accrual_start_date,
value.accrual_end_date,
value.payment_date,
)
}
}