use crate::types::{Real, Size};
pub trait EarlyExercisePathPricer<P> {
type State;
fn value(&self, path: &P, t: Size) -> Real;
fn state(&self, path: &P, t: Size) -> Self::State;
fn basis_system(&self) -> Vec<Box<dyn Fn(Self::State) -> Real>>;
}
#[cfg(test)]
mod tests {
use super::*;
use crate::math::array::Array;
use crate::math::timegrid::TimeGrid;
use crate::methods::montecarlo::{LsmBasisSystem, Path, PolynomialType};
struct AmericanPut {
strike: Real,
order: Size,
}
impl EarlyExercisePathPricer<Path> for AmericanPut {
type State = Real;
fn value(&self, path: &Path, t: Size) -> Real {
(self.strike - path[t]).max(0.0)
}
fn state(&self, path: &Path, t: Size) -> Real {
path[t]
}
fn basis_system(&self) -> Vec<Box<dyn Fn(Real) -> Real>> {
LsmBasisSystem::path_basis_system(self.order, PolynomialType::Monomial)
}
}
fn path(values: [Real; 3]) -> Path {
let grid = TimeGrid::new(1.0, 2).unwrap();
Path::new(grid, Array::from(values)).unwrap()
}
#[test]
fn a_path_implementor_reports_value_state_and_basis() {
let pricer = AmericanPut {
strike: 40.0,
order: 2,
};
let p = path([36.0, 44.0, 38.0]);
assert_eq!(pricer.value(&p, 0), 4.0);
assert_eq!(
pricer.value(&p, 1),
0.0,
"an out-of-the-money put is worth 0"
);
assert_eq!(pricer.value(&p, 2), 2.0);
assert_eq!(pricer.state(&p, 1), 44.0);
assert_eq!(pricer.basis_system().len(), 3);
}
#[test]
fn the_trait_is_object_safe() {
let pricer: Box<dyn EarlyExercisePathPricer<Path, State = Real>> = Box::new(AmericanPut {
strike: 40.0,
order: 1,
});
assert_eq!(pricer.value(&path([36.0, 44.0, 38.0]), 0), 4.0);
}
}