Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
Public Member Functions | List of all members
LgmBuilder Class Reference

Builder for a Linear Gauss Markov model component. More...

#include <ored/model/lgmbuilder.hpp>

+ Inheritance diagram for LgmBuilder:
+ Collaboration diagram for LgmBuilder:

Public Member Functions

 LgmBuilder (const QuantLib::ext::shared_ptr< ore::data::Market > &market, const QuantLib::ext::shared_ptr< IrLgmData > &data, const std::string &configuration=Market::defaultConfiguration, Real bootstrapTolerance=0.001, const bool continueOnError=false, const std::string &referenceCalibrationGrid="", const bool setCalibrationInfo=false, const std::string &id="unknwon")
 
Real error () const
 Return calibration error. More...
 
Inspectors
std::string qualifier ()
 
std::string ccy ()
 
QuantLib::ext::shared_ptr< QuantExt::LGMmodel () const
 
RelinkableHandle< YieldTermStructure > discountCurve ()
 
QuantLib::ext::shared_ptr< QuantExt::IrLgm1fParametrizationparametrization () const
 
std::vector< QuantLib::ext::shared_ptr< BlackCalibrationHelper > > swaptionBasket () const
 
- Public Member Functions inherited from ModelBuilder
void recalibrate () const
 
virtual void forceRecalculate ()
 
virtual bool requiresRecalibration () const=0
 

ModelBuilder interface

QuantLib::ext::shared_ptr< ore::data::Marketmarket_
 
const std::string configuration_
 
QuantLib::ext::shared_ptr< IrLgmDatadata_
 
const Real bootstrapTolerance_
 
const bool continueOnError_
 
const std::string referenceCalibrationGrid_
 
const bool setCalibrationInfo_
 
const std::string id_
 
bool requiresCalibration_ = false
 
std::string currency_
 
Real error_
 
QuantLib::ext::shared_ptr< QuantExt::LGMmodel_
 
Array params_
 
QuantLib::ext::shared_ptr< QuantExt::IrLgm1fParametrizationparametrization_
 
std::vector< boolswaptionActive_
 
std::vector< QuantLib::ext::shared_ptr< BlackCalibrationHelper > > swaptionBasket_
 
std::vector< Real > swaptionStrike_
 
std::vector< QuantLib::ext::shared_ptr< SimpleQuote > > swaptionBasketVols_
 
Array swaptionExpiries_
 
Array swaptionMaturities_
 
Date swaptionBasketRefDate_
 
Handle< QuantLib::SwaptionVolatilityStructure > svts_
 
Handle< SwapIndex > swapIndex_
 
Handle< SwapIndex > shortSwapIndex_
 
RelinkableHandle< YieldTermStructure > modelDiscountCurve_
 
Handle< YieldTermStructure > calibrationDiscountCurve_
 
QuantLib::ext::shared_ptr< OptimizationMethodoptimizationMethod_
 
EndCriteria endCriteria_
 
BlackCalibrationHelper::CalibrationErrorType calibrationErrorType_
 
std::vector< QuantLib::Real > swaptionVolCache_
 
bool forceCalibration_ = false
 
QuantLib::ext::shared_ptr< QuantExt::MarketObservermarketObserver_
 
void forceRecalculate () override
 
bool requiresRecalibration () const override
 
void performCalculations () const override
 
void buildSwaptionBasket () const
 
void updateSwaptionBasketVols () const
 
std::string getBasketDetails (QuantExt::LgmCalibrationInfo &info) const
 
bool volSurfaceChanged (const bool updateCache) const
 
void getExpiryAndTerm (const Size j, Period &expiryPb, Period &termPb, Date &expiryDb, Date &termDb, Real &termT, bool &expiryDateBased, bool &termDateBased) const
 
Real getStrike (const Size j) const
 

Detailed Description

Builder for a Linear Gauss Markov model component.

This class is a utility that turns a Linear Gauss Markov model description into an interest rate model parametrisation which can be used to instantiate a CrossAssetModel.

Definition at line 48 of file lgmbuilder.hpp.

Constructor & Destructor Documentation

◆ LgmBuilder()

LgmBuilder ( const QuantLib::ext::shared_ptr< ore::data::Market > &  market,
const QuantLib::ext::shared_ptr< IrLgmData > &  data,
const std::string &  configuration = Market::defaultConfiguration,
Real  bootstrapTolerance = 0.001,
const bool  continueOnError = false,
const std::string &  referenceCalibrationGrid = "",
const bool  setCalibrationInfo = false,
const std::string &  id = "unknwon" 
)

The configuration refers to the configuration to read swaption vol and swap index from the market. The discounting curve to price calibrating swaptions is derived from the swap index directly though, i.e. it is not read as a discount curve from the market (except as a fallback in case we do not find the swap index).

Definition at line 167 of file lgmbuilder.cpp.

