QuantLib: a free/open-source library for quantitative finance
fully annotated source code - version 1.34
Loading...
Searching...
No Matches
spotlosslatentmodel.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_spotlosslatentmodel_hpp
21#define quantlib_spotlosslatentmodel_hpp
22
24
25namespace QuantLib {
26
27 /*! \brief Random spot recovery rate latent variable portfolio model.\par
28 See: \par
29 <b>A Spot Stochastic Recovery Extension of the Gaussian Copula</b> N.Bennani
30 and J.Maetz, MPRA July 2009 \par
31 <b>Extension of Spot Recovery model for Gaussian Copula</b> H.Li, October
32 2009, MPRA \par
33 The model is adpated here for a multifactor set up and a generic copula so
34 it can be used for pricing in single factor mode or for risk metrics in its
35 multifactor version.\par
36 \todo Rewrite this model: the distribution of the spot recovery given
37 default could be given as a functional of rr_i with the market factors and
38 the rest of methods depend on this. That would offer a family of models.
39 \todo Implement eq. 45 to have the EL(t) and be able to integrate the model
40 */
41 template <class copulaPolicy>
42 class SpotRecoveryLatentModel : public LatentModel<copulaPolicy> {
43 public:
44 // resolve LM interface:
50 private:
51 const std::vector<Real> recoveries_;
53 // products of default and recoveries factors, see refs ('covariances')
54 std::vector<Real> crossIdiosyncFctrs_;
55 mutable Size numNames_;
56 mutable ext::shared_ptr<Basket> basket_;
57 ext::shared_ptr<LMIntegration> integration_;
58 protected:
59 //! access to integration:
60 const ext::shared_ptr<LMIntegration>& integration() const override { return integration_; }
61
62 private:
63 typedef typename copulaPolicy::initTraits initTraits;
64 public:
66 const std::vector<std::vector<Real> >& factorWeights,
67 const std::vector<Real>& recoveries,
68 Real modelA,
70 const initTraits& ini = initTraits()
71 );
72
73 void resetBasket(const ext::shared_ptr<Basket>& basket) const;
75 const std::vector<Real>& mktFactors) const;
77 const std::vector<Real>& mktFactors) const;
79 Size iName,
80 const std::vector<Real>& m) const;
81 /*! Expected conditional spot recovery rate. Conditional on a set of
82 systemic factors and default returns the integrated attainable recovery
83 values. \par
84 Corresponds to a multifactor generalization of the model in eq. 44
85 on p.15 of <b>Extension of Spot Recovery Model for Gaussian Copula</b>
86 Hui Li. 2009 Only remember that \f$\rho_l Z \f$ there is here
87 (multiple betas):
88 \f$ \sum_k \beta_{ik}^l Z_k \f$ and that \f$ \rho_d \rho_l \f$ there is
89 here:
90 \f$ \sum_k \beta_{ik}^d \beta_{ik}^l \f$ \par
91 (d,l corresponds to first and last set of betas)
92 */
93 Real expCondRecovery/*conditionalRecovery*/(const Date& d, Size iName,
94 const std::vector<Real>& mktFactors) const;
95 Real expCondRecoveryP(Real uncondDefP, Size iName,
96 const std::vector<Real>& mktFactors) const;
97 Real expCondRecoveryInvPinvRR(Real invUncondDefP, Real invUncondRR,
98 Size iName, const std::vector<Real>& mktFactors) const;
99 /*! Implements equation 42 on p.14 (second).
100 Remember that for this call to make sense the sample used must be
101 one leading to a default. Theres no check on this. This member
102 typically to be used within a simulation.
103 */
104 Real conditionalRecovery(Real latentVarSample, Size iName,
105 const Date& d) const;
106 /*! Due to the way the latent model is splitted in two parts, we call
107 the base class for the default sample and the LM owned here for the RR
108 model sample. This sample only makes sense if it led to a default.
109 @param allFactors All sampled factors, default and RR valiables.
110 @param iName The index of the name for which we want the RR sample
111
112 \todo Write vector version for all names' RRs
113 */
114 Real latentRRVarValue(const std::vector<Real>& allFactors,
115 Size iName) const;
116 Real conditionalExpLossRR(const Date& d, Size iName,
117 const std::vector<Real>& mktFactors) const;
118 Real conditionalExpLossRRInv(Real invP, Real invRR, Size iName,
119 const std::vector<Real>& mktFactors) const;
120 /*! Single name expected loss.\par
121 The main reason of this method is for the testing of this model. The
122 model is coherent in that it preserves the single name expected loss
123 and thus is coherent with the single name CDS market when used in the
124 pricing context. i.e. it should match: \f$pdef_i(d) \times RR_i \f$
125 */
126 Real expectedLoss(const Date& d, Size iName) const;
127 };
128
129
132
133
134 // ------------------------------------------------------------------------
135
136 template <class CP>
137 inline void
138 SpotRecoveryLatentModel<CP>::resetBasket(const ext::shared_ptr<Basket>& basket) const {
139 basket_ = basket;
140 // in the future change 'size' to 'liveSize'
141 QL_REQUIRE(basket_->size() == numNames_,
142 "Incompatible new basket and model sizes.");
143 }
144
145 template<class CP>
146 inline Probability
148 const Date& date,
149 Size iName, const std::vector<Real>& mktFactors) const
150 {
151 const ext::shared_ptr<Pool>& pool = basket_->pool();
152 Probability pDefUncond =
153 pool->get(pool->names()[iName]).
154 defaultProbability(basket_->defaultKeys()[iName])
155 ->defaultProbability(date);
156 return conditionalDefaultProbability(pDefUncond, iName, mktFactors);
157 }
158
159 template<class CP>
160 inline Probability
162 Probability prob,
163 Size iName, const std::vector<Real>& mktFactors) const
164 {
165 // we can be called from the outside (from an integrable loss model)
166 // but we are called often at integration points. This or
167 // consider a list of friends.
168 #if defined(QL_EXTRA_SAFETY_CHECKS)
169 QL_REQUIRE(basket_, "No portfolio basket set.");
170 #endif
171 /*Avoid redundant call to minimum value inversion (might be \infty),
172 and this independently of the copula function.
173 */
174 if (prob < 1.e-10) return 0.;// use library macro...
175 return conditionalDefaultProbabilityInvP(
176 inverseCumulativeY(prob, iName), iName, mktFactors);
177 }
178
179 template<class CP>
180 inline Probability
182 Real invCumYProb,
183 Size iName,
184 const std::vector<Real>& m) const
185 {
186 Real sumMs =
187 std::inner_product(this->factorWeights_[iName].begin(),
188 this->factorWeights_[iName].end(), m.begin(), 0.);
189 Real res = this->cumulativeZ((invCumYProb - sumMs) /
190 this->idiosyncFctrs_[iName] );
191 #if defined(QL_EXTRA_SAFETY_CHECKS)
192 QL_REQUIRE (res >= 0. && res <= 1.,
193 "conditional probability " << res << "out of range");
194 #endif
195
196 return res;
197 }
198
199 template<class CP>
200 inline Real
202 Size iName,
203 const std::vector<Real>& mktFactors) const
204 {
205 #if defined(QL_EXTRA_SAFETY_CHECKS)
206 QL_REQUIRE(mktFactors.size() == this->numFactors(),
207 "Realization of market factors and latent model size do not match");
208 #endif
209 const ext::shared_ptr<Pool>& pool = basket_->pool();
210 Probability pDefUncond =
211 pool->get(pool->names()[iName]).
212 defaultProbability(basket_->defaultKeys()[iName])
213 ->defaultProbability(d);
214
215 return expCondRecoveryP(pDefUncond, iName, mktFactors);
216 }
217
218 template<class CP>
220 Real uncondDefP, Size iName, const std::vector<Real>& mktFactors) const
221 {
222 return expCondRecoveryInvPinvRR(
223 inverseCumulativeY(uncondDefP, iName),
224 inverseCumulativeY(recoveries_[iName], iName + numNames_),
225 iName, mktFactors);
226 }
227
228 template<class CP>
230 Real invUncondDefP,
231 Real invUncondRR,
232 Size iName,
233 const std::vector<Real>& mktFactors) const
234 {
235 const std::vector<std::vector<Real> >& fctrs_ = factorWeights();
236 //Size iRR = iName + basket_->size();// should be live pool
237 const Real sumMs =
238 std::inner_product(fctrs_[iName].begin(), fctrs_[iName].end(),
239 mktFactors.begin(), 0.);
240 const Real sumBetaLoss =
241 std::inner_product(fctrs_[iName + numNames_].begin(),
242 fctrs_[iName + numNames_].end(),
243 fctrs_[iName + numNames_].begin(),
244 0.);
245 return this->cumulativeZ((sumMs + std::sqrt(1.-crossIdiosyncFctrs_[iName])
246 * std::sqrt(1.+modelA_*modelA_) *
247 invUncondRR
248 - std::sqrt(crossIdiosyncFctrs_[iName]) *
249 invUncondDefP
250 )
251 / std::sqrt(1.- sumBetaLoss + modelA_*modelA_ *
252 (1.-crossIdiosyncFctrs_[iName])) );
253 }
254
255 template<class CP>
257 Size iName, const Date& d) const
258 {
259 const ext::shared_ptr<Pool>& pool = basket_->pool();
260
261 // retrieve the default probability for this name
263 pool->get(basket_->names()[iName]).defaultProbability(
264 basket_->defaultKeys()[iName]);
265 const Probability pdef = dfts->defaultProbability(d, true);
266 // before asking for -\infty
267 if (pdef < 1.e-10) return 0.;
268
269 Size iRecovery = iName + numNames_;// should be live pool
270 return cumulativeY(
271 (latentVarSample - std::sqrt(crossIdiosyncFctrs_[iName])
272 * inverseCumulativeY(pdef, iName)) /
273 (modelA_ * std::sqrt(1.-crossIdiosyncFctrs_[iName]))
274 // cache the sqrts
275 // cache this factor.
276 +std::sqrt(1.+ 1./(modelA_*modelA_)) *
277 inverseCumulativeY(recoveries_[iName], iRecovery)
278 , iRecovery);
279 }
280
281 template<class CP>
283 const std::vector<Real>& allFactors,
284 Size iName) const
285 {
286 Size iRecovery = iName + numNames_;// should be live pool
287 return latentVarValue(allFactors, iRecovery);
288 }
289
290 template<class CP>
292 Size iName,
293 const std::vector<Real>& mktFactors) const
294 {
295 const ext::shared_ptr<Pool>& pool = basket_->pool();
296 Probability pDefUncond =
297 pool->get(pool->names()[iName]).
298 defaultProbability(basket_->defaultKeys()[iName])
299 ->defaultProbability(d);
300
301 Real invP = inverseCumulativeY(pDefUncond, iName);
302 Real invRR = inverseCumulativeY(recoveries_[iName], iName + numNames_);
303
304 return conditionalExpLossRRInv(invP, invRR, iName, mktFactors);
305 }
306
307 template<class CP>
309 Real invP,
310 Real invRR,
311 Size iName,
312 const std::vector<Real>& mktFactors) const
313 {
314 return conditionalDefaultProbabilityInvP(invP, iName, mktFactors)
315 * (1.-this->conditionalRecoveryInvPinvRR(invP, invRR, iName, mktFactors));
316 }
317
318 template<class CP>
320 Size iName) const
321 {
322 const ext::shared_ptr<Pool>& pool = basket_->pool();
323 Probability pDefUncond =
324 pool->get(pool->names()[iName]).
325 defaultProbability(basket_->defaultKeys()[iName])
326 ->defaultProbability(d);
327
328 Real invP = inverseCumulativeY(pDefUncond, iName);
329 Real invRR = inverseCumulativeY(recoveries_[iName], iName + numNames_);
330
331 return integratedExpectedValue(
332 [&](const std::vector<Real>& v){
333 return conditionalExpLossRRInv(invP, invRR, iName, v);
334 });
335 }
336
337 template<class CP>
339 const std::vector<std::vector<Real> >& factorWeights,
340 const std::vector<Real>& recoveries,
341 Real modelA,
343 const typename CP::initTraits& ini
344 )
345 : LatentModel<CP>(factorWeights, ini),
346 recoveries_(recoveries),
347 modelA_(modelA),
348 numNames_(factorWeights.size()/2),
349 integration_(LatentModel<CP>::IntegrationFactory::
350 createLMIntegration(factorWeights[0].size(), integralType))
351 {
352 QL_REQUIRE(factorWeights.size() % 2 == 0,
353 "Number of RR variables must be equal to number of default variables");
354 QL_REQUIRE(recoveries.size() == numNames_ ,
355 "Number of recoveries does not match number of defaultable entities.");
356
357 // reminder: first betas are default, last ones are recovery
358 for(Size iName=0; iName<numNames_; iName++) /// USE STL
359 /* Corresponds to: (k denotes factor, i denotes modelled
360 variable -default and recoveries))
361 \sum_k a^2_{i,k} a^2_{N+i,k}
362 */
363 {
364 Real cumul = 0.;
365 for(Size iB=0; iB<factorWeights[iName].size(); iB++)
366 // actually this size is unique
367 cumul += factorWeights[iName][iB] *
368 factorWeights[iName][iB] *
369 factorWeights[iName + numNames_][iB] *
370 factorWeights[iName + numNames_][iB];
371 crossIdiosyncFctrs_.push_back(cumul);
372 }
373
374 }
375
376
377}
378
379#endif
Concrete date class.
Definition: date.hpp:125
Shared handle to an observable.
Definition: handle.hpp:41
Generic multifactor latent variable model.
Real latentVarValue(const std::vector< Real > &allFactors, Size iVar) const
Real inverseCumulativeY(Probability p, Size iVariable) const
Probability cumulativeY(Real val, Size iVariable) const
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
Random spot recovery rate latent variable portfolio model.
Real conditionalExpLossRR(const Date &d, Size iName, const std::vector< Real > &mktFactors) const
SpotRecoveryLatentModel(const std::vector< std::vector< Real > > &factorWeights, const std::vector< Real > &recoveries, Real modelA, LatentModelIntegrationType::LatentModelIntegrationType integralType, const initTraits &ini=initTraits())
Real expectedLoss(const Date &d, Size iName) const
Probability conditionalDefaultProbability(const Date &date, Size iName, const std::vector< Real > &mktFactors) const
Real expCondRecoveryP(Real uncondDefP, Size iName, const std::vector< Real > &mktFactors) const
void resetBasket(const ext::shared_ptr< Basket > &basket) const
Real expCondRecovery(const Date &d, Size iName, const std::vector< Real > &mktFactors) const
const std::vector< Real > recoveries_
Real conditionalRecovery(Real latentVarSample, Size iName, const Date &d) const
Real latentRRVarValue(const std::vector< Real > &allFactors, Size iName) const
const ext::shared_ptr< LMIntegration > & integration() const override
access to integration:
ext::shared_ptr< LMIntegration > integration_
Real expCondRecoveryInvPinvRR(Real invUncondDefP, Real invUncondRR, Size iName, const std::vector< Real > &mktFactors) const
Real conditionalExpLossRRInv(Real invP, Real invRR, Size iName, const std::vector< Real > &mktFactors) const
Probability conditionalDefaultProbabilityInvP(Real invCumYProb, Size iName, const std::vector< Real > &m) 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
Definition: any.hpp:35
SpotRecoveryLatentModel< TCopulaPolicy > TSpotLossLM
SpotRecoveryLatentModel< GaussianCopulaPolicy > GaussianSpotLossLM
ext::shared_ptr< BlackVolTermStructure > v