@@ -187,9 +187,18 @@ LgmBuilder::LgmBuilder(const boost::shared_ptr<ore::data::Market>& market, const
187187 requiresCalibration_ =
188188 (data_->calibrateA () || data_->calibrateH ()) && data_->calibrationType () != CalibrationType::None;
189189
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 ());
190+ try {
191+ swapIndex_ = market_->swapIndex (market_->swapIndexBase (data_->qualifier (), configuration_), configuration_);
192+ // see the comment for dinscountCurve() in the interface
193+ modelDiscountCurve_ = RelinkableHandle<YieldTermStructure>(*swapIndex_->discountingTermStructure ());
194+ } catch (const std::exception& e) {
195+ StructuredModelErrorMessage (
196+ " Error when retrieving swap index base for qualifier '" + data_->qualifier () +
197+ " '. Use market discount curve instead of swap index discount curve as a fallback." ,
198+ e.what (), id_)
199+ .log ();
200+ modelDiscountCurve_ = RelinkableHandle<YieldTermStructure>(*market_->discountCurve (currency_, configuration_));
201+ }
193202
194203 if (requiresCalibration_) {
195204 svts_ = market_->swaptionVol (data_->qualifier (), configuration_);
@@ -200,7 +209,7 @@ LgmBuilder::LgmBuilder(const boost::shared_ptr<ore::data::Market>& market, const
200209 marketObserver_->addObservable (shortSwapIndex_->forwardingTermStructure ());
201210 marketObserver_->addObservable (shortSwapIndex_->discountingTermStructure ());
202211 }
203- marketObserver_->addObservable (swapIndex_-> discountingTermStructure () );
212+ marketObserver_->addObservable (modelDiscountCurve_ );
204213 registerWith (marketObserver_);
205214 // notify observers of all market data changes, not only when not calculated
206215 alwaysForwardNotifications ();
@@ -320,7 +329,7 @@ void LgmBuilder::performCalculations() const {
320329 // reset lgm observer's updated flag
321330 marketObserver_->hasUpdated (true );
322331
323- if (swaptionBasketRefDate_ != swapIndex_-> discountingTermStructure () ->referenceDate ()) {
332+ if (swaptionBasketRefDate_ != modelDiscountCurve_ ->referenceDate ()) {
324333 // build swaption basket if required, i.e. if reference date has changed since last build
325334 buildSwaptionBasket ();
326335 volSurfaceChanged (true );
@@ -333,7 +342,7 @@ void LgmBuilder::performCalculations() const {
333342
334343 for (Size j = 0 ; j < swaptionBasket_.size (); j++) {
335344 auto engine =
336- boost::make_shared<QuantExt::AnalyticLgmSwaptionEngine>(model_, swapIndex_-> discountingTermStructure () );
345+ boost::make_shared<QuantExt::AnalyticLgmSwaptionEngine>(model_, modelDiscountCurve_ );
337346 engine->enableCache (!data_->calibrateH (), !data_->calibrateA ());
338347 swaptionBasket_[j]->setPricingEngine (engine);
339348 // necessary if notifications are disabled (observation mode = Disable)
@@ -597,29 +606,29 @@ void LgmBuilder::buildSwaptionBasket() const {
597606 Real shift = svts_->volatilityType () == ShiftedLognormal ? svts_->shift (expiryDb, termT) : 0.0 ;
598607 std::tie (helper, updatedStrike) =
599608 createSwaptionHelper (expiryDb, termDb, svts_, vol, iborIndex, fixedLegTenor, fixedDayCounter,
600- floatDayCounter, swapIndex_-> discountingTermStructure () , calibrationErrorType_,
609+ floatDayCounter, modelDiscountCurve_ , calibrationErrorType_,
601610 strikeValue, shift, settlementDays, averagingMethod);
602611 }
603612 if (expiryDateBased && !termDateBased) {
604613 Real shift = svts_->volatilityType () == ShiftedLognormal ? svts_->shift (expiryDb, termPb) : 0.0 ;
605614 std::tie (helper, updatedStrike) =
606615 createSwaptionHelper (expiryDb, termPb, svts_, vol, iborIndex, fixedLegTenor, fixedDayCounter,
607- floatDayCounter, swapIndex_-> discountingTermStructure () , calibrationErrorType_,
616+ floatDayCounter, modelDiscountCurve_ , calibrationErrorType_,
608617 strikeValue, shift, settlementDays, averagingMethod);
609618 }
610619 if (!expiryDateBased && termDateBased) {
611620 Date expiry = svts_->optionDateFromTenor (expiryPb);
612621 Real shift = svts_->volatilityType () == ShiftedLognormal ? svts_->shift (expiryPb, termT) : 0.0 ;
613622 std::tie (helper, updatedStrike) =
614623 createSwaptionHelper (expiry, termDb, svts_, vol, iborIndex, fixedLegTenor, fixedDayCounter,
615- floatDayCounter, swapIndex_-> discountingTermStructure () , calibrationErrorType_,
624+ floatDayCounter, modelDiscountCurve_ , calibrationErrorType_,
616625 strikeValue, shift, settlementDays, averagingMethod);
617626 }
618627 if (!expiryDateBased && !termDateBased) {
619628 Real shift = svts_->volatilityType () == ShiftedLognormal ? svts_->shift (expiryPb, termPb) : 0.0 ;
620629 std::tie (helper, updatedStrike) =
621630 createSwaptionHelper (expiryPb, termPb, svts_, vol, iborIndex, fixedLegTenor, fixedDayCounter,
622- floatDayCounter, swapIndex_-> discountingTermStructure () , calibrationErrorType_,
631+ floatDayCounter, modelDiscountCurve_ , calibrationErrorType_,
623632 strikeValue, shift, settlementDays, averagingMethod);
624633 }
625634
@@ -632,10 +641,10 @@ void LgmBuilder::buildSwaptionBasket() const {
632641 swaptionBasketVols_.push_back (volQuote);
633642 swaptionBasket_.push_back (helper);
634643 swaptionStrike_.push_back (updatedStrike);
635- expiryTimes.push_back (swapIndex_-> discountingTermStructure () ->timeFromReference (expiryDate));
644+ expiryTimes.push_back (modelDiscountCurve_ ->timeFromReference (expiryDate));
636645 Date matDate = helper->underlyingSwap () ? helper->underlyingSwap ()->maturityDate ()
637646 : helper->underlyingOvernightIndexedSwap ()->maturityDate ();
638- maturityTimes.push_back (swapIndex_-> discountingTermStructure () ->timeFromReference (matDate));
647+ maturityTimes.push_back (modelDiscountCurve_ ->timeFromReference (matDate));
639648 if (refCalDate != referenceCalibrationDates.end ())
640649 lastRefCalDate = *refCalDate;
641650 }
@@ -657,7 +666,7 @@ void LgmBuilder::buildSwaptionBasket() const {
657666 for (Size j = 0 ; j < maturityTimes.size (); j++)
658667 swaptionMaturities_[j] = maturityTimes[j];
659668
660- swaptionBasketRefDate_ = swapIndex_-> discountingTermStructure () ->referenceDate ();
669+ swaptionBasketRefDate_ = modelDiscountCurve_ ->referenceDate ();
661670}
662671
663672std::string LgmBuilder::getBasketDetails (LgmCalibrationInfo& info) const {
@@ -668,7 +677,7 @@ std::string LgmBuilder::getBasketDetails(LgmCalibrationInfo& info) const {
668677 info.swaptionData .clear ();
669678 for (Size j = 0 ; j < swaptionBasket_.size (); ++j) {
670679 auto swp = boost::static_pointer_cast<SwaptionHelper>(swaptionBasket_[j])->swaption ();
671- auto sd = swaptionData (swp, swapIndex_-> discountingTermStructure () , svts_);
680+ auto sd = swaptionData (swp, modelDiscountCurve_ , svts_);
672681 log << std::right << std::setw (3 ) << j << std::setw (16 ) << sd.timeToExpiry << std::setw (16 ) << sd.swapLength
673682 << std::setw (16 ) << sd.strike << std::setw (16 ) << sd.atmForward << std::setw (16 ) << sd.annuity
674683 << std::setw (16 ) << sd.vega << std::setw (16 ) << std::setw (16 ) << sd.stdDev / std::sqrt (sd.timeToExpiry )
0 commit comments