171 : market_(market), configuration_(configuration), data_(data), bootstrapTolerance_(bootstrapTolerance),
172 continueOnError_(continueOnError), referenceCalibrationGrid_(referenceCalibrationGrid),
173 setCalibrationInfo_(setCalibrationInfo), id_(id),
174 optimizationMethod_(QuantLib::ext::shared_ptr<OptimizationMethod>(new LevenbergMarquardt(1E-8, 1E-8, 1E-8))),
175 endCriteria_(EndCriteria(1000, 500, 1E-8, 1E-8, 1E-8)),
176 calibrationErrorType_(BlackCalibrationHelper::RelativePriceError) {
177
178 marketObserver_ = QuantLib::ext::make_shared<MarketObserver>();
179 string qualifier = data_->qualifier();
181 QuantLib::ext::shared_ptr<IborIndex> index;
182 if (tryParseIborIndex(qualifier, index)) {
183 currency_ = index->currency().code();
184 }
185 LOG("LgmCalibration for qualifier " << qualifier << " (ccy=" << currency_ << "), configuration is "
186 << configuration_);
187 Currency ccy = parseCurrency(currency_);
188
190 (data_->calibrateA() || data_->calibrateH()) && data_->calibrationType() != CalibrationType::None;
191
192 try {
194 market_->swapIndex(market_->shortSwapIndexBase(data_->qualifier(), configuration_), configuration_);
195 swapIndex_ = market_->swapIndex(market_->swapIndexBase(data_->qualifier(), configuration_), configuration_);
196 svts_ = market_->swaptionVol(data_->qualifier(), configuration_);
197 // see the comment for dinscountCurve() in the interface
198 modelDiscountCurve_ = RelinkableHandle<YieldTermStructure>(*swapIndex_->discountingTermStructure());
199 calibrationDiscountCurve_ = Handle<YieldTermStructure>(*swapIndex_->discountingTermStructure());
200 } catch (const std::exception& e) {
201 StructuredModelErrorMessage(
202 "Error when retrieving swap index base for qualifier '" + data_->qualifier() +
203 "'. Use market discount curve instead of swap index discount curve as a fallback.",
204 e.what(), id_)
205 .log();
206 modelDiscountCurve_ = RelinkableHandle<YieldTermStructure>(*market_->discountCurve(currency_, configuration_));
207 calibrationDiscountCurve_ = Handle<YieldTermStructure>(*market_->discountCurve(currency_, configuration_));
208 }
209
211 registerWith(svts_);
212 marketObserver_->addObservable(swapIndex_->forwardingTermStructure());
213 marketObserver_->addObservable(shortSwapIndex_->forwardingTermStructure());
214 marketObserver_->addObservable(shortSwapIndex_->discountingTermStructure());
215 }
216 // we do not register with modelDiscountCurve_, since this curve does not affect the calibration
218 registerWith(marketObserver_);
219 // notify observers of all market data changes, not only when not calculated
220 alwaysForwardNotifications();
221
222 swaptionActive_ = std::vector<bool>(data_->optionExpiries().size(), false);
223
226 }
227
228 Array aTimes(data_->aTimes().begin(), data_->aTimes().end());
229 Array hTimes(data_->hTimes().begin(), data_->hTimes().end());
230 Array alpha(data_->aValues().begin(), data_->aValues().end());
231 Array h(data_->hValues().begin(), data_->hValues().end());
232
233 if (data_->aParamType() == ParamType::Constant) {
234 QL_REQUIRE(data_->aTimes().size() == 0,
235 "LgmBuilder: empty volatility time grid expected for constant parameter type");
236 QL_REQUIRE(data_->aValues().size() == 1,
237 "LgmBuilder: initial volatility values should have size 1 for constant parameter type");
238 } else if (data_->aParamType() == ParamType::Piecewise) {
239 if (data_->calibrateA() && data_->calibrationType() == CalibrationType::Bootstrap) {
240 if (data_->aTimes().size() > 0) {
241 DLOG("overriding alpha time grid with swaption expiries, set all initial values to first given value");
242 }
243 QL_REQUIRE(swaptionExpiries_.size() > 0, "empty swaptionExpiries");
244 aTimes = Array(swaptionExpiries_.begin(), swaptionExpiries_.end() - 1);
245 alpha = Array(aTimes.size() + 1, data_->aValues()[0]);
246 } else {
247 QL_REQUIRE(alpha.size() == aTimes.size() + 1,
248 "LgmBuilder: LGM volatility time and initial value array sizes do not match");
249 }
250 } else
251 QL_FAIL("LgmBuilder: volatility parameter type not covered");
252
253 if (data_->hParamType() == ParamType::Constant) {
254 QL_REQUIRE(data_->hTimes().size() == 0,
255 "LgmBuilder: empty reversion time grid expected for constant parameter type");
256 QL_REQUIRE(data_->hValues().size() == 1,
257 "LgmBuidler: initial reversion values should have size 1 for constant parameter type");
258 } else if (data_->hParamType() == ParamType::Piecewise) {
259 if (data_->calibrateH() && data_->calibrationType() == CalibrationType::Bootstrap) {
260 if (data_->hTimes().size() > 0) {
261 DLOG("overriding h time grid with swaption underlying maturities, set all initial values to first "
262 "given value");
263 }
264 hTimes = swaptionMaturities_;
265 h = Array(hTimes.size() + 1, data_->hValues()[0]);
266 } else { // use input time grid and input h array otherwise
267 QL_REQUIRE(h.size() == hTimes.size() + 1, "H grids do not match");
268 }
269 } else
270 QL_FAIL("LgmBuilder: reversion parameter type case not covered");
271
272 DLOG("before calibration: alpha times = " << aTimes << " values = " << alpha);
273 DLOG("before calibration: h times = " << hTimes << " values = " << h);
274
275 if (data_->reversionType() == LgmData::ReversionType::HullWhite &&
276 data_->volatilityType() == LgmData::VolatilityType::HullWhite) {
277 DLOG("IR parametrization for " << qualifier << ": IrLgm1fPiecewiseConstantHullWhiteAdaptor");
278 parametrization_ = QuantLib::ext::make_shared<QuantExt::IrLgm1fPiecewiseConstantHullWhiteAdaptor>(
279 ccy, modelDiscountCurve_, aTimes, alpha, hTimes, h);
280 } else if (data_->reversionType() == LgmData::ReversionType::HullWhite &&
281 data_->volatilityType() == LgmData::VolatilityType::Hagan) {
282 DLOG("IR parametrization for " << qualifier << ": IrLgm1fPiecewiseConstant");
283 parametrization_ = QuantLib::ext::make_shared<QuantExt::IrLgm1fPiecewiseConstantParametrization>(
284 ccy, modelDiscountCurve_, aTimes, alpha, hTimes, h);
285 } else if (data_->reversionType() == LgmData::ReversionType::Hagan &&
286 data_->volatilityType() == LgmData::VolatilityType::Hagan) {
287 parametrization_ = QuantLib::ext::make_shared<QuantExt::IrLgm1fPiecewiseLinearParametrization>(
288 ccy, modelDiscountCurve_, aTimes, alpha, hTimes, h);
289 DLOG("IR parametrization for " << qualifier << ": IrLgm1fPiecewiseLinear");
290 } else {
291 QL_FAIL("LgmBuilder: Reversion type Hagan and volatility type HullWhite not covered");
292 }
293 DLOG("alpha times size: " << aTimes.size());
294 DLOG("lambda times size: " << hTimes.size());
295
296 model_ = QuantLib::ext::make_shared<QuantExt::LGM>(parametrization_);
297 params_ = model_->params();
298}
std::vector< bool > swaptionActive_
Definition: lgmbuilder.hpp:110
Handle< SwapIndex > swapIndex_
Definition: lgmbuilder.hpp:119
const std::string configuration_
Definition: lgmbuilder.hpp:94
BlackCalibrationHelper::CalibrationErrorType calibrationErrorType_
Definition: lgmbuilder.hpp:126
QuantLib::ext::shared_ptr< QuantExt::MarketObserver > marketObserver_
Definition: lgmbuilder.hpp:134
const bool continueOnError_
Definition: lgmbuilder.hpp:97
const Real bootstrapTolerance_
Definition: lgmbuilder.hpp:96
const std::string id_
Definition: lgmbuilder.hpp:100
QuantLib::ext::shared_ptr< QuantExt::IrLgm1fParametrization > parametrization_
Definition: lgmbuilder.hpp:107
Handle< YieldTermStructure > calibrationDiscountCurve_
Definition: lgmbuilder.hpp:121
EndCriteria endCriteria_
Definition: lgmbuilder.hpp:125
QuantLib::ext::shared_ptr< OptimizationMethod > optimizationMethod_
Definition: lgmbuilder.hpp:124
QuantLib::ext::shared_ptr< ore::data::Market > market_
Definition: lgmbuilder.hpp:93
void buildSwaptionBasket() const
Definition: lgmbuilder.cpp:557
Handle< SwapIndex > shortSwapIndex_
Definition: lgmbuilder.hpp:119
const std::string referenceCalibrationGrid_
Definition: lgmbuilder.hpp:98
std::string ccy()
Definition: lgmbuilder.hpp:64
std::string qualifier()
Definition: lgmbuilder.hpp:63
QuantLib::ext::shared_ptr< IrLgmData > data_
Definition: lgmbuilder.hpp:95
QuantLib::ext::shared_ptr< QuantExt::LGM > model_
Definition: lgmbuilder.hpp:105
const bool setCalibrationInfo_
Definition: lgmbuilder.hpp:99
Handle< QuantLib::SwaptionVolatilityStructure > svts_
Definition: lgmbuilder.hpp:118
RelinkableHandle< YieldTermStructure > modelDiscountCurve_
Definition: lgmbuilder.hpp:120
@ Hagan
Parametrize LGM H(t) as H(t) = int_0^t h(s) ds with constant or piecewise h(s)
@ HullWhite
Parametrize volatility as HullWhite sigma(t)
@ Hagan
Parametrize volatility as Hagan alpha(t)
bool tryParseIborIndex(const string &s, QuantLib::ext::shared_ptr< IborIndex > &index)
Try to convert std::string to QuantLib::IborIndex.
Currency parseCurrency(const string &s)
Convert text to QuantLib::Currency.
Definition: parsers.cpp:290
#define LOG(text)
Logging Macro (Level = Notice)
Definition: log.hpp:552
#define DLOG(text)
Logging Macro (Level = Debug)
Definition: log.hpp:554
+ Here is the call graph for this function:

