-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathPath.jl
186 lines (169 loc) · 5.91 KB
/
Path.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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
"""
struct Path <: AbstractPath
sim::Simulation
ts_dict::Dict{String,<:Termstructure}
state_alias_dict::Dict{String,Int}
context::Context
interpolation::PathInterpolation
end
A Path combines a model, simulated model states and term structures. The interface
to market references is established by a valuation context.
Paths are used by payoffs to calculate simulated zero bonds, asset prices
and further building blocks of financial instrument payoffs.
"""
struct Path <: AbstractPath
sim::Simulation
ts_dict::Dict{String,<:Termstructure}
state_alias_dict::Dict{String,Int}
context::Context
interpolation::PathInterpolation
end
"""
_check_path_setup(
sim::Simulation,
ts_dict::Dict{String,Termstructure},
cxt::Context,
)
Check for consistent path inputs.
We define an extra function in order to avoid chain rule issues with
automatic differentiation.
"""
function _check_path_setup(
sim::Simulation,
ts_dict::Dict{String,<:Termstructure},
cxt::Context,
)
# all referenced models need to be available
@assert isnothing(cxt.numeraire.model_alias) || cxt.numeraire.model_alias in model_alias(sim.model)
for entry in values(cxt.rates)
@assert isnothing(entry.model_alias) || entry.model_alias in model_alias(sim.model)
end
for entry in values(cxt.assets)
@assert isnothing(entry.asset_model_alias) || entry.asset_model_alias in model_alias(sim.model)
@assert isnothing(entry.domestic_model_alias) || entry.domestic_model_alias in model_alias(sim.model)
@assert isnothing(entry.foreign_model_alias) || entry.foreign_model_alias in model_alias(sim.model)
end
# keys and value aliases must be consistent
for (key, ts) in ts_dict
@assert key == alias(ts)
end
# all referenced term structures need to be available
for alias in unique(values(cxt.numeraire.termstructure_dict))
@assert alias in keys(ts_dict)
@assert isa(ts_dict[alias], YieldTermstructure)
end
for entry in values(cxt.rates)
for alias in unique(values(entry.termstructure_dict))
@assert alias in keys(ts_dict)
@assert isa(ts_dict[alias], YieldTermstructure)
end
end
for entry in values(cxt.assets)
@assert entry.asset_spot_alias in keys(ts_dict)
@assert isa(ts_dict[entry.asset_spot_alias], ParameterTermstructure)
for alias in unique(values(entry.domestic_termstructure_dict))
@assert alias in keys(ts_dict)
@assert isa(ts_dict[alias], YieldTermstructure)
end
for alias in unique(values(entry.foreign_termstructure_dict))
@assert alias in keys(ts_dict)
@assert isa(ts_dict[alias], YieldTermstructure)
end
end
for entry in values(cxt.forward_indices)
@assert entry.forward_index_alias in keys(ts_dict)
@assert isa(ts_dict[entry.forward_index_alias], ParameterTermstructure)
end
for entry in values(cxt.future_indices)
@assert entry.future_index_alias in keys(ts_dict)
@assert isa(ts_dict[entry.future_index_alias], ParameterTermstructure)
end
for entry in values(cxt.fixings)
@assert entry.termstructure_alias in keys(ts_dict)
@assert isa(ts_dict[entry.termstructure_alias], ParameterTermstructure)
end
end
"""
path(
sim::Simulation,
ts_dict::Dict{String,<:Termstructure},
cxt::Context,
ip::PathInterpolation = NoPathInterpolation
)
Create a Path object.
"""
function path(
sim::Simulation,
ts_dict::Dict{String,<:Termstructure},
cxt::Context,
ip::PathInterpolation = NoPathInterpolation
)
_check_path_setup(sim, ts_dict, cxt)
state_alias_dict = alias_dictionary(state_alias(sim.model))
return Path(sim, ts_dict, state_alias_dict, cxt, ip)
end
"""
_check_unique_ts(ts_alias::AbstractVector)
Check for consistent term structure inputs to path.
We define an extra function in order to avoid chain rule issues with
automatic differentiation.
"""
function _check_unique_ts(ts_alias::AbstractVector)
@assert length(ts_alias) == length(unique(ts_alias))
end
"""
path(
sim::Simulation,
ts::Vector{Termstructure},
cxt::Context,
ip::PathInterpolation = NoPathInterpolation
)
Create a Path object from a list of term structures.
"""
function path(
sim::Simulation,
ts::Vector{<:Termstructure},
cxt::Context,
ip::PathInterpolation = NoPathInterpolation
)
#
ts_alias = [ alias(ts_) for ts_ in ts ]
_check_unique_ts(ts_alias)
#
ts_dict = Dict{String,Termstructure}(((alias(ts_), ts_) for ts_ in ts))
return path(sim, ts_dict, cxt, ip)
end
"""
length(p::Path)
Derive the number of realisations from the linked simulation.
"""
length(p::Path) = size(p.sim.X, 2)
"""
state_variable(sim::Simulation, t::ModelTime, ip::PathInterpolation)
Derive a state variable for a given observation time.
"""
function state_variable(sim::Simulation, t::ModelTime, ip::PathInterpolation)
eps = 0.5 / 365 # we want to give a bit tolerance in avoiding interpolation
idx = searchsortedfirst(sim.times, t)
if idx <= length(sim.times) && t > sim.times[idx] - eps
return @view sim.X[:,:,idx]
end
if idx > 1 && t < sim.times[idx-1] + eps
return @view sim.X[:,:,idx-1]
end
# if we end up here we need some interpolation/extrapolation
@assert ip != NoPathInterpolation
# we assume constant extrapolation
if idx == 1
return @view sim.X[:,:,idx]
end
if idx > length(sim.times)
return @view sim.X[:,:,idx-1]
end
# now we have 1 < idx <= length(sim.times)
if ip == LinearPathInterpolation
rho = (t - sim.times[idx-1]) / (sim.times[idx] - sim.times[idx-1])
return rho .* @view(sim.X[:,:,idx]) .+ (1.0-rho) .* @view(sim.X[:,:,idx-1])
end
error("Unknown PathInterpolation.")
end