QuantLib: a free/open-source library for quantitative finance
fully annotated source code - version 1.34
Loading...
Searching...
No Matches
defaultprobabilitylatentmodel.hpp
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) 2014 Jose Aparicio
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
20#ifndef quantlib_default_latent_model_hpp
21#define quantlib_default_latent_model_hpp
22
26#include <boost/dynamic_bitset.hpp>
27
28namespace QuantLib {
29
30 /*! \brief Default event Latent Model.
31
32 This is a model for joint default events based on a generic Latent
33 Model. It models solely the default events in a portfolio, not making any
34 reference to severities, exposures, etc...
35 An implicit correspondence is stablished between the variables modelled and
36 the names in the basket given by the basket and model variable access
37 indices.
38 The class is parametric on the Latent Model copula.
39
40 \todo Consider QL_REQUIRE(basket_, "No portfolio basket set.") test in
41 debug model only for performance reasons.
42 */
43 template<class copulaPolicy>
44 class DefaultLatentModel : public LatentModel<copulaPolicy> {
45 // import template members
46 protected:
50 public:
54 protected:
55 // not a handle, the model doesnt keep any cached magnitudes, no need
56 // for notifications, still...
57 mutable ext::shared_ptr<Basket> basket_;
58 ext::shared_ptr<LMIntegration> integration_;
59 private:
60 typedef typename copulaPolicy::initTraits initTraits;
61 public:
62 /*!
63 @param factorWeights Latent model independent factors weights for each
64 variable.
65 @param integralType Integration type.
66 @param ini Copula initialization if any.
67
68 \warning Baskets with realized defaults not tested/WIP.
69 */
71 const std::vector<std::vector<Real> >& factorWeights,
73 const initTraits& ini = initTraits()
74 )
76 integration_(LatentModel<copulaPolicy>::IntegrationFactory::
77 createLMIntegration(factorWeights[0].size(), integralType))
78 { }
80 const Handle<Quote>& mktCorrel,
81 Size nVariables,
83 const initTraits& ini = initTraits()
84 )
85 : LatentModel<copulaPolicy>(mktCorrel, nVariables, ini),
86 integration_(LatentModel<copulaPolicy>::IntegrationFactory::
87 createLMIntegration(1, integralType))
88 { }
89 /* \todo
90 Add other constructors as in LatentModel for ease of use. (less
91 dimensions, factors, etcc...)
92 */
93
94 /* To interface with loss models. It is possible to change the basket
95 since there are no cached magnitudes.
96 */
97 void resetBasket(const ext::shared_ptr<Basket>& basket) const {
98 basket_ = basket;
99 // in the future change 'size' to 'liveSize'
100 QL_REQUIRE(basket_->size() == factorWeights_.size(),
101 "Incompatible new basket and model sizes.");
102 }
103
104 /*! Returns the probability of default of a given name conditional on
105 the realization of a given set of values of the model independent
106 factors. The date at which the probability is given is implicit in the
107 probability since theres not other time dependence in this model.
108 @param prob Unconditional probability of default.
109 @param iName desired name.
110 @param mktFactors Value of LM independent factors.
111 \warning Most often it is preferred to use the method below avoiding the
112 cumulative inversion.
113 */
115 const std::vector<Real>& mktFactors) const
116 {
117 // we can be called from the outside (from an integrable loss model)
118 // but we are called often at integration points. This or
119 // consider a list of friends.
120 #if defined(QL_EXTRA_SAFETY_CHECKS)
121 QL_REQUIRE(basket_, "No portfolio basket set.");
122 #endif
123 /*Avoid redundant call to minimum value inversion (might be \infty),
124 and this independently of the copula function.
125 */
126 if (prob < 1.e-10) return 0.;// use library macro...
128 inverseCumulativeY(prob, iName), iName, mktFactors);
129 }
130 protected:
131 void update() override {
132 if (basket_ != nullptr)
133 basket_->notifyObservers();
135 }
136
137 public:// open since users access it for performance on joint integrations.
138
139 /*! Returns the probability of default of a given name conditional on
140 the realization of a given set of values of the model independent
141 factors. The date at which the probability is given is implicit in the
142 probability since theres not other time dependent in this model.
143 Same intention as above but provides a performance opportunity, if the
144 integration is along the market factors (as usually is) avoids computing
145 the inverse of the probability on each call.
146 @param invCumYProb Inverse cumul of the unconditional probability of
147 default, has to follow the same copula law for results to be coherent
148 @param iName desired name.
149 @param m Value of LM independent factors.
150 */
152 Size iName,
153 const std::vector<Real>& m) const {
154 Real sumMs =
155 std::inner_product(factorWeights_[iName].begin(),
156 factorWeights_[iName].end(), m.begin(), Real(0.));
157 Real res = cumulativeZ((invCumYProb - sumMs) /
158 idiosyncFctrs_[iName] );
159 #if defined(QL_EXTRA_SAFETY_CHECKS)
160 QL_REQUIRE (res >= 0. && res <= 1.,
161 "conditional probability " << res << "out of range");
162 #endif
163
164 return res;
165 }
166 protected:
167 /*! Returns the probability of default of a given name conditional on
168 the realization of a given set of values of the model independent
169 factors.
170 @param date The date for the probability of default.
171 @param iName desired name.
172 @param mktFactors Value of LM independent factors.
173
174 Same intention as the above methods. Usage of this one is typically more
175 expensive because most often the date we call this method with
176 repeats itself and with this one the probability can not be cached
177 outside the call.
178 */
180 const std::vector<Real>& mktFactors) const
181 {
182 const ext::shared_ptr<Pool>& pool = basket_->pool();
183 Probability pDefUncond =
184 pool->get(pool->names()[iName]).
185 defaultProbability(basket_->defaultKeys()[iName])
186 ->defaultProbability(date);
187 return conditionalDefaultProbability(pDefUncond, iName, mktFactors);
188 }
189 /*! Conditional default probability product, intermediate step in the
190 correlation calculation.*/
191 Probability condProbProduct(Real invCumYProb1, Real invCumYProb2,
192 Size iName1, Size iName2,
193 const std::vector<Real>& mktFactors) const {
194 return
195 conditionalDefaultProbabilityInvP(invCumYProb1, iName1,
196 mktFactors) *
197 conditionalDefaultProbabilityInvP(invCumYProb2, iName2,
198 mktFactors);
199 }
200 //! Conditional probability of n default events or more.
201 // \todo: check the issuer has not defaulted.
203 const std::vector<Real>& mktFactors) const;
204 //! access to integration:
205 const ext::shared_ptr<LMIntegration>& integration() const override { return integration_; }
206
207 public:
208 /*! Computes the unconditional probability of default of a given name.
209 Trivial method for testing
210 */
211 Probability probOfDefault(Size iName, const Date& d) const {
212 QL_REQUIRE(basket_, "No portfolio basket set.");
213 const ext::shared_ptr<Pool>& pool = basket_->pool();
214 // avoid repeating this in the integration:
215 Probability pUncond = pool->get(pool->names()[iName]).
216 defaultProbability(basket_->defaultKeys()[iName])
217 ->defaultProbability(d);
218 if (pUncond < 1.e-10) return 0.;
219
221 [&](const std::vector<Real>& v1) {
223 inverseCumulativeY(pUncond, iName), iName, v1);
224 });
225 }
226 /*! Pearsons' default probability correlation.
227 Users should consider specialization on the copula type for specific
228 distributions since that might simplify the integrations, most
229 importantly if this is to be used in calibration of observations for
230 factor coefficients as it is expensive to integrate directly.
231 */
232 Real defaultCorrelation(const Date& d, Size iNamei, Size iNamej) const;
233
234 /*! Returns the probaility of having a given or larger number of
235 defaults in the basket portfolio at a given time.
236 */
239 [&](const std::vector<Real>& v1) {
240 return conditionalProbAtLeastNEvents(n, date, v1);
241 });
242 }
243 };
244
245
246 //---- Defines -----------------------------------------------------------
247
248 template<class CP>
250 Size iNamei, Size iNamej) const
251 {
252 QL_REQUIRE(basket_, "No portfolio basket set.");
253
254 const ext::shared_ptr<Pool>& pool = basket_->pool();
255 // unconditionals:
256 Probability pi = pool->get(pool->names()[iNamei]).
257 defaultProbability(basket_->defaultKeys()[iNamei])
258 ->defaultProbability(d);
259 Probability pj = pool->get(pool->names()[iNamej]).
260 defaultProbability(basket_->defaultKeys()[iNamej])
261 ->defaultProbability(d);
262 Real pipj = pi * pj;
263 Real invPi = inverseCumulativeY(pi, iNamei);
264 Real invPj = inverseCumulativeY(pj, iNamej);
265 // avoid repetitive calls when i=j?
266 Real E1i1j; // joint default covariance term
267 if(iNamei !=iNamej) {
268 E1i1j = integratedExpectedValue(
269 [&](const std::vector<Real>& v1) {
270 return condProbProduct(invPi, invPj, iNamei, iNamej, v1); });
271 }else{
272 E1i1j = pi;
273 }
274 return (E1i1j - pipj )/std::sqrt(pipj*(1.-pi)*(1.-pj));
275 }
276
277
278 template<class CP>
280 const Date& date,
281 const std::vector<Real>& mktFactors) const {
282 QL_REQUIRE(basket_, "No portfolio basket set.");
283
284 /* \todo
285 This algorithm traverses all permutations starting form the
286 lowest one. This is inneficient, there shouldnt be any need to
287 go through the invalid ones. Use combinations of n elements.
288
289 See integration in O'Kane for homogeneous ntds.
290 */
291 // first position with as many defaults as desired:
292 Size poolSize = basket_->size();//move to 'livesize'
293 const ext::shared_ptr<Pool>& pool = basket_->pool();
294
295 auto limit = static_cast<BigNatural>(std::pow(2., (int)(poolSize)));
296
297 // Precalc conditional probabilities
298 std::vector<Probability> pDefCond;
299 for(Size i=0; i<poolSize; i++)
300 pDefCond.push_back(conditionalDefaultProbability(
301 pool->get(pool->names()[i]).
302 defaultProbability(basket_->defaultKeys()[i])->
303 defaultProbability(date), i, mktFactors));
304
305 Probability probNEventsOrMore = 0.;
306 for (auto mask = static_cast<BigNatural>(std::pow(2., (int)(n)) - 1); mask < limit;
307 mask++) {
308 // cheap permutations
309 boost::dynamic_bitset<> bsetMask(poolSize, mask);
310 if(bsetMask.count() >= n) {
311 Probability pConfig = 1;
312 for(Size i=0; i<bsetMask.size(); i++)
313 pConfig *=
314 (bsetMask[i] ? pDefCond[i] : (1.- pDefCond[i]));
315 probNEventsOrMore += pConfig;
316 }
317 }
318 return probNEventsOrMore;
319 }
320
321
322 // often used:
325}
326
327#endif
basket of issuers and related notionals
Concrete date class.
Definition: date.hpp:125
DefaultLatentModel(const std::vector< std::vector< Real > > &factorWeights, LatentModelIntegrationType::LatentModelIntegrationType integralType, const initTraits &ini=initTraits())
Probability condProbProduct(Real invCumYProb1, Real invCumYProb2, Size iName1, Size iName2, const std::vector< Real > &mktFactors) const
Probability conditionalDefaultProbability(const Date &date, Size iName, const std::vector< Real > &mktFactors) const
Probability conditionalDefaultProbability(Probability prob, Size iName, const std::vector< Real > &mktFactors) const
DefaultLatentModel(const Handle< Quote > &mktCorrel, Size nVariables, LatentModelIntegrationType::LatentModelIntegrationType integralType, const initTraits &ini=initTraits())
void resetBasket(const ext::shared_ptr< Basket > &basket) const
Real defaultCorrelation(const Date &d, Size iNamei, Size iNamej) const
Real conditionalProbAtLeastNEvents(Size n, const Date &date, const std::vector< Real > &mktFactors) const
Conditional probability of n default events or more.
const ext::shared_ptr< LMIntegration > & integration() const override
access to integration:
ext::shared_ptr< LMIntegration > integration_
Probability probOfDefault(Size iName, const Date &d) const
Probability probAtLeastNEvents(Size n, const Date &date) const
Probability conditionalDefaultProbabilityInvP(Real invCumYProb, Size iName, const std::vector< Real > &m) const
Shared handle to an observable.
Definition: handle.hpp:41
Generic multifactor latent variable model.
Real inverseCumulativeY(Probability p, Size iVariable) const
std::vector< std::vector< Real > > factorWeights_
void update() override
Probability cumulativeZ(Real z) const
Cumulative distribution of Z, the idiosyncratic/error factors.
const std::vector< std::vector< Real > > & factorWeights() const
Provides values of the factors .
Real integratedExpectedValue(const ext::function< Real(const std::vector< Real > &v1)> &f) const
#define QL_REQUIRE(condition, message)
throw an error if the given pre-condition is not verified
Definition: errors.hpp:117
Date d
QL_REAL Real
real number
Definition: types.hpp:50
Real Probability
probability
Definition: types.hpp:82
std::size_t Size
size of a container
Definition: types.hpp:58
Generic multifactor latent variable model.
Definition: any.hpp:35
DefaultLatentModel< GaussianCopulaPolicy > GaussianDefProbLM
DefaultLatentModel< TCopulaPolicy > TDefProbLM
unsigned QL_BIG_INTEGER BigNatural
large positive integer
Definition: types.hpp:46