Member Function Documentation

◆ error()

Real error ( ) const

Return calibration error.

Definition at line 300 of file lgmbuilder.cpp.

300 {
301 calculate();
302 return error_;
303}

◆ qualifier()

std::string qualifier ( )

Definition at line 63 of file lgmbuilder.hpp.

63{ return data_->qualifier(); }
+ Here is the caller graph for this function:

◆ ccy()

std::string ccy ( )

Definition at line 64 of file lgmbuilder.hpp.

64{ return currency_; }
+ Here is the caller graph for this function:

◆ model()

QuantLib::ext::shared_ptr< QuantExt::LGM > model ( ) const

Definition at line 305 of file lgmbuilder.cpp.

305 {
306 calculate();
307 return model_;
308}

◆ discountCurve()

RelinkableHandle< YieldTermStructure > discountCurve ( )

Definition at line 69 of file lgmbuilder.hpp.

69{ return modelDiscountCurve_; }

◆ parametrization()

QuantLib::ext::shared_ptr< QuantExt::IrLgm1fParametrization > parametrization ( ) const

Definition at line 310 of file lgmbuilder.cpp.

310 {
311 calculate();
312 return parametrization_;
313}

◆ swaptionBasket()

std::vector< QuantLib::ext::shared_ptr< BlackCalibrationHelper > > swaptionBasket ( ) const

Definition at line 315 of file lgmbuilder.cpp.

315 {
316 calculate();
317 return swaptionBasket_;
318}
std::vector< QuantLib::ext::shared_ptr< BlackCalibrationHelper > > swaptionBasket_
Definition: lgmbuilder.hpp:111

