Skip to content

Commit cb254b3

Browse files
pcaspersjenkins
authored andcommitted
QPR-12329 do not recreate builders, this generates too many recalibrations
1 parent fc01a8a commit cb254b3

2 files changed

Lines changed: 80 additions & 56 deletions

File tree

OREData/ored/model/crossassetmodelbuilder.cpp

Lines changed: 78 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -154,47 +154,50 @@ void CrossAssetModelBuilder::performCalculations() const {
154154
if (!dontCalibrate_ && requiresRecalibration()) {
155155
// reset market observer update flag
156156
marketObserver_->hasUpdated(true);
157-
// the cast is a bit ugly, but we pretty much know what we are doing here
158-
const_cast<CrossAssetModelBuilder*>(this)->unregisterWithSubBuilders();
159157
buildModel();
160-
const_cast<CrossAssetModelBuilder*>(this)->registerWithSubBuilders();
161158
}
162159
}
163160

164161
void CrossAssetModelBuilder::buildModel() const {
165162

166-
QL_REQUIRE(market_ != NULL, "CrossAssetModelBuilder: no market given");
167163
LOG("Start building CrossAssetModel");
164+
165+
QL_REQUIRE(market_ != NULL, "CrossAssetModelBuilder: no market given");
166+
168167
DLOG("configurations: LgmCalibration "
169168
<< configurationLgmCalibration_ << ", FxCalibration " << configurationFxCalibration_ << ", EqCalibration "
170169
<< configurationEqCalibration_ << ", InfCalibration " << configurationInfCalibration_ << ", CrCalibration"
171-
<< configurationCrCalibration_ << ", ComCalibration" << configurationComCalibration_
172-
<< ", FinalModel " << configurationFinalModel_);
170+
<< configurationCrCalibration_ << ", ComCalibration" << configurationComCalibration_ << ", FinalModel "
171+
<< configurationFinalModel_);
172+
173173
if (dontCalibrate_) {
174174
DLOG("Calibration of the model is disabled.");
175175
}
176176

177-
QL_REQUIRE(config_->irConfigs().size() > 0, "missing IR configurations");
178-
QL_REQUIRE(config_->irConfigs().size() == config_->fxConfigs().size() + 1,
179-
"FX configuration size " << config_->fxConfigs().size() << " inconsistent with IR configuration size "
180-
<< config_->irConfigs().size());
181-
182-
swaptionBaskets_.resize(config_->irConfigs().size());
183-
optionExpiries_.resize(config_->irConfigs().size());
184-
swaptionMaturities_.resize(config_->irConfigs().size());
185-
swaptionCalibrationErrors_.resize(config_->irConfigs().size());
186-
fxOptionBaskets_.resize(config_->fxConfigs().size());
187-
fxOptionExpiries_.resize(config_->fxConfigs().size());
188-
fxOptionCalibrationErrors_.resize(config_->fxConfigs().size());
189-
eqOptionBaskets_.resize(config_->eqConfigs().size());
190-
eqOptionExpiries_.resize(config_->eqConfigs().size());
191-
eqOptionCalibrationErrors_.resize(config_->eqConfigs().size());
192-
inflationCalibrationErrors_.resize(config_->infConfigs().size());
193-
comOptionBaskets_.resize(config_->comConfigs().size());
194-
comOptionExpiries_.resize(config_->comConfigs().size());
195-
comOptionCalibrationErrors_.resize(config_->comConfigs().size());
196-
197-
subBuilders_.clear();
177+
bool buildersAreInitialized = !subBuilders_.empty();
178+
179+
if (!buildersAreInitialized) {
180+
QL_REQUIRE(config_->irConfigs().size() > 0, "missing IR configurations");
181+
QL_REQUIRE(config_->irConfigs().size() == config_->fxConfigs().size() + 1,
182+
"FX configuration size " << config_->fxConfigs().size()
183+
<< " inconsistent with IR configuration size "
184+
<< config_->irConfigs().size());
185+
186+
swaptionBaskets_.resize(config_->irConfigs().size());
187+
optionExpiries_.resize(config_->irConfigs().size());
188+
swaptionMaturities_.resize(config_->irConfigs().size());
189+
swaptionCalibrationErrors_.resize(config_->irConfigs().size());
190+
fxOptionBaskets_.resize(config_->fxConfigs().size());
191+
fxOptionExpiries_.resize(config_->fxConfigs().size());
192+
fxOptionCalibrationErrors_.resize(config_->fxConfigs().size());
193+
eqOptionBaskets_.resize(config_->eqConfigs().size());
194+
eqOptionExpiries_.resize(config_->eqConfigs().size());
195+
eqOptionCalibrationErrors_.resize(config_->eqConfigs().size());
196+
inflationCalibrationErrors_.resize(config_->infConfigs().size());
197+
comOptionBaskets_.resize(config_->comConfigs().size());
198+
comOptionExpiries_.resize(config_->comConfigs().size());
199+
comOptionCalibrationErrors_.resize(config_->comConfigs().size());
200+
}
198201

