QuantLib: a free/open-source library for quantitative finance
fully annotated source code - version 1.38
Loading...
Searching...
No Matches
gsrprocesscore.cpp
Go to the documentation of this file.
1/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3/*
4 Copyright (C) 2015 Peter Caspers
5
6 This file is part of QuantLib, a free-software/open-source library
7 for financial quantitative analysts and developers - http://quantlib.org/
8
9 QuantLib is free software: you can redistribute it and/or modify it
10 under the terms of the QuantLib license. You should have received a
11 copy of the license along with this program; if not, please email
12 <quantlib-dev@lists.sf.net>. The license is also available online at
13 <http://quantlib.org/license.shtml>.
14
15 This program is distributed in the hope that it will be useful, but WITHOUT
16 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17 FOR A PARTICULAR PURPOSE. See the license for more details.
18*/
19
21#include <cmath>
22
23using std::exp;
24using std::pow;
25
26namespace QuantLib::detail {
27
28GsrProcessCore::GsrProcessCore(const Array &times, const Array &vols,
29 const Array &reversions, const Real T)
30 : times_(times), vols_(vols), reversions_(reversions),
31 T_(T), revZero_(reversions.size(), false) {
32
33 QL_REQUIRE(times.size() == vols.size() - 1,
34 "number of volatilities ("
35 << vols.size() << ") compared to number of times ("
36 << times_.size() << " must be bigger by one");
37 QL_REQUIRE(times.size() == reversions.size() - 1 || reversions.size() == 1,
38 "number of reversions ("
39 << vols.size() << ") compared to number of times ("
40 << times_.size() << " must be bigger by one, or exactly "
41 "1 reversion must be given");
42 for (int i = 0; i < ((int)times.size()) - 1; i++)
43 QL_REQUIRE(times[i] < times[i + 1], "times must be increasing ("
44 << times[i] << "@" << i << " , "
45 << times[i + 1] << "@" << i + 1
46 << ")");
47 flushCache();
48}
49
51 for (int i = 0; i < (int)reversions_.size(); i++)
52 // small reversions cause numerical problems, so we keep them
53 // away from zero
54 if (std::fabs(reversions_[i]) < 1E-4)
55 revZero_[i] = true;
56 else
57 revZero_[i] = false;
58 cache1_.clear();
59 cache2a_.clear();
60 cache2b_.clear();
61 cache3_.clear();
62 cache4_.clear();
63 cache5_.clear();
64}
65
67 const Time dt) const {
68 Real t = w + dt;
69 std::pair<Real, Real> key;
70 key = std::make_pair(w, t);
71 auto k = cache1_.find(key);
72 if (k != cache1_.end())
73 return xw * (k->second);
74 // A(w,t)x(w)
75 Real res2 = 1.0;
76 for (int i = lowerIndex(w); i <= upperIndex(t) - 1; i++) {
77 res2 *= exp(-rev(i) * (cappedTime(i + 1, t) - flooredTime(i, w)));
78 }
79 cache1_.insert(std::make_pair(key, res2));
80 return res2 * xw;
81}
82
84 const Time dt) const {
85
86 Real t = w + dt;
87
88 std::pair<Real, Real> key;
89 key = std::make_pair(w, t);
90 auto k =
91 cache2a_.find(key);
92 if (k != cache2a_.end())
93 return k->second;
94
95 Real res = 0.0;
96
97 // \int A(s,t)y(s)
98 for (int k = lowerIndex(w); k <= upperIndex(t) - 1; k++) {
99 // l<k
100 for (int l = 0; l <= k - 1; l++) {
101 Real res2 = 1.0;
102 // alpha_l
103 res2 *= revZero(l) ? Real(vol(l) * vol(l) * (time2(l + 1) - time2(l)))
104 : vol(l) * vol(l) / (2.0 * rev(l)) *
105 (1.0 - exp(-2.0 * rev(l) *
106 (time2(l + 1) - time2(l))));
107 // zeta_i (i>k)
108 for (int i = k + 1; i <= upperIndex(t) - 1; i++)
109 res2 *= exp(-rev(i) * (cappedTime(i + 1, t) - time2(i)));
110 // beta_j (j<k)
111 for (int j = l + 1; j <= k - 1; j++)
112 res2 *= exp(-2.0 * rev(j) * (time2(j + 1) - time2(j)));
113 // zeta_k beta_k
114 res2 *=
115 revZero(k)
116 ? Real(2.0 * time2(k) - flooredTime(k, w) -
117 cappedTime(k + 1, t) -
118 2.0 * (time2(k) - cappedTime(k + 1, t)))
119 : Real((exp(rev(k) * (2.0 * time2(k) - flooredTime(k, w) -
120 cappedTime(k + 1, t))) -
121 exp(2.0 * rev(k) * (time2(k) - cappedTime(k + 1, t)))) /
122 rev(k));
123 // add to sum
124 res += res2;
125 }
126 // l=k
127 Real res2 = 1.0;
128 // alpha_k zeta_k
129 res2 *=
130 revZero(k)
131 ? Real(vol(k) * vol(k) / 4.0 *
132 (4.0 * pow(cappedTime(k + 1, t) - time2(k), 2.0) -
133 (pow(flooredTime(k, w) - 2.0 * time2(k) +
134 cappedTime(k + 1, t),
135 2.0) +
136 pow(cappedTime(k + 1, t) - flooredTime(k, w), 2.0))))
137 : Real(vol(k) * vol(k) / (2.0 * rev(k) * rev(k)) *
138 (exp(-2.0 * rev(k) * (cappedTime(k + 1, t) - time2(k))) +
139 1.0 -
140 (exp(-rev(k) * (flooredTime(k, w) - 2.0 * time2(k) +
141 cappedTime(k + 1, t))) +
142 exp(-rev(k) *
143 (cappedTime(k + 1, t) - flooredTime(k, w))))));
144 // zeta_i (i>k)
145 for (int i = k + 1; i <= upperIndex(t) - 1; i++)
146 res2 *= exp(-rev(i) * (cappedTime(i + 1, t) - time2(i)));
147 // no beta_j in this case ...
148 res += res2;
149 }
150
151 cache2a_.insert(std::make_pair(key, res));
152
153 return res;
154} // expectation_rn_part
155
157 const Time dt) const {
158
159 Real t = w + dt;
160
161 std::pair<Real, Real> key;
162 key = std::make_pair(w, t);
163 auto k =
164 cache2b_.find(key);
165 if (k != cache2b_.end())
166 return k->second;
167
168 Real res = 0.0;
169 // int -A(s,t) \sigma^2 G(s,T)
170 for (int k = lowerIndex(w); k <= upperIndex(t) - 1; k++) {
171 Real res2 = 0.0;
172 // l>k
173 for (int l = k + 1; l <= upperIndex(T_) - 1; l++) {
174 Real res3 = 1.0;
175 // eta_l
176 res3 *= revZero(l)
177 ? Real(cappedTime(l + 1, T_) - time2(l))
178 : (1.0 -
179 exp(-rev(l) * (cappedTime(l + 1, T_) - time2(l)))) /
180 rev(l);
181 // zeta_i (i>k)
182 for (int i = k + 1; i <= upperIndex(t) - 1; i++)
183 res3 *= exp(-rev(i) * (cappedTime(i + 1, t) - time2(i)));
184 // gamma_j (j>k)
185 for (int j = k + 1; j <= l - 1; j++)
186 res3 *= exp(-rev(j) * (time2(j + 1) - time2(j)));
187 // zeta_k gamma_k
188 res3 *=
189 revZero(k)
190 ? Real((cappedTime(k + 1, t) - time2(k + 1) -
191 (2.0 * flooredTime(k, w) - cappedTime(k + 1, t) -
192 time2(k + 1))) /
193 2.0)
194 : Real((exp(rev(k) * (cappedTime(k + 1, t) - time2(k + 1))) -
195 exp(rev(k) * (2.0 * flooredTime(k, w) -
196 cappedTime(k + 1, t) - time2(k + 1)))) /
197 (2.0 * rev(k)));
198 // add to sum
199 res2 += res3;
200 }
201 // l=k
202 Real res3 = 1.0;
203 // eta_k zeta_k
204 res3 *=
205 revZero(k)
206 ? Real((-pow(cappedTime(k + 1, t) - cappedTime(k + 1, T_), 2.0) -
207 2.0 * pow(cappedTime(k + 1, t) - flooredTime(k, w), 2.0) +
208 pow(2.0 * flooredTime(k, w) - cappedTime(k + 1, T_) -
209 cappedTime(k + 1, t),
210 2.0)) /
211 4.0)
212 : Real((2.0 - exp(rev(k) *
213 (cappedTime(k + 1, t) - cappedTime(k + 1, T_))) -
214 (2.0 * exp(-rev(k) *
215 (cappedTime(k + 1, t) - flooredTime(k, w))) -
216 exp(rev(k) *
217 (2.0 * flooredTime(k, w) - cappedTime(k + 1, T_) -
218 cappedTime(k + 1, t))))) /
219 (2.0 * rev(k) * rev(k)));
220 // zeta_i (i>k)
221 for (int i = k + 1; i <= upperIndex(t) - 1; i++)
222 res3 *= exp(-rev(i) * (cappedTime(i + 1, t) - time2(i)));
223 // no gamma_j in this case ...
224 res2 += res3;
225 // add to main accumulator
226 res += -vol(k) * vol(k) * res2;
227 }
228
229 cache2b_.insert(std::make_pair(key, res));
230
231 return res;
232} // expectation_tf_part
233
234Real GsrProcessCore::variance(const Time w, const Time dt) const {
235
236 Real t = w + dt;
237
238 std::pair<Real, Real> key;
239 key = std::make_pair(w, t);
240 auto k = cache3_.find(key);
241 if (k != cache3_.end())
242 return k->second;
243
244 Real res = 0.0;
245 for (int k = lowerIndex(w); k <= upperIndex(t) - 1; k++) {
246 Real res2 = vol(k) * vol(k);
247 // zeta_k^2
248 res2 *= revZero(k)
249 ? Real(-(flooredTime(k, w) - cappedTime(k + 1, t)))
250 : (1.0 - exp(2.0 * rev(k) *
251 (flooredTime(k, w) - cappedTime(k + 1, t)))) /
252 (2.0 * rev(k));
253 // zeta_i (i>k)
254 for (int i = k + 1; i <= upperIndex(t) - 1; i++) {
255 res2 *= exp(-2.0 * rev(i) * (cappedTime(i + 1, t) - time2(i)));
256 }
257 res += res2;
258 }
259
260 cache3_.insert(std::make_pair(key, res));
261 return res;
262}
263
265 Real key;
266 key = t;
267 auto k = cache4_.find(key);
268 if (k != cache4_.end())
269 return k->second;
270
271 Real res = 0.0;
272 for (int i = 0; i <= upperIndex(t) - 1; i++) {
273 Real res2 = 1.0;
274 for (int j = i + 1; j <= upperIndex(t) - 1; j++) {
275 res2 *= exp(-2.0 * rev(j) * (cappedTime(j + 1, t) - time2(j)));
276 }
277 res2 *= revZero(i) ? Real(vol(i) * vol(i) * (cappedTime(i + 1, t) - time2(i)))
278 : (vol(i) * vol(i) / (2.0 * rev(i)) *
279 (1.0 - exp(-2.0 * rev(i) *
280 (cappedTime(i + 1, t) - time2(i)))));
281 res += res2;
282 }
283
284 cache4_.insert(std::make_pair(key, res));
285 return res;
286}
287
288Real GsrProcessCore::G(const Time t, const Time w) const {
289 std::pair<Real, Real> key;
290 key = std::make_pair(w, t);
291 auto k = cache5_.find(key);
292 if (k != cache5_.end())
293 return k->second;
294
295 Real res = 0.0;
296 for (int i = lowerIndex(t); i <= upperIndex(w) - 1; i++) {
297 Real res2 = 1.0;
298 for (int j = lowerIndex(t); j <= i - 1; j++) {
299 res2 *= exp(-rev(j) * (time2(j + 1) - flooredTime(j, t)));
300 }
301 res2 *= revZero(i) ? Real(cappedTime(i + 1, w) - flooredTime(i, t))
302 : (1.0 - exp(-rev(i) * (cappedTime(i + 1, w) -
303 flooredTime(i, t)))) /
304 rev(i);
305 res += res2;
306 }
307
308 cache5_.insert(std::make_pair(key, res));
309 return res;
310}
311
313 return static_cast<int>(std::upper_bound(times_.begin(), times_.end(), t) -
314 times_.begin());
315}
316
319 return 0;
320 return static_cast<int>(
321 std::upper_bound(times_.begin(), times_.end(), t - QL_EPSILON) -
322 times_.begin()) +
323 1;
324}
325
326Real GsrProcessCore::cappedTime(const Size index, const Real cap) const {
327 return cap != Null<Real>() ? std::min(cap, time2(index)) : time2(index);
328}
329
331 const Real floor) const {
332 return floor != Null<Real>() ? std::max(floor, time2(index)) : time2(index);
333}
334
335Real GsrProcessCore::time2(const Size index) const {
336 if (index == 0)
337 return 0.0;
338 if (index > times_.size())
339 return T_; // FIXME how to ensure that forward
340 // measure time is geq all times
341 // given
342 return times_[index - 1];
343}
344
345Real GsrProcessCore::vol(const Size index) const {
346 if (index >= vols_.size())
347 return vols_.back();
348 return vols_[index];
349}
350
351Real GsrProcessCore::rev(const Size index) const {
352 if (index >= reversions_.size())
353 return reversions_.back();
354 return reversions_[index];
355}
356
357bool GsrProcessCore::revZero(const Size index) const {
358 if (index >= revZero_.size())
359 return revZero_.back();
360 return revZero_[index];
361}
362
363} // namesapce QuantLib
1-D array used in linear algebra.
Definition: array.hpp:52
const_iterator end() const
Definition: array.hpp:499
Real back() const
Definition: array.hpp:446
Size size() const
dimension of the array
Definition: array.hpp:483
const_iterator begin() const
Definition: array.hpp:491
template class providing a null value for a given type.
Definition: null.hpp:59
Real cappedTime(Size index, Real cap=Null< Real >()) const
GsrProcessCore(const Array &times, const Array &vols, const Array &reversions, Real T=60.0)
Real expectation_x0dep_part(Time w, Real xw, Time dt) const
std::map< Real, Real > cache4_
Real expectation_rn_part(Time w, Time dt) const
Real flooredTime(Size index, Real floor=Null< Real >()) const
std::map< std::pair< Real, Real >, Real > cache2a_
Real expectation_tf_part(Time w, Time dt) const
std::map< std::pair< Real, Real >, Real > cache1_
bool revZero(Size index) const
std::map< std::pair< Real, Real >, Real > cache2b_
std::map< std::pair< Real, Real >, Real > cache3_
Real G(Time t, Time w) const
std::map< std::pair< Real, Real >, Real > cache5_
Real variance(Time w, Time dt) const
const DefaultType & t
#define QL_REQUIRE(condition, message)
throw an error if the given pre-condition is not verified
Definition: errors.hpp:117
#define QL_EPSILON
Definition: qldefines.hpp:178
#define QL_MIN_POSITIVE_REAL
Definition: qldefines.hpp:177
Real Time
continuous quantity with 1-year units
Definition: types.hpp:62
QL_REAL Real
real number
Definition: types.hpp:50
std::size_t Size
size of a container
Definition: types.hpp:58
Core computations for the gsr process in risk neutral and T-forward measure.