• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

lballabio / QuantLib / 14910176578

08 May 2025 03:28PM UTC coverage: 73.315% (+0.02%) from 73.3%
14910176578

Pull #2195

github

web-flow
Merge 3a61f499c into 5d972fb7b
Pull Request #2195: Added `Handle<Quote>` for spread in `OISRateHelper`

32 of 33 new or added lines in 2 files covered. (96.97%)

277 existing lines in 25 files now uncovered.

56277 of 76761 relevant lines covered (73.31%)

8687029.35 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

81.25
/ql/experimental/credit/inhomogeneouspooldef.hpp
1
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2

3
/*
4
 Copyright (C) 2008 Roland Lichters
5
 Copyright (C) 2009, 2014 Jose Aparicio
6

7
 This file is part of QuantLib, a free-software/open-source library
8
 for financial quantitative analysts and developers - http://quantlib.org/
9

10
 QuantLib is free software: you can redistribute it and/or modify it
11
 under the terms of the QuantLib license.  You should have received a
12
 copy of the license along with this program; if not, please email
13
 <quantlib-dev@lists.sf.net>. The license is also available online at
14
 <http://quantlib.org/license.shtml>.
15

16
 This program is distributed in the hope that it will be useful, but WITHOUT
17
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18
 FOR A PARTICULAR PURPOSE.  See the license for more details.
19
*/
20

21
#ifndef quantlib_inhomogenous_pool_default_model_hpp
22
#define quantlib_inhomogenous_pool_default_model_hpp
23

24
#include <ql/experimental/credit/lossdistribution.hpp>
25
#include <ql/experimental/credit/basket.hpp>
26
#include <ql/experimental/credit/constantlosslatentmodel.hpp>
27
#include <ql/experimental/credit/defaultlossmodel.hpp>
28

29
// Intended to replace InhomogeneousPoolCDOEngine in syntheticcdoengines.hpp
30