199202
// Store information on the number of factors for each process. This is used when requesting a correlation matrix
200203
// from the CorrelationMatrixBuilder below.
@@ -229,10 +232,12 @@ void CrossAssetModelBuilder::buildModel() const {
229232
DLOG("IR Parametrization " << i << " qualifier " << irConfig->qualifier());
230233

231234
if (auto ir = boost::dynamic_pointer_cast<IrLgmData>(irConfig)) {
232-
233-
auto builder =
234-
boost::make_shared<LgmBuilder>(market_, ir, configurationLgmCalibration_, config_->bootstrapTolerance(),
235-
continueOnError_, referenceCalibrationGrid_, false, id_);
235+
if (!buildersAreInitialized) {
236+
subBuilders_[CrossAssetModel::AssetType::IR][i] = boost::make_shared<LgmBuilder>(
237+
market_, ir, configurationLgmCalibration_, config_->bootstrapTolerance(), continueOnError_,
238+
referenceCalibrationGrid_, false, id_);
239+
}
240+
auto builder = boost::dynamic_pointer_cast<LgmBuilder>(subBuilders_[CrossAssetModel::AssetType::IR][i]);
236241
if (dontCalibrate_)
237242
builder->freeze();
238243
lgmBuilder.push_back(builder);
@@ -246,16 +251,18 @@ void CrossAssetModelBuilder::buildModel() const {
246251
currencies.push_back(parametrization->currency().code());
247252
irParametrizations.push_back(parametrization);
248253
irDiscountCurves.push_back(builder->discountCurve());
249-
subBuilders_[CrossAssetModel::AssetType::IR][i] = builder;
250254
processInfo[CrossAssetModel::AssetType::IR].emplace_back(ir->ccy(), 1);
251255
}
252256
else if(auto ir = boost::dynamic_pointer_cast<HwModelData>(irConfig)) {
253257
bool evaluateBankAccount = true; // updated in cross asset model for non-base ccys
254258
bool setCalibrationInfo = false;
255259
HwModel::Discretization discr = HwModel::Discretization::Euler;
256-
auto builder = boost::make_shared<HwBuilder>(
257-
market_, ir, measure, discr, evaluateBankAccount, configurationLgmCalibration_,
258-
config_->bootstrapTolerance(), continueOnError_, referenceCalibrationGrid_, setCalibrationInfo);
260+
if(!buildersAreInitialized) {
261+
subBuilders_[CrossAssetModel::AssetType::IR][i] = boost::make_shared<HwBuilder>(
262+
market_, ir, measure, discr, evaluateBankAccount, configurationLgmCalibration_,
263+
config_->bootstrapTolerance(), continueOnError_, referenceCalibrationGrid_, setCalibrationInfo);
264+
}
265+
auto builder = boost::dynamic_pointer_cast<HwBuilder>(subBuilders_[CrossAssetModel::AssetType::IR][i]);
259266
if (dontCalibrate_)
260267
builder->freeze();
261268
hwBuilder.push_back(builder);
@@ -269,7 +276,6 @@ void CrossAssetModelBuilder::buildModel() const {
269276
currencies.push_back(parametrization->currency().code());
270277
irParametrizations.push_back(parametrization);
271278
irDiscountCurves.push_back(builder->discountCurve());
272-
subBuilders_[CrossAssetModel::AssetType::IR][i] = builder;
273279
processInfo[CrossAssetModel::AssetType::IR].emplace_back(ir->ccy(), parametrization->m());
274280
}
275281
}
@@ -295,13 +301,16 @@ void CrossAssetModelBuilder::buildModel() const {
295301
QL_REQUIRE(domCcy == domesticCcy, "FX parametrization [" << i << "]=" << ccy << "/" << domCcy
296302
<< " does not match domestic ccy " << domesticCcy);
297303

298-
boost::shared_ptr<FxBsBuilder> builder =
299-
boost::make_shared<FxBsBuilder>(market_, fx, configurationFxCalibration_, referenceCalibrationGrid_);
304+
if (!buildersAreInitialized) {
305+
subBuilders_[CrossAssetModel::AssetType::FX][i] =
306+
boost::make_shared<FxBsBuilder>(market_, fx, configurationFxCalibration_, referenceCalibrationGrid_);
307+
}
308+
auto builder = boost::dynamic_pointer_cast<FxBsBuilder>(subBuilders_[CrossAssetModel::AssetType::FX][i]);
309+
300310
boost::shared_ptr<QuantExt::FxBsParametrization> parametrization = builder->parametrization();
301311

302312
fxOptionBaskets_[i] = builder->optionBasket();
303313
fxParametrizations.push_back(parametrization);
304-
subBuilders_[CrossAssetModel::AssetType::FX][i] = builder;
305314
processInfo[CrossAssetModel::AssetType::FX].emplace_back(ccy.code() + domCcy.code(), 1);
306315
}
307316

@@ -316,13 +325,16 @@ void CrossAssetModelBuilder::buildModel() const {
316325
QuantLib::Currency eqCcy = ore::data::parseCurrency(eq->currency());
317326
QL_REQUIRE(std::find(currencies.begin(), currencies.end(), eqCcy.code()) != currencies.end(),
318327
"Currency (" << eqCcy << ") for equity " << eqName << " not covered by CrossAssetModelData");
319-
boost::shared_ptr<EqBsBuilder> builder = boost::make_shared<EqBsBuilder>(
328+
if(!buildersAreInitialized) {
329+
subBuilders_[CrossAssetModel::AssetType::EQ][i] = boost::make_shared<EqBsBuilder>(
320330
market_, eq, domesticCcy, configurationEqCalibration_, referenceCalibrationGrid_);
331+
}
332+
boost::shared_ptr<EqBsBuilder> builder =
333+
boost::dynamic_pointer_cast<EqBsBuilder>(subBuilders_[CrossAssetModel::AssetType::EQ][i]);
321334
boost::shared_ptr<QuantExt::EqBsParametrization> parametrization = builder->parametrization();
322335
eqOptionBaskets_[i] = builder->optionBasket();
323336
eqParametrizations.push_back(parametrization);
324337
eqNames.push_back(eqName);
325-
subBuilders_[CrossAssetModel::AssetType::EQ][i] = builder;
326338
processInfo[CrossAssetModel::AssetType::EQ].emplace_back(eqName, 1);
327339
}
328340

@@ -332,18 +344,23 @@ void CrossAssetModelBuilder::buildModel() const {
332344
boost::shared_ptr<InflationModelData> imData = config_->infConfigs()[i];
333345
DLOG("Inflation parameterisation (" << i << ") for index " << imData->index());
334346
if (auto dkData = boost::dynamic_pointer_cast<InfDkData>(imData)) {
335-
boost::shared_ptr<InfDkBuilder> builder = boost::make_shared<InfDkBuilder>(
347+
if(!buildersAreInitialized) {
348+
subBuilders_[CrossAssetModel::AssetType::INF][i] = boost::make_shared<InfDkBuilder>(
336349
market_, dkData, configurationInfCalibration_, referenceCalibrationGrid_, dontCalibrate_);
350+
}
351+
boost::shared_ptr<InfDkBuilder> builder =
352+
boost::dynamic_pointer_cast<InfDkBuilder>(subBuilders_[CrossAssetModel::AssetType::INF][i]);
337353
if (dontCalibrate_)
338354
builder->freeze();
339355
infParameterizations.push_back(builder->parametrization());
340-
subBuilders_[CrossAssetModel::AssetType::INF][i] = builder;
341356
processInfo[CrossAssetModel::AssetType::INF].emplace_back(dkData->index(), 1);
342357
} else if (auto jyData = boost::dynamic_pointer_cast<InfJyData>(imData)) {
343-
boost::shared_ptr<InfJyBuilder> builder = boost::make_shared<InfJyBuilder>(
344-
market_, jyData, configurationInfCalibration_, referenceCalibrationGrid_);
358+
if (!buildersAreInitialized) {
359+
subBuilders_[CrossAssetModel::AssetType::INF][i] = boost::make_shared<InfJyBuilder>(
360+
market_, jyData, configurationInfCalibration_, referenceCalibrationGrid_);
361+
}
362+
auto builder = boost::dynamic_pointer_cast<InfJyBuilder>(subBuilders_[CrossAssetModel::AssetType::INF][i]);
345363
infParameterizations.push_back(builder->parameterization());
346-
subBuilders_[CrossAssetModel::AssetType::INF][i] = builder;
347364
processInfo[CrossAssetModel::AssetType::INF].emplace_back(jyData->index(), 2);
348365
} else {
349366
QL_FAIL("CrossAssetModelBuilder expects either DK or JY inflation model data.");
@@ -360,12 +377,13 @@ void CrossAssetModelBuilder::buildModel() const {
360377
LOG("CR LGM Parametrization " << i);
361378
boost::shared_ptr<CrLgmData> cr = config_->crLgmConfigs()[i];
362379
string crName = cr->name();
363-
boost::shared_ptr<CrLgmBuilder> builder =
364-
boost::make_shared<CrLgmBuilder>(market_, cr, configurationCrCalibration_);
380+
if(!buildersAreInitialized) {
381+
subBuilders_[CrossAssetModel::AssetType::CR][i] = boost::make_shared<CrLgmBuilder>(market_, cr, configurationCrCalibration_);
382+
}
383+
auto builder = boost::dynamic_pointer_cast<CrLgmBuilder>(subBuilders_[CrossAssetModel::AssetType::CR][i]);
365384
boost::shared_ptr<QuantExt::CrLgm1fParametrization> parametrization = builder->parametrization();
366385
crLgmParametrizations.push_back(parametrization);
367386
crNames.push_back(crName);
368-
subBuilders_[CrossAssetModel::AssetType::CR][i] = builder;
369387
processInfo[CrossAssetModel::AssetType::CR].emplace_back(crName, 1);
370388
}
371389

@@ -375,12 +393,14 @@ void CrossAssetModelBuilder::buildModel() const {
375393
LOG("CR CIR Parametrization " << i);
376394
boost::shared_ptr<CrCirData> cr = config_->crCirConfigs()[i];
377395
string crName = cr->name();
378-
boost::shared_ptr<CrCirBuilder> builder =
379-
boost::make_shared<CrCirBuilder>(market_, cr, configurationCrCalibration_);
396+
if (!buildersAreInitialized) {
397+
subBuilders_[CrossAssetModel::AssetType::CR][i] =
398+
boost::make_shared<CrCirBuilder>(market_, cr, configurationCrCalibration_);
399+
}
400+
auto builder = boost::dynamic_pointer_cast<CrCirBuilder>(subBuilders_[CrossAssetModel::AssetType::CR][i]);
380401
boost::shared_ptr<QuantExt::CrCirppParametrization> parametrization = builder->parametrization();
381402
crCirParametrizations.push_back(parametrization);
382403
crNames.push_back(crName);
383-
subBuilders_[CrossAssetModel::AssetType::CR][i] = builder;
384404
processInfo[CrossAssetModel::AssetType::CR].emplace_back(crName, 1);
385405
}
386406

@@ -395,14 +415,17 @@ void CrossAssetModelBuilder::buildModel() const {
395415
QuantLib::Currency comCcy = ore::data::parseCurrency(com->currency());
396416
QL_REQUIRE(std::find(currencies.begin(), currencies.end(), comCcy.code()) != currencies.end(),
397417
"Currency (" << comCcy << ") for commodity " << comName << " not covered by CrossAssetModelData");
398-
boost::shared_ptr<CommoditySchwartzModelBuilder> builder = boost::make_shared<CommoditySchwartzModelBuilder>(
399-
market_, com, domesticCcy, configurationComCalibration_, referenceCalibrationGrid_);
418+
if (!buildersAreInitialized) {
419+
subBuilders_[CrossAssetModel::AssetType::COM][i] = boost::make_shared<CommoditySchwartzModelBuilder>(
420+
market_, com, domesticCcy, configurationComCalibration_, referenceCalibrationGrid_);
421+
}
422+
auto builder = boost::dynamic_pointer_cast<CommoditySchwartzModelBuilder>(
423+
subBuilders_[CrossAssetModel::AssetType::COM][i]);
400424
csBuilder.push_back(builder);
401425
boost::shared_ptr<QuantExt::CommoditySchwartzParametrization> parametrization = builder->parametrization();
402426
comOptionBaskets_[i] = builder->optionBasket();
403427
comParametrizations.push_back(parametrization);
404428
comNames.push_back(comName);
405-
subBuilders_[CrossAssetModel::AssetType::COM][i] = builder;
406429
processInfo[CrossAssetModel::AssetType::COM].emplace_back(comName, 1);
407430
}
408431

OREData/ored/model/crossassetmodelbuilder.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,8 @@ class CrossAssetModelBuilder : public QuantExt::ModelBuilder {
129129
mutable std::vector<Real> comOptionCalibrationErrors_;
130130

131131
//! Store model builders for each asset under each asset type.
132-
mutable std::map<QuantExt::CrossAssetModel::AssetType, std::map<QuantLib::Size, boost::shared_ptr<QuantExt::ModelBuilder>>>
132+
mutable std::map<QuantExt::CrossAssetModel::AssetType,
133+
std::map<QuantLib::Size, boost::shared_ptr<QuantExt::ModelBuilder>>>
133134
subBuilders_;
134135

135136
const boost::shared_ptr<ore::data::Market> market_;

0 commit comments

Comments
 (0)