1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
use crate::{common::*, constants::*, Inputs, OptionType, lets_be_rational};
use num_traits::Float;
pub trait Pricing<T>
where
T: Float,
{
fn calc_price(&self) -> Result<T, String>;
fn calc_rational_price(&self) -> Result<f64, String>;
}
impl Pricing<f32> for Inputs {
/// Calculates the price of the option.
/// # Requires
/// s, k, r, q, t, sigma.
/// # Returns
/// f32 of the price of the option.
/// # Example
/// ```
/// use blackscholes::{Inputs, OptionType, Pricing};
/// let inputs = Inputs::new(OptionType::Call, 100.0, 100.0, None, 0.05, 0.2, 20.0/365.25, Some(0.2));
/// let price = inputs.calc_price().unwrap();
/// ```
fn calc_price(&self) -> Result<f32, String> {
// Calculates the price of the option
let (nd1, nd2): (f32, f32) = calc_nd1nd2(&self)?;
let price: f32 = match self.option_type {
OptionType::Call => f32::max(
0.0,
nd1 * self.s * E.powf(-self.q * self.t) - nd2 * self.k * E.powf(-self.r * self.t),
),
OptionType::Put => f32::max(
0.0,
nd2 * self.k * E.powf(-self.r * self.t) - nd1 * self.s * E.powf(-self.q * self.t),
),
};
Ok(price)
}
/// Calculates the price of the option using the "Let's Be Rational" implementation.
/// # Requires
/// s, k, r, q, t, sigma.
/// # Returns
/// f64 of the price of the option.
/// # Example
/// ```
/// use blackscholes::{Inputs, OptionType, Pricing};
/// let inputs = Inputs::new(OptionType::Call, 100.0, 100.0, None, 0.05, 0.2, 20.0/365.25, Some(0.2));
/// let price = inputs.calc_rational_price().unwrap();
/// ```
fn calc_rational_price(&self) -> Result<f64, String> {
let sigma = self
.sigma
.ok_or("Expected Some(f32) for self.sigma, received None")?;
// let's be rational wants the forward price, not the spot price.
let forward = self.s * ((self.r - self.q) * self.t).exp();
// convert the option type into \theta
let q: f64 = match self.option_type {
OptionType::Call => 1.0,
OptionType::Put => -1.0,
};
// price using `black`
let undiscounted_price = lets_be_rational::black(
forward as f64,
self.k as f64,
sigma as f64,
self.t as f64,
q,
);
// discount the price
let price = undiscounted_price * (-self.r as f64 * self.t as f64).exp();
Ok(price)
}
}