Skip to content

Commit dde3d72

Browse files
committed
added analytical greeks for black scholes
1 parent ce2d22e commit dde3d72

File tree

3 files changed

+98
-5
lines changed

3 files changed

+98
-5
lines changed

examples/black_scholes_sensi.jl

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,3 +94,20 @@ for (i, d) in enumerate(zero_deltas)
9494
t = spine_tenors(rate_curve)[i]
9595
println("Tenor $(t)y: ∂Price/∂z[$i] = ", round(d, sigdigits=6))
9696
end
97+
98+
vega_an = solve(gprob, AnalyticGreek(), bs_method).greek
99+
100+
gamma_an = solve(gammaprob, AnalyticGreek(), bs_method).greek
101+
volga_an = solve(volgaprob, AnalyticGreek(), bs_method).greek
102+
103+
println("Vega (Analytic): $vega_an")
104+
println("Vega (Forward AD): $vega_ad")
105+
println("Vega (Finite Diff): $vega_fd\n")
106+
107+
println("Gamma (Analytic): $gamma_an")
108+
println("Gamma (Forward AD): $gamma_ad")
109+
println("Gamma (Finite Diff): $gamma_fd\n")
110+
111+
println("Volga (Analytic): $volga_an")
112+
println("Volga (Forward AD): $volga_ad")
113+
println("Volga (Finite Diff): $volga_fd")

src/greeks/greeks_problem.jl

Lines changed: 79 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Exports
2-
export ForwardAD, FiniteDifference, GreekProblem, SecondOrderGreekProblem
2+
export ForwardAD, FiniteDifference, GreekProblem, SecondOrderGreekProblem, AnalyticGreek
33

44
# Method types
55
abstract type GreekMethod end
@@ -10,13 +10,16 @@ struct FDForward <: FDScheme end
1010
struct FDBackward <: FDScheme end
1111
struct FDCentral <: FDScheme end
1212

13+
struct AnalyticGreek <: GreekMethod end
14+
1315
struct ForwardAD <: GreekMethod end
16+
1417
struct FiniteDifference{S<:FDScheme} <: GreekMethod
1518
bump
1619
scheme::S
1720
end
1821

19-
FiniteDifference(bump) = FiniteDifference(bump, CentralFiniteDifference())
22+
FiniteDifference(bump) = FiniteDifference(bump, FDCentral())
2023

2124
# First-order GreekProblem
2225
struct GreekProblem{P, L}
@@ -60,7 +63,7 @@ function compute_fd_derivative(::FDCentral, prob, lens, ε, pricing_method)
6063
return (v_up - v_down) / (2ε)
6164
end
6265

63-
function solve(gprob::GreekProblem, method::FiniteDifference{S}, pricing_method::P) where {S<:FiniteDifferenceScheme, P<:AbstractPricingMethod}
66+
function solve(gprob::GreekProblem, method::FiniteDifference{S}, pricing_method::P) where {S<:FDScheme, P<:AbstractPricingMethod}
6467
prob = gprob.pricing_problem
6568
lens = gprob.wrt
6669
ε = method.bump
@@ -119,3 +122,76 @@ function solve(gprob::SecondOrderGreekProblem, method::FiniteDifference, pricing
119122

120123
return (greek = deriv,)
121124
end
125+
126+
function solve(gprob::GreekProblem, ::AnalyticGreek, ::BlackScholesAnalytic)
127+
prob = gprob.pricing_problem
128+
lens = gprob.wrt
129+
inputs = prob.market
130+
131+
S = inputs.spot
132+
σ = inputs.sigma
133+
T = yearfrac(prob.market.referenceDate, prob.payoff.expiry)
134+
K = prob.payoff.strike
135+
136+
D = df(prob.market.rate, T)
137+
F = prob.market.spot / D
138+
T = sqrt(T)
139+
d1 = (log(F / K) + 0.5 * σ^2 * T) /* T)
140+
d2 = d1 - σ * T
141+
142+
Φ = x -> cdf(Normal(), x)
143+
ϕ = x -> pdf(Normal(), x)
144+
145+
greek = if lens === @optic _.market.spot
146+
# Delta = ∂V/∂S = ∂V/∂F * ∂F/∂S = (cp * N(cp·d1)) * (1/D)
147+
cp * Φ(cp * d1)
148+
149+
elseif lens === @optic _.market.sigma
150+
# Vega = ∂V/∂σ = D · F · φ(d1) · √T
151+
D * F * ϕ(d1) * T
152+
153+
else
154+
error("Unsupported lens for analytic Greek")
155+
end
156+
157+
return (greek = greek,)
158+
end
159+
160+
function solve(
161+
gprob::SecondOrderGreekProblem,
162+
::AnalyticGreek,
163+
::BlackScholesAnalytic
164+
)
165+
prob = gprob.pricing_problem
166+
lens1 = gprob.wrt1
167+
lens2 = gprob.wrt2
168+
inputs = prob.market
169+
170+
S = inputs.spot
171+
σ = inputs.sigma
172+
T = yearfrac(inputs.referenceDate, prob.payoff.expiry)
173+
K = prob.payoff.strike
174+
175+
D = df(inputs.rate, T)
176+
F = S / D
177+
T = sqrt(T)
178+
d1 = (log(F / K) + 0.5 * σ^2 * T) /* T)
179+
d2 = d1 - σ * T
180+
181+
ϕ = x -> pdf(Normal(), x)
182+
183+
greek = if (lens1 === @optic _.market.spot) && (lens2 === @optic _.market.spot)
184+
# Gamma = ∂²V/∂S² = φ(d1) / (Sσ√T)
185+
ϕ(d1) / (S * σ * T)
186+
187+
elseif (lens1 === @optic _.market.sigma) && (lens2 === @optic _.market.sigma)
188+
# Volga = Vega * d1 * d2 / σ
189+
vega = D * F * ϕ(d1) * T
190+
vega * d1 * d2 / σ
191+
192+
else
193+
error("Unsupported second-order analytic Greek")
194+
end
195+
196+
return (greek = greek,)
197+
end

src/pricing_methods/black_scholes.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,9 @@ end
5353

5454
# Define the calibration problem
5555
struct BlackScholesCalibrationProblem{P<:PricingProblem, M}
56-
prob::P
56+
prob::P
5757
method::M
58-
price_target::Float64
58+
price_target
5959
end
6060

6161
function solve(calib::BlackScholesCalibrationProblem; initial_guess=0.2, lower=1e-6, upper=5.0, kwargs...)

0 commit comments

Comments
 (0)