1 /* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 
3 /*
4  Copyright (C) 2008, 2016 Jose Aparicio
5  Copyright (C) 2008 Chris Kenyon
6  Copyright (C) 2008 Roland Lichters
7  Copyright (C) 2008 StatPro Italia srl
8  Copyright (C) 2009, 2011 Ferdinando Ametrano
9 
10  This file is part of QuantLib, a free-software/open-source library
11  for financial quantitative analysts and developers - http://quantlib.org/
12 
13  QuantLib is free software: you can redistribute it and/or modify it
14  under the terms of the QuantLib license.  You should have received a
15  copy of the license along with this program; if not, please email
16  <quantlib-dev@lists.sf.net>. The license is also available online at
17  <http://quantlib.org/license.shtml>.
18 
19  This program is distributed in the hope that it will be useful, but WITHOUT
20  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
21  FOR A PARTICULAR PURPOSE.  See the license for more details.
22 */
23 
24 /*! \file probabilitytraits.hpp
25     \brief default-probability bootstrap traits
26 */
27 
28 #ifndef ql_probability_traits_hpp
29 #define ql_probability_traits_hpp
30 
31 #include <ql/termstructures/credit/interpolatedsurvivalprobabilitycurve.hpp>
32 #include <ql/termstructures/credit/interpolatedhazardratecurve.hpp>
33 #include <ql/termstructures/credit/interpolateddefaultdensitycurve.hpp>
34 #include <ql/termstructures/bootstraphelper.hpp>
35 
36 namespace QuantLib {
37 
38     namespace detail {
39         const Real avgHazardRate = 0.01;
40         const Real maxHazardRate = 1.0;
41     }
42 
43     //! Survival-Probability-curve traits
44     struct SurvivalProbability {
45         // interpolated curve type
46         template <class Interpolator>
47         struct curve {
48             typedef InterpolatedSurvivalProbabilityCurve<Interpolator> type;
49         };
50         // helper class
51         typedef BootstrapHelper<DefaultProbabilityTermStructure> helper;
52 
53         // start of curve data
initialDateQuantLib::SurvivalProbability54         static Date initialDate(const DefaultProbabilityTermStructure* c) {
55             return c->referenceDate();
56         }
57         // value at reference date
initialValueQuantLib::SurvivalProbability58         static Real initialValue(const DefaultProbabilityTermStructure*) {
59             return 1.0;
60         }
61 
62         // guesses
63         template <class C>
guessQuantLib::SurvivalProbability64         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::avgHazardRate*0.25);
74 
75             // extrapolate
76             Date d = c->dates()[i];
77             return c->survivalProbability(d,true);
78         }
79         // constraints
80         template <class C>
minValueAfterQuantLib::SurvivalProbability81         static Real minValueAfter(Size i,
82                                   const C* c,
83                                   bool validData,
84                                   Size) // firstAliveHelper
85         {
86             if (validData) {
87                 return c->data().back()/2.0;
88             }
89             Time dt = c->times()[i] - c->times()[i-1];
90             return c->data()[i-1] * std::exp(- detail::maxHazardRate * dt);
91         }
92         template <class C>
maxValueAfterQuantLib::SurvivalProbability93         static Real maxValueAfter(Size i,
94                                   const C* c,
95                                   bool validData,
96                                   Size) // firstAliveHelper
97         {
98             // survival probability cannot increase
99             return c->data()[i-1];
100         }
101 
102         // root-finding update
updateGuessQuantLib::SurvivalProbability103         static void updateGuess(std::vector<Real>& data,
104                                 Probability p,
105                                 Size i) {
106             data[i] = p;
107         }
108         // upper bound for convergence loop
maxIterationsQuantLib::SurvivalProbability109         static Size maxIterations() { return 50; }
110     };
111 
112 
113 
114     //! Hazard-rate-curve traits
115     struct HazardRate {
116         // interpolated curve type
117         template <class Interpolator>
118         struct curve {
119             typedef InterpolatedHazardRateCurve<Interpolator> type;
120         };
121         // helper class
122         typedef BootstrapHelper<DefaultProbabilityTermStructure> helper;
123 
124         // start of curve data
initialDateQuantLib::HazardRate125         static Date initialDate(const DefaultProbabilityTermStructure* c) {
126             return c->referenceDate();
127         }
128         // dummy value at reference date
initialValueQuantLib::HazardRate129         static Real initialValue(const DefaultProbabilityTermStructure*) {
130             return detail::avgHazardRate;
131         }
132 
133         // guesses
134         template <class C>
guessQuantLib::HazardRate135         static Real guess(Size i,
136                           const C* c,
137                           bool validData,
138                           Size) // firstAliveHelper
139         {
140             if (validData) // previous iteration value
141                 return c->data()[i];
142 
143             if (i==1) // first pillar
144                 return detail::avgHazardRate;
145 
146             // extrapolate
147             Date d = c->dates()[i];
148             return c->hazardRate(d, true);
149         }
150 
151         // constraints
152         template <class C>
minValueAfterQuantLib::HazardRate153         static Real minValueAfter(Size i,
154                                   const C* c,
155                                   bool validData,
156                                   Size) // firstAliveHelper
157         {
158             if (validData) {
159                 Real r = *(std::min_element(c->data().begin(), c->data().end()));
160                 return r/2.0;
161             }
162             return QL_EPSILON;
163         }
164         template <class C>
maxValueAfterQuantLib::HazardRate165         static Real maxValueAfter(Size i,
166                                   const C* c,
167                                   bool validData,
168                                   Size) // firstAliveHelper
169         {
170             if (validData) {
171                 Real r = *(std::max_element(c->data().begin(), c->data().end()));
172                 return r*2.0;
173             }
174             // no constraints.
175             // We choose as max a value very unlikely to be exceeded.
176             return detail::maxHazardRate;
177         }
178         // update with new guess
updateGuessQuantLib::HazardRate179         static void updateGuess(std::vector<Real>& data,
180                                 Real rate,
181                                 Size i) {
182             data[i] = rate;
183             if (i==1)
184                 data[0] = rate; // first point is updated as well
185         }
186         // upper bound for convergence loop
maxIterationsQuantLib::HazardRate187         static Size maxIterations() { return 30; }
188     };
189 
190 
191     //! Default-density-curve traits
192     struct DefaultDensity {
193         // interpolated curve type
194         template <class Interpolator>
195         struct curve {
196             typedef InterpolatedDefaultDensityCurve<Interpolator> type;
197         };
198         // helper class
199         typedef BootstrapHelper<DefaultProbabilityTermStructure> helper;
200         // start of curve data
initialDateQuantLib::DefaultDensity201         static Date initialDate(const DefaultProbabilityTermStructure* c) {
202             return c->referenceDate();
203         }
204         // value at reference date
initialValueQuantLib::DefaultDensity205         static Real initialValue(const DefaultProbabilityTermStructure*) {
206             return detail::avgHazardRate;
207         }
208 
209         // guesses
210         template <class C>
guessQuantLib::DefaultDensity211         static Real guess(Size i,
212                           const C* c,
213                           bool validData,
214                           Size) // firstAliveHelper
215         {
216             if (validData) // previous iteration value
217                 return c->data()[i];
218 
219             if (i==1) // first pillar
220                 return detail::avgHazardRate;
221 
222             // extrapolate
223             Date d = c->dates()[i];
224             return c->defaultDensity(d, true);
225         }
226 
227         // constraints
228         template <class C>
minValueAfterQuantLib::DefaultDensity229         static Real minValueAfter(Size i,
230                                   const C* c,
231                                   bool validData,
232                                   Size) // firstAliveHelper
233         {
234             if (validData) {
235                 Real r = *(std::min_element(c->data().begin(), c->data().end()));
236                 return r/2.0;
237             }
238             return QL_EPSILON;
239         }
240         template <class C>
maxValueAfterQuantLib::DefaultDensity241         static Real maxValueAfter(Size i,
242                                   const C* c,
243                                   bool validData,
244                                   Size) // firstAliveHelper
245         {
246             if (validData) {
247                 Real r = *(std::max_element(c->data().begin(), c->data().end()));
248                 return r*2.0;
249             }
250             // no constraints.
251             // We choose as max a value very unlikely to be exceeded.
252             return detail::maxHazardRate;
253         }
254 
255         // update with new guess
updateGuessQuantLib::DefaultDensity256         static void updateGuess(std::vector<Real>& data,
257                                 Real density,
258                                 Size i) {
259             data[i] = density;
260             if (i==1)
261                 data[0] = density; // first point is updated as well
262         }
263         // upper bound for convergence loop
maxIterationsQuantLib::DefaultDensity264         static Size maxIterations() { return 30; }
265     };
266 
267 }
268 
269 #endif
270