Coverage Report

Created: 2025-12-08 06:13

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/quantlib/ql/termstructures/yield/bootstraptraits.hpp
Line
Count
Source
1
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3
/*
4
 Copyright (C) 2005, 2007 StatPro Italia srl
5
 Copyright (C) 2011 Ferdinando Ametrano
6
 Copyright (C) 2007 Chris Kenyon
7
 Copyright (C) 2019 SoftSolutions! S.r.l.
8
9
 This file is part of QuantLib, a free-software/open-source library
10
 for financial quantitative analysts and developers - http://quantlib.org/
11
12
 QuantLib is free software: you can redistribute it and/or modify it
13
 under the terms of the QuantLib license.  You should have received a
14
 copy of the license along with this program; if not, please email
15
 <quantlib-dev@lists.sf.net>. The license is also available online at
16
 <https://www.quantlib.org/license.shtml>.
17
18
 This program is distributed in the hope that it will be useful, but WITHOUT
19
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
20
 FOR A PARTICULAR PURPOSE.  See the license for more details.
21
*/
22
23
/*! \file bootstraptraits.hpp
24
    \brief bootstrap traits
25
*/
26
27
#ifndef ql_bootstrap_traits_hpp
28
#define ql_bootstrap_traits_hpp
29
30
#include <ql/termstructures/yield/discountcurve.hpp>
31
#include <ql/termstructures/yield/zerocurve.hpp>
32
#include <ql/termstructures/yield/interpolatedsimplezerocurve.hpp>
33
#include <ql/termstructures/yield/forwardcurve.hpp>
34
#include <ql/termstructures/bootstraphelper.hpp>
35
36
namespace QuantLib {
37
38
    namespace detail {
39
        const Real avgRate = 0.05;
40
        const Real maxRate = 1.0;
41
    }
42
43
    //! Discount-curve traits
44
    struct Discount {
45
        // interpolated curve type
46
        template <class Interpolator>
47
        struct curve {
48
            typedef InterpolatedDiscountCurve<Interpolator> type;
49
        };
50
        // helper class
51
        typedef BootstrapHelper<YieldTermStructure> helper;
52
53
        // start of curve data
54
0
        static Date initialDate(const YieldTermStructure* c) {
55
0
            return c->referenceDate();
56
0
        }
57
        // value at reference date
58
0
        static Real initialValue(const YieldTermStructure*) {
59
0
            return 1.0;
60
0
        }
61
62
        // guesses
63
        template <class C>
64
        static Real guess(Size i,
65
                          const C* c,
66
                          bool validData,
67
                          Size) // firstAliveHelper
68
        {
69
            if (validData) // previous iteration value
70
                return c->data()[i];
71
72
            if (i==1) // first pillar
73
                return 1.0/(1.0+detail::avgRate*c->times()[1]);
74
75
            // flat rate extrapolation
76
            Real r = -std::log(c->data()[i-1])/c->times()[i-1];
77
            return std::exp(-r * c->times()[i]);
78
        }
79
80
        // possible constraints based on previous values
81
        template <class C>
82
        static Real minValueAfter(Size i,
83
                                  const C* c,
84
                                  bool validData,
85
                                  Size) // firstAliveHelper
86
        {
87
            if (validData) {
88
                return *(std::min_element(c->data().begin(),
89
                                          c->data().end()))/2.0;
90
            }
91
            Time dt = c->times()[i] - c->times()[i-1];
92
            return c->data()[i-1] * std::exp(- detail::maxRate * dt);
93
        }
94
        template <class C>
95
        static Real maxValueAfter(Size i,
96
                                  const C* c,
97
                                  bool validData,
98
                                  Size) // firstAliveHelper
99
        {
100
            Time dt = c->times()[i] - c->times()[i-1];
101
            return c->data()[i-1] * std::exp(detail::maxRate * dt);
102
        }
103
104
        // transformation to add constraints to an unconstrained optimization
105
        template <class C>
106
        static Real transformDirect(Real x, Size i, const C* c)
107
        {
108
            return std::exp(x);
109
        }
110
        template <class C>
111
        static Real transformInverse(Real x, Size i, const C* c)
112
        {
113
            return std::log(x);
114
        }
115
116
        // root-finding update
117
        static void updateGuess(std::vector<Real>& data,
118
                                Real discount,
119
0
                                Size i) {
120
0
            data[i] = discount;
121
0
        }
122
        // upper bound for convergence loop
123
0
        static Size maxIterations() { return 100; }
124
    };
125
126
127
    //! Zero-curve traits
128
    struct ZeroYield {
129
        // interpolated curve type
130
        template <class Interpolator>
131
        struct curve {
132
            typedef InterpolatedZeroCurve<Interpolator> type;
133
        };
134
        // helper class
135
        typedef BootstrapHelper<YieldTermStructure> helper;
136
137
        // start of curve data
138
0
        static Date initialDate(const YieldTermStructure* c) {
139
0
            return c->referenceDate();
140
0
        }
141
        // dummy value at reference date
142
0
        static Real initialValue(const YieldTermStructure*) {
143
0
            return detail::avgRate;
144
0
        }
145
146
        // guesses
147
        template <class C>
148
        static Real guess(Size i,
149
                          const C* c,
150
                          bool validData,
151
                          Size) // firstAliveHelper
152
        {
153
            if (validData) // previous iteration value
154
                return c->data()[i];
155
156
            if (i==1) // first pillar
157
                return detail::avgRate;
158
159
            // extrapolate
160
            Date d = c->dates()[i];
161
            return c->zeroRate(d, c->dayCounter(),
162
                               Continuous, Annual, true);
163
        }
164
165
        // possible constraints based on previous values
166
        template <class C>
167
        static Real minValueAfter(Size,
168
                                  const C* c,
169
                                  bool validData,
170
                                  Size) // firstAliveHelper
171
        {
172
            if (validData) {
173
                Real r = *(std::min_element(c->data().begin(), c->data().end()));
174
                return r<0.0 ? Real(r*2.0) : Real(r/2.0);
175
            }
176
            // no constraints.
177
            // We choose as min a value very unlikely to be exceeded.
178
            return -detail::maxRate;
179
        }
180
        template <class C>
181
        static Real maxValueAfter(Size,
182
                                  const C* c,
183
                                  bool validData,
184
                                  Size) // firstAliveHelper
185
        {
186
            if (validData) {
187
                Real r = *(std::max_element(c->data().begin(), c->data().end()));
188
                return r<0.0 ? Real(r/2.0) : Real(r*2.0);
189
            }
190
            // no constraints.
191
            // We choose as max a value very unlikely to be exceeded.
192
            return detail::maxRate;
193
        }
194
195
        // transformation to add constraints to an unconstrained optimization
196
        template <class C>
197
        static Real transformDirect(Real x, Size i, const C* c)
198
        {
199
            return x;
200
        }
201
        template <class C>
202
        static Real transformInverse(Real x, Size i, const C* c)
203
        {
204
            return x;
205
        }
206
207
        // root-finding update
208
        static void updateGuess(std::vector<Real>& data,
209
                                Real rate,
210
0
                                Size i) {
211
0
            data[i] = rate;
212
0
            if (i==1)
213
0
                data[0] = rate; // first point is updated as well
214
0
        }
215
        // upper bound for convergence loop
216
0
        static Size maxIterations() { return 100; }
217
    };
218
219
220
    //! Forward-curve traits
221
    struct ForwardRate {
222
        // interpolated curve type
223
        template <class Interpolator>
224
        struct curve {
225
            typedef InterpolatedForwardCurve<Interpolator> type;
226
        };
227
        // helper class
228
        typedef BootstrapHelper<YieldTermStructure> helper;
229
230
        // start of curve data
231
0
        static Date initialDate(const YieldTermStructure* c) {
232
0
            return c->referenceDate();
233
0
        }
234
        // dummy value at reference date
235
0
        static Real initialValue(const YieldTermStructure*) {
236
0
            return detail::avgRate;
237
0
        }
238
239
        // guesses
240
        template <class C>
241
        static Real guess(Size i,
242
                          const C* c,
243
                          bool validData,
244
                          Size) // firstAliveHelper
245
        {
246
            if (validData) // previous iteration value
247
                return c->data()[i];
248
249
            if (i==1) // first pillar
250
                return detail::avgRate;
251
252
            // extrapolate
253
            Date d = c->dates()[i];
254
            return c->forwardRate(d, d, c->dayCounter(),
255
                                  Continuous, Annual, true);
256
        }
257
258
        // possible constraints based on previous values
259
        template <class C>
260
        static Real minValueAfter(Size,
261
                                  const C* c,
262
                                  bool validData,
263
                                  Size) // firstAliveHelper
264
        {
265
            if (validData) {
266
                Real r = *(std::min_element(c->data().begin(), c->data().end()));
267
                return r<0.0 ? Real(r*2.0) : Real(r/2.0);
268
            }
269
            // no constraints.
270
            // We choose as min a value very unlikely to be exceeded.
271
            return -detail::maxRate;
272
        }
273
        template <class C>
274
        static Real maxValueAfter(Size,
275
                                  const C* c,
276
                                  bool validData,
277
                                  Size) // firstAliveHelper
278
        {
279
            if (validData) {
280
                Real r = *(std::max_element(c->data().begin(), c->data().end()));
281
                return r<0.0 ? Real(r/2.0) : Real(r*2.0);
282
            }
283
            // no constraints.
284
            // We choose as max a value very unlikely to be exceeded.
285
            return detail::maxRate;
286
        }
287
288
        // transformation to add constraints to an unconstrained optimization
289
        template <class C>
290
        static Real transformDirect(Real x, Size i, const C* c)
291
        {
292
            return x;
293
        }
294
        template <class C>
295
        static Real transformInverse(Real x, Size i, const C* c)
296
        {
297
            return x;
298
        }
299
300
        // root-finding update
301
        static void updateGuess(std::vector<Real>& data,
302
                                Real forward,
303
0
                                Size i) {
304
0
            data[i] = forward;
305
0
            if (i==1)
306
0
                data[0] = forward; // first point is updated as well
307
0
        }
308
        // upper bound for convergence loop
309
0
        static Size maxIterations() { return 100; }
310
    };
311
312
    //! Simple Zero-curve traits
313
    struct SimpleZeroYield {
314
        // interpolated curve type
315
        template <class Interpolator>
316
        struct curve {
317
            typedef InterpolatedSimpleZeroCurve<Interpolator> type;
318
        };
319
        // helper class
320
        typedef BootstrapHelper<YieldTermStructure> helper;
321
322
        // start of curve data
323
0
        static Date initialDate(const YieldTermStructure* c) {
324
0
            return c->referenceDate();
325
0
        }
326
        // dummy value at reference date
327
0
        static Real initialValue(const YieldTermStructure*) {
328
0
            return detail::avgRate;
329
0
        }
330
331
        // guesses
332
        template <class C>
333
        static Real guess(Size i,
334
                          const C* c,
335
                          bool validData,
336
                          Size) // firstAliveHelper
337
        {
338
            if (validData) // previous iteration value
339
                return c->data()[i];
340
341
            if (i==1) // first pillar
342
                return detail::avgRate;
343
344
            // extrapolate
345
            Date d = c->dates()[i];
346
            return c->zeroRate(d, c->dayCounter(),
347
                               Simple, Annual, true);
348
        }
349
350
        // possible constraints based on previous values
351
        template <class C>
352
        static Real minValueAfter(Size i,
353
                                  const C* c,
354
                                  bool validData,
355
                                  Size) // firstAliveHelper
356
        {
357
            Real result;
358
            if (validData) {
359
                Real r = *(std::min_element(c->data().begin(), c->data().end()));
360
                result = r<0.0 ? Real(r*2.0) : r/2.0;
361
            } else {
362
                // no constraints.
363
                // We choose as min a value very unlikely to be exceeded.
364
                result = -detail::maxRate;
365
            }
366
            return std::max(result, -1.0 / c->times()[i] + 1E-8);
367
        }
368
        template <class C>
369
        static Real maxValueAfter(Size,
370
                                  const C* c,
371
                                  bool validData,
372
                                  Size) // firstAliveHelper
373
        {
374
            if (validData) {
375
                Real r = *(std::max_element(c->data().begin(), c->data().end()));
376
                return r<0.0 ? Real(r/2.0) : r*2.0;
377
            }
378
            // no constraints.
379
            // We choose as max a value very unlikely to be exceeded.
380
            return detail::maxRate;
381
        }
382
383
        // transformation to add constraints to an unconstrained optimization
384
        template <class C>
385
        static Real transformDirect(Real x, Size i, const C* c)
386
        {
387
            return std::exp(x) + (-1.0 / c->times()[i] + 1E-8);
388
        }
389
        template <class C>
390
        static Real transformInverse(Real x, Size i, const C* c)
391
        {
392
            return std::log(x - (-1.0 / c->times()[i] + 1E-8));
393
        }
394
395
        // root-finding update
396
        static void updateGuess(std::vector<Real>& data,
397
                                Real rate,
398
0
                                Size i) {
399
0
            data[i] = rate;
400
0
            if (i==1)
401
0
                data[0] = rate; // first point is updated as well
402
0
        }
403
        // upper bound for convergence loop
404
0
        static Size maxIterations() { return 100; }
405
    };
406
407
408
}
409
410
#endif