Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
List of all members
DefaultCurve Class Reference

Wrapper class for building Swaption volatility structures. More...

#include <ored/marketdata/defaultcurve.hpp>

+ Collaboration diagram for DefaultCurve:

Public Member Functions

Constructors
 DefaultCurve ()
 Default constructor. More...
 
 DefaultCurve (Date asof, DefaultCurveSpec spec, const Loader &loader, const CurveConfigurations &curveConfigs, map< string, QuantLib::ext::shared_ptr< YieldCurve > > &yieldCurves, map< string, QuantLib::ext::shared_ptr< DefaultCurve > > &defaultCurves)
 Detailed constructor. More...
 

Inspectors

DefaultCurveSpec spec_
 
QuantLib::ext::shared_ptr< QuantExt::CreditCurvecurve_
 
Real recoveryRate_
 
const DefaultCurveSpecspec () const
 
const QuantLib::ext::shared_ptr< QuantExt::CreditCurve > & creditCurve () const
 
Real recoveryRate ()
 
void buildCdsCurve (const std::string &curveID, const DefaultCurveConfig::Config &config, const QuantLib::Date &asof, const DefaultCurveSpec &spec, const Loader &loader, std::map< std::string, QuantLib::ext::shared_ptr< YieldCurve > > &yieldCurves)
 Build a default curve from CDS spread quotes. More...
 
void buildHazardRateCurve (const std::string &curveID, const DefaultCurveConfig::Config &config, const QuantLib::Date &asof, const DefaultCurveSpec &spec, const Loader &loader)
 Build a default curve from hazard rate quotes. More...
 
void buildBenchmarkCurve (const std::string &curveID, const DefaultCurveConfig::Config &config, const QuantLib::Date &asof, const DefaultCurveSpec &spec, const Loader &loader, std::map< std::string, QuantLib::ext::shared_ptr< YieldCurve > > &yieldCurves)
 Build a default curve implied from a spread over a benchmark curve. More...
 
void buildMultiSectionCurve (const std::string &curveID, const DefaultCurveConfig::Config &config, const Date &asof, const DefaultCurveSpec &spec, const Loader &loader, map< string, QuantLib::ext::shared_ptr< DefaultCurve > > &defaultCurves)
 Build a multi section curve. More...
 
void buildTransitionMatrixCurve (const std::string &curveID, const DefaultCurveConfig::Config &config, const Date &asof, const DefaultCurveSpec &spec, const Loader &loader, map< string, QuantLib::ext::shared_ptr< DefaultCurve > > &defaultCurves)
 
void buildNullCurve (const std::string &curveID, const DefaultCurveConfig::Config &config, const Date &asof, const DefaultCurveSpec &spec)
 Build a null curve (null rate, null recovery) More...
 

Detailed Description

Wrapper class for building Swaption volatility structures.

Definition at line 46 of file defaultcurve.hpp.

Constructor & Destructor Documentation

◆ DefaultCurve() [1/2]

Default constructor.

Definition at line 51 of file defaultcurve.hpp.

51: recoveryRate_(QuantLib::Null<QuantLib::Real>()) {}

◆ DefaultCurve() [2/2]

DefaultCurve ( Date  asof,
DefaultCurveSpec  spec,
const Loader loader,
const CurveConfigurations curveConfigs,
map< string, QuantLib::ext::shared_ptr< YieldCurve > > &  yieldCurves,
map< string, QuantLib::ext::shared_ptr< DefaultCurve > > &  defaultCurves 
)

Detailed constructor.

Definition at line 226 of file defaultcurve.cpp.

