-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathSimulation.jl
133 lines (124 loc) · 3.95 KB
/
Simulation.jl
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
"""
struct Simulation
model::Model
times::AbstractVector
X::AbstractArray
dZ::Union{AbstractArray, Nothing}
end
A `Simulation` object represents the result of a Monte Carlo simulation.
Elements are:
- `model` - the model used for simulation.
- `times` - vector of simulation times starting with 0.
- `X` - tensor of size (`N_1`, `N_2`, `N_3`) and type `ModelValue` where
- `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
"""
simple_simulation(
model::Model,
ch::CorrelationHolder,
times::AbstractVector,
n_paths::Int;
with_progress_bar::Bool = true,
brownian_increments::Function = pseudo_brownian_increments,
store_brownian_increments::Bool = false,
)
A simple Monte Carlo simulation method assuming all model components are state-independent.
"""
function simple_simulation(
model::Model,
ch::CorrelationHolder,
times::AbstractVector,
n_paths::Int;
with_progress_bar::Bool = true,
brownian_increments::Function = pseudo_brownian_increments,
store_brownian_increments::Bool = false,
)
dZ = brownian_increments(
length(state_alias(model)),
n_paths,
length(times) - 1,
)
X = zeros(length(state_alias(model)), n_paths, 1)
iter = 2:length(times)
if with_progress_bar
iter = ProgressBar(iter)
end
for k in iter
# E[X(t) | X(s)]
X_t = Theta(model,times[k-1],times[k]) .+ H_T(model,times[k-1],times[k])' * X[:,:,k-1]
(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)) * dZ[:,:,k-1]
X = cat(X, X_t, dims=3)
end
if !store_brownian_increments
dZ = nothing
end
#
return Simulation(model, times, X, dZ)
end
"""
diagonal_simulation(
model::Model,
ch::CorrelationHolder,
times::AbstractVector,
n_paths::Int;
with_progress_bar::Bool = true,
brownian_increments::Function = pseudo_brownian_increments,
store_brownian_increments::Bool = false,
)
A Monte Carlo simulation method assuming all model components are diagonal models.
"""
function diagonal_simulation(
model::Model,
ch::CorrelationHolder,
times::AbstractVector,
n_paths::Int;
with_progress_bar::Bool = true,
brownian_increments::Function = pseudo_brownian_increments,
store_brownian_increments::Bool = false,
)
dZ = brownian_increments(
length(state_alias(model)),
n_paths,
length(times) - 1,
)
X = zeros(length(state_alias(model)), n_paths, 1)
iter = 2:length(times)
if with_progress_bar
iter = ProgressBar(iter)
end
idx = alias_dictionary(state_alias(model))
for k in iter
# E[X(t) | X(s)]
params = simulation_parameters(model, ch, times[k-1], times[k])
Θ = hcat([
Theta(model, times[k-1], times[k], model_state(X[:,p:p,k-1], idx, params))
for p in 1:n_paths
]...)
X_t = Θ + H_T(model,times[k-1],times[k])' * X[:,:,k-1]
SX0 = model_state(zeros(length(state_alias(model)), 1), idx, params)
(vol, corr) = volatility_and_correlation(model,ch,times[k-1],times[k], SX0) # effectively, state-independent calculation
SX = model_state(X[:,:,k-1], idx, params)
Vol = diagonal_volatility(model, times[k-1], times[k], SX)
L = cholesky(corr).L
# apply diffusion
X_t += sqrt(times[k] - times[k-1]) * L * dZ[:,:,k-1] .* Vol
X = cat(X, X_t, dims=3)
end
if !store_brownian_increments
dZ = nothing
end
#
return Simulation(model, times, X, dZ)
end