/src/quantlib/ql/experimental/credit/syntheticcdo.hpp
Line | Count | Source |
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 | | <https://www.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 syntheticcdo.hpp |
21 | | \brief Synthetic Collateralized Debt Obligation and pricing engines |
22 | | */ |
23 | | |
24 | | #ifndef quantlib_synthetic_cdo_hpp |
25 | | #define quantlib_synthetic_cdo_hpp |
26 | | |
27 | | #include <ql/qldefines.hpp> |
28 | | |
29 | | #ifndef QL_PATCH_SOLARIS |
30 | | |
31 | | #include <ql/instrument.hpp> |
32 | | #include <ql/default.hpp> |
33 | | #include <ql/optional.hpp> |
34 | | #include <ql/time/schedule.hpp> |
35 | | |
36 | | #include <ql/experimental/credit/basket.hpp> |
37 | | #include <ql/cashflows/fixedratecoupon.hpp> |
38 | | |
39 | | namespace QuantLib { |
40 | | |
41 | | class YieldTermStructure; |
42 | | |
43 | | //! Synthetic Collateralized Debt Obligation |
44 | | /*! |
45 | | The instrument prices a mezzanine CDO tranche with loss given default |
46 | | between attachment point \f$ D_1\f$ and detachment point |
47 | | \f$ D_2 > D_1 \f$. |
48 | | |
49 | | For purchased protection, the instrument value is given by the difference |
50 | | of the protection value \f$ V_1 \f$ and premium value \f$ V_2 \f$, |
51 | | |
52 | | \f[ V = V_1 - V_2. \f] |
53 | | |
54 | | The protection leg is priced as follows: |
55 | | |
56 | | - Build the probability distribution for volume of defaults \f$ L \f$ |
57 | | (before recovery) or Loss Given Default \f$ LGD = (1-r)\,L \f$ at |
58 | | times/dates \f$ t_i, i=1, ..., N\f$ (premium schedule times with |
59 | | intermediate steps) |
60 | | |
61 | | - Determine the expected value |
62 | | \f$ E_i = E_{t_i}\,\left[Pay(LGD)\right] \f$ |
63 | | of the protection payoff \f$ Pay(LGD) \f$ at each time \f$ t_i\f$ where |
64 | | \f[ |
65 | | Pay(L) = min (D_1, LGD) - min (D_2, LGD) = \left\{ |
66 | | \begin{array}{lcl} |
67 | | \displaystyle 0 &;& LGD < D_1 \\ |
68 | | \displaystyle LGD - D_1 &;& D_1 \leq LGD \leq D_2 \\ |
69 | | \displaystyle D_2 - D_1 &;& LGD > D_2 |
70 | | \end{array} |
71 | | \right. |
72 | | \f] |
73 | | |
74 | | - The protection value is then calculated as |
75 | | \f[ V_1 \:=\: \sum_{i=1}^N (E_i - E_{i-1}) \cdot d_i \f] |
76 | | where \f$ d_i\f$ is the discount factor at time/date \f$ t_i \f$ |
77 | | |
78 | | The premium is paid on the protected notional amount, initially |
79 | | \f$ D_2 - D_1. \f$ This notional amount is reduced by the expected |
80 | | protection |
81 | | payments \f$ E_i \f$ at times \f$ t_i, \f$ so that the premium value is |
82 | | calculated as |
83 | | |
84 | | \f[ |
85 | | V_2 =m \, \cdot \sum_{i=1}^N \,(D_2 - D_1 - E_i) \cdot \Delta_{i-1,i}\,d_i |
86 | | \f] |
87 | | |
88 | | where \f$ m \f$ is the premium rate, \f$ \Delta_{i-1, i}\f$ is the day |
89 | | count fraction between date/time \f$ t_{i-1}\f$ and \f$ t_i.\f$ |
90 | | |
91 | | The construction of the portfolio loss distribution \f$ E_i \f$ is |
92 | | based on the probability bucketing algorithm described in |
93 | | |
94 | | <strong> |
95 | | John Hull and Alan White, "Valuation of a CDO and nth to default CDS |
96 | | without Monte Carlo simulation", Journal of Derivatives 12, 2, 2004 |
97 | | </strong> |
98 | | |
99 | | The pricing algorithm allows for varying notional amounts and |
100 | | default termstructures of the underlyings. |
101 | | |
102 | | \todo Investigate and fix cases \f$ E_{i+1} < E_i. \f$ |
103 | | */ |
104 | | class SyntheticCDO : public Instrument { |
105 | | public: |
106 | | class arguments; |
107 | | class results; |
108 | | class engine; |
109 | | |
110 | | // Review: No accrual settlement flag. No separate upfront payment date. |
111 | | // Review: Forward start case. |
112 | | /*! If the notional exceeds the basket inception tranche |
113 | | notional, the cdo is leveraged by that factor. |
114 | | |
115 | | \todo: allow for extra payment flags, arbitrary upfront |
116 | | payment date... |
117 | | */ |
118 | | SyntheticCDO (const ext::shared_ptr<Basket>& basket, |
119 | | Protection::Side side, |
120 | | Schedule schedule, |
121 | | Rate upfrontRate, |
122 | | Rate runningRate, |
123 | | const DayCounter& dayCounter, |
124 | | BusinessDayConvention paymentConvention, |
125 | | ext::optional<Real> notional = ext::nullopt); |
126 | | |
127 | 0 | const ext::shared_ptr<Basket>& basket() const { return basket_; } |
128 | | |
129 | | bool isExpired() const override; |
130 | | Rate fairPremium() const; |
131 | | Rate fairUpfrontPremium() const; |
132 | | Rate premiumValue () const; |
133 | | Rate protectionValue () const; |
134 | | Real premiumLegNPV() const; |
135 | | Real protectionLegNPV() const; |
136 | | /*! |
137 | | Total outstanding tranche notional, not wiped out |
138 | | */ |
139 | | Real remainingNotional() const; |
140 | | /*! The number of times the contract contains the portfolio tranched |
141 | | notional. |
142 | | */ |
143 | 0 | Real leverageFactor() const { |
144 | 0 | return leverageFactor_; |
145 | 0 | } |
146 | | //! Last protection date. |
147 | 0 | const Date& maturity() const { |
148 | 0 | return ext::dynamic_pointer_cast<FixedRateCoupon>( |
149 | 0 | normalizedLeg_.back())->accrualEndDate(); |
150 | 0 | } |
151 | | /*! The Gaussian Copula LHP implied correlation that makes the |
152 | | contract zero value. This is for a flat correlation along |
153 | | time and portfolio loss level. |
154 | | */ |
155 | | Real implicitCorrelation(const std::vector<Real>& recoveries, |
156 | | const Handle<YieldTermStructure>& discountCurve, |
157 | | Real targetNPV = 0., |
158 | | Real accuracy = 1.0e-3) const; |
159 | | |
160 | | /*! |
161 | | Expected tranche loss for all payment dates |
162 | | */ |
163 | | std::vector<Real> expectedTrancheLoss() const; |
164 | | Size error () const; |
165 | | |
166 | | void setupArguments(PricingEngine::arguments*) const override; |
167 | | void fetchResults(const PricingEngine::results*) const override; |
168 | | |
169 | | private: |
170 | | void setupExpired() const override; |
171 | | |
172 | | ext::shared_ptr<Basket> basket_; |
173 | | Protection::Side side_; |
174 | | Leg normalizedLeg_; |
175 | | |
176 | | Rate upfrontRate_; |
177 | | Rate runningRate_; |
178 | | const Real leverageFactor_; |
179 | | DayCounter dayCounter_; |
180 | | BusinessDayConvention paymentConvention_; |
181 | | |
182 | | mutable Real premiumValue_; |
183 | | mutable Real protectionValue_; |
184 | | mutable Real upfrontPremiumValue_; |
185 | | mutable Real remainingNotional_; |
186 | | mutable Size error_; |
187 | | mutable std::vector<Real> expectedTrancheLoss_; |
188 | | }; |
189 | | |
190 | | class SyntheticCDO::arguments : public virtual PricingEngine::arguments { |
191 | | public: |
192 | 0 | arguments() : side(Protection::Side(-1)), |
193 | 0 | upfrontRate(Null<Real>()), |
194 | 0 | runningRate(Null<Real>()) {} |
195 | | void validate() const override; |
196 | | |
197 | | ext::shared_ptr<Basket> basket; |
198 | | Protection::Side side; |
199 | | Leg normalizedLeg; |
200 | | |
201 | | Rate upfrontRate; |
202 | | Rate runningRate; |
203 | | Real leverageFactor; |
204 | | DayCounter dayCounter; |
205 | | BusinessDayConvention paymentConvention; |
206 | | }; |
207 | | |
208 | | class SyntheticCDO::results : public Instrument::results { |
209 | | public: |
210 | | void reset() override; |
211 | | Real premiumValue; |
212 | | Real protectionValue; |
213 | | Real upfrontPremiumValue; |
214 | | Real remainingNotional; |
215 | | Real xMin, xMax; |
216 | | Size error; |
217 | | /* Expected tranche losses affecting this tranche coupons. Notice this |
218 | | number might be below the actual basket losses, since the cdo protection |
219 | | might start after basket inception (forward start CDO)*/ |
220 | | std::vector<Real> expectedTrancheLoss; |
221 | | }; |
222 | | |
223 | | |
224 | | //! CDO base engine |
225 | | class SyntheticCDO::engine : |
226 | | public GenericEngine<SyntheticCDO::arguments, |
227 | | SyntheticCDO::results> { }; |
228 | | |
229 | | } |
230 | | |
231 | | #endif |
232 | | |
233 | | #endif |