3232#include < ored/model/structuredmodelerror.hpp>
3333#include < ored/model/utilities.hpp>
3434#include < ored/utilities/dategrid.hpp>
35+ #include < ored/utilities/indexparser.hpp>
3536#include < ored/utilities/log.hpp>
3637#include < ored/utilities/parsers.hpp>
37- #include < ored/utilities/indexparser.hpp>
3838#include < ored/utilities/strike.hpp>
3939
4040using namespace QuantLib ;
@@ -177,31 +177,30 @@ LgmBuilder::LgmBuilder(const boost::shared_ptr<ore::data::Market>& market, const
177177 string qualifier = data_->qualifier ();
178178 currency_ = qualifier;
179179 boost::shared_ptr<IborIndex> index;
180- if (tryParseIborIndex (qualifier,index)) {
181- currency_ = index->currency ().code ();
180+ if (tryParseIborIndex (qualifier, index)) {
181+ currency_ = index->currency ().code ();
182182 }
183- LOG (" LgmCalibration for qualifier " << qualifier << " (ccy=" << currency_ << " ), configuration is " << configuration_);
183+ LOG (" LgmCalibration for qualifier " << qualifier << " (ccy=" << currency_ << " ), configuration is "
184+ << configuration_);
184185 Currency ccy = parseCurrency (currency_);
185186
186187 requiresCalibration_ =
187188 (data_->calibrateA () || data_->calibrateH ()) && data_->calibrationType () != CalibrationType::None;
188189
189- // the discount curve underlying the model might be relinked to a different curve outside this builder
190- // the calibration curve should always stay the same though, therefore we create a different handle for this
191- modelDiscountCurve_ = RelinkableHandle<YieldTermStructure>(*market_->discountCurve (currency_, configuration_));
192- calibrationDiscountCurve_ = Handle<YieldTermStructure>(*modelDiscountCurve_);
190+ swapIndex_ = market_->swapIndex (market_->swapIndexBase (data_->qualifier (), configuration_), configuration_);
191+ // see the comment for dinscountCurve() in the interface
192+ modelDiscountCurve_ = RelinkableHandle<YieldTermStructure>(*swapIndex_->discountingTermStructure ());
193193
194194 if (requiresCalibration_) {
195195 svts_ = market_->swaptionVol (data_->qualifier (), configuration_);
196- swapIndex_ = market_-> swapIndex (market_-> swapIndexBase (data_-> qualifier (), configuration_), configuration_);
197- shortSwapIndex_ = market_->swapIndex (market_->shortSwapIndexBase (data_->qualifier (), configuration_), configuration_);
196+ shortSwapIndex_ =
197+ market_->swapIndex (market_->shortSwapIndexBase (data_->qualifier (), configuration_), configuration_);
198198 registerWith (svts_);
199199 marketObserver_->addObservable (swapIndex_->forwardingTermStructure ());
200- marketObserver_->addObservable (swapIndex_->discountingTermStructure ());
201200 marketObserver_->addObservable (shortSwapIndex_->forwardingTermStructure ());
202201 marketObserver_->addObservable (shortSwapIndex_->discountingTermStructure ());
203202 }
204- marketObserver_->addObservable (calibrationDiscountCurve_ );
203+ marketObserver_->addObservable (swapIndex_-> discountingTermStructure () );
205204 registerWith (marketObserver_);
206205 // notify observers of all market data changes, not only when not calculated
207206 alwaysForwardNotifications ();
@@ -321,7 +320,7 @@ void LgmBuilder::performCalculations() const {
321320 // reset lgm observer's updated flag
322321 marketObserver_->hasUpdated (true );
323322
324- if (swaptionBasketRefDate_ != calibrationDiscountCurve_ ->referenceDate ()) {
323+ if (swaptionBasketRefDate_ != swapIndex_-> discountingTermStructure () ->referenceDate ()) {
325324 // build swaption basket if required, i.e. if reference date has changed since last build
326325 buildSwaptionBasket ();
327326 volSurfaceChanged (true );
@@ -333,7 +332,8 @@ void LgmBuilder::performCalculations() const {
333332 }
334333
335334 for (Size j = 0 ; j < swaptionBasket_.size (); j++) {
336- auto engine = boost::make_shared<QuantExt::AnalyticLgmSwaptionEngine>(model_, calibrationDiscountCurve_);
335+ auto engine =
336+ boost::make_shared<QuantExt::AnalyticLgmSwaptionEngine>(model_, swapIndex_->discountingTermStructure ());
337337 engine->enableCache (!data_->calibrateH (), !data_->calibrateA ());
338338 swaptionBasket_[j]->setPricingEngine (engine);
339339 // necessary if notifications are disabled (observation mode = Disable)
@@ -387,15 +387,15 @@ void LgmBuilder::performCalculations() const {
387387 if (Log::instance ().filter (ORE_DATA) || setCalibrationInfo_) {
388388 TLOGGERSTREAM (" Basket details:" );
389389 try {
390- auto d = getBasketDetails (calibrationInfo);
390+ auto d = getBasketDetails (calibrationInfo);
391391 TLOGGERSTREAM (d);
392392 } catch (const std::exception& e) {
393393 WLOG (" An error occurred: " << e.what ());
394394 }
395395 TLOGGERSTREAM (" Calibration details (with time grid = calibration swaption expiries):" );
396396 try {
397- auto d = getCalibrationDetails (calibrationInfo, swaptionBasket_, parametrization_);
398- TLOGGERSTREAM (d);
397+ auto d = getCalibrationDetails (calibrationInfo, swaptionBasket_, parametrization_);
398+ TLOGGERSTREAM (d);
399399 } catch (const std::exception& e) {
400400 WLOG (" An error occurred: " << e.what ());
401401 }
@@ -410,14 +410,14 @@ void LgmBuilder::performCalculations() const {
410410 StructuredModelErrorMessage (errorTemplate, exceptionMessage, id_).log ();
411411 WLOGGERSTREAM (" Basket details:" );
412412 try {
413- auto d = getBasketDetails (calibrationInfo);
413+ auto d = getBasketDetails (calibrationInfo);
414414 WLOGGERSTREAM (d);
415415 } catch (const std::exception& e) {
416416 WLOG (" An error occurred: " << e.what ());
417417 }
418418 WLOGGERSTREAM (" Calibration details (with time grid = calibration swaption expiries):" );
419419 try {
420- auto d = getCalibrationDetails (calibrationInfo, swaptionBasket_, parametrization_);
420+ auto d = getCalibrationDetails (calibrationInfo, swaptionBasket_, parametrization_);
421421 WLOGGERSTREAM (d);
422422 } catch (const std::exception& e) {
423423 WLOG (" An error occurred: " << e.what ());
@@ -548,8 +548,6 @@ void LgmBuilder::buildSwaptionBasket() const {
548548
549549 std::ostringstream log;
550550
551- Handle<YieldTermStructure> yts = market_->discountCurve (currency_, configuration_);
552-
553551 std::vector<Time> expiryTimes;
554552 std::vector<Time> maturityTimes;
555553 swaptionBasket_.clear ();
@@ -586,7 +584,7 @@ void LgmBuilder::buildSwaptionBasket() const {
586584 RateAveraging::Type averagingMethod = RateAveraging::Compound;
587585 if (auto on = dynamic_pointer_cast<OvernightIndexedSwapIndex>(*swapIndex_)) {
588586 settlementDays = on->fixingDays ();
589- averagingMethod = on->averagingMethod ();
587+ averagingMethod = on->averagingMethod ();
590588 }
591589
592590 Real dummyQuote = svts_->volatilityType () == Normal ? 0.0020 : 0.10 ;
@@ -597,28 +595,32 @@ void LgmBuilder::buildSwaptionBasket() const {
597595
598596 if (expiryDateBased && termDateBased) {
599597 Real shift = svts_->volatilityType () == ShiftedLognormal ? svts_->shift (expiryDb, termT) : 0.0 ;
600- std::tie (helper, updatedStrike) = createSwaptionHelper (
601- expiryDb, termDb, svts_, vol, iborIndex, fixedLegTenor, fixedDayCounter, floatDayCounter, yts,
602- calibrationErrorType_, strikeValue, shift, settlementDays, averagingMethod);
598+ std::tie (helper, updatedStrike) =
599+ createSwaptionHelper (expiryDb, termDb, svts_, vol, iborIndex, fixedLegTenor, fixedDayCounter,
600+ floatDayCounter, swapIndex_->discountingTermStructure (), calibrationErrorType_,
601+ strikeValue, shift, settlementDays, averagingMethod);
603602 }
604603 if (expiryDateBased && !termDateBased) {
605604 Real shift = svts_->volatilityType () == ShiftedLognormal ? svts_->shift (expiryDb, termPb) : 0.0 ;
606- std::tie (helper, updatedStrike) = createSwaptionHelper (
607- expiryDb, termPb, svts_, vol, iborIndex, fixedLegTenor, fixedDayCounter, floatDayCounter, yts,
608- calibrationErrorType_, strikeValue, shift, settlementDays, averagingMethod);
605+ std::tie (helper, updatedStrike) =
606+ createSwaptionHelper (expiryDb, termPb, svts_, vol, iborIndex, fixedLegTenor, fixedDayCounter,
607+ floatDayCounter, swapIndex_->discountingTermStructure (), calibrationErrorType_,
608+ strikeValue, shift, settlementDays, averagingMethod);
609609 }
610610 if (!expiryDateBased && termDateBased) {
611611 Date expiry = svts_->optionDateFromTenor (expiryPb);
612612 Real shift = svts_->volatilityType () == ShiftedLognormal ? svts_->shift (expiryPb, termT) : 0.0 ;
613- std::tie (helper, updatedStrike) = createSwaptionHelper (
614- expiry, termDb, svts_, vol, iborIndex, fixedLegTenor, fixedDayCounter, floatDayCounter, yts,
615- calibrationErrorType_, strikeValue, shift, settlementDays, averagingMethod);
613+ std::tie (helper, updatedStrike) =
614+ createSwaptionHelper (expiry, termDb, svts_, vol, iborIndex, fixedLegTenor, fixedDayCounter,
615+ floatDayCounter, swapIndex_->discountingTermStructure (), calibrationErrorType_,
616+ strikeValue, shift, settlementDays, averagingMethod);
616617 }
617618 if (!expiryDateBased && !termDateBased) {
618619 Real shift = svts_->volatilityType () == ShiftedLognormal ? svts_->shift (expiryPb, termPb) : 0.0 ;
619- std::tie (helper, updatedStrike) = createSwaptionHelper (
620- expiryPb, termPb, svts_, vol, iborIndex, fixedLegTenor, fixedDayCounter, floatDayCounter, yts,
621- calibrationErrorType_, strikeValue, shift, settlementDays, averagingMethod);
620+ std::tie (helper, updatedStrike) =
621+ createSwaptionHelper (expiryPb, termPb, svts_, vol, iborIndex, fixedLegTenor, fixedDayCounter,
622+ floatDayCounter, swapIndex_->discountingTermStructure (), calibrationErrorType_,
623+ strikeValue, shift, settlementDays, averagingMethod);
622624 }
623625
624626 // check if we want to keep the helper when a reference calibration grid is given
@@ -630,10 +632,10 @@ void LgmBuilder::buildSwaptionBasket() const {
630632 swaptionBasketVols_.push_back (volQuote);
631633 swaptionBasket_.push_back (helper);
632634 swaptionStrike_.push_back (updatedStrike);
633- expiryTimes.push_back (yts ->timeFromReference (expiryDate));
635+ expiryTimes.push_back (swapIndex_-> discountingTermStructure () ->timeFromReference (expiryDate));
634636 Date matDate = helper->underlyingSwap () ? helper->underlyingSwap ()->maturityDate ()
635637 : helper->underlyingOvernightIndexedSwap ()->maturityDate ();
636- maturityTimes.push_back (yts ->timeFromReference (matDate));
638+ maturityTimes.push_back (swapIndex_-> discountingTermStructure () ->timeFromReference (matDate));
637639 if (refCalDate != referenceCalibrationDates.end ())
638640 lastRefCalDate = *refCalDate;
639641 }
@@ -655,19 +657,18 @@ void LgmBuilder::buildSwaptionBasket() const {
655657 for (Size j = 0 ; j < maturityTimes.size (); j++)
656658 swaptionMaturities_[j] = maturityTimes[j];
657659
658- swaptionBasketRefDate_ = calibrationDiscountCurve_ ->referenceDate ();
660+ swaptionBasketRefDate_ = swapIndex_-> discountingTermStructure () ->referenceDate ();
659661}
660662
661663std::string LgmBuilder::getBasketDetails (LgmCalibrationInfo& info) const {
662664 std::ostringstream log;
663- Handle<YieldTermStructure> yts = market_->discountCurve (currency_, configuration_);
664665 log << std::right << std::setw (3 ) << " #" << std::setw (16 ) << " expiry" << std::setw (16 ) << " swapLength"
665666 << std::setw (16 ) << " strike" << std::setw (16 ) << " atmForward" << std::setw (16 ) << " annuity" << std::setw (16 )
666667 << " vega" << std::setw (16 ) << " vol\n " ;
667668 info.swaptionData .clear ();
668669 for (Size j = 0 ; j < swaptionBasket_.size (); ++j) {
669670 auto swp = boost::static_pointer_cast<SwaptionHelper>(swaptionBasket_[j])->swaption ();
670- auto sd = swaptionData (swp, yts , svts_);
671+ auto sd = swaptionData (swp, swapIndex_-> discountingTermStructure () , svts_);
671672 log << std::right << std::setw (3 ) << j << std::setw (16 ) << sd.timeToExpiry << std::setw (16 ) << sd.swapLength
672673 << std::setw (16 ) << sd.strike << std::setw (16 ) << sd.atmForward << std::setw (16 ) << sd.annuity
673674 << std::setw (16 ) << sd.vega << std::setw (16 ) << std::setw (16 ) << sd.stdDev / std::sqrt (sd.timeToExpiry )
0 commit comments