Skip to content

Commit d38909e

Browse files
committed
Trying to reproduce BK price
1 parent 16bb332 commit d38909e

File tree

4 files changed

+64
-27
lines changed

4 files changed

+64
-27
lines changed

examples/heston_noise.jl

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@ using Revise, Hedgehog2, Distributions, DifferentialEquations, Random, Plots
22

33
# Define Heston model parameters
44
S0 = 1.0 # Initial stock price
5-
V0 = 0.04 # Initial variance
6-
κ = 2.0 # Mean reversion speed
7-
θ = 0.04 # Long-run variance
8-
σ = 0.02 # Volatility of variance
9-
ρ = -0.7 # Correlation
10-
r = 0.05 # Risk-free rate
5+
V0 = 0.010201 # Initial variance
6+
κ = 6.21 # Mean reversion speed
7+
θ = 0.019 # Long-run variance
8+
σ = 0.61 # Volatility of variance
9+
ρ = -0.7 # Correlation
10+
r = 0.0319 # Risk-free rate
1111
T = 1.0 # Time to maturity
1212

1313
# Create the exact sampling Heston distribution
@@ -19,19 +19,21 @@ heston_noise = Hedgehog2.HestonNoise(0.0, heston_dist)
1919
# Define `NoiseProblem`
2020
problem = NoiseProblem(heston_noise, (0.0, T))
2121

22-
trajectories = 10
22+
trajectories = 1000
2323
# Solve with multiple trajectories
24-
solution_h = solve(EnsembleProblem(problem), dt=T, trajectories=trajectories)
24+
solution_exact = solve(EnsembleProblem(problem), dt=T, trajectories=trajectories)
2525

2626
u0 = [S0, V0] # Initial (Stock Price, Variance)
2727
tspan = (0.0, 1.0) # Simulation for 1 year
2828
process = HestonProcess(r, κ, θ, σ, ρ) # Heston parameters
2929
prob = SDEProblem(get_sde_function(process), u0, tspan, process)
3030
ensemble_problem = EnsembleProblem(prob)
31-
solution_h2 = solve(ensemble_problem, dt=T/1000.0, trajectories=trajectories)
31+
# solution_h2 = solve(ensemble_problem, dt=T/100.0, trajectories=trajectories)
3232

33-
final_prices_2 = [sol.u[end][1] for sol in solution_h2] # Extract S_T for each trajectory
34-
final_prices = [sol.u[end] for sol in solution_h] # Transform log-prices to prices
33+
# final_prices_2 = [sol.u[end][1] for sol in solution_h2] # Extract S_T for each trajectory
34+
final_prices_exact = [sol.u[end] for sol in solution_exact] # Transform log-prices to prices
3535

36-
println(mean(final_prices_2))
37-
println(mean(final_prices))
36+
# println("Euler: ", mean(max.(final_prices_2 .- 1, 0)), " ", var(final_prices_2))
37+
price = mean(max.(final_prices_exact.- 1, 0))
38+
variance = var(final_prices_exact)
39+
println("Exact: ", price, " variance: ",variance, " error ", (price - 6.8061)^2)

examples/sample_int_var_heston.jl

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
using Revise, Hedgehog2, Distributions, DifferentialEquations, Random, Plots
2+
3+
# Define Heston model parameters
4+
S0 = 1.0 # Initial stock price
5+
V0 = 0.04 # Initial variance
6+
κ = 0.5 # Mean reversion speed
7+
θ = 0.04 # Long-run variance
8+
σ = 0.1 # Volatility of variance
9+
ρ = -0.9 # Correlation
10+
r = 0.1 # Risk-free rate
11+
T = 1.0 # Time to maturity
12+
13+
# Create the exact sampling Heston distribution
14+
heston_dist = Hedgehog2.HestonDistribution(S0, V0, κ, θ, σ, ρ, r, T)
15+
16+
rng = Xoshiro()
17+
VT = Hedgehog2.sample_V_T(rng, heston_dist)
18+
phi(u) = Hedgehog2.integral_var_char(u, VT, heston_dist)
19+
F = Hedgehog2.integral_V_cdf(VT, rng, heston_dist)
20+

src/distributions/heston.jl

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -33,28 +33,38 @@ Samples `log(S_T)` using the exact Broadie-Kaya method.
3333
function sample_V_T(rng::AbstractRNG, d::HestonDistribution)
3434
κ, θ, σ, V0, T = d.κ, d.θ, d.σ, d.V0, d.T
3535

36-
ν = 4κ*θ / σ^2 # Degrees of freedom
37-
ψ = 4κ * exp(-κ * T) * V0 /^2 * (1 - exp(-κ * T))) # Noncentrality parameter
38-
c = σ^2 * (1 - exp(-κ * T)) / (4κ) # Scaling factor
36+
d = 4*κ*θ / σ^2 # Degrees of freedom
37+
λ = 4*κ * exp(-κ * T) * V0 /^2 * (1 - exp(-κ * T))) # Noncentrality parameter
38+
c = σ^2 * (1 - exp(-κ * T)) / (4*κ) # Scaling factor
3939