229 {
230 const QuantLib::ext::shared_ptr<DefaultCurveConfig>& configs = curveConfigs.defaultCurveConfig(spec.curveConfigID());
231 bool built = false;
232 std::string errors;
233 for (auto const& config : configs->configs()) {
234 try {
235 recoveryRate_ = Null<Real>();
236 if (!config.second.recoveryRateQuote().empty()) {
237 // handle case where the recovery rate is hardcoded in the curve config
238 if (!tryParseReal(config.second.recoveryRateQuote(), recoveryRate_)) {
239 Wildcard wc(config.second.recoveryRateQuote());
240 if (wc.hasWildcard()) {
241 for (auto const& q : loader.get(wc, asof)) {
242 if (wc.matches(q->name())) {
243 QL_REQUIRE(recoveryRate_ == Null<Real>(),
244 "There is more than one recovery rate matching the pattern '" << wc.pattern()
245 << "'.");
246 recoveryRate_ = q->quote()->value();
247 }
248 }
249 } else {
250 QL_REQUIRE(loader.has(config.second.recoveryRateQuote(), asof),
251 "There is no market data for the requested recovery rate "
252 << config.second.recoveryRateQuote());
253 recoveryRate_ = loader.get(config.second.recoveryRateQuote(), asof)->quote()->value();
254 }
255 }
256 }
257 // Build the default curve of the requested type
258 switch (config.second.type()) {
261 buildCdsCurve(configs->curveID(), config.second, asof, spec, loader, yieldCurves);
262 break;
264 buildHazardRateCurve(configs->curveID(), config.second, asof, spec, loader);
265 break;
267 buildBenchmarkCurve(configs->curveID(), config.second, asof, spec, loader, yieldCurves);
268 break;
270 buildMultiSectionCurve(configs->curveID(), config.second, asof, spec, loader, defaultCurves);
271 break;
273 buildTransitionMatrixCurve(configs->curveID(), config.second, asof, spec, loader, defaultCurves);
274 break;
276 buildNullCurve(configs->curveID(), config.second, asof, spec);
277 break;
278 default:
279 QL_FAIL("The DefaultCurveConfig type " << static_cast<int>(config.second.type())
280 << " was not recognised");
281 }
282 built = true;
283 break;
284 } catch (exception& e) {
285 std::ostringstream message;
286 message << "build attempt failed for " << configs->curveID() << " using config with priority "
287 << config.first << ": " << e.what();
288 DLOG(message.str());
289 if (!errors.empty())
290 errors += ", ";
291 errors += message.str();
292 }
293 }
294 QL_REQUIRE(built, "default curve building failed for " << spec.curveConfigID() << ": " << errors);
295}
const std::string & curveConfigID() const
Definition: curvespec.hpp:83
void buildHazardRateCurve(const std::string &curveID, const DefaultCurveConfig::Config &config, const QuantLib::Date &asof, const DefaultCurveSpec &spec, const Loader &loader)
Build a default curve from hazard rate quotes.
const DefaultCurveSpec & spec() const
void buildMultiSectionCurve(const std::string &curveID, const DefaultCurveConfig::Config &config, const Date &asof, const DefaultCurveSpec &spec, const Loader &loader, map< string, QuantLib::ext::shared_ptr< DefaultCurve > > &defaultCurves)
Build a multi section curve.
void buildCdsCurve(const std::string &curveID, const DefaultCurveConfig::Config &config, const QuantLib::Date &asof, const DefaultCurveSpec &spec, const Loader &loader, std::map< std::string, QuantLib::ext::shared_ptr< YieldCurve > > &yieldCurves)
Build a default curve from CDS spread quotes.
void buildBenchmarkCurve(const std::string &curveID, const DefaultCurveConfig::Config &config, const QuantLib::Date &asof, const DefaultCurveSpec &spec, const Loader &loader, std::map< std::string, QuantLib::ext::shared_ptr< YieldCurve > > &yieldCurves)
Build a default curve implied from a spread over a benchmark curve.
void buildTransitionMatrixCurve(const std::string &curveID, const DefaultCurveConfig::Config &config, const Date &asof, const DefaultCurveSpec &spec, const Loader &loader, map< string, QuantLib::ext::shared_ptr< DefaultCurve > > &defaultCurves)
void buildNullCurve(const std::string &curveID, const DefaultCurveConfig::Config &config, const Date &asof, const DefaultCurveSpec &spec)
Build a null curve (null rate, null recovery)
virtual QuantLib::ext::shared_ptr< MarketDatum > get(const std::string &name, const QuantLib::Date &d) const
get quote by its unique name, throws if not existent, override in derived classes for performance
Definition: loader.cpp:24
virtual bool has(const std::string &name, const QuantLib::Date &d) const
Default implementation, returns false if get throws or returns a null pointer.
Definition: loader.cpp:53
bool tryParseReal(const string &s, QuantLib::Real &result)
Attempt to convert text to Real.
Definition: parsers.cpp:126
#define DLOG(text)
Logging Macro (Level = Debug)
Definition: log.hpp:554
vector< string > curveConfigs
+ Here is the call graph for this function:

Member Function Documentation

◆ spec()

const DefaultCurveSpec & spec ( ) const

Definition at line 60 of file defaultcurve.hpp.

60{ return spec_; }
DefaultCurveSpec spec_
+ Here is the caller graph for this function:

◆ creditCurve()

const QuantLib::ext::shared_ptr< QuantExt::CreditCurve > & creditCurve ( ) const

Definition at line 61 of file defaultcurve.hpp.

61{ return curve_; }
QuantLib::ext::shared_ptr< QuantExt::CreditCurve > curve_

◆ recoveryRate()

Real recoveryRate ( )

Definition at line 62 of file defaultcurve.hpp.

62{ return recoveryRate_; }
+ Here is the caller graph for this function:

◆ buildCdsCurve()

void buildCdsCurve ( const std::string &  curveID,
const DefaultCurveConfig::Config config,
const QuantLib::Date &  asof,
const DefaultCurveSpec spec,
const Loader loader,
std::map< std::string, QuantLib::ext::shared_ptr< YieldCurve > > &  yieldCurves 
)
private