◆ forceRecalculate()

void forceRecalculate ( )
overridevirtual

Reimplemented from ModelBuilder.

Definition at line 692 of file lgmbuilder.cpp.

692 {
693 forceCalibration_ = true;
695 forceCalibration_ = false;
696}
virtual void forceRecalculate()
+ Here is the call graph for this function:

◆ requiresRecalibration()

bool requiresRecalibration ( ) const
overridevirtual

Implements ModelBuilder.

Definition at line 320 of file lgmbuilder.cpp.

320 {
321 return requiresCalibration_ &&
322 (volSurfaceChanged(false) || marketObserver_->hasUpdated(false) || forceCalibration_);
323}
bool volSurfaceChanged(const bool updateCache) const
Definition: lgmbuilder.cpp:508
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ performCalculations()

void performCalculations ( ) const
overrideprivate

Definition at line 325 of file lgmbuilder.cpp.

325 {
326
327 DLOG("Recalibrate LGM model for qualifier " << data_->qualifier() << " currency " << currency_);
328
329 if (!requiresRecalibration()) {
330 DLOG("Skipping calibration as nothing has changed");
331 return;
332 }
333
334 // reset lgm observer's updated flag
335 marketObserver_->hasUpdated(true);
336
337 if (swaptionBasketRefDate_ != calibrationDiscountCurve_->referenceDate()) {
338 // build swaption basket if required, i.e. if reference date has changed since last build
340 volSurfaceChanged(true);
342 } else {
343 // otherwise just update vols
344 volSurfaceChanged(true);
346 }
347
348 for (Size j = 0; j < swaptionBasket_.size(); j++) {
349 auto engine = QuantLib::ext::make_shared<QuantExt::AnalyticLgmSwaptionEngine>(model_, calibrationDiscountCurve_,
350 data_->floatSpreadMapping());
351 engine->enableCache(!data_->calibrateH(), !data_->calibrateA());
352 swaptionBasket_[j]->setPricingEngine(engine);
353 // necessary if notifications are disabled (observation mode = Disable)
354 swaptionBasket_[j]->update();
355 }
356
357 // reset model parameters to ensure identical results on identical market data input
358 model_->setParams(params_);
359 parametrization_->shift() = 0.0;
360 parametrization_->scaling() = 1.0;
361
362 LgmCalibrationInfo calibrationInfo;
363 error_ = QL_MAX_REAL;
364 std::string errorTemplate =
365 std::string("Failed to calibrate LGM Model. ") +
366 (continueOnError_ ? std::string("Calculation will proceed anyway - using the calibration as is!")
367 : std::string("Calculation will aborted."));
368 try {
369 if (data_->calibrateA() && !data_->calibrateH() && data_->calibrationType() == CalibrationType::Bootstrap) {
370 DLOG("call calibrateVolatilitiesIterative for volatility calibration (bootstrap)");
371 model_->calibrateVolatilitiesIterative(swaptionBasket_, *optimizationMethod_, endCriteria_);
372 } else if (data_->calibrateH() && !data_->calibrateA() &&
373 data_->calibrationType() == CalibrationType::Bootstrap) {
374 DLOG("call calibrateReversionsIterative for reversion calibration (bootstrap)");
375 model_->calibrateVolatilitiesIterative(swaptionBasket_, *optimizationMethod_, endCriteria_);
376 } else {
377 QL_REQUIRE(data_->calibrationType() != CalibrationType::Bootstrap,
378 "LgmBuidler: Calibration type Bootstrap can be used with volatilities and reversions calibrated "
379 "simultaneously. Either choose BestFit oder fix one of these parameters.");
380 if (data_->calibrateA() && !data_->calibrateH()) {
381 DLOG("call calibrateVolatilities for (global) volatility calibration")
382 model_->calibrateVolatilities(swaptionBasket_, *optimizationMethod_, endCriteria_);
383 } else if (data_->calibrateH() && !data_->calibrateA()) {
384 DLOG("call calibrateReversions for (global) reversion calibration")
386 } else {
387 DLOG("call calibrate for global volatility and reversion calibration");
389 }
390 }
391 TLOG("LGM " << data_->qualifier() << " calibration errors:");
393 } catch (const std::exception& e) {
394 // just log a warning, we check below if we meet the bootstrap tolerance and handle the result there
395 StructuredModelErrorMessage(errorTemplate, e.what(), id_).log();
396 }
397 calibrationInfo.rmse = error_;
398 if (fabs(error_) < bootstrapTolerance_ ||
399 (data_->calibrationType() == CalibrationType::BestFit && error_ != QL_MAX_REAL)) {
400 // we check the log level here to avoid unnecessary computations
401 if (Log::instance().filter(ORE_DATA) || setCalibrationInfo_) {
402 TLOGGERSTREAM("Basket details:");
403 try {
404 auto d = getBasketDetails(calibrationInfo);
405 TLOGGERSTREAM(d);
406 } catch (const std::exception& e) {
407 WLOG("An error occurred: " << e.what());
408 }
409 TLOGGERSTREAM("Calibration details (with time grid = calibration swaption expiries):");
410 try {
411 auto d = getCalibrationDetails(calibrationInfo, swaptionBasket_, parametrization_);
412 TLOGGERSTREAM(d);
413 } catch (const std::exception& e) {
414 WLOG("An error occurred: " << e.what());
415 }
416 TLOGGERSTREAM("Parameter details (with parameter time grid)");
418 TLOGGERSTREAM("rmse = " << error_);
419 calibrationInfo.valid = true;
420 }
421 } else {
422 std::string exceptionMessage = "LGM (" + data_->qualifier() + ") calibration error " + std::to_string(error_) +
423 " exceeds tolerance " + std::to_string(bootstrapTolerance_);
424 StructuredModelErrorMessage(errorTemplate, exceptionMessage, id_).log();
425 WLOGGERSTREAM("Basket details:");
426 try {
427 auto d = getBasketDetails(calibrationInfo);
428 WLOGGERSTREAM(d);
429 } catch (const std::exception& e) {
430 WLOG("An error occurred: " << e.what());
431 }
432 WLOGGERSTREAM("Calibration details (with time grid = calibration swaption expiries):");
433 try {
434 auto d = getCalibrationDetails(calibrationInfo, swaptionBasket_, parametrization_);
435 WLOGGERSTREAM(d);
436 } catch (const std::exception& e) {
437 WLOG("An error occurred: " << e.what());
438 }
439 WLOGGERSTREAM("Parameter details (with parameter time grid)");
441 WLOGGERSTREAM("rmse = " << error_);
442 calibrationInfo.valid = true;
443 if (!continueOnError_) {
444 QL_FAIL(exceptionMessage);
445 }
446 }
447 model_->setCalibrationInfo(calibrationInfo);
448
449 DLOG("Apply shift horizon and scale (if not 0.0 and 1.0 respectively)");
450
451 QL_REQUIRE(data_->shiftHorizon() >= 0.0, "shift horizon must be non negative");
452 QL_REQUIRE(data_->scaling() > 0.0, "scaling must be positive");
453
454 if (data_->shiftHorizon() > 0.0) {
455 Real value = -parametrization_->H(data_->shiftHorizon());
456 DLOG("Apply shift horizon " << data_->shiftHorizon() << " (C=" << value << ") to the " << data_->qualifier()
457 << " LGM model");
458 parametrization_->shift() = value;
459 }
460
461 if (data_->scaling() != 1.0) {
462 DLOG("Apply scaling " << data_->scaling() << " to the " << data_->qualifier() << " LGM model");
463 parametrization_->scaling() = data_->scaling();
464 }
465} // performCalculations()
std::string getBasketDetails(QuantExt::LgmCalibrationInfo &info) const
Definition: lgmbuilder.cpp:674
void updateSwaptionBasketVols() const
Definition: lgmbuilder.cpp:552
bool requiresRecalibration() const override
Definition: lgmbuilder.cpp:320
SafeStack< ValueType > value
SafeStack< Filter > filter
#define WLOGGERSTREAM(text)
Definition: log.hpp:630
#define TLOGGERSTREAM(text)
Definition: log.hpp:633
#define ORE_DATA
Definition: log.hpp:33
#define WLOG(text)
Logging Macro (Level = Warning)
Definition: log.hpp:550
#define TLOG(text)
Logging Macro (Level = Data)
Definition: log.hpp:556
Real getCalibrationError(const std::vector< QuantLib::ext::shared_ptr< Helper > > &basket)
Definition: utilities.hpp:47
std::string getCalibrationDetails(LgmCalibrationInfo &info, const std::vector< QuantLib::ext::shared_ptr< BlackCalibrationHelper > > &basket, const QuantLib::ext::shared_ptr< IrLgm1fParametrization > &parametrization)
Definition: utilities.cpp:125
+ Here is the call graph for this function:

