Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
gaussianlhplossmodel.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2016 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//#include <ql/experimental/credit/gaussianlhplossmodel.hpp>
21
22#ifndef QL_PATCH_SOLARIS
23
24#include <boost/make_shared.hpp>
25
26using std::sqrt;
27
28using namespace QuantLib;
29
30namespace QuantExt {
31
32CumulativeNormalDistribution const GaussianLHPLossModel::phi_ = CumulativeNormalDistribution();
33
34GaussianLHPLossModel::GaussianLHPLossModel(const Handle<Quote>& correlQuote,
35 const std::vector<Handle<RecoveryRateQuote>>& quotes)
36 : LatentModel<GaussianCopulaPolicy>(sqrt(correlQuote->value()), quotes.size(),
37 // g++ complains default value not seen as typename
38 GaussianCopulaPolicy::initTraits()),
39 sqrt1minuscorrel_(std::sqrt(1. - correlQuote->value())), correl_(correlQuote), rrQuotes_(quotes),
40 beta_(sqrt(correlQuote->value())), biphi_(-sqrt(correlQuote->value())) {
41 registerWith(correl_);
42 for (Size i = 0; i < quotes.size(); i++)
43 registerWith(quotes[i]);
44}
45
46GaussianLHPLossModel::GaussianLHPLossModel(Real correlation, const std::vector<Real>& recoveries)
47 : LatentModel<GaussianCopulaPolicy>(sqrt(correlation), recoveries.size(),
48 // g++ complains default value not seen as typename
49 GaussianCopulaPolicy::initTraits()),
50 sqrt1minuscorrel_(std::sqrt(1. - correlation)),
51 correl_(Handle<Quote>(QuantLib::ext::make_shared<SimpleQuote>(correlation))), beta_(sqrt(correlation)),
52 biphi_(-sqrt(correlation)) {
53 for (Size i = 0; i < recoveries.size(); i++)
54 rrQuotes_.push_back(Handle<RecoveryRateQuote>(QuantLib::ext::make_shared<RecoveryRateQuote>(recoveries[i])));
55}
56
57GaussianLHPLossModel::GaussianLHPLossModel(const Handle<Quote>& correlQuote, const std::vector<Real>& recoveries)
58 : LatentModel<GaussianCopulaPolicy>(sqrt(correlQuote->value()), recoveries.size(),
59 // g++ complains default value not seen as typename
60 GaussianCopulaPolicy::initTraits()),
61 sqrt1minuscorrel_(std::sqrt(1. - correlQuote->value())), correl_(correlQuote), beta_(sqrt(correlQuote->value())),
62 biphi_(-sqrt(correlQuote->value())) {
63 registerWith(correl_);
64 for (Size i = 0; i < recoveries.size(); i++)
65 rrQuotes_.push_back(Handle<RecoveryRateQuote>(QuantLib::ext::make_shared<RecoveryRateQuote>(recoveries[i])));
66}
67
68Real GaussianLHPLossModel::expectedTrancheLossImpl(Real remainingNot, // << at the given date 'd'
69 Real prob, // << at the given date 'd'
70 Real averageRR, // << at the given date 'd'
71 // these are percentual values:
72 Real attachLimit, Real detachLimit) const {
73
74 if (attachLimit >= detachLimit)
75 return 0.; // or is it an error?
76 // expected remaining notional:
77 if (remainingNot == 0.)
78 return 0.;
79
80 const Real one = 1.0 - 1.0e-12; // FIXME DUE TO THE INV CUMUL AT 1
81 const Real k1 = std::min(one, attachLimit / (1.0 - averageRR)) + QL_EPSILON;
82 const Real k2 = std::min(one, detachLimit / (1.0 - averageRR)) + QL_EPSILON;
83
84 if (prob > 0) {
85 const Real ip = InverseCumulativeNormal::standard_value(prob);
86 const Real invFlightK1 = (ip - sqrt1minuscorrel_ * InverseCumulativeNormal::standard_value(k1)) / beta_;
87 const Real invFlightK2 = (ip - sqrt1minuscorrel_ * InverseCumulativeNormal::standard_value(k2)) / beta_;
88
89 return remainingNot * (detachLimit * phi_(invFlightK2) - attachLimit * phi_(invFlightK1) +
90 (1. - averageRR) * (biphi_(ip, -invFlightK2) - biphi_(ip, -invFlightK1)));
91 } else
92 return 0.0;
93}
94
95Real GaussianLHPLossModel::probOverLoss(const Date& d, Real remainingLossFraction) const {
96 // these test goes into basket<<<<<<<<<<<<<<<<<<<<<<<<<
97 QL_REQUIRE(remainingLossFraction >= 0., "Incorrect loss fraction.");
98 QL_REQUIRE(remainingLossFraction <= 1., "Incorrect loss fraction.");
99
100 Real remainingAttachAmount = basket_->remainingAttachmentAmount();
101 Real remainingDetachAmount = basket_->remainingDetachmentAmount();
102 // live unerlying portfolio loss fraction (remaining portf fraction)
103
104 const Real remainingBasktNot = basket_->remainingNotional(d);
105 const Real attach = std::min(remainingAttachAmount / remainingBasktNot, 1.);
106 const Real detach = std::min(remainingDetachAmount / remainingBasktNot, 1.);
107
108 Real portfFract = attach + remainingLossFraction * (detach - attach);
109
110 Real averageRR = averageRecovery(d);
111 Real maxAttLossFract = (1. - averageRR);
112 if (portfFract > maxAttLossFract)
113 return 0.;
114
115 // for non-equity losses add the probability jump at zero tranche
116 // losses (since this method returns prob of losing more or
117 // equal to)
118 if (portfFract <= QL_EPSILON)
119 return 1.;
120
121 Probability prob = averageProb(d);
122
123 Real ip = InverseCumulativeNormal::standard_value(prob);
124 Real invFlightK =
125 (ip - sqrt1minuscorrel_ * InverseCumulativeNormal::standard_value(portfFract / (1. - averageRR))) / beta_;
126
127 return phi_(invFlightK); // probOver
128}
129
130Real GaussianLHPLossModel::expectedShortfall(const Date& d, Probability perctl) const {
131 // loss as a fraction of the live portfolio
132 Real ptflLossPerc = percentilePortfolioLossFraction(d, perctl);
133 Real remainingAttachAmount = basket_->remainingAttachmentAmount();
134 Real remainingDetachAmount = basket_->remainingDetachmentAmount();
135
136 const Real remainingNot = basket_->remainingNotional(d);
137 const Real attach = std::min(remainingAttachAmount / remainingNot, 1.);
138 const Real detach = std::min(remainingDetachAmount / remainingNot, 1.);
139
140 if (ptflLossPerc >= detach - QL_EPSILON)
141 return remainingNot * (detach - attach); // equivalent
142
143 Real maxLossLevel = std::max(attach, ptflLossPerc);
144 Probability prob = averageProb(d);
145 Real averageRR = averageRecovery(d);
146
147 Real valA = expectedTrancheLossImpl(remainingNot, prob, averageRR, maxLossLevel, detach);
148 Real valB = // probOverLoss(d, maxLossLevel);//in live tranche units
149 // from fraction of basket notional to fraction of tranche notional
150 probOverLoss(d, std::min(std::max((maxLossLevel - attach) / (detach - attach), 0.), 1.));
151 return (valA + (maxLossLevel - attach) * remainingNot * valB) / (1. - perctl);
152}
153
154Real GaussianLHPLossModel::percentilePortfolioLossFraction(const Date& d, Real perctl) const {
155 // this test goes into basket<<<<<<<<<<<<<<<<<<<<<<<<<
156 QL_REQUIRE(perctl >= 0. && perctl <= 1., "Percentile argument out of bounds.");
157
158 if (perctl == 0.)
159 return 0.; // portfl == attach
160 if (perctl == 1.)
161 perctl = 1. - QL_EPSILON; // portfl == detach
162
163 return (1. - averageRecovery(d)) * phi_((InverseCumulativeNormal::standard_value(averageProb(d)) +
164 beta_ * InverseCumulativeNormal::standard_value(perctl)) /
166}
167
168} // namespace QuantExt
169
170#endif
RelinkableHandle< QuantExt::Basket > basket_
Probability averageProb(const Date &d) const
Real percentilePortfolioLossFraction(const Date &d, Real perctl) const
std::vector< Handle< QuantLib::RecoveryRateQuote > > rrQuotes_
Real expectedTrancheLossImpl(Real remainingNot, Real prob, Real averageRR, Real attachLimit, Real detachLimit) const
BivariateCumulativeNormalDistribution biphi_
Real averageRecovery(const Date &d) const
Real probOverLoss(const Date &d, Real remainingLossFraction) const override
Real expectedShortfall(const Date &d, Probability perctl) const override
Returns the ESF as an absolute amount (rather than a fraction)
static CumulativeNormalDistribution const phi_
GaussianLHPLossModel(const Handle< Quote > &correlQuote, const std::vector< Handle< QuantLib::RecoveryRateQuote > > &quotes)
RandomVariable sqrt(RandomVariable x)