Build a default curve from CDS spread quotes.

Definition at line 297 of file defaultcurve.cpp.

299 {
300
301 LOG("Start building default curve of type SpreadCDS for curve " << curveID);
302
303 QL_REQUIRE(config.type() == DefaultCurveConfig::Config::Type::SpreadCDS ||
305 "DefaultCurve::buildCdsCurve expected a default curve configuration with type SpreadCDS/Price");
306 QL_REQUIRE(recoveryRate_ != Null<Real>(), "DefaultCurve: recovery rate needed to build SpreadCDS curve");
307
308 // Get the CDS curve conventions
309 QuantLib::ext::shared_ptr<Conventions> conventions = InstrumentConventions::instance().conventions();
310 QL_REQUIRE(conventions->has(config.conventionID()), "No conventions found with id " << config.conventionID());
311 QuantLib::ext::shared_ptr<CdsConvention> cdsConv =
312 QuantLib::ext::dynamic_pointer_cast<CdsConvention>(conventions->get(config.conventionID()));
313 QL_REQUIRE(cdsConv, "SpreadCDS curves require CDS convention");
314
315 // Get the discount curve for use in the CDS spread curve bootstrap
316 auto it = yieldCurves.find(config.discountCurveID());
317 QL_REQUIRE(it != yieldCurves.end(), "The discount curve, " << config.discountCurveID()
318 << ", required in the building of the curve, "
319 << spec.name() << ", was not found.");
320 Handle<YieldTermStructure> discountCurve = it->second->handle();
321
322 // Get the CDS spread / price curve quotes
323 set<QuoteData> quotes = getConfiguredQuotes(curveID, config, asof, loader);
324
325 // Set up ref data for the curve, except runningSpread which is set below
327 refData.indexTerm = config.indexTerm();
328 refData.startDate = config.startDate();
329 refData.tenor = Period(cdsConv->frequency());
330 refData.calendar = cdsConv->calendar();
331 refData.convention = cdsConv->paymentConvention();
332 refData.termConvention = cdsConv->paymentConvention();
333 refData.rule = cdsConv->rule();
334 refData.payConvention = cdsConv->paymentConvention();
335 refData.dayCounter = cdsConv->dayCounter();
336 refData.lastPeriodDayCounter = cdsConv->lastPeriodDayCounter();
337 refData.cashSettlementDays = cdsConv->upfrontSettlementDays();
338
339 // If the configuration instructs us to imply a default from the market data, we do it here.
340 if (config.implyDefaultFromMarket() && *config.implyDefaultFromMarket()) {
341 if (recoveryRate_ != Null<Real>() && quotes.empty()) {
342 // Assume entity is in default, between event determination date and auction date. Build a survival
343 // probability curve with value 0.0 tomorrow to approximate this and allow dependent instruments to price.
344 // Need to use small but positive numbers to avoid downstream issues with log linear survivals e.g. below
345 // and in places like ScenarioSimMarket.
346 vector<Date> dates{asof, asof + 1 * Years, asof + 10 * Years};
347 vector<Real> survivalProbs{1.0, 1e-16, 1e-18};
348 curve_ = QuantLib::ext::make_shared<QuantExt::CreditCurve>(
349 Handle<DefaultProbabilityTermStructure>(
351 dates, survivalProbs, config.dayCounter(), Calendar(), std::vector<Handle<Quote>>(),
352 std::vector<Date>(), LogLinear())),
353 discountCurve, Handle<Quote>(QuantLib::ext::make_shared<SimpleQuote>(recoveryRate_)), refData);
354 curve_->curve()->enableExtrapolation();
355 WLOG("DefaultCurve: recovery rate found but no CDS quotes for "
356 << curveID << " and "
357 << "ImplyDefaultFromMarket is true. Curve built that gives default immediately.");
358 return;
359 }
360 } else {
361 QL_REQUIRE(!quotes.empty(), "No market points found for CDS curve config " << curveID);
362 }
363
364 // Create the CDS instrument helpers, only keep alive helpers
365 vector<QuantLib::ext::shared_ptr<QuantExt::DefaultProbabilityHelper>> helpers;
366 std::map<QuantLib::Date, QuantLib::Period> helperQuoteTerms;
367 Real runningSpread = Null<Real>();
368 QuantExt::CreditDefaultSwap::ProtectionPaymentTime ppt = cdsConv->paysAtDefaultTime()
369 ? QuantExt::CreditDefaultSwap::atDefault
370 : QuantExt::CreditDefaultSwap::atPeriodEnd;
371
373 for (auto quote : quotes) {
374 QuantLib::ext::shared_ptr<SpreadCdsHelper> tmp;
375 try {
376 tmp = QuantLib::ext::make_shared<SpreadCdsHelper>(
377 quote.value, quote.term, cdsConv->settlementDays(), cdsConv->calendar(), cdsConv->frequency(),
378 cdsConv->paymentConvention(), cdsConv->rule(), cdsConv->dayCounter(), recoveryRate_, discountCurve,
379 cdsConv->settlesAccrual(), ppt, config.startDate(), cdsConv->lastPeriodDayCounter());
380
381 } catch (exception& e) {
382 if (quote.term == Period(0, Months)) {
383 WLOG("DefaultCurve:: Cannot add quote of term 0M to CDS curve " << curveID << " for asof date "
384 << asof);
385 } else {
386 QL_FAIL("DefaultCurve:: Failed to add quote of term " << quote.term << " to CDS curve " << curveID
387 << " for asof date " << asof
388 << ", with error: " << e.what());
389 }
390 }
391 if (tmp) {
392 if (tmp->latestDate() > asof) {
393 helpers.push_back(tmp);
394 runningSpread = config.runningSpread();
395 }
396 helperQuoteTerms[tmp->latestDate()] = quote.term;
397 }
398 }
399 } else {
400 for (auto quote : quotes) {
401 // If there is no running spread encoded in the quote, the config must have one.
402 runningSpread = quote.runningSpread;
403 if (runningSpread == Null<Real>()) {
404 QL_REQUIRE(config.runningSpread() != Null<Real>(),
405 "A running spread was not provided in the quote "
406 << "string so it must be provided in the config for CDS upfront curve " << curveID);
407 runningSpread = config.runningSpread();
408 }
409 auto tmp = QuantLib::ext::make_shared<UpfrontCdsHelper>(
410 quote.value, runningSpread, quote.term, cdsConv->settlementDays(), cdsConv->calendar(),
411 cdsConv->frequency(), cdsConv->paymentConvention(), cdsConv->rule(), cdsConv->dayCounter(),
412 recoveryRate_, discountCurve, cdsConv->upfrontSettlementDays(), cdsConv->settlesAccrual(), ppt,
413 config.startDate(), cdsConv->lastPeriodDayCounter());
414 if (tmp->latestDate() > asof) {
415 helpers.push_back(tmp);
416 }
417 helperQuoteTerms[tmp->latestDate()] = quote.term;
418 }
419 }
420
421 QL_REQUIRE(!helpers.empty(), "DefaultCurve: no alive quotes found.");
422
423 refData.runningSpread = runningSpread;
424
425 // Ensure that the helpers are sorted. This is done in IterativeBootstrap, but we need
426 // a sorted instruments vector in the code here as well.
427 std::sort(helpers.begin(), helpers.end(), QuantLib::detail::BootstrapHelperSorter());
428
429 // Get configuration values for bootstrap
430 Real accuracy = config.bootstrapConfig().accuracy();
431 Real globalAccuracy = config.bootstrapConfig().globalAccuracy();
432 bool dontThrow = config.bootstrapConfig().dontThrow();
433 Size maxAttempts = config.bootstrapConfig().maxAttempts();
434 Real maxFactor = config.allowNegativeRates() ? config.bootstrapConfig().maxFactor() : 1.0;
435 Real minFactor = config.bootstrapConfig().minFactor();
436 Size dontThrowSteps = config.bootstrapConfig().dontThrowSteps();
437
438 typedef PiecewiseDefaultCurve<QuantExt::SurvivalProbability, LogLinear, QuantExt::IterativeBootstrap> SpCurve;
439 SpCurve::bootstrap_type btconfig(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
440 minFactor, dontThrowSteps);
441 QuantLib::ext::shared_ptr<DefaultProbabilityTermStructure> qlCurve;
442
443 if (config.indexTerm() != 0 * Days) {
444
445 // build flat index curve picking a quote with identical term as configured if possible
446 // otherwise build interpolated curve using the existing quotes
447
448 std::vector<Real> helperTermTimes;
449 for (auto const& h : helpers) {
450 helperTermTimes.push_back(QuantExt::periodToTime(helperQuoteTerms[h->latestDate()]));
451 }
452
453 Real t = QuantExt::periodToTime(config.indexTerm());
454 Size helperIndex_m, helperIndex_p;
455 Real alpha;
456 std::tie(helperIndex_m, helperIndex_p, alpha) = QuantExt::interpolationIndices(helperTermTimes, t);
457
458 auto tmp1 = QuantLib::ext::make_shared<SpCurve>(
459 asof, std::vector<QuantLib::ext::shared_ptr<QuantExt::DefaultProbabilityHelper>>{helpers[helperIndex_m]},
460 config.dayCounter(), LogLinear(), btconfig);
461 Date d1 = helpers[helperIndex_m]->pillarDate();
462 Real p1 = tmp1->survivalProbability(d1);
463 auto tmp1i = QuantLib::ext::make_shared<QuantExt::InterpolatedSurvivalProbabilityCurve<LogLinear>>(
464 std::vector<Date>{asof, d1}, std::vector<Real>{1.0, p1}, config.dayCounter(), Calendar(),
465 std::vector<Handle<Quote>>(), std::vector<Date>(), LogLinear(), config.allowNegativeRates());
466
467 if (close_enough(alpha, 1.0)) {
468 qlCurve = tmp1i;
469 } else {
470 auto tmp2 = QuantLib::ext::make_shared<SpCurve>(
471 asof, std::vector<QuantLib::ext::shared_ptr<QuantExt::DefaultProbabilityHelper>>{helpers[helperIndex_p]},
472 config.dayCounter(), LogLinear(), btconfig);
473 Date d2 = helpers[helperIndex_p]->pillarDate();
474 Real p2 = tmp2->survivalProbability(d2);
475 auto tmp2i = QuantLib::ext::make_shared<QuantExt::InterpolatedSurvivalProbabilityCurve<LogLinear>>(
476 std::vector<Date>{asof, d2}, std::vector<Real>{1.0, p2}, config.dayCounter(), Calendar(),
477 std::vector<Handle<Quote>>(), std::vector<Date>(), LogLinear(), config.allowNegativeRates());
478 tmp1i->enableExtrapolation();
479 tmp2i->enableExtrapolation();
480 qlCurve = QuantLib::ext::make_shared<QuantExt::TermInterpolatedDefaultCurve>(
481 Handle<DefaultProbabilityTermStructure>(tmp1i), Handle<DefaultProbabilityTermStructure>(tmp2i), alpha);
482 }
483
484 } else {
485
486 // build single name curve
487
488 QuantLib::ext::shared_ptr<DefaultProbabilityTermStructure> tmp = QuantLib::ext::make_shared<SpCurve>(
489 asof, helpers, config.dayCounter(), LogLinear(),
490 QuantExt::IterativeBootstrap<SpCurve>(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
491 minFactor, dontThrowSteps));
492
493 // As for yield curves we need to copy the piecewise curve because on eval date changes the relative date
494 // helpers with trigger a bootstrap.
495 vector<Date> dates;
496 vector<Real> survivalProbs;
497 dates.push_back(asof);
498 survivalProbs.push_back(1.0);
499
500 for (Size i = 0; i < helpers.size(); ++i) {
501 if (helpers[i]->latestDate() > asof) {
502 Date pillarDate = helpers[i]->pillarDate();
503 Probability sp = tmp->survivalProbability(pillarDate);
504
505 // In some cases the bootstrapped survival probability at one tenor will be `close` to that at a
506 // previous tenor. Here we don't add that survival probability and date to avoid issues when creating
507 // the InterpolatedSurvivalProbabilityCurve below.
508 if (!survivalProbs.empty() && close(survivalProbs.back(), sp)) {
509 DLOG("Survival probability for curve " << spec.name() << " at date " << io::iso_date(pillarDate)
510 << " is the same as that at previous date "
511 << io::iso_date(dates.back()) << " so skipping it.");
512 continue;
513 }
514
515 dates.push_back(pillarDate);
516 survivalProbs.push_back(sp);
517 TLOG(io::iso_date(pillarDate) << "," << fixed << setprecision(9) << sp);
518 }
519 }
520 if (dates.size() == 1) {
521 // We might have removed points above. To make the interpolation work, we need at least two points though.
522 dates.push_back(dates.back() + 1);
523 survivalProbs.push_back(survivalProbs.back());
524 }
525 qlCurve = QuantLib::ext::make_shared<QuantExt::InterpolatedSurvivalProbabilityCurve<LogLinear>>(
526 dates, survivalProbs, config.dayCounter(), Calendar(), std::vector<Handle<Quote>>(), std::vector<Date>(),
527 LogLinear(), config.allowNegativeRates());
528 }
529
530 if (config.extrapolation()) {
531 qlCurve->enableExtrapolation();
532 DLOG("DefaultCurve: Enabled Extrapolation");
533 }
534
535 curve_ = QuantLib::ext::make_shared<QuantExt::CreditCurve>(Handle<DefaultProbabilityTermStructure>(qlCurve), discountCurve,
536 Handle<Quote>(QuantLib::ext::make_shared<SimpleQuote>(recoveryRate_)),
537 refData);
538
539 LOG("Finished building default curve of type SpreadCDS for curve " << curveID);
540}
QuantLib::Real maxFactor() const
QuantLib::Size dontThrowSteps() const
QuantLib::Real globalAccuracy() const
QuantLib::Real accuracy() const
QuantLib::Real minFactor() const
QuantLib::Size maxAttempts() const
string name() const
returns the unique curve name
Definition: curvespec.hpp:78
const QuantLib::Period & indexTerm() const
const QuantLib::Date & startDate() const
const boost::optional< bool > & implyDefaultFromMarket() const
const BootstrapConfig & bootstrapConfig() const
#define LOG(text)
Logging Macro (Level = Notice)
Definition: log.hpp:552
#define WLOG(text)
Logging Macro (Level = Warning)
Definition: log.hpp:550
#define TLOG(text)
Logging Macro (Level = Data)
Definition: log.hpp:556
std::tuple< Size, Size, Real > interpolationIndices(const T &x, const Real v)
Filter close_enough(const RandomVariable &x, const RandomVariable &y)
Real periodToTime(const Period &p)
QuantLib::DayCounter lastPeriodDayCounter
QuantLib::DateGeneration::Rule rule
QuantLib::DayCounter dayCounter
QuantLib::Natural cashSettlementDays
QuantLib::BusinessDayConvention termConvention
QuantLib::Calendar calendar
QuantLib::BusinessDayConvention payConvention
QuantLib::BusinessDayConvention convention
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ buildHazardRateCurve()