◆ buildSwaptionBasket()

void buildSwaptionBasket ( ) const
private

Definition at line 557 of file lgmbuilder.cpp.

557 {
558
559 DLOG("build swaption basket");
560
561 QL_REQUIRE(data_->optionExpiries().size() == data_->optionTerms().size(), "swaption vector size mismatch");
562 QL_REQUIRE(data_->optionExpiries().size() == data_->optionStrikes().size(), "swaption vector size mismatch");
563
564 std::ostringstream log;
565
566 std::vector<Time> expiryTimes;
567 std::vector<Time> maturityTimes;
568 swaptionBasket_.clear();
569 swaptionBasketVols_.clear();
570 swaptionVolCache_.clear();
571 swaptionStrike_.clear();
572
573 DLOG("build reference date grid '" << referenceCalibrationGrid_ << "'");
574 Date lastRefCalDate = Date::minDate();
575 std::vector<Date> referenceCalibrationDates;
576 if (!referenceCalibrationGrid_.empty())
577 referenceCalibrationDates = DateGrid(referenceCalibrationGrid_).dates();
578
579 for (Size j = 0; j < data_->optionExpiries().size(); j++) {
580 bool expiryDateBased, termDateBased;
581 Period expiryPb, termPb;
582 Date expiryDb, termDb;
583 Real termT = Null<Real>();
584
585 getExpiryAndTerm(j, expiryPb, termPb, expiryDb, termDb, termT, expiryDateBased, termDateBased);
586 Real strikeValue = getStrike(j);
587
588 // rounded to whole years, only used to distinguish between short and long
589 // swap tenors, which in practice always are multiples of whole years
590 Period termTmp = static_cast<Size>(termT + 0.5) * Years;
591 auto iborIndex = termTmp > shortSwapIndex_->tenor() ? swapIndex_->iborIndex() : shortSwapIndex_->iborIndex();
592 auto fixedLegTenor =
593 termTmp > shortSwapIndex_->tenor() ? swapIndex_->fixedLegTenor() : shortSwapIndex_->fixedLegTenor();
594 auto fixedDayCounter =
595 termTmp > shortSwapIndex_->tenor() ? swapIndex_->dayCounter() : shortSwapIndex_->dayCounter();
596 auto floatDayCounter = termTmp > shortSwapIndex_->tenor() ? swapIndex_->iborIndex()->dayCounter()
597 : shortSwapIndex_->iborIndex()->dayCounter();
598 Size settlementDays = Null<Size>();
599 RateAveraging::Type averagingMethod = RateAveraging::Compound;
600 if (auto on = dynamic_pointer_cast<OvernightIndexedSwapIndex>(*swapIndex_)) {
601 settlementDays = on->fixingDays();
602 averagingMethod = on->averagingMethod();
603 }
604
605 Real dummyQuote = svts_->volatilityType() == Normal ? 0.0020 : 0.10;
606 auto volQuote = QuantLib::ext::make_shared<SimpleQuote>(dummyQuote);
607 Handle<Quote> vol = Handle<Quote>(volQuote);
608 QuantLib::ext::shared_ptr<SwaptionHelper> helper;
609 Real updatedStrike;
610
611 if (expiryDateBased && termDateBased) {
612 Real shift = svts_->volatilityType() == ShiftedLognormal ? svts_->shift(expiryDb, termT) : 0.0;
613 std::tie(helper, updatedStrike) = createSwaptionHelper(
614 expiryDb, termDb, svts_, vol, iborIndex, fixedLegTenor, fixedDayCounter, floatDayCounter,
615 calibrationDiscountCurve_, calibrationErrorType_, strikeValue, shift, settlementDays, averagingMethod);
616 }
617 if (expiryDateBased && !termDateBased) {
618 Real shift = svts_->volatilityType() == ShiftedLognormal ? svts_->shift(expiryDb, termPb) : 0.0;
619 std::tie(helper, updatedStrike) = createSwaptionHelper(
620 expiryDb, termPb, svts_, vol, iborIndex, fixedLegTenor, fixedDayCounter, floatDayCounter,
621 calibrationDiscountCurve_, calibrationErrorType_, strikeValue, shift, settlementDays, averagingMethod);
622 }
623 if (!expiryDateBased && termDateBased) {
624 Date expiry = svts_->optionDateFromTenor(expiryPb);
625 Real shift = svts_->volatilityType() == ShiftedLognormal ? svts_->shift(expiryPb, termT) : 0.0;
626 std::tie(helper, updatedStrike) = createSwaptionHelper(
627 expiry, termDb, svts_, vol, iborIndex, fixedLegTenor, fixedDayCounter, floatDayCounter,
628 calibrationDiscountCurve_, calibrationErrorType_, strikeValue, shift, settlementDays, averagingMethod);
629 }
630 if (!expiryDateBased && !termDateBased) {
631 Real shift = svts_->volatilityType() == ShiftedLognormal ? svts_->shift(expiryPb, termPb) : 0.0;
632 std::tie(helper, updatedStrike) = createSwaptionHelper(
633 expiryPb, termPb, svts_, vol, iborIndex, fixedLegTenor, fixedDayCounter, floatDayCounter,
634 calibrationDiscountCurve_, calibrationErrorType_, strikeValue, shift, settlementDays, averagingMethod);
635 }
636
637 // check if we want to keep the helper when a reference calibration grid is given
638 Date expiryDate = helper->swaption()->exercise()->date(0);
639 auto refCalDate =
640 std::lower_bound(referenceCalibrationDates.begin(), referenceCalibrationDates.end(), expiryDate);
641 if (refCalDate == referenceCalibrationDates.end() || *refCalDate > lastRefCalDate) {
642 swaptionActive_[j] = true;
643 swaptionBasketVols_.push_back(volQuote);
644 swaptionBasket_.push_back(helper);
645 swaptionStrike_.push_back(updatedStrike);
646 expiryTimes.push_back(calibrationDiscountCurve_->timeFromReference(expiryDate));
647 Date matDate = helper->underlyingSwap() ? helper->underlyingSwap()->maturityDate()
648 : helper->underlyingOvernightIndexedSwap()->maturityDate();
649 maturityTimes.push_back(calibrationDiscountCurve_->timeFromReference(matDate));
650 if (refCalDate != referenceCalibrationDates.end())
651 lastRefCalDate = *refCalDate;
652 }
653 }
654
655 std::sort(expiryTimes.begin(), expiryTimes.end());
656 auto itExpiryTime = unique(expiryTimes.begin(), expiryTimes.end());
657 expiryTimes.resize(distance(expiryTimes.begin(), itExpiryTime));
658
659 swaptionExpiries_ = Array(expiryTimes.size());
660 for (Size j = 0; j < expiryTimes.size(); j++)
661 swaptionExpiries_[j] = expiryTimes[j];
662
663 std::sort(maturityTimes.begin(), maturityTimes.end());
664 auto itMaturityTime = unique(maturityTimes.begin(), maturityTimes.end());
665 maturityTimes.resize(distance(maturityTimes.begin(), itMaturityTime));
666
667 swaptionMaturities_ = Array(maturityTimes.size());
668 for (Size j = 0; j < maturityTimes.size(); j++)
669 swaptionMaturities_[j] = maturityTimes[j];
670
672}
std::vector< QuantLib::ext::shared_ptr< SimpleQuote > > swaptionBasketVols_
Definition: lgmbuilder.hpp:113
std::vector< QuantLib::Real > swaptionVolCache_
Definition: lgmbuilder.hpp:129
std::vector< Real > swaptionStrike_
Definition: lgmbuilder.hpp:112
Real getStrike(const Size j) const
Definition: lgmbuilder.cpp:494
void getExpiryAndTerm(const Size j, Period &expiryPb, Period &termPb, Date &expiryDb, Date &termDb, Real &termT, bool &expiryDateBased, bool &termDateBased) const
Definition: lgmbuilder.cpp:467
RandomVariable log(RandomVariable x)
Size size(const ValueType &v)
Definition: value.cpp:145
QuantLib::BootstrapHelper< QuantLib::OptionletVolatilityStructure > helper
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ updateSwaptionBasketVols()

