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 }
0 commit comments