void buildHazardRateCurve ( const std::string &  curveID,
const DefaultCurveConfig::Config config,
const QuantLib::Date &  asof,
const DefaultCurveSpec spec,
const Loader loader 
)
private

Build a default curve from hazard rate quotes.

Definition at line 542 of file defaultcurve.cpp.

543 {
544
545 LOG("Start building default curve of type HazardRate for curve " << curveID);
546
548 "DefaultCurve::buildHazardRateCurve expected a default curve configuration with type HazardRate");
549
550 // Get the hazard rate curve conventions
551 QuantLib::ext::shared_ptr<Conventions> conventions = InstrumentConventions::instance().conventions();
552 QL_REQUIRE(conventions->has(config.conventionID()), "No conventions found with id " << config.conventionID());
553 QuantLib::ext::shared_ptr<CdsConvention> cdsConv =
554 QuantLib::ext::dynamic_pointer_cast<CdsConvention>(conventions->get(config.conventionID()));
555 QL_REQUIRE(cdsConv, "HazardRate curves require CDS convention");
556
557 // Get the hazard rate quotes
558 set<QuoteData> quotes = getConfiguredQuotes(curveID, config, asof, loader);
559
560 // Build the hazard rate curve
561 Calendar cal = cdsConv->calendar();
562 vector<Date> dates;
563 vector<Real> quoteValues;
564
565 // If first term is not zero, add asof point
566 if (quotes.begin()->term != 0 * Days) {
567 LOG("DefaultCurve: add asof (" << asof << "), hazard rate " << quotes.begin()->value << ", as not given");
568 dates.push_back(asof);
569 quoteValues.push_back(quotes.begin()->value);
570 }
571
572 for (auto quote : quotes) {
573 dates.push_back(cal.advance(asof, quote.term, Following, false));
574 quoteValues.push_back(quote.value);
575 }
576
577 LOG("DefaultCurve: set up interpolated hazard rate curve");
578 curve_ = QuantLib::ext::make_shared<QuantExt::CreditCurve>(
579 Handle<DefaultProbabilityTermStructure>(QuantLib::ext::make_shared<QuantExt::InterpolatedHazardRateCurve<BackwardFlat>>(
580 dates, quoteValues, config.dayCounter(), BackwardFlat(), config.allowNegativeRates())));
581
582 if (config.extrapolation()) {
583 curve_->curve()->enableExtrapolation();
584 DLOG("DefaultCurve: Enabled Extrapolation");
585 }
586
587 if (recoveryRate_ == Null<Real>()) {
588 LOG("DefaultCurve: setting recovery rate to 0.0 for hazard rate curve, because none is given.");
589 recoveryRate_ = 0.0;
590 }
591
592 // Force bootstrap so that errors are thrown during the build, not later
593 curve_->curve()->survivalProbability(QL_EPSILON);
594
595 LOG("Finished building default curve of type HazardRate for curve " << curveID);
596}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ buildBenchmarkCurve()

