Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
bondbasket.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2020 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
21#include <ql/cashflows/simplecashflow.hpp>
22
23using namespace std;
24using namespace QuantLib;
25
26namespace QuantExt {
27
28 const double BondBasket::getScalar(const std::string& name, const QuantLib::Date& currentDate) const{
29 double result = -1.0;
30 for(auto& bond : qlBonds_){
31 if(bond.first == name){
32 const QuantLib::Leg& leg = bond.second->cashflows();
33 vector<Real> scalar = reinvestmentScalar(name);
34 for(size_t d = 1; d < leg.size(); d++){
35 if(leg[d-1]->date() < currentDate && leg[d]->date() >= currentDate)
36 result = scalar[d];
37 }
38 }
39 }
40 return result;
41 }
42
44
45 cashflows_.clear();
46 interestFlows_.clear();
47 notionalFlows_.clear();
48 feeFlows_.clear();
49
50 for(auto bond : qlBonds_){
51
52 std::string name = bond.first;
53 double multi = multiplier(name);
54 vector<double> scalar = reinvestmentScalar(name);
55 Leg leg = bond.second->cashflows();
56
57 std::vector<ext::shared_ptr<QuantLib::CashFlow> > cashflows;
58 std::vector<ext::shared_ptr<QuantLib::CashFlow> > interestFlows;
59 std::vector<ext::shared_ptr<QuantLib::CashFlow> > notionalFlows;
60 std::vector<ext::shared_ptr<QuantLib::CashFlow> > feeFlows;
61
62 for (size_t j = 0; j < leg.size(); j++) {
63
64 QuantLib::ext::shared_ptr<QuantLib::CashFlow> ptrFlow = leg[j];
65
66 if(flowType(name,j) == "int"){
67
68 QuantLib::ext::shared_ptr<QuantLib::Coupon> ptrCoupon =
69 QuantLib::ext::dynamic_pointer_cast<QuantLib::Coupon>(ptrFlow);
70 QL_REQUIRE(ptrCoupon, "expected couopn type");
71
72 QuantLib::ext::shared_ptr<QuantExt::ScaledCoupon> newPtr( new QuantExt::ScaledCoupon(multi * scalar[j], ptrCoupon ));
73 interestFlows.push_back(newPtr);
74 cashflows.push_back(newPtr);
75
76 } else if(flowType(name,j) == "xnl"){
77
78 double amort = 1.0;
79 if(reinvestmentEndDate_ > ptrFlow->date())
80 amort = 0.0;
81
82 ext::shared_ptr<CashFlow>
83 flow(new SimpleCashFlow(ptrFlow->amount() * multi * scalar[j] * amort, ptrFlow->date()));
84 notionalFlows.push_back(flow);
85 cashflows.push_back(flow);
86
87 } else if (flowType(name,j) == "fee"){
88
89 ext::shared_ptr<CashFlow>
90 flow(new SimpleCashFlow(ptrFlow->amount() * multi * scalar[j], ptrFlow->date()));
91 feeFlows.push_back(flow);
92 cashflows.push_back(flow);
93
94 } else {
95 //ALOG("bond " << name << " leg " << j << " paymentDate " << leg[j]->date() << " could not be assigned");
96 }
97
98 }//leg - j
99 cashflows_[name] = cashflows;
100 notionalFlows_[name] = notionalFlows;
101 feeFlows_[name] = feeFlows;
102 interestFlows_[name] = interestFlows;
103 }//bonds - b
104 }//void BondBasket::fillFlowMaps()
105
106
107 Real sum(const Cash& c, const Cash& d) {
108 return c.flow_ + d.flow_;
109 }
110
111 Real sumDiscounted(const Cash& c, const Cash& d) {
112 return c.discountedFlow_ + d.discountedFlow_;
113 }
114
115 Real BondBasket::convert(Real amount, Currency ccy, Date date) {
116
117 if(date == Date())
118 date = Settings::instance().evaluationDate();
119
120 if (ccy == baseCcy_)
121 return amount;
122 else {
123 std::string code = ccy.code();
124 double fxRate = fxIndex(code)->fixing(date, false);
125 double inBase = fxRate * amount;
126 return inBase;
127 }
128 }
129
130 BondBasket::BondBasket(const std::map<std::string, QuantLib::ext::shared_ptr<QuantLib::Bond>>& qlBonds,
131 const std::map<std::string, double>& recoveries,
132 const std::map<std::string, double>& multipliers,
133 const std::map<std::string, QuantLib::Handle<QuantLib::YieldTermStructure>>& yieldTermStructures,
134 const std::map<std::string, Currency>& currencies,
135 const QuantLib::ext::shared_ptr<Pool> pool,
136 Currency baseCcy,
137 const std::map <string, QuantLib::ext::shared_ptr<QuantExt::FxIndex>>& fxIndexMap,
138 const QuantLib::Date & reinvestmentEndDate,
139 const std::map<std::string, std::vector<double>>& reinvestmentScalar,
140 const std::map<std::string, std::vector<std::string>>& flowType)
141 : qlBonds_(qlBonds),
142 recoveries_(recoveries),
143 multipliers_(multipliers),
144 yieldTermStructures_(yieldTermStructures),
145 currencies_(currencies),
146 pool_(pool),
147 baseCcy_(baseCcy),
148 fxIndexMap_(fxIndexMap),
149 reinvestmentEndDate_(reinvestmentEndDate),
150 reinvestmentScalar_(reinvestmentScalar),
151 flowType_(flowType)
152 {
153
154 QL_REQUIRE(!qlBonds_.empty(), "no bonds given");
155 QL_REQUIRE(qlBonds_.size() == recoveries_.size(), "mismatch number bonds vs recoveries");
156 QL_REQUIRE(qlBonds_.size() == multipliers_.size(), "mismatch number bonds vs multipliers");
157 QL_REQUIRE(qlBonds_.size() == yieldTermStructures_.size(), "mismatch number bonds vs yieldTermStructures");
158 QL_REQUIRE(qlBonds_.size() == currencies_.size(), "mismatch number bonds vs currencies");
159
160 for (const auto& ccy : currencies_)
161 unique_currencies_.insert(ccy.second);
162
163 grid_ = vector<Date>();
164
165 }
166
167 const QuantLib::ext::shared_ptr<Pool>& BondBasket::pool() const {
168 return pool_;
169 }
170
171 const double BondBasket::recoveryRate (const std::string& name) const {
172 auto it = recoveries_.find(name);
173 if(it != recoveries_.end())
174 return it->second;
175 QL_FAIL("no recovery value for bond " << name);
176 };
177
178 const double BondBasket::multiplier (const std::string& name) const {
179 auto it = multipliers_.find(name);
180 if(it != multipliers_.end())
181 return it->second;
182 QL_FAIL("no multiplier for bond " << name);
183 };
184
185 const QuantLib::Handle<QuantLib::YieldTermStructure> BondBasket::yts(const std::string& name) const{
186 auto it = yieldTermStructures_.find(name);
187 if(it != yieldTermStructures_.end())
188 return it->second;
189 QL_FAIL("no yieldTermStructure for bond " << name);
190 }
191
192 const Currency BondBasket::currency(const std::string& name) const{
193 auto it = currencies_.find(name);
194 if(it != currencies_.end())
195 return it->second;
196 QL_FAIL("no currency for bond " << name);
197 }
198
199 const vector<double> BondBasket::reinvestmentScalar(const std::string& name) const{
200 auto it = reinvestmentScalar_.find(name);
201 if(it != reinvestmentScalar_.end())
202 return it->second;
203 QL_FAIL("no reinvestmentScalar for bond " << name);
204 }
205
206 const string BondBasket::flowType(const std::string& name, int idx) const{
207 auto it = flowType_.find(name);
208 if(it != flowType_.end())
209 return it->second[idx];
210 QL_FAIL("no flowType for bond " << name);
211 }
212
213 const QuantLib::ext::shared_ptr<QuantExt::FxIndex> BondBasket::fxIndex(const std::string& name) const{
214 auto it = fxIndexMap_.find(name);
215 if(it != fxIndexMap_.end())
216 return it->second;
217 QL_FAIL("no fxIndex for bond " << name);
218 }
219
220 void BondBasket::setGrid(vector<Date> dates) {
221 grid_ = dates;
222 for (auto bond : qlBonds_) {
223 string name = bond.first;
224 cashflow2grid_[name].resize(cashflows_[name].size(), -1);
225 for (Size j = 0; j < cashflows_[name].size(); j++) {
226 Date d = cashflows_[name][j]->date();
227 for (Size k = 1; k < dates.size(); k++) {
228 if (d > dates[k-1] && d <= dates[k]) {
229 cashflow2grid_[name][j] = k;
230 continue;
231 }
232 }
233 }
234 interestflow2grid_[name].resize(interestFlows_[name].size(),-1);
235 for (Size j = 0; j < interestFlows_[name].size(); j++) {
236 Date d = interestFlows_[name][j]->date();
237 for (Size k = 1; k < dates.size(); k++) {
238 if (d > dates[k-1] && d <= dates[k]) {
239 interestflow2grid_[name][j] = k;
240 continue;
241 }
242 }
243 }
244 notionalflow2grid_[name].resize(notionalFlows_[name].size(), -1);
245 for (Size j = 0; j < notionalFlows_[name].size(); j++) {
246 Date d = notionalFlows_[name][j]->date();
247 for (Size k = 1; k < dates.size(); k++) {
248 if (d > dates[k-1] && d <= dates[k]) {
249 notionalflow2grid_[name][j] = k;
250 continue;
251 }
252 }
253 }
254 feeflow2grid_[name].resize(feeFlows_[name].size(), -1);
255 for (Size j = 0; j < feeFlows_[name].size(); j++) {
256 Date d = feeFlows_[name][j]->date();
257 for (Size k = 1; k < dates.size(); k++) {
258 if (d > dates[k-1] && d <= dates[k]) {
259 feeflow2grid_[name][j] = k;
260 continue;
261 }
262 }
263 }
264 }
265 }
266
267 std::map<Currency, vector<Cash> >
268 BondBasket::scenarioCashflow(vector<Date> dates) {
269 QL_REQUIRE(grid_.size() > 0, "grid not set");
270 Date today = Settings::instance().evaluationDate();
271 map<Currency,vector<Cash> > cf;
272 for (const auto & ccy : unique_currencies_)
273 cf[ccy].resize(dates.size(), Cash());
274 for (const auto & bond : qlBonds_) {
275 string name = bond.first;
276 DayCounter dc = yts(name)->dayCounter();
277 Currency ccy = currency(name);
278 Real defaultTime = pool_->getTime(name);
279 Real maturityTime = dc.yearFraction(today, bond.second->maturityDate());
280 for (Size j = 0; j < cashflows_[name].size(); j++) {
281 Date d = cashflows_[name][j]->date();
282 Real t = dc.yearFraction(today, d);
283
284 if (t < defaultTime) {
285 Size k = cashflow2grid_[name][j];
286 //QL_REQUIRE(k >= 0 && k < grid_.size(), "k out of range");
287 if (k < grid_.size()) {
288 cf[ccy][k].flow_ += cashflows_[name][j]->amount();
289 cf[ccy][k].discountedFlow_
290 += cashflows_[name][j]->amount()
291 * yts(name)->discount(t);
292 }
293 }
294 else break;
295 }
296 if (defaultTime < maturityTime) {
297 for (Size k = 1; k < dates.size(); k++) {
298 Real t1 = dc.yearFraction(today, dates[k-1]);
299 Real t2 = dc.yearFraction(today, dates[k]);
300 if (defaultTime >= t1 && defaultTime < t2) {
301 cf[ccy][k].flow_
302 += recoveryRate(name) * bond.second->notional(dates[k-1]) * multiplier(name);
303 cf[ccy][k].discountedFlow_
304 += recoveryRate(name) * bond.second->notional(dates[k-1]) * multiplier(name)
305 * yts(name)->discount(defaultTime);
306 }
307 }
308 }
309 }
310 return cf;
311 }
312
313 std::map<Currency, vector<Cash> >
315 QL_REQUIRE(grid_.size() > 0, "grid not set");
316 Date today = Settings::instance().evaluationDate();
317 map<Currency,vector<Cash> > cf;
318 for (const auto & ccy : unique_currencies_)
319 cf[ccy].resize(dates.size(), Cash());
320 for (const auto & bond : qlBonds_) {
321 string name = bond.first;
322 DayCounter dc = yts(name)->dayCounter();
323 Currency ccy = currency(name);
324 Real defaultTime = pool_->getTime(name);
325 for (Size j = 0; j < interestFlows_[name].size(); j++) {
326 Date d = interestFlows_[name][j]->date();
327 Real t = dc.yearFraction(today, d);
328 if (t < defaultTime) {
329 Size k = interestflow2grid_[name][j];
330 //QL_REQUIRE(k >= 0 && k < grid_.size(), "k out of range");
331 if (k < grid_.size()) {
332 cf[ccy][k].flow_ += interestFlows_[name][j]->amount();
333 cf[ccy][k].discountedFlow_
334 += interestFlows_[name][j]->amount()
335 * yts(name)->discount(t);
336 }
337 }
338 else break;
339 }
340 }
341 return cf;
342 }
343
344 std::map<Currency, vector<Cash> >
346 QL_REQUIRE(grid_.size() > 0, "grid not set");
347 Date today = Settings::instance().evaluationDate();
348 map<Currency,vector<Cash> > cf;
349 for (const auto & ccy : unique_currencies_)
350 cf[ccy].resize(dates.size(), Cash());
351 for (const auto & bond : qlBonds_) {
352 string name = bond.first;
353 DayCounter dc = yts(name)->dayCounter();
354 Currency ccy = currency(name);
355 Real defaultTime = pool_->getTime(name);
356 Real maturityTime = dc.yearFraction(today, bond.second->maturityDate());
357 for (Size j = 0; j < notionalFlows_[name].size(); j++) {
358 Date d = notionalFlows_[name][j]->date();
359 Real t = dc.yearFraction(today, d);
360 if (t < defaultTime) {
361 Size k = notionalflow2grid_[name][j];
362 //QL_REQUIRE(k >= 0 && k < grid_.size(), "k out of range");
363 if (k < grid_.size()) {
364 cf[ccy][k].flow_ += notionalFlows_[name][j]->amount();
365 cf[ccy][k].discountedFlow_
366 += notionalFlows_[name][j]->amount()
367 * yts(name)->discount(t);
368 }
369 }
370 else break;
371 }
372 if (defaultTime < maturityTime) {
373 for (Size k = 1; k < dates.size(); k++) {
374 Real t1 = dc.yearFraction(today, dates[k-1]);
375 Real t2 = dc.yearFraction(today, dates[k]);
376 if (defaultTime >= t1 &&
377 defaultTime < t2) {
378 cf[ccy][k].flow_
379 += recoveryRate(name) * bond.second->notional(dates[k-1]) * multiplier(name);
380 cf[ccy][k].discountedFlow_
381 += recoveryRate(name) * bond.second->notional(dates[k-1]) * multiplier(name)
382 * yts(name)->discount(defaultTime);
383 }
384 }
385 }
386 }
387 return cf;
388 }
389
390 std::map<Currency, vector<Cash>> BondBasket::scenarioFeeflow(const std::vector<QuantLib::Date>& dates) {
391 QL_REQUIRE(grid_.size() > 0, "grid not set");
392 Date today = Settings::instance().evaluationDate();
393 map<Currency,vector<Cash> > cf;
394 for (const auto & ccy : unique_currencies_)
395 cf[ccy].resize(dates.size(), Cash());
396 for (const auto & bond : qlBonds_) {
397 string name = bond.first;
398 DayCounter dc = yts(name)->dayCounter();
399 Currency ccy = currency(name);
400 Real defaultTime = pool_->getTime(name);
401 for (Size j = 0; j < feeFlows_[name].size(); j++) {
402 Date d = feeFlows_[name][j]->date();
403 Real t = dc.yearFraction(today, d);
404 if (t < defaultTime) {
405 Size k = feeflow2grid_[name][j];
406 if (k < dates.size()) {
407 cf[ccy][k].flow_ += feeFlows_[name][j]->amount();
408 cf[ccy][k].discountedFlow_
409 += feeFlows_[name][j]->amount() * yts(name)->discount(t);
410
411 }
412 }
413 else break;
414 }
415 }
416 return cf;
417 }
418
419 std::map<Currency, vector<Cash> >
420 BondBasket::scenarioLossflow(vector<Date> dates) {
421 QL_REQUIRE(grid_.size() > 0, "grid not set");
422 Date today = Settings::instance().evaluationDate();
423 map<Currency,vector<Cash> > cf;
424 for (const auto & ccy : unique_currencies_)
425 cf[ccy].resize(dates.size(), Cash());
426 for (const auto & bond : qlBonds_) {
427 string name = bond.first;
428 DayCounter dc = yts(name)->dayCounter();
429 Currency ccy = currency(name);
430 Real defaultTime = pool_->getTime(name);
431 Real maturityTime = dc.yearFraction(today, bond.second->maturityDate());
432 if (defaultTime < maturityTime) {
433 for (Size k = 1; k < dates.size(); k++) {
434 Real t1 = dc.yearFraction(today, dates[k-1]);
435 Real t2 = dc.yearFraction(today, dates[k]);
436 if (defaultTime >= t1 &&
437 defaultTime < t2) {
438 cf[ccy][k].flow_
439 += (1.0 - recoveryRate(name)) * bond.second->notional(dates[k-1]) * multiplier(name);
440 cf[ccy][k].discountedFlow_
441 += (1.0 - recoveryRate(name)) * bond.second->notional(dates[k-1]) * multiplier(name)
442 * yts(name)->discount(defaultTime);
443 }
444 }
445 }
446 }
447 return cf;
448 }
449
450 std::map<Currency, vector<Real> >
452 QL_REQUIRE(grid_.size() > 0, "grid not set");
453 Date today = Settings::instance().evaluationDate();
454 map<Currency,vector<Real> > cf;
455 for (const auto & ccy : unique_currencies_)
456 cf[ccy].resize(dates.size(), 0.0);
457 for (const auto & bond : qlBonds_) {
458 string name = bond.first;
459 DayCounter dc = yts(name)->dayCounter();
460 Currency ccy = currency(name);
461 Real defaultTime = pool_->getTime(name);
462 for (Size k = 1; k < dates.size(); k++) {
463 Real t1 = dc.yearFraction(today, dates[k]);
464 if (defaultTime >= t1) {
465 cf[ccy][k] += bond.second->notional(dates[k]) * multiplier(name) * getScalar(name, dates[k]);
466 }
467 }
468 }
469 return cf;
470 }
471
472}
473
Basket of defaultable bonds.
const QuantLib::ext::shared_ptr< QuantLib::Pool > pool_
Definition: bondbasket.hpp:144
const QuantLib::ext::shared_ptr< QuantExt::FxIndex > fxIndex(const std::string &name) const
Definition: bondbasket.cpp:213
std::map< std::string, std::vector< int > > interestflow2grid_
Definition: bondbasket.hpp:155
const Date reinvestmentEndDate_
Definition: bondbasket.hpp:147
std::map< std::string, std::vector< ext::shared_ptr< QuantLib::CashFlow > > > feeFlows_
Definition: bondbasket.hpp:162
const Currency baseCcy_
Definition: bondbasket.hpp:145
std::map< Currency, std::vector< Cash > > scenarioLossflow(std::vector< Date > dates)
Definition: bondbasket.cpp:420
std::vector< Date > grid_
Definition: bondbasket.hpp:152
const std::map< std::string, std::vector< double > > reinvestmentScalar_
Definition: bondbasket.hpp:148
std::map< Currency, std::vector< Cash > > scenarioCashflow(std::vector< Date > dates)
Definition: bondbasket.cpp:268
const double multiplier(const std::string &name) const
Definition: bondbasket.cpp:178
std::map< Currency, std::vector< Cash > > scenarioInterestflow(std::vector< Date > dates)
Definition: bondbasket.cpp:314
const Currency currency(const std::string &name) const
Definition: bondbasket.cpp:192
const std::map< std::string, double > recoveries_
Definition: bondbasket.hpp:140
Real convert(Real amount, Currency ccy, Date date=Date())
Definition: bondbasket.cpp:115
std::map< std::string, std::vector< ext::shared_ptr< QuantLib::CashFlow > > > notionalFlows_
Definition: bondbasket.hpp:161
void setGrid(std::vector< Date > dates)
Definition: bondbasket.cpp:220
std::map< std::string, std::vector< int > > cashflow2grid_
Definition: bondbasket.hpp:154
const double recoveryRate(const std::string &name) const
Definition: bondbasket.cpp:171
std::map< Currency, std::vector< Real > > scenarioRemainingNotional(std::vector< Date > dates)
Definition: bondbasket.cpp:451
const std::vector< double > reinvestmentScalar(const std::string &name) const
Definition: bondbasket.cpp:199
const double getScalar(const std::string &name, const QuantLib::Date &currentDate) const
Definition: bondbasket.cpp:28
std::map< std::string, std::vector< ext::shared_ptr< QuantLib::CashFlow > > > interestFlows_
Definition: bondbasket.hpp:160
const std::map< std::string, QuantLib::ext::shared_ptr< QuantExt::FxIndex > > fxIndexMap_
Definition: bondbasket.hpp:146
const std::map< std::string, QuantLib::ext::shared_ptr< QuantLib::Bond > > qlBonds_
Definition: bondbasket.hpp:139
const QuantLib::Handle< QuantLib::YieldTermStructure > yts(const std::string &name) const
Definition: bondbasket.cpp:185
std::set< QuantLib::Currency > unique_currencies_
Definition: bondbasket.hpp:151
std::map< Currency, std::vector< Cash > > scenarioPrincipalflow(std::vector< Date > dates)
Definition: bondbasket.cpp:345
const std::map< std::string, QuantLib::Currency > currencies_
Definition: bondbasket.hpp:143
std::map< Currency, std::vector< Cash > > scenarioFeeflow(const std::vector< QuantLib::Date > &dates)
Definition: bondbasket.cpp:390
std::map< std::string, std::vector< int > > notionalflow2grid_
Definition: bondbasket.hpp:156
const std::map< std::string, std::vector< std::string > > flowType_
Definition: bondbasket.hpp:149
std::map< std::string, std::vector< int > > feeflow2grid_
Definition: bondbasket.hpp:157
const std::string flowType(const std::string &name, int idx) const
Definition: bondbasket.cpp:206
const QuantLib::ext::shared_ptr< QuantLib::Pool > & pool() const
Definition: bondbasket.cpp:167
std::map< std::string, std::vector< ext::shared_ptr< QuantLib::CashFlow > > > cashflows_
Definition: bondbasket.hpp:159
const std::map< std::string, QuantLib::Handle< QuantLib::YieldTermStructure > > yieldTermStructures_
Definition: bondbasket.hpp:142
BondBasket(const std::map< std::string, QuantLib::ext::shared_ptr< QuantLib::Bond > > &qlBonds, const std::map< std::string, double > &recoveries, const std::map< std::string, double > &multipliers, const std::map< std::string, QuantLib::Handle< QuantLib::YieldTermStructure > > &yieldTermStructures, const std::map< std::string, Currency > &currencies, const QuantLib::ext::shared_ptr< QuantLib::Pool > pool, Currency baseCcy, const std::map< std::string, QuantLib::ext::shared_ptr< QuantExt::FxIndex > > &fxIndexMap, const QuantLib::Date &reinvestmentEndDate, const std::map< std::string, std::vector< double > > &reinvestmentScalar, const std::map< std::string, std::vector< std::string > > &flowType)
Definition: bondbasket.cpp:130
const std::map< std::string, double > multipliers_
Definition: bondbasket.hpp:141
Real discountedFlow_
Definition: bondbasket.hpp:48
Real sumDiscounted(const Cash &c, const Cash &d)
Definition: bondbasket.cpp:111
Real sum(const Cash &c, const Cash &d)
Definition: bondbasket.cpp:107
Coupon / Cashflow paying scaled amounts.