void updateSwaptionBasketVols ( ) const
private

Definition at line 552 of file lgmbuilder.cpp.

552 {
553 for (Size j = 0; j < swaptionBasketVols_.size(); ++j)
554 swaptionBasketVols_.at(j)->setValue(swaptionVolCache_.at(j));
555}
+ Here is the caller graph for this function:

◆ getBasketDetails()

std::string getBasketDetails ( QuantExt::LgmCalibrationInfo info) const
private

Definition at line 674 of file lgmbuilder.cpp.

674 {
675 std::ostringstream log;
676 log << std::right << std::setw(3) << "#" << std::setw(16) << "expiry" << std::setw(16) << "swapLength"
677 << std::setw(16) << "strike" << std::setw(16) << "atmForward" << std::setw(16) << "annuity" << std::setw(16)
678 << "vega" << std::setw(16) << "vol\n";
679 info.swaptionData.clear();
680 for (Size j = 0; j < swaptionBasket_.size(); ++j) {
681 auto swp = QuantLib::ext::static_pointer_cast<SwaptionHelper>(swaptionBasket_[j])->swaption();
682 auto sd = swaptionData(swp, calibrationDiscountCurve_, svts_);
683 log << std::right << std::setw(3) << j << std::setw(16) << sd.timeToExpiry << std::setw(16) << sd.swapLength
684 << std::setw(16) << sd.strike << std::setw(16) << sd.atmForward << std::setw(16) << sd.annuity
685 << std::setw(16) << sd.vega << std::setw(16) << std::setw(16) << sd.stdDev / std::sqrt(sd.timeToExpiry)
686 << "\n";
687 info.swaptionData.push_back(sd);
688 }
689 return log.str();
690}
std::vector< SwaptionData > swaptionData
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ volSurfaceChanged()