void buildBenchmarkCurve ( const std::string &  curveID,
const DefaultCurveConfig::Config config,
const QuantLib::Date &  asof,
const DefaultCurveSpec spec,
const Loader loader,
std::map< std::string, QuantLib::ext::shared_ptr< YieldCurve > > &  yieldCurves 
)
private

Build a default curve implied from a spread over a benchmark curve.

Definition at line 598 of file defaultcurve.cpp.

600 {
601
602 LOG("Start building default curve of type Benchmark for curve " << curveID);
603
605 "DefaultCurve::buildBenchmarkCurve expected a default curve configuration with type Benchmark");
606
607 if (recoveryRate_ == Null<Real>())
608 recoveryRate_ = 0.0;
609
610 // Populate benchmark yield curve
611 auto it = yieldCurves.find(config.benchmarkCurveID());
612 QL_REQUIRE(it != yieldCurves.end(), "The benchmark curve, " << config.benchmarkCurveID()
613 << ", required in the building of the curve, "
614 << spec.name() << ", was not found.");
615 QuantLib::ext::shared_ptr<YieldCurve> benchmarkCurve = it->second;
616
617 // Populate source yield curve
618 it = yieldCurves.find(config.sourceCurveID());
619 QL_REQUIRE(it != yieldCurves.end(), "The source curve, " << config.sourceCurveID()
620 << ", required in the building of the curve, "
621 << spec.name() << ", was not found.");
622 QuantLib::ext::shared_ptr<YieldCurve> sourceCurve = it->second;
623
624 // Parameters from the configuration
625 vector<Period> pillars = parseVectorOfValues<Period>(config.pillars(), &parsePeriod);
626 Calendar cal = config.calendar();
627 Size spotLag = config.spotLag();
628
629 // Create the implied survival curve
630 vector<Date> dates;
631 vector<Real> impliedSurvProb;
632 Date spot = cal.advance(asof, spotLag * Days);
633 for (Size i = 0; i < pillars.size(); ++i) {
634 dates.push_back(cal.advance(spot, pillars[i]));
635 Real tmp = dates[i] == asof
636 ? 1.0
637 : sourceCurve->handle()->discount(dates[i]) / benchmarkCurve->handle()->discount(dates[i]);
638 // if a non-zero recovery rate is given, we adjust the implied surv probability according to a market value
639 // recovery model (see the documentation of the benchmark curve in the user guide for more details)
640 impliedSurvProb.push_back(std::pow(tmp, 1.0 / (1.0 - recoveryRate_)));
641 }
642 QL_REQUIRE(dates.size() > 0, "DefaultCurve (Benchmark): no dates given");
643
644 // Insert SP = 1.0 at asof if asof date is not in the pillars
645 if (dates[0] != asof) {
646 dates.insert(dates.begin(), asof);
647 impliedSurvProb.insert(impliedSurvProb.begin(), 1.0);
648 }
649
650 LOG("DefaultCurve: set up interpolated surv prob curve as yield over benchmark");
651 curve_ = QuantLib::ext::make_shared<QuantExt::CreditCurve>(Handle<DefaultProbabilityTermStructure>(
653 dates, impliedSurvProb, config.dayCounter(), Calendar(), std::vector<Handle<Quote>>(), std::vector<Date>(),
654 LogLinear(), config.allowNegativeRates())));
655
656 if (config.extrapolation()) {
657 curve_->curve()->enableExtrapolation();
658 DLOG("DefaultCurve: Enabled Extrapolation");
659 }
660
661 // Force bootstrap so that errors are thrown during the build, not later
662 curve_->curve()->survivalProbability(QL_EPSILON);
663
664 LOG("Finished building default curve of type Benchmark for curve " << curveID);
665}
const std::vector< string > & pillars() const
Period parsePeriod(const string &s)
Convert text to QuantLib::Period.
Definition: parsers.cpp:171
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ buildMultiSectionCurve()

