use crate::time::{today, DayCountConvention};
use time::Date;
#[allow(clippy::module_name_repetitions)]
#[derive(Debug, Clone, Copy)]
pub struct PowerOption {
pub initial_price: f64,
pub strike_price: f64,
pub power: f64,
pub risk_free_rate: f64,
pub cost_of_carry: f64,
pub volatility: f64,
pub evaluation_date: Option<Date>,
pub expiration_date: Date,
}
impl PowerOption {
#[allow(clippy::too_many_arguments)]
#[must_use]
pub fn new(
initial_price: f64,
strike_price: f64,
power: f64,
risk_free_rate: f64,
cost_of_carry: f64,
volatility: f64,
evaluation_date: Option<Date>,
expiration_date: Date,
) -> Self {
Self {
initial_price,
strike_price,
power,
risk_free_rate,
cost_of_carry,
volatility,
evaluation_date,
expiration_date,
}
}
#[must_use]
pub fn price(&self) -> f64 {
let S = self.initial_price;
let K = self.strike_price;
let r = self.risk_free_rate;
let v = self.volatility;
let b = self.cost_of_carry;
let i = self.power;
let T = DayCountConvention::default().day_count_factor(
self.evaluation_date.unwrap_or(today()),
self.expiration_date,
);
(S / K).powf(i) * (((b - 0.5 * v.powi(2)) * i - r + 0.5 * (i * v).powi(2)) * T).exp()
}
}
#[cfg(test)]
mod tests_power_contract {
use super::*;
use crate::{assert_approx_equal, RUSTQUANT_EPSILON};
use time::Duration;
#[test]
fn test_power() {
let power_option = PowerOption {
initial_price: 400.,
strike_price: 450.,
power: 2.,
risk_free_rate: 0.08,
cost_of_carry: 0.06,
volatility: 0.25,
evaluation_date: None,
expiration_date: today() + Duration::days(182),
};
assert_approx_equal!(power_option.price(), 0.83144001309052, RUSTQUANT_EPSILON);
}
}