Coverage Report

Created: 2025-08-05 06:45

/src/quantlib/ql/experimental/credit/cdo.hpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3
/*
4
 Copyright (C) 2008 Roland Lichters
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
20
/*! \file cdo.hpp
21
    \brief collateralized debt obligation
22
*/
23
24
#ifndef quantlib_cdo_hpp
25
#define quantlib_cdo_hpp
26
27
#include <ql/instrument.hpp>
28
#include <ql/termstructures/yieldtermstructure.hpp>
29
#include <ql/termstructures/defaulttermstructure.hpp>
30
#include <ql/experimental/credit/lossdistribution.hpp>
31
#include <ql/experimental/credit/onefactorcopula.hpp>
32
#include <ql/time/schedule.hpp>
33
34
namespace QuantLib {
35
36
    //! collateralized debt obligation
37
    /*! The instrument prices a mezzanine CDO tranche with loss given
38
        default between attachment point \f$ D_1\f$ and detachment
39
        point \f$ D_2 > D_1 \f$.
40
41
        For purchased protection, the instrument value is given by the
42
        difference of the protection value \f$ V_1 \f$ and premium
43
        value \f$ V_2 \f$,
44
45
        \f[ V = V_1 - V_2. \f]
46
47
        The protection leg is priced as follows:
48
49
        - Build the probability distribution for volume of defaults
50
          \f$ L \f$ (before recovery) or Loss Given Default \f$ LGD =
51
          (1-r)\,L \f$ at times/dates \f$ t_i, i=1, ..., N\f$ (premium
52
          schedule times with intermediate steps)
53
        - Determine the expected value
54
          \f$ E_i = E_{t_i}\,\left[Pay(LGD)\right] \f$
55
          of the protection payoff \f$ Pay(LGD) \f$ at each time
56
          \f$ t_i\f$ where
57
         \f[
58
         Pay(L) = min (D_1, LGD) - min (D_2, LGD) = \left\{
59
         \begin{array}{lcl}
60
         \displaystyle 0 &;& LGD < D_1 \\
61
         \displaystyle LGD - D_1 &;& D_1 \leq LGD \leq D_2 \\
62
         \displaystyle D_2 - D_1 &;& LGD > D_2
63
         \end{array}
64
         \right.
65
         \f]
66
        - The protection value is then calculated as
67
          \f[ V_1 \:=\: \sum_{i=1}^N (E_i - E_{i-1}) \cdot  d_i \f]
68
          where \f$ d_i\f$ is the discount factor at time/date \f$ t_i \f$
69
70
        The premium is paid on the protected notional amount,
71
        initially \f$ D_2 - D_1. \f$ This notional amount is reduced
72
        by the expected protection payments \f$ E_i \f$ at times
73
        \f$ t_i, \f$ so that the premium value is calculated as
74
75
        \f[
76
        V_2 = m \, \cdot \sum_{i=1}^N \,(D_2 - D_1 - E_i)
77
                   \cdot \Delta_{i-1,i}\,d_i
78
        \f]
79
80
        where \f$ m \f$ is the premium rate, \f$ \Delta_{i-1, i}\f$ is
81
        the day count fraction between date/time \f$ t_{i-1}\f$ and
82
        \f$ t_i.\f$
83
84
        The construction of the portfolio loss distribution \f$ E_i
85
        \f$ is based on the probability bucketing algorithm described
86
        in
87
88
        <strong>
89
        John Hull and Alan White, "Valuation of a CDO and nth to default CDS
90
        without Monte Carlo simulation", Journal of Derivatives 12, 2, 2004
91
        </strong>
92
93
        The pricing algorithm allows for varying notional amounts and
94
        default termstructures of the underlyings.
95
96
        \todo Investigate and fix cases \f$ E_{i+1} < E_i. \f$
97
    */
98
    class CDO : public Instrument {
99
      public:
100
        /*! \param attachment  fraction of the LGD where protection starts
101
            \param detachment  fraction of the LGD where protection ends
102
            \param nominals    vector of basket nominal amounts
103
            \param basket      default basket represented by a vector of
104
                               default term structures that allow
105
                               computing single name default
106
                               probabilities depending on time
107
            \param copula      one-factor copula
108
            \param protectionSeller   sold protection if set to true, purchased
109
                                      otherwise
110
            \param premiumSchedule    schedule for premium payments
111
            \param premiumRate        annual premium rate, e.g. 0.05 for 5% p.a.
112
            \param dayCounter         day count convention for the premium rate
113
            \param recoveryRate       recovery rate as a fraction
114
            \param upfrontPremiumRate premium as a tranche notional fraction
115
            \param yieldTS            yield term structure handle
116
            \param nBuckets           number of distribution buckets
117
            \param integrationStep    time step for integrating over one
118
                                      premium period; if larger than premium
119
                                      period length, a single step is taken
120
        */
121
        CDO(Real attachment,
122
            Real detachment,
123
            std::vector<Real> nominals,
124
            const std::vector<Handle<DefaultProbabilityTermStructure> >& basket,
125
            Handle<OneFactorCopula> copula,
126
            bool protectionSeller,
127
            Schedule premiumSchedule,
128
            Rate premiumRate,
129
            DayCounter dayCounter,
130
            Rate recoveryRate,
131
            Rate upfrontPremiumRate,
132
            Handle<YieldTermStructure> yieldTS,
133
            Size nBuckets,
134
            const Period& integrationStep = Period(10, Years));
135
136
0
        Real nominal() const { return nominal_; }
137
0
        Real lgd() const { return lgd_; }
138
0
        Real attachment() const { return attachment_; }
139
0
        Real detachment() const { return detachment_; }
140
0
        std::vector<Real> nominals() { return nominals_; }
141
0
        Size size() { return basket_.size(); }
142
143
        bool isExpired() const override;
144
        Rate fairPremium() const;
145
        Rate premiumValue () const;
146
        Rate protectionValue () const;
147
        Size error () const;
148
149
      private:
150
        void setupExpired() const override;
151
        void performCalculations() const override;
152
        Real expectedTrancheLoss (Date d) const;
153
154
        Real attachment_;
155
        Real detachment_;
156
        std::vector<Real> nominals_;
157
        std::vector<Handle<DefaultProbabilityTermStructure> > basket_;
158
        Handle<OneFactorCopula> copula_;
159
        bool protectionSeller_;
160
161
        Schedule premiumSchedule_;
162
        Rate premiumRate_;
163
        DayCounter dayCounter_;
164
        Rate recoveryRate_;
165
        Rate upfrontPremiumRate_;
166
        Handle<YieldTermStructure> yieldTS_;
167
        Size nBuckets_; // number of buckets up to detachment point
168
        Period integrationStep_;
169
170
        std::vector<Real> lgds_;
171
172
        Real nominal_;  // total basket volume (sum of nominals_)
173
        Real lgd_;      // maximum loss given default (sum of lgds_)
174
        Real xMax_;     // tranche detachment point (tranche_ * nominal_)
175
        Real xMin_;     // tranche attachment point (tranche_ * nominal_)
176
177
        mutable Size error_;
178
179
        mutable Real premiumValue_;
180
        mutable Real protectionValue_;
181
        mutable Real upfrontPremiumValue_;
182
    };
183
184
}
185
186
#endif