void buildMultiSectionCurve ( const std::string &  curveID,
const DefaultCurveConfig::Config config,
const Date &  asof,
const DefaultCurveSpec spec,
const Loader loader,
map< string, QuantLib::ext::shared_ptr< DefaultCurve > > &  defaultCurves 
)
private

Build a multi section curve.

Definition at line 667 of file defaultcurve.cpp.

669 {
670 LOG("Start building default curve of type MultiSection for curve " << curveID);
671
672 std::vector<Handle<DefaultProbabilityTermStructure>> curves;
673 std::vector<Handle<Quote>> recoveryRates;
674 std::vector<Date> switchDates;
675
676 for (auto const& s : config.multiSectionSourceCurveIds()) {
677 auto it = defaultCurves.find(s);
678 QL_REQUIRE(it != defaultCurves.end(),
679 "The multi section source curve " << s << " required for " << spec.name() << " was not found.");
680 curves.push_back(Handle<DefaultProbabilityTermStructure>(it->second->creditCurve()->curve()));
681 recoveryRates.push_back(Handle<Quote>(QuantLib::ext::make_shared<SimpleQuote>(it->second->recoveryRate())));
682 }
683
684 for (auto const& d : config.multiSectionSwitchDates()) {
685 switchDates.push_back(parseDate(d));
686 }
687
688 Handle<Quote> recoveryRate(QuantLib::ext::make_shared<SimpleQuote>(recoveryRate_));
689 LOG("DefaultCurve: set up multi section curve with " << curves.size() << " sections");
690 curve_ = QuantLib::ext::make_shared<QuantExt::CreditCurve>(
691 Handle<DefaultProbabilityTermStructure>(QuantLib::ext::make_shared<QuantExt::MultiSectionDefaultCurve>(
692 curves, recoveryRates, switchDates, recoveryRate, config.dayCounter(), config.extrapolation())));
693
694 LOG("Finished building default curve of type MultiSection for curve " << curveID);
695}
const vector< string > & multiSectionSwitchDates() const
const vector< string > & multiSectionSourceCurveIds() const
Date parseDate(const string &s)
Convert std::string to QuantLib::Date.
Definition: parsers.cpp:51
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ buildTransitionMatrixCurve()

