use crate::fdm::DifferenceMethod;
pub struct FdmWithoutCarry<'a> {
pub price: Box<dyn Fn(f64, f64, f64, f64, f64) -> f64 + 'a>,
}
impl<'a> FdmWithoutCarry<'a> {
pub fn new(price: impl Fn(f64, f64, f64, f64, f64) -> f64 + 'a) -> Self {
FdmWithoutCarry {
price: Box::new(price),
}
}
#[allow(non_snake_case)]
pub fn delta(
&self,
S: f64,
K: f64,
t: f64,
r: f64,
v: f64,
dS: f64,
method: DifferenceMethod,
) -> f64 {
match method {
DifferenceMethod::Backward => {
((self.price)(S, K, t, r, v) - (self.price)(S - dS, K, t, r, v)) / dS
}
DifferenceMethod::Central => {
((self.price)(S + dS, K, t, r, v) - (self.price)(S - dS, K, t, r, v)) / (2.0 * dS)
}
DifferenceMethod::Forward => {
((self.price)(S + dS, K, t, r, v) - (self.price)(S, K, t, r, v)) / dS
}
}
}
#[allow(non_snake_case)]
pub fn gamma(
&self,
S: f64,
K: f64,
t: f64,
r: f64,
v: f64,
dS: f64,
method: DifferenceMethod,
) -> f64 {
match method {
DifferenceMethod::Backward => {
((self.price)(S, K, t, r, v) - 2.0 * (self.price)(S - dS, K, t, r, v)
+ (self.price)(S - 2.0 * dS, K, t, r, v))
/ (dS * dS)
}
DifferenceMethod::Central => {
((self.price)(S + dS, K, t, r, v) - 2.0 * (self.price)(S, K, t, r, v)
+ (self.price)(S - dS, K, t, r, v))
/ (dS * dS)
}
DifferenceMethod::Forward => {
((self.price)(S + 2.0 * dS, K, t, r, v) - 2.0 * (self.price)(S + dS, K, t, r, v)
+ (self.price)(S, K, t, r, v))
/ (dS * dS)
}
}
}
#[allow(non_snake_case)]
pub fn theta(
&self,
S: f64,
K: f64,
t: f64,
r: f64,
v: f64,
dT: f64,
method: DifferenceMethod,
) -> f64 {
match method {
DifferenceMethod::Backward => {
((self.price)(S, K, t - dT, r, v) - (self.price)(S, K, t, r, v)) / dT
}
DifferenceMethod::Central => {
((self.price)(S, K, t - dT, r, v) - (self.price)(S, K, t + dT, r, v)) / (2.0 * dT)
}
DifferenceMethod::Forward => {
((self.price)(S, K, t, r, v) - (self.price)(S, K, t + dT, r, v)) / dT
}
}
}
#[allow(non_snake_case)]
pub fn vega(
&self,
S: f64,
K: f64,
t: f64,
r: f64,
v: f64,
dv: f64,
method: DifferenceMethod,
) -> f64 {
match method {
DifferenceMethod::Backward => {
((self.price)(S, K, t, r, v) - (self.price)(S, K, t, r, v - dv)) / dv
}
DifferenceMethod::Central => {
((self.price)(S, K, t, r, v + dv) - (self.price)(S, K, t, r, v - dv)) / (2.0 * dv)
}
DifferenceMethod::Forward => {
((self.price)(S, K, t, r, v + dv) - (self.price)(S, K, t, r, v)) / dv
}
}
}
#[allow(non_snake_case)]
pub fn rho(
&self,
S: f64,
K: f64,
t: f64,
r: f64,
v: f64,
dr: f64,
method: DifferenceMethod,
) -> f64 {
match method {
DifferenceMethod::Backward => {
((self.price)(S, K, t, r, v) - (self.price)(S, K, t, r - dr, v)) / dr
}
DifferenceMethod::Central => {
((self.price)(S, K, t, r + dr, v) - (self.price)(S, K, t, r - dr, v)) / (2.0 * dr)
}
DifferenceMethod::Forward => {
((self.price)(S, K, t, r + dr, v) - (self.price)(S, K, t, r, v)) / dr
}
}
}
#[allow(non_snake_case)]
pub fn elasticity(
&self,
S: f64,
K: f64,
t: f64,
r: f64,
v: f64,
dS: f64,
method: DifferenceMethod,
) -> f64 {
self.delta(S, K, t, r, v, dS, method) * S / (self.price)(S, K, t, r, v)
}
#[allow(non_snake_case)]
pub fn speed(
&self,
S: f64,
K: f64,
t: f64,
r: f64,
v: f64,
dS: f64,
_method: DifferenceMethod,
) -> f64 {
((self.price)(S + 2.0 * dS, K, t, r, v) - 3.0 * (self.price)(S + dS, K, t, r, v)
+ 3.0 * (self.price)(S, K, t, r, v)
- (self.price)(S - dS, K, t, r, v))
/ (dS * dS * dS)
}
#[allow(non_snake_case)]
pub fn deltap(
&self,
S: f64,
K: f64,
t: f64,
r: f64,
v: f64,
dS: f64,
_method: DifferenceMethod,
) -> f64 {
((self.price)(S * (1.0 + dS), K, t, r, v) - (self.price)(S * (1.0 - dS), K, t, r, v))
/ (2.0 * S)
}
#[allow(non_snake_case)]
pub fn gammap(
&self,
S: f64,
K: f64,
t: f64,
r: f64,
v: f64,
dS: f64,
method: DifferenceMethod,
) -> f64 {
S / 100.0 * self.gamma(S, K, t, r, v, dS, method)
}
#[allow(non_snake_case)]
pub fn vegap(
&self,
S: f64,
K: f64,
t: f64,
r: f64,
v: f64,
dv: f64,
_method: DifferenceMethod,
) -> f64 {
((self.price)(S, K, t, r, v + dv) - (self.price)(S, K, t, r, v - dv)) * v / 0.1 / 2.0
}
#[allow(non_snake_case)]
pub fn vanna(
&self,
S: f64,
K: f64,
t: f64,
r: f64,
v: f64,
dS: f64,
dv: f64,
_method: DifferenceMethod,
) -> f64 {
((self.price)(S + dS, K, t, r, v + dv)
- (self.price)(S + dS, K, t, r, v - dv)
- (self.price)(S - dS, K, t, r, v + dv)
+ (self.price)(S - dS, K, t, r, v - dv))
/ (4.0 * dS)
/ dv
}
#[allow(non_snake_case)]
pub fn charm(
&self,
S: f64,
K: f64,
t: f64,
r: f64,
v: f64,
dS: f64,
dT: f64,
_method: DifferenceMethod,
) -> f64 {
((self.price)(S + dS, K, t + dT, r, v)
- (self.price)(S + dS, K, t - dT, r, v)
- (self.price)(S - dS, K, t + dT, r, v)
+ (self.price)(S - dS, K, t - dT, r, v))
/ (4.0 * dS)
/ -dT
}
#[allow(non_snake_case)]
pub fn dgamma_dvol(
&self,
S: f64,
K: f64,
t: f64,
r: f64,
v: f64,
dS: f64,
dv: f64,
_method: DifferenceMethod,
) -> f64 {
((self.price)(S + dS, K, t, r, v + dv) - 2.0 * (self.price)(S, K, t, r, v + dv)
+ (self.price)(S - dS, K, t, r, v + dv)
- (self.price)(S + dS, K, t, r, v - dv)
+ 2.0 * (self.price)(S, K, t, r, v - dv)
- (self.price)(S - dS, K, t, r, v - dv))
/ (2.0 * dv * (dS * dS))
/ 100.0
}
#[allow(non_snake_case)]
pub fn vomma(
&self,
S: f64,
K: f64,
t: f64,
r: f64,
v: f64,
dv: f64,
_method: DifferenceMethod,
) -> f64 {
((self.price)(S, K, t, r, v + dv) - 2.0 * (self.price)(S, K, t, r, v)
+ (self.price)(S, K, t, r, v - dv))
/ (dv * dv)
}
#[allow(non_snake_case)]
pub fn time_gamma(
&self,
S: f64,
K: f64,
t: f64,
r: f64,
v: f64,
dT: f64,
_method: DifferenceMethod,
) -> f64 {
((self.price)(S, K, t + dT, r, v) - 2.0 * (self.price)(S, K, t, r, v)
+ (self.price)(S, K, t - dT, r, v))
/ (dT * dT)
}
#[allow(non_snake_case)]
pub fn strike_delta(
&self,
S: f64,
K: f64,
t: f64,
r: f64,
v: f64,
dK: f64,
_method: DifferenceMethod,
) -> f64 {
((self.price)(S, K + dK, t, r, v) - (self.price)(S, K - dK, t, r, v)) / (2.0 * dK)
}
#[allow(non_snake_case)]
pub fn strike_gamma(
&self,
S: f64,
K: f64,
t: f64,
r: f64,
v: f64,
dK: f64,
_method: DifferenceMethod,
) -> f64 {
((self.price)(S, K + dK, t, r, v) - 2.0 * (self.price)(S, K, t, r, v)
+ (self.price)(S, K - dK, t, r, v))
/ (dK * dK)
}
}