use crate::{
ad::adreal::{ADReal, FloatExt, IsReal},
instruments::cashflows::cashflow::Cashflow,
time::date::Date,
utils::errors::Result,
};
pub trait LinearCoupon<T>: Cashflow<T>
where
T: IsReal,
{
fn accrued_amount(&self, start_date: Date, end_date: Date) -> Result<T>;
fn accrual_start_date(&self) -> Date;
fn accrual_end_date(&self) -> Date;
fn notional(&self) -> f64;
}
#[derive(Clone)]
pub enum PayoffOps {
Max(Box<Self>, Box<Self>),
Min(Box<Self>, Box<Self>),
Times(Box<Self>, Box<Self>),
Plus(Box<Self>, Box<Self>),
Minus(Box<Self>, Box<Self>),
Const(f64),
Index,
}
impl PayoffOps {
pub fn evaluate(&self, index_fixing: ADReal) -> Result<ADReal> {
match self {
Self::Max(left, right) => Ok(left
.evaluate(index_fixing)?
.max(right.evaluate(index_fixing)?)
.into()),
Self::Min(left, right) => Ok(left
.evaluate(index_fixing)?
.min(right.evaluate(index_fixing)?)
.into()),
Self::Times(left, right) => {
Ok((left.evaluate(index_fixing)? * right.evaluate(index_fixing)?).into())
}
Self::Plus(left, right) => {
Ok((left.evaluate(index_fixing)? + right.evaluate(index_fixing)?).into())
}
Self::Minus(left, right) => {
Ok((left.evaluate(index_fixing)? - right.evaluate(index_fixing)?).into())
}
Self::Const(value) => Ok(ADReal::new(*value)),
Self::Index => Ok(index_fixing),
}
}
}
pub trait NonLinearCoupon<T> {
fn payoff_description(&self) -> PayoffOps;
fn accrued_amount(&self, start_date: Date, end_date: Date) -> Result<T>;
fn accrual_start_date(&self) -> Date;
fn accrual_end_date(&self) -> Date;
fn notional(&self) -> f64;
fn payment_date(&self) -> Date;
}