use super::vanila_option::{EquityOption};
use super::utils::{Engine, Payoff};
use crate::core::trade::{ PutOrCall, Transection};
use crate::core::utils::{ContractStyle};
use ndarray::Array2;
pub fn npv(option: &EquityOption) -> f64 {
assert!(option.base.volatility() >= 0.0);
assert!(option.time_to_maturity() >= 0.0);
assert!(option.base.underlying_price.value >= 0.0);
let num_steps = 1000;
let dt = option.time_to_maturity() / num_steps as f64;
let risk_free_rate = option.base.risk_free_rate();
let discount_factor = (-risk_free_rate * dt).exp();
let u = (option.base.volatility()*dt.sqrt()).exp(); let d = 1.0 / u; let a_factor = ((risk_free_rate-option.base.carry_yield()) * dt).exp();
let p = (a_factor - d) / (u - d); let mut tree = Array2::from_elem((num_steps + 1, num_steps + 1), 0.0);
let strike = option.base.strike_price;
for j in 0..=num_steps {
let spot_price_j = option.base.effective_spot() * u.powi(num_steps as i32 - j as i32) * d.powi(j as i32);
tree[[j,num_steps]] = option.payoff.payoff(spot_price_j, strike);
}
match option.payoff.exercise_style() {
ContractStyle::European => {
for i in (0..num_steps).rev() {
for j in 0..=i {
let discounted_option_price = discount_factor * (p * tree[[ j,i+1]] + (1.0 - p) * tree[[ j + 1,i+1]]);
tree[[j,i]] = discounted_option_price;
}
}
}
ContractStyle::American => {
for i in (0..num_steps).rev() {
for j in 0..=i {
let spot_price_i = option.base.effective_spot() * u.powi(i as i32 - j as i32) * d.powi(j as i32);
let discounted_option_price = discount_factor * (p * tree[[ j,i+1]] + (1.0 - p) * tree[[ j + 1,i+1]]);
tree[[j,i]] = option.payoff.payoff(spot_price_i, strike).max(discounted_option_price);
}
}
}
_ => {
panic!("Invalid option style");
}
}
return tree[[0,0]];
}