Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
homogeneouspooldef.hpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2017 Quaternion Risk Management Ltd
3 All rights reserved.
4
5 This file is part of ORE, a free-software/open-source library
6 for transparent pricing and risk analysis - http://opensourcerisk.org
7
8 ORE is free software: you can redistribute it and/or modify it
9 under the terms of the Modified BSD License. You should have received a
10 copy of the license along with this program.
11 The license is also available online at <http://opensourcerisk.org>
12
13 This program is distributed on the basis that it will form a useful
14 contribution to risk analytics and model standardisation, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the license for more details.
17*/
18
19#ifndef quantext_homogenous_pool_default_model_hpp
20#define quantext_homogenous_pool_default_model_hpp
21
22#include <ql/experimental/credit/lossdistribution.hpp>
23//#include <ql/experimental/credit/basket.hpp>
24#include <qle/models/basket.hpp>
25//#include <ql/experimental/credit/constantlosslatentmodel.hpp>
27//#include <ql/experimental/credit/defaultlossmodel.hpp>
29
30// Intended to replace HomogeneousPoolCDOEngine in syntheticcdoengines.hpp
31
32namespace QuantExt {
33using namespace QuantLib;
34
35//-------------------------------------------------------------------------
36//! Default loss distribution convolution for finite homogeneous pool
37/* A note on the number of buckets: As it is now the code goes splitting
38losses into buckets from loses equal to zero to losses up to the value of
39the underlying basket. This is in view of a stochastic loss given default
40but in a constant LGD situation this is a waste and it is more efficient to
41go up to the attainable losses.
42\todo Extend to the multifactor case for a generic LM
43*/
44template <class copulaPolicy> class HomogeneousPoolLossModel : public QuantExt::DefaultLossModel {
45private:
46 void resetModel();
47
48public:
49 HomogeneousPoolLossModel(const QuantLib::ext::shared_ptr<ConstantLossLatentmodel<copulaPolicy>>& copula, Size nBuckets,
50 Real max = 5., Real min = -5., Real nSteps = 50)
51 : copula_(copula), nBuckets_(nBuckets), max_(max), min_(min), nSteps_(nSteps), delta_((max - min) / nSteps) {
52 QL_REQUIRE(copula->numFactors() == 1, "Inhomogeneous model not implemented for multifactor");
53 }
54
55protected:
56 // RL: additional flag
57 Distribution lossDistrib(const Date& d, bool zeroRecovery = false) const;
58
59public:
60 // RL: additional flag
61 Real expectedTrancheLoss(const Date& d, bool zeroRecovery = false) const {
62 Distribution dist = lossDistrib(d, zeroRecovery);
63 // RL: dist.trancheExpectedValue() using x = dist.average(i)
64 // FIXME: some remaining inaccuracy in dist.cumulativeDensity(detachAmount_)
65 Real expectedLoss = 0;
66 dist.normalize();
67 for (Size i = 0; i < dist.size(); i++) {
68 // Real x = dist.x(i) + dist.dx(i)/2; // in QL distribution.cpp
69 Real x = dist.average(i);
70 if (x < attachAmount_)
71 continue;
72 if (x > detachAmount_)
73 break;
74 expectedLoss += (x - attachAmount_) * dist.dx(i) * dist.density(i);
75 }
76 expectedLoss += (detachAmount_ - attachAmount_) * (1.0 - dist.cumulativeDensity(detachAmount_));
77 return expectedLoss;
78
79 return lossDistrib(d, zeroRecovery).cumulativeExcessProbability(attachAmount_, detachAmount_);
80 // This one if the distribution is over the whole loss structure:
81 // but it becomes very expensive
82 /*
83 return lossDistrib(d).trancheExpectedValue(attach_ * notional_,
84 detach_ * notional_);
85 */
86 }
87 Real percentile(const Date& d, Real percentile) const {
88 Real portfLoss = lossDistrib(d).confidenceLevel(percentile);
89 return std::min(std::max(portfLoss - attachAmount_, 0.), detachAmount_ - attachAmount_);
90 }
91 Real expectedShortfall(const Date& d, Probability percentile) const {
92 Distribution dist = lossDistrib(d);
93 dist.tranche(attachAmount_, detachAmount_);
94 return dist.expectedShortfall(percentile);
95 }
96
97protected:
98 const QuantLib::ext::shared_ptr<ConstantLossLatentmodel<copulaPolicy>> copula_;
101 mutable std::vector<Real> notionals_;
102
103private:
104 // integration:
105 // \todo move integration to latent model types when moving to a
106 // multifactor version
107 const Real max_; // redundant?
108 const Real min_;
109 const Real nSteps_;
110 const Real delta_;
111};
112// \todo Add other loss distribution statistics
115
116//-----------------------------------------------------------------------
117
119 // need to be capped now since the limit amounts might be over the
120 // remaining notional (think amortizing)
121 attach_ = std::min(basket_->remainingAttachmentAmount() / basket_->remainingNotional(), 1.);
122 detach_ = std::min(basket_->remainingDetachmentAmount() / basket_->remainingNotional(), 1.);
123 notional_ = basket_->remainingNotional();
124 notionals_ = basket_->remainingNotionals();
125 attachAmount_ = basket_->remainingAttachmentAmount();
126 detachAmount_ = basket_->remainingDetachmentAmount();
127
128 copula_->resetBasket(basket_.currentLink());
129}
130
131// RL: additional flag
132template <class CP> Distribution HomogeneousPoolLossModel<CP>::lossDistrib(const Date& d, bool zeroRecovery) const {
133 LossDistHomogeneous bucktLDistBuff(nBuckets_, detachAmount_);
134
135 std::vector<Real> lgd; // switch to a mutable cache member
136 // RL: additional option used to set set recovery rates to zero
137 // std::vector<Real> recoveries = copula_->recoveries();
138 std::vector<Real> recoveries =
139 zeroRecovery ? std::vector<Real>(copula_->recoveries().size(), 0.0) : copula_->recoveries();
140 std::transform(recoveries.begin(), recoveries.end(), std::back_inserter(lgd), [](Real x) { return 1.0 - x; });
141 std::transform(lgd.begin(), lgd.end(), notionals_.begin(), lgd.begin(), std::multiplies<Real>());
142 std::vector<Real> prob = basket_->remainingProbabilities(d);
143 for (Size iName = 0; iName < prob.size(); iName++)
144 prob[iName] = copula_->inverseCumulativeY(prob[iName], iName);
145
146 // integrate locally (1 factor).
147 // use explicitly a 1D latent model object?
148 Distribution dist(nBuckets_, 0.0, detachAmount_);
149 // notional_);
150 std::vector<Real> mkft(1, min_ + delta_ / 2.);
151 for (Size i = 0; i < nSteps_; i++) {
152 std::vector<Real> conditionalProbs;
153 for (Size iName = 0; iName < notionals_.size(); iName++)
154 conditionalProbs.push_back(copula_->conditionalDefaultProbabilityInvP(prob[iName], iName, mkft));
155 Distribution d = bucktLDistBuff(lgd, conditionalProbs);
156 Real densitydm = delta_ * copula_->density(mkft);
157 // also, instead of calling the static method it could be wrapped
158 // through an inlined call in the latent model
159 for (Size j = 0; j < nBuckets_; j++) {
160 dist.addDensity(j, d.density(j) * densitydm);
161 dist.addAverage(j, d.average(j) * densitydm); // RL
162 }
163 mkft[0] += delta_;
164 }
165 return dist;
166}
167
168} // namespace QuantExt
169
170#endif
basket of issuers and related notionals
Default loss distribution convolution for finite homogeneous pool.
Real expectedTrancheLoss(const Date &d, bool zeroRecovery=false) const
Real expectedShortfall(const Date &d, Probability percentile) const
HomogeneousPoolLossModel(const QuantLib::ext::shared_ptr< ConstantLossLatentmodel< copulaPolicy > > &copula, Size nBuckets, Real max=5., Real min=-5., Real nSteps=50)
const QuantLib::ext::shared_ptr< ConstantLossLatentmodel< copulaPolicy > > copula_
Distribution lossDistrib(const Date &d, bool zeroRecovery=false) const
void resetModel()
Concrete models do now any updates/inits they need on basket reset.
Real percentile(const Date &d, Real percentile) const
Value at Risk given a default loss percentile.
HomogeneousPoolLossModel< TCopulaPolicy > HomogTPoolLossModel
HomogeneousPoolLossModel< GaussianCopulaPolicy > HomogGaussPoolLossModel
CompiledFormula min(CompiledFormula x, const CompiledFormula &y)
CompiledFormula max(CompiledFormula x, const CompiledFormula &y)