31
namespace QuantLib {
32

33
    //-------------------------------------------------------------------------
34
    //! Default loss distribution convolution for finite non homogeneous pool
35
    /* A note on the number of buckets: As it is now the code goes splitting
36
    losses into buckets from loses equal to zero to losses up to the value of
37
    the underlying basket. This is in view of a stochastic loss given default
38
    but in a constant LGD situation this is a waste and it is more efficient to
39
    go up to the attainable losses.
40
    \todo Extend to the multifactor case for a generic LM
41
    \todo Many common code with the homogeneous version, both classes perform
42
    the same work on different loss distribution types, merge and send the 
43
    distribution object?
44
    */
45
    template<class copulaPolicy>
46
    class InhomogeneousPoolLossModel : public DefaultLossModel {
47
    private:
48
      void resetModel() override;
49

50
    public:
51
        // allow base correlations:
52
        typedef copulaPolicy copulaType;
53

54
        InhomogeneousPoolLossModel(
6✔
55
        // restricted to non random recoveries, but it could be possible.
56
            const ext::shared_ptr<ConstantLossLatentmodel<copulaPolicy> >& 
57
                copula,
58
            Size nBuckets,
59
            Real max = 5.,
60
            Real min = -5.,
61
            Size nSteps = 50)
62
        : copula_(copula), 
63
          nBuckets_(nBuckets), 
6✔
64
          max_(max), min_(min), nSteps_(nSteps), delta_((max - min)/nSteps)
6✔
65
        { 
66
            QL_REQUIRE(copula->numFactors() == 1, 
6✔
67
                "Inhomogeneous model not implemented for multifactor");
68
        }
6✔
69
    // Write another constructor sending the LM factors and recoveries.
70
    protected:
71
        Distribution lossDistrib(const Date& d) const;
72
    public:
73
      Real expectedTrancheLoss(const Date& d) const override {
881✔
74
          return lossDistrib(d).cumulativeExcessProbability(attachAmount_, detachAmount_);
881✔
75
          // This one if the distribution is over the whole loss structure:
76
          // but it becomes very expensive
77
          /*
78
          return lossDistrib(d).trancheExpectedValue(
79
              attachAmount_, detachAmount_);
80
          */
81
      }
82
      Real percentile(const Date& d, Real percentile) const override {
×
83
          Real portfLoss = lossDistrib(d).confidenceLevel(percentile);
×
84
          return std::min(std::max(portfLoss - attachAmount_, 0.), detachAmount_ - attachAmount_);
×
85
      }
86
      Real expectedShortfall(const Date& d, Probability percentile) const override {
×
87
          Distribution dist = lossDistrib(d);
×
88
          dist.tranche(attachAmount_, detachAmount_);
×
89
          return dist.expectedShortfall(percentile);
×
90
      }
×
91

92
    protected:
93
        const ext::shared_ptr<ConstantLossLatentmodel<copulaPolicy> > copula_;
94
        Size nBuckets_;
95
        mutable Real attach_, detach_, notional_, attachAmount_, detachAmount_;
96
        mutable std::vector<Real> notionals_;
97
    private:
98
        // integration:
99
        //  \todo move integration to latent model types when moving to a 
100
        //  multifactor version
101
        const Real max_;// redundant?
102
        const Real min_;
103
        const Size nSteps_;
104
        const Real delta_; 
105
    };
106
    // \todo Add other loss distribution statistics
107
    typedef InhomogeneousPoolLossModel<GaussianCopulaPolicy> 
108
        IHGaussPoolLossModel;
109
    typedef InhomogeneousPoolLossModel<TCopulaPolicy> IHStudentPoolLossModel;
110

111
    //-----------------------------------------------------------------------
112

113
    template<class CP>
114
    void InhomogeneousPoolLossModel<CP>::resetModel()
21✔
115
    {
116
        // need to be capped now since the limit amounts might be over the 
117
        //  remaining notional (think amortizing)
118
        attach_ = std::min(basket_->remainingAttachmentAmount() / 
42✔
119
            basket_->remainingNotional(), 1.);
42✔
120
        detach_ = std::min(basket_->remainingDetachmentAmount() / 
42✔
121
            basket_->remainingNotional(), 1.);
42✔
122
        notional_ = basket_->remainingNotional();
21✔
123
        notionals_ = basket_->remainingNotionals();
21✔
124
        attachAmount_ = basket_->remainingAttachmentAmount();
21✔
125
        detachAmount_ = basket_->remainingDetachmentAmount();
21✔
126

127
        copula_->resetBasket(basket_.currentLink());
21✔
128
    }
21✔
129

130
    template<class CP>
131
    Distribution InhomogeneousPoolLossModel<CP>::lossDistrib(
881✔
132
        const Date& d) const 
133
    {
134
        LossDistBucketing bucktLDistBuff(nBuckets_, detachAmount_);
881✔
135

136
        std::vector<Real> lgd;// switch to a mutable cache member
137
        std::vector<Real> recoveries = copula_->recoveries();
881✔
138
        std::transform(recoveries.begin(), recoveries.end(), 
881✔
139
                       std::back_inserter(lgd),
140
                       [](Real x) -> Real { return 1.0-x; });
88,010✔
141
        std::transform(lgd.begin(), lgd.end(), notionals_.begin(), 
881✔
142
                       lgd.begin(), std::multiplies<>());
143
        std::vector<Real> prob = basket_->remainingProbabilities(d);
881✔
144
        for(Size iName=0; iName<prob.size(); iName++)
88,891✔
145
            prob[iName] = copula_->inverseCumulativeY(prob[iName], iName);
88,010✔
146

147
        // integrate locally (1 factor). 
148
        // use explicitly a 1D latent model object? 
149
        // \todo Use a library integrator here and in the homogeneous case.
150
        Distribution dist(nBuckets_, 0.0, 
881✔
151
            detachAmount_);
152
            //notional_);
153
        std::vector<Real> mkft(1, min_ + delta_ /2.);
881✔
154
        for (Size i = 0; i < nSteps_; i++) {
14,131✔
155
            std::vector<Real> conditionalProbs;
156
            conditionalProbs.reserve(notionals_.size());
13,250✔
157
            for(Size iName=0; iName<notionals_.size(); iName++)
1,333,750✔
158
                conditionalProbs.push_back(
159
                copula_->conditionalDefaultProbabilityInvP(prob[iName], iName, 
1,320,500✔
160
                    mkft));
161
            Distribution bld = bucktLDistBuff(lgd, conditionalProbs);
13,250✔
162
            Real densitydm = delta_ * copula_->density(mkft);
13,250✔
163
            // also, instead of calling the static method it could be wrapped 
164
            // through an inlined call in the latent model
165
            for (Size j = 0; j < nBuckets_; j++)
2,658,250✔
166
                dist.addDensity(j, bld.density(j) * densitydm);
2,645,000✔
167
            mkft[0] += delta_;
13,250✔
168
        }
169
        return dist;
881✔
UNCOV
170
    }
×
171

172

173
}
174

175
#endif
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc