1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294
|
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
Copyright (C) 2014 Jose Aparicio
This file is part of QuantLib, a free-software/open-source library
for financial quantitative analysts and developers - http://quantlib.org/
QuantLib is free software: you can redistribute it and/or modify it
under the terms of the QuantLib license. You should have received a
copy of the license along with this program; if not, please email
<quantlib-dev@lists.sf.net>. The license is also available online at
<https://www.quantlib.org/license.shtml>.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the license for more details.
*/
#ifndef quantlib_base_correl_lossmodel_hpp
#define quantlib_base_correl_lossmodel_hpp
#include <ql/quote.hpp>
#include <ql/quotes/simplequote.hpp>
#include <ql/experimental/credit/basket.hpp>
#include <ql/experimental/credit/defaultlossmodel.hpp>
#include <ql/experimental/credit/basecorrelationstructure.hpp>
// move these to the CPP (and the template spezs)
#include <ql/experimental/credit/binomiallossmodel.hpp>
#include <ql/experimental/credit/gaussianlhplossmodel.hpp>
#include <ql/experimental/credit/inhomogeneouspooldef.hpp>
#include <utility>
namespace QuantLib {
/*! Base Correlation loss model; interpolation is performed by portfolio
(live) amount percentage.\par
Though the literature on this model is inmense, see for a more than
introductory level (precrisis) chapters 19, 20 and 21 of <b>Modelling single
name and multi-name credit derivatives.</b> Dominic O'Kane, Wiley Finance,
2008\par
For freely available documentation see:\par
Credit Correlation: A Guide; JP Morgan Credit Derivatives Strategy;
12 March 2004 \par
Introducing Base Correlations; JP Morgan Credit Derivatives Strategy;
22 March 2004 \par
A Relative Value Framework for Credit Correlation; JP Morgan Credit
Derivatives Strategy; 27 April 2004 \par
Valuing and Hedging Synthetic CDO Tranches Using Base Correlations; Bear
Stearns; May 17, 2004 \par
Correlation Primer; Nomura Fixed Income Research, August 6, 2004 \par
Base Correlation Explained; Lehman Brothers Fixed Income Quantitative
Credit Research; 15 November 2004 \par
'Pricing CDOs with a smile' in Societe Generale Credit Research;
February 2005 \par
For bespoke base correlation see: \par
Base Correlation Mapping in Lehman Brothers' Quantitative Credit Research
Quarterly; Volume 2007-Q1 \par
You can explore typical postcrisis data by perusing some of the JPMorgan
Global Correlation Daily Analytics \par
Here the crisis model problems of ability to price stressed portfolios
or tranches over the maximum loss are the responsibility of the base models.
Users should select their models according to this; choosing the copula or
a random loss given default base model (or more exotic ones). \par
Notice this is different to a bespoke base correlation loss (bespoke here
referring to basket composition, not just attachment levels) ; where
loss interpolation is on the expected loss value to match the two baskets.
Therefore the correlation surface should refer to the same basket intended
to be priced. But this is left to the user and is not implemented in the
correlation surface (yet...)
\todo Bespoke portfolios BC models are yet to be implemented.
BaseModel_T must have a constructor with a single quote value
*/
/* Criticism:
This model is not as generic as it could be. In principle a default loss
model dependent on a single factor correlation parameter is the only
restriction on the base loss model(s) type. This class however is tied to a
LatentModel single factor. But there is no need for the
underlying model to be of a latent type. This link is due to the copula
initialization traits which have to be present for non trivial copula
policies initialization (e.g. Student-T base correl models)
Maybe a possibility is to pass copiable instances of the model and relinking
to the correlation in two internal copies.
*/
template <class BaseModel_T, class Corr2DInt_T>
class BaseCorrelationLossModel : public DefaultLossModel,
public virtual Observer {
private:
typedef typename BaseModel_T::copulaType::initTraits initTraits;
public:
BaseCorrelationLossModel(const Handle<BaseCorrelationTermStructure<Corr2DInt_T> >& correlTS,
std::vector<Real> recoveries,
const initTraits& traits = initTraits())
: localCorrelationAttach_(ext::make_shared<SimpleQuote>(0.)),
localCorrelationDetach_(ext::make_shared<SimpleQuote>(0.)),
recoveries_(std::move(recoveries)), correlTS_(correlTS), copulaTraits_(traits) {
registerWith(correlTS);
registerWith(Settings::instance().evaluationDate());
}
private:
// react to base correl surface notifications (quotes or reference date)
void update() override {
setupModels();
// tell basket to notify instruments, etc, we are invalid
if (!basket_.empty())
basket_->notifyObservers();
}
/* Update model caches after basket assignement. */
void resetModel() override {
remainingNotional_ = basket_->remainingNotional();
attachRatio_ = basket_->remainingAttachmentAmount() / remainingNotional_;
detachRatio_ = basket_->remainingDetachmentAmount() / remainingNotional_;
basketAttach_ = ext::make_shared<Basket>(basket_->refDate(), basket_->remainingNames(),
basket_->remainingNotionals(), basket_->pool(),
0.0, attachRatio_, basket_->claim());
basketDetach_ = ext::make_shared<Basket>(basket_->refDate(), basket_->remainingNames(),
basket_->remainingNotionals(), basket_->pool(),
0.0, detachRatio_, basket_->claim());
setupModels();
}
/* Most of the statistics are not implemented, not impossible but
the model is intended for pricing rather than ptfolio risk management.
*/
Real expectedTrancheLoss(const Date& d) const override;
protected:
/*! Sets up attach/detach models. Gets called on basket update.
To be specialized on the spacific model type.
*/
void setupModels() const;
private:
mutable Real attachRatio_, detachRatio_;
mutable Real remainingNotional_;
//! Correlation buffer to pick up values from the surface and
// trigger calculation.
ext::shared_ptr<SimpleQuote> localCorrelationAttach_,
localCorrelationDetach_;
mutable ext::shared_ptr<Basket> basketAttach_,
basketDetach_;
// just cached for the update method
mutable std::vector<Real> recoveries_;
Handle<BaseCorrelationTermStructure<Corr2DInt_T> > correlTS_;
// Initialization parameters for models copula
mutable typename BaseModel_T::copulaType::initTraits copulaTraits_;
// Models of equity baskets.
mutable ext::shared_ptr<BaseModel_T> scalarCorrelModelAttach_;
mutable ext::shared_ptr<BaseModel_T> scalarCorrelModelDetach_;
};
// Remember ETL returns the EL on the live part of the basket.
template<class LM, class I>
Real BaseCorrelationLossModel<LM, I>::expectedTrancheLoss(
const Date& d) const
{
Real correlK1 = correlTS_->correlation(d, attachRatio_);
Real correlK2 = correlTS_->correlation(d, detachRatio_);
/* reset correl and call base models which have the different baskets
associated.*/
localCorrelationAttach_->setValue(correlK1);
Real expLossK1 =
basketAttach_->expectedTrancheLoss(d);
localCorrelationDetach_->setValue(correlK2);
Real expLossK2 =
basketDetach_->expectedTrancheLoss(d);
return expLossK2 - expLossK1;
}
// ----------------------------------------------------------------------
/* Concrete specializations submodels construction. With the dummy template
parameter trick partial specializations leaving the interpolation open
would be possible.
*/
#ifndef QL_PATCH_SOLARIS
template<>
inline void BaseCorrelationLossModel<GaussianLHPLossModel,
BilinearInterpolation>::setupModels() const
{
// on this assignment any previous registration with the attach and
// detach baskets should be removed
scalarCorrelModelAttach_ = ext::make_shared<GaussianLHPLossModel>(
Handle<Quote>(localCorrelationAttach_), recoveries_);
scalarCorrelModelDetach_ = ext::make_shared<GaussianLHPLossModel>(
Handle<Quote>(localCorrelationDetach_), recoveries_);
basketAttach_->setLossModel(scalarCorrelModelAttach_);
basketDetach_->setLossModel(scalarCorrelModelDetach_);
}
template<>
inline void BaseCorrelationLossModel<GaussianBinomialLossModel,
BilinearInterpolation>::setupModels() const
{
ext::shared_ptr<GaussianConstantLossLM> lmA =
ext::make_shared<GaussianConstantLossLM>(
Handle<Quote>(localCorrelationAttach_), recoveries_,
LatentModelIntegrationType::GaussianQuadrature,
recoveries_.size(), copulaTraits_);
ext::shared_ptr<GaussianConstantLossLM> lmD =
ext::make_shared<GaussianConstantLossLM>(
Handle<Quote>(localCorrelationDetach_), recoveries_,
LatentModelIntegrationType::GaussianQuadrature,
recoveries_.size(), copulaTraits_);
scalarCorrelModelAttach_ =
ext::make_shared<GaussianBinomialLossModel>(lmA);
scalarCorrelModelDetach_ =
ext::make_shared<GaussianBinomialLossModel>(lmD);
basketAttach_->setLossModel(scalarCorrelModelAttach_);
basketDetach_->setLossModel(scalarCorrelModelDetach_);
}
template<>
inline void BaseCorrelationLossModel<TBinomialLossModel,
BilinearInterpolation>::setupModels() const
{
ext::shared_ptr<TConstantLossLM> lmA =
ext::make_shared<TConstantLossLM>(
Handle<Quote>(localCorrelationAttach_), recoveries_,
LatentModelIntegrationType::GaussianQuadrature,
recoveries_.size(), copulaTraits_);
ext::shared_ptr<TConstantLossLM> lmD =
ext::make_shared<TConstantLossLM>(
Handle<Quote>(localCorrelationDetach_), recoveries_,
LatentModelIntegrationType::GaussianQuadrature,
recoveries_.size(), copulaTraits_);
scalarCorrelModelAttach_ =
ext::make_shared<TBinomialLossModel>(lmA);
scalarCorrelModelDetach_ =
ext::make_shared<TBinomialLossModel>(lmD);
basketAttach_->setLossModel(scalarCorrelModelAttach_);
basketDetach_->setLossModel(scalarCorrelModelDetach_);
}
/* \todo Fix this model, is failing for equity tranches at least, the
base model works all right, its the link here.
*/
template<>
inline void BaseCorrelationLossModel<IHGaussPoolLossModel,
BilinearInterpolation>::setupModels() const
{
ext::shared_ptr<GaussianConstantLossLM> lmA =
ext::make_shared<GaussianConstantLossLM>(
Handle<Quote>(localCorrelationAttach_), recoveries_,
LatentModelIntegrationType::GaussianQuadrature,
recoveries_.size(), copulaTraits_);
ext::shared_ptr<GaussianConstantLossLM> lmD =
ext::make_shared<GaussianConstantLossLM>(
Handle<Quote>(localCorrelationDetach_), recoveries_,
LatentModelIntegrationType::GaussianQuadrature,
recoveries_.size(), copulaTraits_);
// \todo Allow the sending specific model params, as the number of
// buckets here.
scalarCorrelModelAttach_ =
ext::make_shared<IHGaussPoolLossModel>(lmA, 500);
scalarCorrelModelDetach_ =
ext::make_shared<IHGaussPoolLossModel>(lmD, 500);
basketAttach_->setLossModel(scalarCorrelModelAttach_);
basketDetach_->setLossModel(scalarCorrelModelDetach_);
}
#endif
// Vanilla BC model
#ifndef QL_PATCH_SOLARIS
typedef BaseCorrelationLossModel<GaussianLHPLossModel,
BilinearInterpolation> GaussianLHPFlatBCLM;
#endif
}
#endif
|