QuantLib: a free/open-source library for quantitative finance
Fully annotated sources - version 1.32
Loading...
Searching...
No Matches
syntheticcdo.cpp
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#include <ql/experimental/credit/syntheticcdo.hpp>
21
22#ifndef QL_PATCH_SOLARIS
23
24#include <ql/cashflows/fixedratecoupon.hpp>
25#include <ql/event.hpp>
26#include <ql/math/solvers1d/brent.hpp>
27#include <ql/termstructures/yieldtermstructure.hpp>
28#include <ql/experimental/credit/gaussianlhplossmodel.hpp>
29#include <ql/experimental/credit/midpointcdoengine.hpp>
30#include <ql/optional.hpp>
31
32using namespace std;
33
34namespace QuantLib {
35
36 SyntheticCDO::SyntheticCDO(const ext::shared_ptr<Basket>& basket,
38 const Schedule& schedule,
39 Rate upfrontRate,
40 Rate runningRate,
41 const DayCounter& dayCounter,
42 BusinessDayConvention paymentConvention,
43 ext::optional<Real> notional)
44 : basket_(basket), side_(side), upfrontRate_(upfrontRate), runningRate_(runningRate),
45 leverageFactor_(notional ? *notional / basket->trancheNotional() : Real(1.)), // NOLINT(readability-implicit-bool-conversion)
46 dayCounter_(dayCounter), paymentConvention_(paymentConvention) {
47 QL_REQUIRE(!basket->names().empty(), "basket is empty");
48 // Basket inception must lie before contract protection start.
49 QL_REQUIRE(basket->refDate() <= schedule.startDate(),
50 //using the start date of the schedule might be wrong, think of the
51 // CDS rule
52 "Basket did not exist before contract start.");
53
54 // Notice the notional is that of the basket at basket inception, some
55 // names might have defaulted in between
57 .withNotionals(basket_->trancheNotional() * leverageFactor_)
58 .withCouponRates(runningRate, dayCounter)
59 .withPaymentAdjustment(paymentConvention);
60
61 // Date today = Settings::instance().evaluationDate();
62
63 // register with probabilities if the corresponding issuer is, baskets
64 // are not registered with the DTS
65 for (Size i = 0; i < basket->names().size(); i++) {
66 /* This turns out to be a problem: depends on today but I am not
67 modifying the registrations, if we go back in time in the
68 calculations this would left me unregistered to some. Not impossible
69 to de-register and register when updating but i am dropping it.
70
71 if(!basket->pool()->get(basket->names()[i]).
72 defaultedBetween(schedule.dates()[0], today,
73 basket->pool()->defaultKeys()[i]))
74 */
75 // registers with the associated curve (issuer and event type)
76 // \todo make it possible to access them by name instead of index
77 registerWith(basket->pool()->get(basket->names()[i]).
78 defaultProbability(basket->pool()->defaultKeys()[i]));
79 /* \todo Issuers should be observables/obsrvr and they would in turn
80 regiter with the DTS; only we might get updates from curves we do
81 not use.
82 */
83 }
85 }
86
88 calculate();
89 return premiumValue_;
90 }
91
93 calculate();
94 return protectionValue_;
95 }
96
98 calculate();
100 return -premiumValue_;
101 }
102
104 calculate();
106 return protectionValue_;
107 }
108
110 calculate();
111 QL_REQUIRE(premiumValue_ != 0, "Attempted divide by zero while calculating syntheticCDO premium.");
112 return runningRate_
114 }
115
117 calculate();
119 }
120
121 std::vector<Real> SyntheticCDO::expectedTrancheLoss() const {
122 calculate();
124 }
125
127 calculate();
128 return error_;
129 }
130
132 // FIXME: it could have also expired (knocked out) because theres
133 // no remaining tranche notional.
134 return detail::simple_event(normalizedLeg_.back()->date())
135 .hasOccurred();
136 }
137
139 calculate();
140 return remainingNotional_;
141 }
142
144 auto* arguments = dynamic_cast<SyntheticCDO::arguments*>(args);
145 QL_REQUIRE(arguments != nullptr, "wrong argument type");
149
155 }
156
159
160 const auto* results = dynamic_cast<const SyntheticCDO::results*>(r);
161 QL_REQUIRE(results != nullptr, "wrong result type");
162
169 }
170
173 premiumValue_ = 0.0;
174 protectionValue_ = 0.0;
176 remainingNotional_ = 1.0;
177 expectedTrancheLoss_.clear();
178 }
179
181 QL_REQUIRE(side != Protection::Side(-1), "side not set");
182 QL_REQUIRE(basket && !basket->names().empty(), "no basket given");
183 QL_REQUIRE(runningRate != Null<Real>(), "no premium rate given");
184 QL_REQUIRE(upfrontRate != Null<Real>(), "no upfront rate given");
185 QL_REQUIRE(!dayCounter.empty(), "no day counter given");
186 }
187
192 upfrontPremiumValue = Null<Real>();
194 error = 0;
195 expectedTrancheLoss.clear();
196 }
197
198
199
200
201
202 namespace {
203
204 class ObjectiveFunction {
205 public:
206 ObjectiveFunction(Real target,
207 SimpleQuote& quote,
210 : target_(target), quote_(quote),
211 engine_(engine), results_(results) {}
212
213 Real operator()(Real guess) const {
214 quote_.setValue(guess);
215 engine_.calculate();
216 return results_->value - target_;
217 }
218 private:
219 Real target_;
220 SimpleQuote& quote_;
221 PricingEngine& engine_;
222 const SyntheticCDO::results* results_;
223 };
224
225 }
226
227 // untested, not sure this is not messing up, once it comes out of this
228 // the basket model is different.....
229 Real SyntheticCDO::implicitCorrelation(const std::vector<Real>& recoveries,
230 const Handle<YieldTermStructure>& discountCurve,
231 Real targetNPV,
232 Real accuracy) const
233 {
234 ext::shared_ptr<SimpleQuote> correl(new SimpleQuote(0.0));
235
236 ext::shared_ptr<GaussianLHPLossModel> lhp(new
237 GaussianLHPLossModel(Handle<Quote>(correl), recoveries));
238
239 // lock
240 basket_->setLossModel(lhp);
241
242 MidPointCDOEngine engineIC(discountCurve);
243 setupArguments(engineIC.getArguments());
244 const auto* results = dynamic_cast<const SyntheticCDO::results*>(engineIC.getResults());
245
246 // aviod recal of the basket on engine updates through the quote
247 basket_->recalculate();
248 basket_->freeze();
249
250 ObjectiveFunction f(targetNPV, *correl, engineIC, results);
251 Rate guess = 0.001;
252 // Rate step = guess*0.1;
253
254 // wrap/catch to be able to unfreeze the basket:
255 Real solution = Brent().solve(f, accuracy, guess, QL_EPSILON, 1.-QL_EPSILON);
256 basket_->unfreeze();
257 return solution;
258 }
259
260}
261
262#endif
Brent 1-D solver
Definition: brent.hpp:37
day counter class
Definition: daycounter.hpp:44
bool empty() const
Returns whether or not the day counter is initialized.
Definition: daycounter.hpp:113
virtual bool hasOccurred(const Date &refDate=Date(), ext::optional< bool > includeRefDate=ext::nullopt) const
returns true if an event has already occurred before a date
Definition: event.cpp:28
helper class building a sequence of fixed rate coupons
FixedRateLeg & withNotionals(Real)
FixedRateLeg & withPaymentAdjustment(BusinessDayConvention)
FixedRateLeg & withCouponRates(Rate, const DayCounter &paymentDayCounter, Compounding comp=Simple, Frequency freq=Annual)
PricingEngine::arguments * getArguments() const override
const PricingEngine::results * getResults() const override
Shared handle to an observable.
Definition: handle.hpp:41
void calculate() const override
Definition: instrument.hpp:129
virtual void fetchResults(const PricingEngine::results *) const
Definition: instrument.hpp:155
virtual void setupExpired() const
Definition: instrument.hpp:140
CDO base engine taking schedule steps.
template class providing a null value for a given type.
Definition: null.hpp:76
std::pair< iterator, bool > registerWith(const ext::shared_ptr< Observable > &)
Definition: observable.hpp:228
interface for pricing engines
Payment schedule.
Definition: schedule.hpp:40
const Date & startDate() const
Definition: schedule.hpp:180
market element returning a stored value
Definition: simplequote.hpp:33
Real solve(const F &f, Real accuracy, Real guess, Real step) const
Definition: solver1d.hpp:84
ext::shared_ptr< Basket > basket
void validate() const override
BusinessDayConvention paymentConvention
std::vector< Real > expectedTrancheLoss
Rate fairUpfrontPremium() const
ext::shared_ptr< Basket > basket_
void setupArguments(PricingEngine::arguments *) const override
const ext::shared_ptr< Basket > & basket() const
bool isExpired() const override
returns whether the instrument might have value greater than zero.
SyntheticCDO(const ext::shared_ptr< Basket > &basket, Protection::Side side, const Schedule &schedule, Rate upfrontRate, Rate runningRate, const DayCounter &dayCounter, BusinessDayConvention paymentConvention, ext::optional< Real > notional=ext::nullopt)
Real implicitCorrelation(const std::vector< Real > &recoveries, const Handle< YieldTermStructure > &discountCurve, Real targetNPV=0., Real accuracy=1.0e-3) const
Rate protectionValue() const
Protection::Side side_
Real protectionLegNPV() const
BusinessDayConvention paymentConvention_
Real premiumLegNPV() const
void setupExpired() const override
void fetchResults(const PricingEngine::results *) const override
std::vector< Real > expectedTrancheLoss() const
Rate premiumValue() const
std::vector< Real > expectedTrancheLoss_
Real remainingNotional() const
BusinessDayConvention
Business Day conventions.
#define QL_EPSILON
Definition: qldefines.hpp:178
QL_REAL Real
real number
Definition: types.hpp:50
Real Rate
interest rates
Definition: types.hpp:70
std::size_t Size
size of a container
Definition: types.hpp:58
Definition: any.hpp:35
STL namespace.