use crate::options::types::*;
use crate::options::Instrument;
use std::any::Any;
use super::OptionPricing;
pub trait Option: Clone + Send + Sync {
fn instrument(&self) -> &Instrument;
fn instrument_mut(&mut self) -> &mut Instrument;
fn set_instrument(&mut self, instrument: Instrument);
fn strike(&self) -> f64;
fn time_to_maturity(&self) -> f64;
fn expiration_dates(&self) -> std::option::Option<&Vec<f64>> {
None
}
fn set_time_to_maturity(&mut self, time_to_maturity: f64);
fn option_type(&self) -> OptionType;
fn style(&self) -> &OptionStyle;
fn flip(&self) -> Self;
fn payoff(&self, spot: std::option::Option<f64>) -> f64 {
let spot_price = spot.unwrap_or_else(|| self.instrument().spot());
match self.option_type() {
OptionType::Call => (spot_price - self.strike()).max(0.0),
OptionType::Put => (self.strike() - spot_price).max(0.0),
}
}
fn price<T: OptionPricing>(&self, model: T) -> f64 {
model.price(self)
}
fn time_value<T: OptionPricing>(&self, model: T) -> f64 {
model.price(self) - self.payoff(None)
}
fn as_call(&self) -> Self {
if self.is_call() {
self.clone()
} else {
self.flip()
}
}
fn as_put(&self) -> Self {
if self.is_put() {
self.clone()
} else {
self.flip()
}
}
fn is_call(&self) -> bool {
matches!(self.option_type(), OptionType::Call)
}
fn is_put(&self) -> bool {
matches!(self.option_type(), OptionType::Put)
}
fn atm(&self) -> bool {
match self.option_type() {
OptionType::Call => self.instrument().spot() == self.strike(),
OptionType::Put => self.instrument().spot() == self.strike(),
}
}
fn itm(&self) -> bool {
match self.option_type() {
OptionType::Call => self.instrument().spot() > self.strike(),
OptionType::Put => self.instrument().spot() < self.strike(),
}
}
fn otm(&self) -> bool {
match self.option_type() {
OptionType::Call => self.instrument().spot() < self.strike(),
OptionType::Put => self.instrument().spot() > self.strike(),
}
}
fn as_any(&self) -> &dyn Any;
}