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
|
# File 'lib/pure_greeks/engines/black_scholes_european.rb', line 11
def calculate(type:, strike:, underlying_price:, time_to_expiry:, implied_volatility:, risk_free_rate:, dividend_yield:)
d1, d2 = d1_d2(strike, underlying_price, time_to_expiry, implied_volatility, risk_free_rate, dividend_yield)
sqrt_t = ::Math.sqrt(time_to_expiry)
s_disc = underlying_price * ::Math.exp(-dividend_yield * time_to_expiry)
k_disc = strike * ::Math.exp(-risk_free_rate * time_to_expiry)
nd1 = Math::Normal.cdf(d1)
nd2 = Math::Normal.cdf(d2)
n_neg_d1 = Math::Normal.cdf(-d1)
n_neg_d2 = Math::Normal.cdf(-d2)
pdf_d1 = Math::Normal.pdf(d1)
price = type == :call ? s_disc * nd1 - k_disc * nd2 : k_disc * n_neg_d2 - s_disc * n_neg_d1
delta = if type == :call
::Math.exp(-dividend_yield * time_to_expiry) * nd1
else
-::Math.exp(-dividend_yield * time_to_expiry) * n_neg_d1
end
gamma = ::Math.exp(-dividend_yield * time_to_expiry) * pdf_d1 / (underlying_price * implied_volatility * sqrt_t)
theta_year =
if type == :call
-s_disc * pdf_d1 * implied_volatility / (2 * sqrt_t) -
risk_free_rate * k_disc * nd2 +
dividend_yield * s_disc * nd1
else
-s_disc * pdf_d1 * implied_volatility / (2 * sqrt_t) +
risk_free_rate * k_disc * n_neg_d2 -
dividend_yield * s_disc * n_neg_d1
end
vega_unit = s_disc * pdf_d1 * sqrt_t
rho_unit = type == :call ? k_disc * time_to_expiry * nd2 : -k_disc * time_to_expiry * n_neg_d2
Greeks.new(
delta: delta,
gamma: gamma,
theta: theta_year / 365.0,
vega: vega_unit / 100.0,
rho: rho_unit / 100.0,
price: price,
model: :black_scholes_european
)
end
|