40-
V_T = c * Distributions.rand(rng, NoncentralChisq(ν, ψ))
40+
V_T = c * Distributions.rand(rng, NoncentralChisq(d, λ))
4141
return V_T
4242
end
4343

44-
function sample_integral_V(VT, rng, dist::HestonDistribution)
44+
function integral_V_cdf(VT, rng, dist::HestonDistribution)
4545
Φ(u) = integral_var_char(u, VT, dist)
4646
integrand(x) = u -> sin(u * x) / u * real(Φ(u))
47-
F(x) = 2 / π * quadgk(integrand(x), 0, Inf)[1] # specify like in paper (trapz)
47+
F(x) = 2 / π * quadgk(integrand(x), 0, 100; maxevals=10000)[1] # specify like in paper (trapz)
48+
return F
49+
end
50+
51+
function sample_integral_V(VT, rng, dist::HestonDistribution)
52+
F = integral_V_cdf(VT, rng, dist)
4853
lower_bound = 0.0
49-
upper_bound = 1000
54+
upper_bound = 1
5055
# Generate samples
5156
unif = Uniform(0,1) # Define uniform distribution
5257
u = Distributions.rand(rng, unif)
5358
return inverse_cdf_rootfinding(F, u, lower_bound, upper_bound)
5459
end
5560

5661
function inverse_cdf_rootfinding(cdf_func, u, y_min, y_max)
57-
return find_zero(y -> cdf_func(y) - u, (y_min, y_max); atol=1E-2, maxiters=5) # Solve F(y) = u like in paper (newton 2nd order)
62+
func = y -> cdf_func(y) - u
63+
if (func(y_min)*func(y_max) < 0)
64+
return find_zero(y -> cdf_func(y) - u, (y_min, y_max); atol=1E-5, maxiters=100) # Solve F(y) = u like in paper (newton 2nd order)
65+
else
66+
return find_zero(y -> cdf_func(y) - u, y_min; atol=1E-5, maxiters=100)
67+
end
5868
end
5969

6070
using SpecialFunctions
@@ -64,19 +74,20 @@ function adjust_argument(z)
6474
θ = angle(z) # Compute current argument
6575
m = round(Int, θ / π) # Find the nearest integer multiple of π
6676
z_adjusted = z * exp(-im * m * π) # Shift argument back into (-π, π]
67-
return z_adjusted
77+
return z_adjusted, m
6878
end
6979

7080
""" Compute the modified Bessel function I_{-ν}(z) with argument correction. """
7181
function besseli_corrected(nu, z)
72-
z_adj = adjust_argument(z) # Ensure argument is in (-π, π]
73-
return besseli(nu, z_adj) # Compute Bessel function with corrected input
82+
z_adj, m = adjust_argument(z) # Ensure argument is in (-π, π]
83+
# println("adjusted besseli: ",m, " value ", nu, " val: ", z_adj)
84+
return exp(im * m * π * nu) * besseli(nu, z_adj) # Compute Bessel function with corrected input
7485
end
7586

7687
function integral_var_char(a, VT, dist::HestonDistribution)
77-
κ, θ, σ, ρ, V0, T, S0, r = dist.κ, dist.θ, dist.σ, dist.ρ, dist.V0, dist.T, dist.S0, dist.r
88+
κ, θ, σ, V0, T = dist.κ, dist.θ, dist.σ, dist.V0, dist.T
7889
γ(a) = ^2 - 2 * σ^2 * a * im)
79-
d = 4 * θ * κ / σ^2
90+
d = 4*κ*θ / σ^2 # Degrees of freedom
8091

8192
ζ(x) = (1 - exp(- x * T)) / x
8293
first_term = exp(-0.5 * (γ(a) - κ) * T) * ζ(κ) / ζ(γ(a))
@@ -85,6 +96,10 @@ function integral_var_char(a, VT, dist::HestonDistribution)
8596
second_term = exp((V0 + VT) / σ^2 * ( η(κ) - η(γ(a)) ))
8697

8798
ν(x) = (V0 * VT) * 4 * x * exp(-0.5 * x * T) / σ^2 / (1 - exp(- x * T))
99+
100+
# println("kappa ", ν( κ))
101+
# println("gamma: ",γ(a))
102+
# println("a ",a)
88103
numerator = besseli_corrected(0.5*d - 1, ν(γ(a)))
89104
denominator = besseli_corrected(0.5*d - 1, ν(κ))
90105
third_term = numerator / denominator

src/stochastic_processes/heston_noise.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ Constructs a `NoiseProcess` for exact Heston model sampling.
1111
function HestonNoise(t0, heston_dist::HestonDistribution, Z0=nothing)
1212
log_S0 = log(heston_dist.S0) # Work in log-space
1313
u0 = SVector(log_S0, heston_dist.V0) # Use SVector for efficiency
14-
14+
println("Heston noise")
1515
# Correct function signature for WHITE_NOISE_DIST
1616
@inline function Heston_dist(DW, W, dt, u, p, t, rng) #dist
1717
return rand(rng, heston_dist) # Calls exact Heston sampler

0 commit comments

Comments
 (0)