bool volSurfaceChanged ( const bool  updateCache) const
private

Definition at line 508 of file lgmbuilder.cpp.

508 {
509 bool hasUpdated = false;
510
511 // create cache if not equal to required size
512 if (swaptionVolCache_.size() != swaptionBasket_.size())
513 swaptionVolCache_ = vector<Real>(swaptionBasket_.size(), Null<Real>());
514
515 Size swaptionCounter = 0;
516 for (Size j = 0; j < data_->optionExpiries().size(); j++) {
517 if (!swaptionActive_[j])
518 continue;
519
520 Real volCache = swaptionVolCache_.at(swaptionCounter);
521
522 bool expiryDateBased, termDateBased;
523 Period expiryPb, termPb;
524 Date expiryDb, termDb;
525 Real termT;
526
527 getExpiryAndTerm(j, expiryPb, termPb, expiryDb, termDb, termT, expiryDateBased, termDateBased);
528 Real strikeValue = swaptionStrike_.at(swaptionCounter);
529
530 Real vol;
531 if (expiryDateBased && termDateBased) {
532 vol = svts_->volatility(expiryDb, termT, strikeValue);
533 } else if (expiryDateBased && !termDateBased) {
534 vol = svts_->volatility(expiryDb, termPb, strikeValue);
535 } else if (!expiryDateBased && termDateBased) {
536 vol = svts_->volatility(expiryPb, termT, strikeValue);
537 } else {
538 // !expiryDateBased && !termDateBased
539 vol = svts_->volatility(expiryPb, termPb, strikeValue);
540 }
541
542 if (!close_enough(volCache, vol)) {
543 if (updateCache)
544 swaptionVolCache_[swaptionCounter] = vol;
545 hasUpdated = true;
546 }
547 swaptionCounter++;
548 }
549 return hasUpdated;
550}
Filter close_enough(const RandomVariable &x, const RandomVariable &y)
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ getExpiryAndTerm()

void getExpiryAndTerm ( const Size  j,
Period &  expiryPb,
Period &  termPb,
Date &  expiryDb,
Date &  termDb,
Real &  termT,
bool expiryDateBased,
bool termDateBased 
) const
private

Definition at line 467 of file lgmbuilder.cpp.

468 {
469 std::string expiryString = data_->optionExpiries()[j];
470 std::string termString = data_->optionTerms()[j];
471 parseDateOrPeriod(expiryString, expiryDb, expiryPb, expiryDateBased);
472 parseDateOrPeriod(termString, termDb, termPb, termDateBased);
473 if (termDateBased) {
474 Date tmpExpiry = expiryDateBased ? expiryDb : svts_->optionDateFromTenor(expiryPb);
475 Date tmpStart = swapIndex_->iborIndex()->valueDate(swapIndex_->iborIndex()->fixingCalendar().adjust(tmpExpiry));
476 // ensure that we have a term >= 1 Month, otherwise QL might throw "non-positive swap length (0) given" from
477 // the black swaption engine during calibration helper pricing; also notice that we use the swap length
478 // calculated in the svts (i.e. a length rounded to whole months) to read the volatility from the cube, which is
479 // consistent with what is done in BlackSwaptionEngine (although one might ask whether an interpolated
480 // volatility would be more appropriate)
481 termDb = std::max(termDb, tmpStart + 1 * Months);
482 termT = svts_->swapLength(tmpStart, termDb);
483 } else {
484 termT = svts_->swapLength(termPb);
485 // same as above, make sure the underlying term is at least >= 1 Month, but since Period::operator<
486 // throws in certain circumstances, we do the comparison based on termT here:
487 if (termT < 1.0 / 12.0) {
488 termT = 1.0 / 12.0;
489 termPb = 1 * Months;
490 }
491 }
492}
boost::variant< QuantLib::Date, QuantLib::Period > parseDateOrPeriod(const string &s)
Convert text to QuantLib::Period or QuantLib::Date.
Definition: parsers.cpp:493
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ getStrike()

