@@ -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
164161void 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
0 commit comments