Skip to content

Commit 3d2c1e1

Browse files
committed
Merge branch 'feature/QPR-12830' into 'master'
QPR-13739 ISDA Fix + ABX Fix to use MidPoint if Price Closes QPR-12830 See merge request qs/oreplus!3088
2 parents d72e3a7 + f2960ed commit 3d2c1e1

2 files changed

Lines changed: 73 additions & 13 deletions

File tree

OREData/ored/marketdata/defaultcurve.cpp

Lines changed: 72 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@
3636
#include <ql/termstructures/credit/interpolatedsurvivalprobabilitycurve.hpp>
3737
#include <ql/termstructures/credit/flathazardrate.hpp>
3838
#include <ql/time/daycounters/actual365fixed.hpp>
39+
#include <ql/pricingengines/credit/isdacdsengine.hpp>
40+
#include <ql/pricingengines/credit/midpointcdsengine.hpp>
41+
#include <ql/termstructures/yield/flatforward.hpp>
42+
// #include <ql/termstructures/yield/bootstraptraits.hpp>
43+
// #include <ql/termstructures/yield/piecewiseyieldcurve.hpp>
3944

4045
#include <algorithm>
4146
#include <set>
@@ -428,9 +433,8 @@ void DefaultCurve::buildCdsCurve(const std::string& curveID, const DefaultCurveC
428433
}
429434
}
430435
}
431-
/*}else if(config.type() == DefaultCurveConfig::Config::Type::ConvSpreadCDS){
436+
}else if(config.type() == DefaultCurveConfig::Config::Type::ConvSpreadCDS){
432437
refData.type = "ConvSpreadCDS";
433-
// Currently same than SpreadCDS
434438
for (auto quote : quotes) {
435439
try {
436440
if ((cdsConv->rule() == DateGeneration::CDS || cdsConv->rule() == DateGeneration::CDS2015 ||
@@ -444,12 +448,66 @@ void DefaultCurve::buildCdsCurve(const std::string& curveID, const DefaultCurveC
444448
"date strictly after T + 1.");
445449
continue;
446450
};
447-
helpers.push_back(QuantLib::ext::make_shared<SpreadCdsHelper>(
448-
quote.value, quote.term, cdsConv->settlementDays(), cdsConv->calendar(), cdsConv->frequency(),
449-
cdsConv->paymentConvention(), cdsConv->rule(), cdsConv->dayCounter(), recoveryRate_, discountCurve, CreditDefaultSwap::PricingModel::ISDA,
450-
cdsConv->settlesAccrual(), ppt, config.startDate(), cdsConv->lastPeriodDayCounter()));
451-
runningSpread = config.runningSpread();
452-
helperQuoteTerms[helpers.back()->latestDate()] = quote.term;
451+
Real notional = 1000000;
452+
auto convSpread = quote.value;
453+
// Use configured/convention start date and calendar
454+
Date maturity = cdsMaturity(asof, quote.term, cdsConv->rule());
455+
Schedule schedule(asof, maturity, Period(cdsConv->frequency()), cdsConv->calendar(), cdsConv->paymentConvention(),
456+
cdsConv->paymentConvention(), cdsConv->rule(), false);
457+
458+
// CDS quoted at conventional/quoted spread
459+
// Solve for flat hazard with quoted spread
460+
ext::shared_ptr<CreditDefaultSwap> cdsConvSpread = ext::make_shared<CreditDefaultSwap>(
461+
Protection::Buyer, notional, convSpread, schedule, cdsConv->paymentConvention(), Actual360(),
462+
cdsConv->settlesAccrual(), QuantLib::CreditDefaultSwap::atDefault,
463+
Date(), QuantLib::ext::shared_ptr<Claim>());
464+
465+
ext::shared_ptr<SimpleQuote> flatRate = ext::make_shared<SimpleQuote>(0.0);
466+
Handle<DefaultProbabilityTermStructure> dProbTS(
467+
ext::shared_ptr<DefaultProbabilityTermStructure>(
468+
new FlatHazardRate(0, NullCalendar(), Handle<Quote>(flatRate), Actual365Fixed())
469+
)
470+
);
471+
auto dummyYTS = Handle<YieldTermStructure>(ext::make_shared<FlatForward>(0, NullCalendar(), 0.0, Actual365Fixed()));
472+
ext::shared_ptr<PricingEngine> engineInit( new IsdaCdsEngine(dProbTS, 0.4, dummyYTS));
473+
cdsConvSpread->setPricingEngine(engineInit);
474+
475+
// Flat hazard implied by conventional spread (ISDA model)
476+
Real h = cdsConvSpread->impliedHazardRate(0.0, discountCurve, Actual365Fixed(), recoveryRate_, 1e-12,
477+
CreditDefaultSwap::ISDA);
478+
479+
// Price the fixed-coupon CDS with h and real recovery rate to get upfront
480+
Handle<DefaultProbabilityTermStructure> dProb(
481+
boost::shared_ptr<DefaultProbabilityTermStructure>(
482+
new FlatHazardRate(0, cdsConv->calendar(), h, Actual365Fixed())
483+
)
484+
);
485+
486+
Rate fixedCoupon = config.runningSpread() == QuantLib::Null<Real>() ? 100 / 10000.0 : config.runningSpread();
487+
488+
// Fixed-coupon CDS; ask for fairUpfront
489+
Date upfrontSettle = cdsConv->calendar().advance(asof, cdsConv->upfrontSettlementDays() * Days);
490+
ext::shared_ptr<CreditDefaultSwap> fixedCpnTrade = ext::make_shared<CreditDefaultSwap>(
491+
Protection::Buyer, notional, 0.0, fixedCoupon, schedule, cdsConv->paymentConvention(),
492+
Actual360(), cdsConv->settlesAccrual(), QuantLib::CreditDefaultSwap::atDefault,
493+
asof, upfrontSettle);
494+
495+
ext::shared_ptr<PricingEngine> engine(new IsdaCdsEngine(dProb, recoveryRate_, discountCurve));
496+
fixedCpnTrade->setPricingEngine(engine);
497+
498+
// Real fairSpreadClean = fixedCpnTrade->fairSpreadClean();
499+
Rate calcUpfront = fixedCpnTrade->fairUpfront();
500+
501+
auto tmp = QuantLib::ext::make_shared<UpfrontCdsHelper>(
502+
calcUpfront, fixedCoupon, quote.term, cdsConv->settlementDays(), cdsConv->calendar(),
503+
cdsConv->frequency(), cdsConv->paymentConvention(), cdsConv->rule(), cdsConv->dayCounter(),
504+
recoveryRate_, discountCurve, CreditDefaultSwap::PricingModel::Midpoint, cdsConv->upfrontSettlementDays(), cdsConv->settlesAccrual(), ppt,
505+
config.startDate(), cdsConv->lastPeriodDayCounter());
506+
507+
if (tmp->latestDate() > asof) {
508+
helpers.push_back(tmp);
509+
}
510+
helperQuoteTerms[tmp->latestDate()] = quote.term;
453511
} catch (exception& e) {
454512
if (quote.term == Period(0, Months)) {
455513
WLOG("DefaultCurve:: Cannot add quote of term 0M to CDS curve " << curveID << " for asof date "
@@ -460,7 +518,7 @@ void DefaultCurve::buildCdsCurve(const std::string& curveID, const DefaultCurveC
460518
<< ", with error: " << e.what());
461519
}
462520
}
463-
}*/
521+
}
464522
}else {
465523
refData.type = "Upfront";
466524
for (auto quote : quotes) {
@@ -473,10 +531,11 @@ void DefaultCurve::buildCdsCurve(const std::string& curveID, const DefaultCurveC
473531
runningSpread = config.runningSpread();
474532
}
475533
auto tmp = QuantLib::ext::make_shared<UpfrontCdsHelper>(
476-
quote.value, runningSpread, quote.term, cdsConv->settlementDays(), cdsConv->calendar(),
477-
cdsConv->frequency(), cdsConv->paymentConvention(), cdsConv->rule(), cdsConv->dayCounter(),
478-
recoveryRate_, discountCurve, CreditDefaultSwap::PricingModel::Midpoint, cdsConv->upfrontSettlementDays(), cdsConv->settlesAccrual(), ppt,
479-
config.startDate(), cdsConv->lastPeriodDayCounter());
534+
quote.value, runningSpread, quote.term, cdsConv->settlementDays(), cdsConv->calendar(),
535+
cdsConv->frequency(), cdsConv->paymentConvention(), cdsConv->rule(), cdsConv->dayCounter(),
536+
recoveryRate_, discountCurve, CreditDefaultSwap::PricingModel::Midpoint, cdsConv->upfrontSettlementDays(), cdsConv->settlesAccrual(), ppt,
537+
config.startDate(), cdsConv->lastPeriodDayCounter());
538+
480539
if (tmp->latestDate() > asof) {
481540
helpers.push_back(tmp);
482541
}

OREData/ored/portfolio/referencedata.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -480,6 +480,7 @@ class CreditReferenceDatum : public ReferenceDatum {
480480
QuantLib::Date predecessorImplementationDate;
481481
string entityType;
482482
string primaryPriceType;
483+
Real runningSpread;
483484
};
484485
CreditReferenceDatum() {}
485486

0 commit comments

Comments
 (0)