Skip to content

Commit

Permalink
Add Brownian increments to simulation
Browse files Browse the repository at this point in the history
  • Loading branch information
FrameConsult authored and sschlenkrich committed Apr 12, 2024
1 parent 942be47 commit 314fd35
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 8 deletions.
18 changes: 13 additions & 5 deletions src/simulations/Simulation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
model::Model
times::AbstractVector
X::AbstractArray
dZ::Union{AbstractArray, Nothing}
end
A `Simulation` object represents the result of a Monte Carlo simulation.
Expand All @@ -15,11 +16,13 @@ Elements are:
- `N_1` is `length(m.state_alias)`,
- `N_2` is number of Monte Carlo paths,
- `N_3` is `length(times)`.
- `dZ` - Brownian motion increments.
"""
struct Simulation
model::Model
times::AbstractVector
X::AbstractArray
dZ::Union{AbstractArray, Nothing}
end


Expand All @@ -30,7 +33,8 @@ end
times::AbstractVector,
n_paths::Int;
with_progress_bar::Bool = true,
brownian_increments::Function = pseudo_brownian_increments
brownian_increments::Function = pseudo_brownian_increments,
store_brownian_increments::Bool = false,
)
A simple Monte Carlo simulation method assuming all model components are state-independent.
Expand All @@ -41,9 +45,10 @@ function simple_simulation(
times::AbstractVector,
n_paths::Int;
with_progress_bar::Bool = true,
brownian_increments::Function = pseudo_brownian_increments
brownian_increments::Function = pseudo_brownian_increments,
store_brownian_increments::Bool = false,
)
Z = brownian_increments(
dZ = brownian_increments(
length(state_alias(model)),
n_paths,
length(times) - 1,
Expand All @@ -59,10 +64,13 @@ function simple_simulation(
(vol, corr) = volatility_and_correlation(model,ch,times[k-1],times[k])
L = cholesky(corr).L
# apply diffusion
X_t += (sqrt(times[k] - times[k-1]) * (L .* vol)) * Z[:,:,k-1]
X_t += (sqrt(times[k] - times[k-1]) * (L .* vol)) * dZ[:,:,k-1]
X = cat(X, X_t, dims=3)
end
if !store_brownian_increments
dZ = nothing
end
#
return Simulation(model, times, X)
return Simulation(model, times, X, dZ)
end

6 changes: 3 additions & 3 deletions test/unittests/paths/path.jl
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ end
X = ones(length(DiffFusion.state_alias(m)), n_paths, length(times))
X[:,:,1] = zeros(length(DiffFusion.state_alias(m)), n_paths)
X[:,:,5] = 2.0 * ones(length(DiffFusion.state_alias(m)), n_paths)
sim = DiffFusion.Simulation(m, times, X)
sim = DiffFusion.Simulation(m, times, X, nothing)

# valuation context with deterministic dividend yield

Expand Down Expand Up @@ -293,7 +293,7 @@ end
@test_throws KeyError DiffFusion.zero_bond(p, t, T, "SXE50:OIS")
#
X = zeros(length(DiffFusion.state_alias(m)), n_paths, length(times))
sim = DiffFusion.Simulation(m, times, X) # simplify calculations
sim = DiffFusion.Simulation(m, times, X, nothing) # simplify calculations
p = DiffFusion.path(sim, ts, context)
@test isapprox(DiffFusion.asset(p, t, "EUR-USD"), ones(5) * 1.25 * exp(0.01*t), atol=5.0e-15)
@test isapprox(DiffFusion.asset(p, t, "SXE50"), ones(5) * 3750.00 * exp(0.01*t), atol=5.0e-15)
Expand Down Expand Up @@ -368,7 +368,7 @@ end
("SOFR", DiffFusion.FixingEntry("SOFR", "USD-SOFR-Fixings")),
]),
)
det_sim = DiffFusion.Simulation(m, zeros(0), zeros(0,1,0) )
det_sim = DiffFusion.Simulation(m, zeros(0), zeros(0,1,0), nothing)
p = DiffFusion.path(det_sim, ts, det_context)
t = 2.0
T = 5.0
Expand Down
8 changes: 8 additions & 0 deletions test/unittests/simulations/simple_models.jl
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ using Test
n_paths = 2^13
sim = DiffFusion.simple_simulation(m, ch_full, times, n_paths, with_progress_bar = false)
# println(size(sim.X))
@test isnothing(sim.dZ)
@test size(sim.X) == (9,8192,6)
# martingale test domestic numeraire
one = mean(exp.(-sim.X[4,:,:]), dims=1)
Expand Down Expand Up @@ -222,6 +223,13 @@ using Test
@test isapprox(one[4], 0.9967937694265642, atol=abs_tol)
@test isapprox(one[5], 0.9976008565308596, atol=abs_tol)
@test isapprox(one[6], 0.9947929666530295, atol=abs_tol)
#
# store Brownian increments
sim_w_dZ = DiffFusion.simple_simulation(m, ch_full, times, n_paths,
with_progress_bar = false, store_brownian_increments = true)
@test !isnothing(sim_w_dZ.dZ)
@test size(sim_w_dZ.dZ) == (9,8192,5)
@test sim_w_dZ.X == sim.X
end

end

0 comments on commit 314fd35

Please sign in to comment.