Skip to content

Commit b3622bf

Browse files
pcaspersjenkins
authored andcommitted
QPR-12201 handle case where no swap index is available
1 parent d4d2c52 commit b3622bf

1 file changed

Lines changed: 23 additions & 14 deletions

File tree

OREData/ored/model/lgmbuilder.cpp

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -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

663672
std::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

Comments
 (0)