Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
syntheticcdo.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2017 Quaternion Risk Management Ltd
3 All rights reserved.
4
5 This file is part of ORE, a free-software/open-source library
6 for transparent pricing and risk analysis - http://opensourcerisk.org
7
8 ORE is free software: you can redistribute it and/or modify it
9 under the terms of the Modified BSD License. You should have received a
10 copy of the license along with this program.
11 The license is also available online at <http://opensourcerisk.org>
12
13 This program is distributed on the basis that it will form a useful
14 contribution to risk analytics and model standardisation, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the license for more details.
17*/
18
19//#include <ql/experimental/credit/syntheticcdo.hpp>
21
22#ifndef QL_PATCH_SOLARIS
23
24#include <ql/cashflows/cashflows.hpp>
25#include <ql/cashflows/fixedratecoupon.hpp>
26#include <ql/cashflows/simplecashflow.hpp>
27#include <ql/event.hpp>
28#include <ql/math/solvers1d/brent.hpp>
29#include <ql/termstructures/yieldtermstructure.hpp>
30//#include <ql/experimental/credit/gaussianlhplossmodel.hpp>
32//#include <ql/experimental/credit/midpointcdoengine.hpp>
34
35using namespace std;
36using namespace QuantLib;
37
38namespace QuantExt {
39
40SyntheticCDO::SyntheticCDO(const QuantLib::ext::shared_ptr<QuantExt::Basket>& basket, Protection::Side side,
41 const Schedule& schedule, Rate upfrontRate, Rate runningRate, const DayCounter& dayCounter,
42 BusinessDayConvention paymentConvention, bool settlesAccrual,
43 CreditDefaultSwap::ProtectionPaymentTime protectionPaymentTime, Date protectionStart,
44 Date upfrontDate, boost::optional<Real> notional, Real recoveryRate,
45 const DayCounter& lastPeriodDayCounter)
46 : basket_(basket), side_(side), upfrontRate_(upfrontRate), runningRate_(runningRate),
47 leverageFactor_(notional ? notional.get() / basket->trancheNotional() : 1.), dayCounter_(dayCounter),
48 paymentConvention_(paymentConvention), settlesAccrual_(settlesAccrual),
49 protectionPaymentTime_(protectionPaymentTime),
50 protectionStart_(protectionStart == Null<Date>() ? schedule[0] : protectionStart),
51 recoveryRate_(recoveryRate) {
52 QL_REQUIRE((schedule.rule() == DateGeneration::CDS || schedule.rule() == DateGeneration::CDS2015) ||
53 protectionStart_ <= schedule[0],
54 "protection can not start after accrual for (pre big bang-) CDS");
55 QL_REQUIRE(basket->names().size() > 0, "basket is empty");
56 // Basket inception must lie before contract protection start.
57 QL_REQUIRE(basket->refDate() <= schedule.startDate(),
58 // using the start date of the schedule might be wrong, think of the
59 // CDS rule
60 "Basket did not exist before contract start.");
61
62 // Notice the notional is that of the basket at basket inception, some
63 // names might have defaulted in between
64 normalizedLeg_ = FixedRateLeg(schedule)
65 .withNotionals(basket_->trancheNotional() * leverageFactor_)
66 .withCouponRates(runningRate, dayCounter)
67 .withPaymentAdjustment(paymentConvention)
68 .withLastPeriodDayCounter(lastPeriodDayCounter);
69
70 // If empty, adjust to T+3 standard settlement
71 Date effectiveUpfrontDate =
72 upfrontDate == Null<Date>()
73 ? schedule.calendar().advance(schedule.calendar().adjust(protectionStart_, paymentConvention), 3, Days,
74 paymentConvention)
75 : upfrontDate;
76 // '2' is used above since the protection start is assumed to be
77 // on trade_date + 1
78 upfrontPayment_.reset(
79 new SimpleCashFlow(basket_->trancheNotional() * leverageFactor_ * upfrontRate, effectiveUpfrontDate));
80
81 QL_REQUIRE(upfrontPayment_->date() >= protectionStart_, "upfront can not be due before contract start");
82
83 if (schedule.rule() == DateGeneration::CDS || schedule.rule() == DateGeneration::CDS2015) {
84 accrualRebate_= QuantLib::ext::make_shared<SimpleCashFlow>(QuantLib::CashFlows::accruedAmount(normalizedLeg_, false, protectionStart_+1),
85 effectiveUpfrontDate);
86 Date current = std::max((Date)Settings::instance().evaluationDate(), protectionStart_);
87 accrualRebateCurrent_ = QuantLib::ext::make_shared<SimpleCashFlow>(
88 CashFlows::accruedAmount(normalizedLeg_, false, current + 1),
89 schedule.calendar().advance(current, 3, Days, paymentConvention));
90
91 }
92
93
94
95 // register with probabilities if the corresponding issuer is, baskets
96 // are not registered with the DTS
97 for (Size i = 0; i < basket->names().size(); i++) {
98 /* This turns out to be a problem: depends on today but I am not
99 modifying the registrations, if we go back in time in the
100 calculations this would left me unregistered to some. Not impossible
101 to de-register and register when updating but i am dropping it.
102
103 if(!basket->pool()->get(basket->names()[i]).
104 defaultedBetween(schedule.dates()[0], today,
105 basket->pool()->defaultKeys()[i]))
106 */
107 // registers with the associated curve (issuer and event type)
108 // \todo make it possible to access them by name instead of index
109 registerWith(basket->pool()->get(basket->names()[i]).defaultProbability(basket->pool()->defaultKeys()[i]));
110 /* \todo Issuers should be observables/obsrvr and they would in turn
111 regiter with the DTS; only we might get updates from curves we do
112 not use.
113 */
114 }
115 registerWith(basket_);
116}
117
119 calculate();
120 return premiumValue_;
121}
122
124 calculate();
125 return protectionValue_;
126}
127
129 calculate();
130 if (side_ == Protection::Buyer)
131 return premiumValue_;
132 return -premiumValue_;
133}
134
136 calculate();
137 if (side_ == Protection::Buyer)
138 return -protectionValue_;
139 return premiumValue_;
140}
141
143 calculate();
145}
146
148 calculate();
150}
151
153 calculate();
155}
156
158 calculate();
159 return error_;
160}
161
163 // FIXME: it could have also expired (knocked out) because theres
164 // no remaining tranche notional.
165 return detail::simple_event(normalizedLeg_.back()->date()).hasOccurred();
166}
167
169 calculate();
170 return remainingNotional_;
171}
172
175 QL_REQUIRE(arguments != 0, "wrong argument type");
179
193}
194
195void SyntheticCDO::fetchResults(const PricingEngine::results* r) const {
196 Instrument::fetchResults(r);
197
198 const SyntheticCDO::results* results = dynamic_cast<const SyntheticCDO::results*>(r);
199 QL_REQUIRE(results != 0, "wrong result type");
200
207}
208
210 Instrument::setupExpired();
211 premiumValue_ = 0.0;
212 protectionValue_ = 0.0;
214 remainingNotional_ = 1.0;
215 expectedTrancheLoss_.clear();
216}
217
219 QL_REQUIRE(side != Protection::Side(-1), "side not set");
220 QL_REQUIRE(basket && !basket->names().empty(), "no basket given");
221 QL_REQUIRE(runningRate != Null<Real>(), "no premium rate given");
222 QL_REQUIRE(upfrontRate != Null<Real>(), "no upfront rate given");
223 QL_REQUIRE(!dayCounter.empty(), "no day counter given");
224}
225
227 Instrument::results::reset();
228 premiumValue = Null<Real>();
229 protectionValue = Null<Real>();
230 upfrontPremiumValue = Null<Real>();
231 remainingNotional = Null<Real>();
232 error = 0;
233 expectedTrancheLoss.clear();
234}
235
236namespace {
237
238class ObjectiveFunction {
239public:
240 ObjectiveFunction(Real target, SimpleQuote& quote, PricingEngine& engine, const SyntheticCDO::results* results)
241 : target_(target), quote_(quote), engine_(engine), results_(results) {}
242
243 Real operator()(Real guess) const {
244 quote_.setValue(guess);
245 engine_.calculate();
246 return results_->value - target_;
247 }
248
249private:
251 SimpleQuote& quote_;
252 PricingEngine& engine_;
253 const SyntheticCDO::results* results_;
254};
255} // namespace
256
257// untested, not sure this is not messing up, once it comes out of this
258// the basket model is different.....
259Real SyntheticCDO::implicitCorrelation(const std::vector<Real>& recoveries,
260 const Handle<YieldTermStructure>& discountCurve, Real targetNPV,
261 Real accuracy) const {
262 QuantLib::ext::shared_ptr<SimpleQuote> correl(new SimpleQuote(0.0));
263
264 QuantLib::ext::shared_ptr<GaussianLHPLossModel> lhp(new GaussianLHPLossModel(Handle<Quote>(correl), recoveries));
265
266 // lock
267 basket_->setLossModel(lhp);
268
269 QuantExt::MidPointCDOEngine engineIC(discountCurve);
270 setupArguments(engineIC.getArguments());
271 const SyntheticCDO::results* results = dynamic_cast<const SyntheticCDO::results*>(engineIC.getResults());
272
273 // aviod recal of the basket on engine updates through the quote
274 basket_->recalculate();
275 basket_->freeze();
276
277 ObjectiveFunction f(targetNPV, *correl, engineIC, results);
278 Rate guess = 0.001;
279 // Rate step = guess*0.1;
280
281 // wrap/catch to be able to unfreeze the basket:
282 Real solution = Brent().solve(f, accuracy, guess, QL_EPSILON, 1. - QL_EPSILON);
283 basket_->unfreeze();
284 return solution;
285}
286} // namespace QuantExt
287
288#endif
QuantLib::ext::shared_ptr< PricingEngine > engine_
Definition: cdsoption.cpp:78
const Instrument::results * results_
Definition: cdsoption.cpp:81
CDO base engine taking schedule steps.
QuantLib::ext::shared_ptr< QuantExt::Basket > basket
QuantLib::CreditDefaultSwap::ProtectionPaymentTime protectionPaymentTime
QuantLib::ext::shared_ptr< CashFlow > upfrontPayment
void validate() const override
QuantLib::ext::shared_ptr< CashFlow > accrualRebate
QuantLib::ext::shared_ptr< CashFlow > accrualRebateCurrent
BusinessDayConvention paymentConvention
std::vector< Real > expectedTrancheLoss
QuantLib::ext::shared_ptr< CashFlow > accrualRebateCurrent_
std::vector< Real > expectedTrancheLoss() const
Rate fairUpfrontPremium() const
SyntheticCDO(const QuantLib::ext::shared_ptr< QuantExt::Basket > &basket, Protection::Side side, const Schedule &schedule, Rate upfrontRate, Rate runningRate, const DayCounter &dayCounter, BusinessDayConvention paymentConvention, bool settlesAccrual=true, const QuantLib::CreditDefaultSwap::ProtectionPaymentTime protectionPaymentTime=QuantLib::CreditDefaultSwap::ProtectionPaymentTime::atDefault, Date protectionStart=Date(), Date upfrontDate=Date(), boost::optional< Real > notional=boost::none, Real recoveryRate=Null< Real >(), const DayCounter &lastPeriodDayCounter=DayCounter())
QuantLib::CreditDefaultSwap::ProtectionPaymentTime protectionPaymentTime_
QuantLib::ext::shared_ptr< QuantExt::Basket > basket_
const QuantLib::ext::shared_ptr< QuantExt::Basket > & basket() const
void setupArguments(PricingEngine::arguments *) const override
bool isExpired() const override
const Date & maturity() const
Last protection date.
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
QuantLib::ext::shared_ptr< CashFlow > accrualRebate_
BusinessDayConvention paymentConvention_
Real premiumLegNPV() const
void setupExpired() const override
void fetchResults(const PricingEngine::results *) const override
std::vector< Real > expectedTrancheLoss_
Real remainingNotional() const
QuantLib::ext::shared_ptr< CashFlow > upfrontPayment_
SimpleQuote & quote_
Real target_
Synthetic Collateralized Debt Obligation and pricing engines.