void buildTransitionMatrixCurve ( const std::string &  curveID,
const DefaultCurveConfig::Config config,
const Date &  asof,
const DefaultCurveSpec spec,
const Loader loader,
map< string, QuantLib::ext::shared_ptr< DefaultCurve > > &  defaultCurves 
)
private

Definition at line 697 of file defaultcurve.cpp.

699 {
700 LOG("Start building default curve of type TransitionMatrix for curve " << curveID);
701 Size dim = config.states().size();
702 QL_REQUIRE(dim >= 2,
703 "DefaultCurve::buildTransitionMatrixCurve(): transition matrix dimension >= 2 required, found " << dim);
704 Matrix transitionMatrix(dim, dim, Null<Real>());
705 map<string, Size> stateIndex;
706 for (Size i = 0; i < config.states().size(); ++i)
707 stateIndex[config.states()[i]] = i;
708 QL_REQUIRE(!config.cdsQuotes().empty(), "DefaultCurve::buildTransitionMatrixCurve(): not quotes given.");
709 std::vector<std::string> tmp;
710 std::transform(config.cdsQuotes().begin(), config.cdsQuotes().end(), std::back_inserter(tmp),
711 [](const std::pair<std::string, bool>& p) { return p.first; });
712 auto wildcard = getUniqueWildcard(tmp);
713 std::set<QuantLib::ext::shared_ptr<MarketDatum>> mdData;
714 if (wildcard) {
715 mdData = loader.get(*wildcard, asof);
716 } else {
717 for (auto const& q : config.cdsQuotes()) {
718 if (auto m = loader.get(q, asof))
719 mdData.insert(m);
720 }
721 }
722 for (const auto& md : mdData) {
723 QL_REQUIRE(md->instrumentType() == MarketDatum::InstrumentType::RATING,
724 "DefaultCurve::buildTransitionMatrixCurve(): quote instrument type must be RATING.");
725 QuantLib::ext::shared_ptr<TransitionProbabilityQuote> q = QuantLib::ext::dynamic_pointer_cast<TransitionProbabilityQuote>(md);
726 Size i = stateIndex[q->fromRating()];
727 Size j = stateIndex[q->toRating()];
728 transitionMatrix[i][j] = q->quote()->value();
729 }
730 for (Size i = 0; i < dim; ++i) {
731 for (Size j = 0; j < dim; ++j) {
732 QL_REQUIRE(transitionMatrix[i][j] != Null<Real>(),
733 "DefaultCurve::buildTransitionMatrixCurve():matrix element "
734 << config.states()[i] << " -> " << config.states()[j] << " missing in market data");
735 }
736 }
737 Size initialStateIndex = stateIndex[config.initialState()];
738 curve_ = QuantLib::ext::make_shared<QuantExt::CreditCurve>(
739 Handle<DefaultProbabilityTermStructure>(QuantLib::ext::make_shared<QuantExt::GeneratorDefaultProbabilityTermStructure>(
740 QuantExt::GeneratorDefaultProbabilityTermStructure::MatrixType::Transition, transitionMatrix,
741 initialStateIndex, asof)));
742 if (recoveryRate_ == Null<Real>())
743 recoveryRate_ = 0.0;
744 LOG("Finished building default curve of type TransitionMatrix for curve " << curveID);
745}
const vector< string > & states() const
const std::vector< std::pair< std::string, bool > > & cdsQuotes() const
Size size(const ValueType &v)
Definition: value.cpp:145
boost::optional< Wildcard > getUniqueWildcard(const C &c)
checks if at most one element in C has a wild card and returns it in this case
Definition: wildcard.hpp:65
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ buildNullCurve()

void buildNullCurve ( const std::string &  curveID,
const DefaultCurveConfig::Config config,
const Date &  asof,
const DefaultCurveSpec spec 
)
private

Build a null curve (null rate, null recovery)

Definition at line 747 of file defaultcurve.cpp.

748 {
749 LOG("Start building null default curve for " << curveID);
750 curve_ = QuantLib::ext::make_shared<QuantExt::CreditCurve>(Handle<DefaultProbabilityTermStructure>(
751 QuantLib::ext::make_shared<QuantLib::FlatHazardRate>(asof, 0.0, config.dayCounter())));
752 recoveryRate_ = 0.0;
753 LOG("Finished building default curve of type Null for curve " << curveID);
754}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Member Data Documentation

◆ spec_

DefaultCurveSpec spec_
private

Definition at line 65 of file defaultcurve.hpp.

◆ curve_

QuantLib::ext::shared_ptr<QuantExt::CreditCurve> curve_
private

Definition at line 66 of file defaultcurve.hpp.

◆ recoveryRate_

Real recoveryRate_
private

Definition at line 67 of file defaultcurve.hpp.