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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
extern crate num;
extern crate num_complex;
extern crate black_scholes;
extern crate rayon;
extern crate fang_oost;
#[macro_use]
#[cfg(test)]
extern crate approx;
#[cfg(test)]
extern crate statrs;
use num_complex::Complex;
use rayon::prelude::*;
fn chi_k(a:f64, c:f64, d:f64, u:f64)->f64{
let iter_s=|x|u*(x-a);
let exp_d=d.exp();
let exp_c=c.exp();
(iter_s(d).cos()*exp_d-iter_s(c).cos()*exp_c+u*iter_s(d).sin()*exp_d-u*iter_s(c).sin()*exp_c)/(1.0+u*u)
}
fn phi_k(a:f64, c:f64, d:f64, u:f64, k:usize)->f64{
let iter_s=|x|u*(x-a);
if k==0 {d-c} else{(iter_s(d).sin()-iter_s(c).sin())/u}
}
fn get_x_from_k(asset:f64, strikes:&Vec<f64>)->Vec<f64>{
strikes.iter().map(|strike|(asset/strike).ln()).collect()
}
fn option_price_transform(cf:&Complex<f64>)->Complex<f64>{
*cf
}
fn fang_oost_generic<'a, T, U, S>(
num_u:usize,
x_values:&'a Vec<f64>,
enh_cf:T,
m_output:U,
cf:S
)->Vec<f64>
where T: Fn(&Complex<f64>, &Complex<f64>)->Complex<f64>+std::marker::Sync+std::marker::Send+'a,
U: Fn(f64, usize)->f64+std::marker::Sync+std::marker::Send+'a,
S:Fn(&Complex<f64>)->Complex<f64>+std::marker::Sync+std::marker::Send+'a
{
let x_min=*x_values.first().unwrap();
fang_oost::get_expectation_discrete_extended(
num_u,
&x_values,
|u| enh_cf(&cf(u), u),
move |u, _, k|phi_k(x_min, x_min, 0.0, u, k)-chi_k(x_min, x_min, 0.0, u)
).enumerate().map(|(index, result)|{
m_output(result, index)
}).collect()
}
pub fn fang_oost_call_price<'a, S>(
num_u:usize,
asset:f64,
strikes:&'a Vec<f64>,
rate:f64,
t_maturity:f64,
cf:S
)->Vec<f64>
where S:Fn(&Complex<f64>)->Complex<f64>+std::marker::Sync+std::marker::Send
{
let discount=(-rate*t_maturity).exp();
let t_strikes:Vec<f64>=get_x_from_k(asset, &strikes);
fang_oost_generic(
num_u,
&t_strikes,
|cfu, _|option_price_transform(&cfu),
|val, index|(val-1.0)*discount*strikes[index]+asset,
cf
)
}
#[cfg(test)]
mod tests {
use super::*;
fn get_fang_oost_k_at_index(
x_min:f64,
dk:f64,
asset:f64,
index:usize
)->f64{
asset*(-x_min-dk*(index as f64)).exp()
}
fn get_fang_oost_strike(
x_min:f64,
x_max:f64,
asset:f64,
num_x:usize
)->Vec<f64>{
let dx=(x_max-x_min)/(num_x as f64-1.0);
(0..num_x).map(|index|{
get_fang_oost_k_at_index(x_min, dx, asset, index)
}).collect()
}
#[test]
fn test_fang_oost_call(){
let r=0.05;
let sig=0.3;
let t=1.0;
let asset=50.0;
let bs_cf=|u:&Complex<f64>| ((r-sig*sig*0.5)*t*u+sig*sig*t*u*u*0.5).exp();
let x_max=5.0;
let num_x=(2 as usize).pow(10);
let num_u=64;
let k_array=get_fang_oost_strike(-x_max, x_max, asset, num_x);
let my_option_price=fang_oost_call_price(num_u, asset, &k_array, r, t, bs_cf);
let min_n=num_x/4;
let max_n=num_x-num_x/4;
let discount=(-r*t).exp();
for i in min_n..max_n{
assert_abs_diff_eq!(
black_scholes::call(asset, k_array[i], discount, sig),
my_option_price[i],
epsilon=0.001
);
}
}
}