QuantLib: a free/open-source library for quantitative finance
Fully annotated sources - version 1.32
Loading...
Searching...
No Matches
randomlosslatentmodel.hpp
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#ifndef quantlib_randomloss_latent_model_hpp
20#define quantlib_randomloss_latent_model_hpp
21
22#include <ql/experimental/credit/basket.hpp>
23#include <ql/experimental/credit/randomdefaultlatentmodel.hpp>
24#include <ql/experimental/credit/spotlosslatentmodel.hpp>
25#include <ql/experimental/math/gaussiancopulapolicy.hpp>
26#include <ql/experimental/math/latentmodel.hpp>
27#include <ql/experimental/math/tcopulapolicy.hpp>
28#include <ql/math/randomnumbers/mt19937uniformrng.hpp>
29#include <ql/math/solvers1d/brent.hpp>
30#include <cmath>
31
32namespace QuantLib {
33
34
35 template<class , class > class RandomLossLM;
36 template<class copulaPolicy, class USNG>
38 simEvent(unsigned int n, unsigned int d, Real r)
39 : nameIdx(n), dayFromRef(d),
40 // truncates the value:
41 compactRR(std::lround(r/rrGranular)) {}
42 unsigned int nameIdx : 12; // can index up to 4095 names
43 unsigned int dayFromRef : 12; // can index up to 4095 days = 11 yrs
44 private:
45 unsigned int compactRR : 8;
46 public:
47 // ..............still one bit left
48 bool operator<(const simEvent& evt) const {
49 return dayFromRef < evt.dayFromRef;
50 }
51 Real recovery() const {
52 /* we pay the price of this product (plus the division at
53 construction) for the memory we save. Precission is lost though,
54 e.g. figures from 0.0 to 0.00390625/2. are stored as 0.0
55 */
56 return rrGranular * compactRR;
57 }
58 static const Real rrGranular;// = 1./256.;// 2^8
59 };
60
61#ifndef __DOXYGEN__
62
63 template <class C, class G> const Real
64 simEvent<RandomLossLM<C, G> >::rrGranular = 1./256.;// 2^8
65
66#endif
67
70 template<class copulaPolicy, class USNG = SobolRsg>
71 class RandomLossLM : public RandomLM<RandomLossLM, copulaPolicy, USNG>
72 {
73 private:
75
76 const ext::shared_ptr<SpotRecoveryLatentModel<copulaPolicy> > copula_;
77 // for time inversion:
79 public:
80 explicit RandomLossLM(
81 const ext::shared_ptr<SpotRecoveryLatentModel<copulaPolicy> >&
82 copula,
83 Size nSims = 0,
84 Real accuracy = 1.e-6,
85 BigNatural seed = 2863311530UL)
87 (copula->numFactors(), copula->size(), copula->copula(),
88 nSims, seed),
89 copula_(copula), accuracy_(accuracy)
90 {
91 // redundant through basket?
92 this->registerWith(Settings::instance().evaluationDate());
93 }
94
95 // grant access to static polymorphism:
96 /* While this works on g++, VC9 refuses to compile it.
97 Not completely sure whos right; individually making friends of the
98 calling members or writting explicitly the derived class T parameters
99 throws the same errors.
100 The access is then open to the member fucntions.
101 */
102 friend class RandomLM< ::QuantLib::RandomLossLM, copulaPolicy, USNG>;
103 protected:
104 void nextSample(const std::vector<Real>& values) const;
105
106 // see note on randomdefaultlatentmodel
107 void initDates() const {
108 /* Precalculate horizon time default probabilities (used to
109 determine if the default took place and subsequently compute its
110 event time)
111 */
113 Date maxHorizonDate = today + Period(this->maxHorizon_, Days);
114
115 const ext::shared_ptr<Pool>& pool = this->basket_->pool();
116 for(Size iName=0; iName < this->basket_->size(); ++iName)//use'live'
117 horizonDefaultPs_.push_back(pool->get(pool->names()[iName]).
118 defaultProbability(this->basket_->defaultKeys()[iName])
119 ->defaultProbability(maxHorizonDate, true));
120 }
122 return evt.recovery();
123 }
124
125 Real latentVarValue(const std::vector<Real>& factorsSample,
126 Size iVar) const {
127 return copula_->latentVarValue(factorsSample, iVar);
128 }
129 Size basketSize() const { return this->basket_->size(); }
130 // conditional to default, defined as spot-recovery.
131 Real conditionalRecovery(Real latentVarSample, Size iName,
132 const Date& d) const;
133 private:
134 void resetModel() override {
135 /* Explore: might save recalculation if the basket is the same
136 (some situations, like BC or control variates) in that case do not
137 update, only reset the copula's basket.
138 */
139 copula_->resetBasket(this->basket_.currentLink());
140
141 QL_REQUIRE(2 * this->basket_->size() == copula_->size(),
142 "Incompatible basket and model sizes.");
143 // invalidate current calculations if any and notify observers
144 // NOLINTNEXTLINE(bugprone-parent-virtual-call)
146 }
147 // Default probabilities for each name at the time of the maximun
148 // horizon date. Cached for perf.
149 mutable std::vector<Probability> horizonDefaultPs_;
150 };
151
152
153 // --------------------------------------------------------------
154
155
156 template<class C, class URNG>
158 const std::vector<Real>& values) const
159 {
160 const ext::shared_ptr<Pool>& pool = this->basket_->pool();
161 this->simsBuffer_.push_back(std::vector<defaultSimEvent> ());
162
163 // half the model is defaults, the other half are RRs...
164 for(Size iName=0; iName<copula_->size()/2; iName++) {
165 // ...but samples must be full
166 /* This is really a trick, we are passing a longer than
167 expected set of values in the sample but the last idiosyncratic
168 values corresponding to the RR are not used. They are used below
169 only if we are in default. This works due to the way the SpotLossLM
170 is split in two almost disjoint latent models and that theres no
171 check on the vector size in the LM base class.
172 */
173 Real latentVarSample =
174 copula_->latentVarValue(values, iName);
175 Probability simDefaultProb =
176 copula_->cumulativeY(latentVarSample, iName);
177 // If the default simulated lies before the max date:
178 if (horizonDefaultPs_[iName] >= simDefaultProb) {
180 pool->get(pool->names()[iName]). // use 'live' names
181 defaultProbability(this->basket_->defaultKeys()[iName]);
182 // compute and store default time with respect to the
183 // curve ref date:
184 Size dateSTride =
185 static_cast<Size>(Brent().solve(// casted from Real:
186 detail::Root(dfts, simDefaultProb), accuracy_, 0., 1.));
187 /*
188 // value if one approximates to a flat HR;
189 // faster (>x2) but it introduces an error:..
190 // \todo: see how to include this 'polymorphically'. While
191 // not the case in pricing in risk metrics/real
192 // probabilities the curves are often flat
193 static_cast<Size>(ceil(maxHorizon_ *
194 std::log(1.-simDefaultProb)
195 /std::log(1.-data_.horizonDefaultPs_[iName])));
196 */
197 // Determine the realized recovery rate:
198 /* For this; 'conditionalRecovery' needs to compute the pdef on
199 the realized def event date from the simulation. Yet, this might
200 have fallen between todays date and the default TS reference
201 date(usually a two day gap) To avoid requesting a negative time
202 probability the date is moved to the TS date
203 Unless the gap is ridiculous this has no practical effect for
204 the RR value*/
206 Date eventDate = today+Period(static_cast<Integer>(dateSTride),
207 Days);
208 if(eventDate<dfts->referenceDate())
209 eventDate = dfts->referenceDate();
210 Real latentRRVarSample =
211 copula_->latentRRVarValue(values, iName);
212 Real recovery =
213 copula_->conditionalRecovery(latentRRVarSample,
214 iName, eventDate);
215 this->simsBuffer_.back().push_back(
216 defaultSimEvent(iName, dateSTride, recovery));
217 //emplace_back
218 }
219 /* Used to remove sims with no events. Uses less memory, faster
220 post-statistics. But only if all names in the portfolio have low
221 default probability, otherwise is more expensive and sim access has
222 to be modified. However low probability is also an indicator that
223 variance reduction is needed. */
224 //if(simsBuffer.back().empty()) {
225 // emptySims_++;// Size; intilzd to zero
226 // simsBuffer.pop_back();
227 //}
228 }
229 }
230
231
232 // Common uses: Not valid in multithread version.
233 // ---------- Gaussian default generators options ------------------------
234 /* Uses copula direct normal inversion and MT generator
235 typedef RandomLossLM<GaussianCopulaPolicy,
236 RandomSequenceGenerator<MersenneTwisterUniformRng> >
237 GaussianRandomLossLM;
238 */
239 /* Uses BoxMuller for gaussian generation, bypassing copula inversions
240 typedef RandomLossLM<GaussianCopulaPolicy, RandomSequenceGenerator<
241 BoxMullerGaussianRng<MersenneTwisterUniformRng> > >
242 GaussianRandomLossLM;
243 */
244 /* Default case, uses the copula inversion directly and sobol sequence */
246
247 // ---------- T default generators options ----------------------------
248 /*
249 typedef RandomLossLM<TCopulaPolicy,
250 RandomSequenceGenerator<MersenneTwisterUniformRng> > TRandomLossLM;
251 */
252 /*
253 typedef RandomLossLM<TCopulaPolicy,
254 RandomSequenceGenerator<PolarStudentTRng<MersenneTwisterUniformRng> > >
255 TRandomLossLM;
256 */
258
259}
260
261#endif
Brent 1-D solver
Definition: brent.hpp:37
Concrete date class.
Definition: date.hpp:125
RelinkableHandle< Basket > basket_
Shared handle to an observable.
Definition: handle.hpp:41
void update() override
Definition: lazyobject.hpp:188
std::pair< iterator, bool > registerWith(const ext::shared_ptr< Observable > &)
Definition: observable.hpp:228
void nextSample(const std::vector< Real > &values) const
simEvent< RandomLossLM > defaultSimEvent
std::vector< Probability > horizonDefaultPs_
Real conditionalRecovery(Real latentVarSample, Size iName, const Date &d) const
void resetModel() override
Concrete models do now any updates/inits they need on basket reset.
Real latentVarValue(const std::vector< Real > &factorsSample, Size iVar) const
const ext::shared_ptr< SpotRecoveryLatentModel< copulaPolicy > > copula_
Real getEventRecovery(const defaultSimEvent &evt) const
DateProxy & evaluationDate()
the date at which pricing is to be performed.
Definition: settings.hpp:147
static Settings & instance()
access to the unique instance
Definition: singleton.hpp:104
Real solve(const F &f, Real accuracy, Real guess, Real step) const
Definition: solver1d.hpp:84
Random spot recovery rate latent variable portfolio model.
Utility for the numerical time solver.
QL_REAL Real
real number
Definition: types.hpp:50
QL_INTEGER Integer
integer number
Definition: types.hpp:35
Real Probability
probability
Definition: types.hpp:82
std::size_t Size
size of a container
Definition: types.hpp:58
Definition: any.hpp:35
RandomLossLM< TCopulaPolicy > TRandomLossLM
RandomLossLM< GaussianCopulaPolicy > GaussianRandomLossLM
unsigned QL_BIG_INTEGER BigNatural
large positive integer
Definition: types.hpp:46
STL namespace.