Real getStrike ( const Size  j) const
private

Definition at line 494 of file lgmbuilder.cpp.

494 {
495 DLOG("LgmBuilder::getStrike(" << j << "): '" << data_->optionStrikes()[j] << "'");
496 Strike strike = parseStrike(data_->optionStrikes()[j]);
497 Real strikeValue;
498 // TODO: Extend strike type coverage
499 if (strike.type == Strike::Type::ATM)
500 strikeValue = Null<Real>();
501 else if (strike.type == Strike::Type::Absolute)
502 strikeValue = strike.value;
503 else
504 QL_FAIL("strike type ATM or Absolute expected");
505 return strikeValue;
506}
Strike parseStrike(const std::string &s)
Convert text to Strike.
Definition: strike.cpp:30
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Member Data Documentation

◆ market_

QuantLib::ext::shared_ptr<ore::data::Market> market_
private

Definition at line 93 of file lgmbuilder.hpp.

◆ configuration_

const std::string configuration_
private

Definition at line 94 of file lgmbuilder.hpp.

◆ data_

QuantLib::ext::shared_ptr<IrLgmData> data_
private

Definition at line 95 of file lgmbuilder.hpp.

◆ bootstrapTolerance_

const Real bootstrapTolerance_
private

Definition at line 96 of file lgmbuilder.hpp.

◆ continueOnError_

const bool continueOnError_
private

Definition at line 97 of file lgmbuilder.hpp.

◆ referenceCalibrationGrid_

const std::string referenceCalibrationGrid_
private

Definition at line 98 of file lgmbuilder.hpp.

◆ setCalibrationInfo_

const bool setCalibrationInfo_
private

Definition at line 99 of file lgmbuilder.hpp.

◆ id_

const std::string id_
private

Definition at line 100 of file lgmbuilder.hpp.

◆ requiresCalibration_

bool requiresCalibration_ = false
private

Definition at line 101 of file lgmbuilder.hpp.

◆ currency_

std::string currency_
private

Definition at line 102 of file lgmbuilder.hpp.

◆ error_

Real error_
mutableprivate

Definition at line 104 of file lgmbuilder.hpp.

◆ model_

QuantLib::ext::shared_ptr<QuantExt::LGM> model_
mutableprivate

Definition at line 105 of file lgmbuilder.hpp.

◆ params_

Array params_
mutableprivate

Definition at line 106 of file lgmbuilder.hpp.

◆ parametrization_

QuantLib::ext::shared_ptr<QuantExt::IrLgm1fParametrization> parametrization_
mutableprivate

Definition at line 107 of file lgmbuilder.hpp.

◆ swaptionActive_

std::vector<bool> swaptionActive_
mutableprivate

Definition at line 110 of file lgmbuilder.hpp.

◆ swaptionBasket_

std::vector<QuantLib::ext::shared_ptr<BlackCalibrationHelper> > swaptionBasket_
mutableprivate

Definition at line 111 of file lgmbuilder.hpp.

◆ swaptionStrike_

std::vector<Real> swaptionStrike_
mutableprivate

Definition at line 112 of file lgmbuilder.hpp.

◆ swaptionBasketVols_

std::vector<QuantLib::ext::shared_ptr<SimpleQuote> > swaptionBasketVols_
mutableprivate

Definition at line 113 of file lgmbuilder.hpp.

◆ swaptionExpiries_

Array swaptionExpiries_
mutableprivate

Definition at line 114 of file lgmbuilder.hpp.

◆ swaptionMaturities_

Array swaptionMaturities_
mutableprivate

Definition at line 115 of file lgmbuilder.hpp.

◆ swaptionBasketRefDate_

Date swaptionBasketRefDate_
mutableprivate

Definition at line 116 of file lgmbuilder.hpp.

◆ svts_

Handle<QuantLib::SwaptionVolatilityStructure> svts_
private

Definition at line 118 of file lgmbuilder.hpp.

◆ swapIndex_

Handle<SwapIndex> swapIndex_
private

Definition at line 119 of file lgmbuilder.hpp.

◆ shortSwapIndex_

Handle<SwapIndex> shortSwapIndex_
private

Definition at line 119 of file lgmbuilder.hpp.

◆ modelDiscountCurve_

RelinkableHandle<YieldTermStructure> modelDiscountCurve_
private

Definition at line 120 of file lgmbuilder.hpp.

◆ calibrationDiscountCurve_

Handle<YieldTermStructure> calibrationDiscountCurve_
private

Definition at line 121 of file lgmbuilder.hpp.

◆ optimizationMethod_

QuantLib::ext::shared_ptr<OptimizationMethod> optimizationMethod_
private

Definition at line 124 of file lgmbuilder.hpp.

◆ endCriteria_

EndCriteria endCriteria_
private

Definition at line 125 of file lgmbuilder.hpp.

◆ calibrationErrorType_

BlackCalibrationHelper::CalibrationErrorType calibrationErrorType_
private

Definition at line 126 of file lgmbuilder.hpp.

◆ swaptionVolCache_

std::vector<QuantLib::Real> swaptionVolCache_
mutableprivate

Definition at line 129 of file lgmbuilder.hpp.

◆ forceCalibration_

bool forceCalibration_ = false
private

Definition at line 131 of file lgmbuilder.hpp.

◆ marketObserver_

QuantLib::ext::shared_ptr<QuantExt::MarketObserver> marketObserver_
private

Definition at line 134 of file lgmbuilder.hpp.