2121
2222#include < qle/models/commodityschwartzparametrization.hpp>
2323#include < qle/models/futureoptionhelper.hpp>
24+ #include < qle/pricingengines/commodityschwartzfutureoptionengine.hpp>
2425
2526#include < ored/model/commodityschwartzmodelbuilder.hpp>
27+ #include < ored/model/utilities.hpp>
2628#include < ored/utilities/dategrid.hpp>
2729#include < ored/utilities/log.hpp>
2830#include < ored/utilities/parsers.hpp>
@@ -40,7 +42,10 @@ CommoditySchwartzModelBuilder::CommoditySchwartzModelBuilder(
4042 const QuantLib::Currency& baseCcy, const std::string& configuration,
4143 const std::string& referenceCalibrationGrid)
4244 : market_(market), configuration_(configuration), data_(data), referenceCalibrationGrid_(referenceCalibrationGrid),
43- baseCcy_ (baseCcy) {
45+ baseCcy_ (baseCcy),
46+ optimizationMethod_(boost::shared_ptr<OptimizationMethod>(new LevenbergMarquardt(1E-8 , 1E-8 , 1E-8 ))),
47+ endCriteria_(EndCriteria(1000 , 500 , 1E-8 , 1E-8 , 1E-8 )),
48+ calibrationErrorType_(BlackCalibrationHelper::RelativePriceError) {
4449
4550 optionActive_ = std::vector<bool >(data_->optionExpiries ().size (), false );
4651 marketObserver_ = boost::make_shared<MarketObserver>();
@@ -73,6 +78,12 @@ CommoditySchwartzModelBuilder::CommoditySchwartzModelBuilder(
7378 parametrization_ = boost::make_shared<QuantExt::CommoditySchwartzParametrization>(ccy, name, curve_, fxSpot_,
7479 data->sigmaValue (), data->kappaValue (),
7580 data->driftFreeState ());
81+ model_ = boost::make_shared<QuantExt::CommoditySchwartzModel>(parametrization_);
82+ }
83+
84+ boost::shared_ptr<QuantExt::CommoditySchwartzModel> CommoditySchwartzModelBuilder::model () const {
85+ calculate ();
86+ return model_;
7687}
7788
7889Real CommoditySchwartzModelBuilder::error () const {
@@ -96,12 +107,68 @@ bool CommoditySchwartzModelBuilder::requiresRecalibration() const {
96107
97108void CommoditySchwartzModelBuilder::performCalculations () const {
98109 if (requiresRecalibration ()) {
110+ DLOG (" COM model requires recalibration" );
111+
99112 // reset market observer updated flag
100113 marketObserver_->hasUpdated (true );
101114 // build option basket
102115 buildOptionBasket ();
103116 // update vol cache
104117 volSurfaceChanged (true );
118+
119+ // attach pricing engine to helpers
120+ boost::shared_ptr<QuantExt::CommoditySchwartzFutureOptionEngine> engine =
121+ boost::make_shared<QuantExt::CommoditySchwartzFutureOptionEngine>(model_);
122+ for (Size j = 0 ; j < optionBasket_.size (); j++)
123+ optionBasket_[j]->setPricingEngine (engine);
124+
125+ QL_REQUIRE (data_->calibrationType () != CalibrationType::Bootstrap, " Bootstrap COM calibration not supported yet" );
126+
127+ if (data_->calibrationType () == CalibrationType::None ||
128+ (data_->calibrateSigma () == false && data_->calibrateKappa () == false )) {
129+ LOG (" COM calibration is deactivated in the CommoditySchwartzModelData for name " << data_->name ());
130+ return ;
131+ }
132+
133+ // check which parameters are kept fixed
134+ std::vector<bool > fix (model_->parametrization ()->numberOfParameters (), true );
135+ Constraint constraint;
136+ std::vector<Real> weights;
137+ Size freeParams = 0 ;
138+ if (data_->calibrateSigma ()) {
139+ fix[0 ] = false ;
140+ freeParams++;
141+ LOG (" CommoditySchwartzModel: calibrate sigma for name " << data_->name ());
142+ }
143+ if (data_->calibrateKappa ()) {
144+ fix[1 ] = false ;
145+ freeParams++;
146+ LOG (" CommoditySchwartzModel: calibrate kappa for name " << data_->name ());
147+ }
148+ if (freeParams == 0 ) {
149+ WLOG (" CommoditySchwartzModel: skip calibration for name " << data_->name () << " , no free parameters" );
150+ error_ = 0.0 ;
151+ return ;
152+ }
153+
154+ LOG (" CommoditySchwartzModel for name " << data_->name () << " before calibration:"
155+ << " sigma=" << parametrization_->sigmaParameter ()
156+ << " kappa=" << parametrization_->kappaParameter ());
157+
158+ model_->calibrate (optionBasket_, *optimizationMethod_, endCriteria_, constraint, weights, fix);
159+
160+ LOG (" CommoditySchwartzModel for name " << data_->name () << " after calibration:"
161+ << " sigma=" << parametrization_->sigmaParameter ()
162+ << " kappa=" << parametrization_->kappaParameter ());
163+
164+ error_ = getCalibrationError (optionBasket_);
165+ LOG (" CommoditySchwartzModel calibration rmse error " << error_ << " for name " << data_->name ());
166+ try {
167+ auto d = getCalibrationDetails (optionBasket_, parametrization_);
168+ LOG (d);
169+ } catch (const std::exception& e) {
170+ WLOG (" An error occurred: " << e.what ());
171+ }
105172 }
106173}
107174
@@ -152,7 +219,6 @@ bool CommoditySchwartzModelBuilder::volSurfaceChanged(const bool updateCache) co
152219}
153220
154221void CommoditySchwartzModelBuilder::buildOptionBasket () const {
155- QL_FAIL (" CommoditySchwartzModelBuilder::buildOptionBasket() not implemented yet" );
156222
157223 QL_REQUIRE (data_->optionExpiries ().size () == data_->optionStrikes ().size (), " Commodity option vector size mismatch" );
158224
@@ -178,7 +244,7 @@ void CommoditySchwartzModelBuilder::buildOptionBasket() const {
178244 Real strikeValue = optionStrike (j);
179245 Handle<Quote> volQuote (boost::make_shared<SimpleQuote>(vol_->blackVol (expiryDate, strikeValue)));
180246 boost::shared_ptr<QuantExt::FutureOptionHelper> helper = boost::make_shared<QuantExt::FutureOptionHelper>(
181- expiryDate, strikeValue, curve_, volQuote);
247+ expiryDate, strikeValue, curve_, volQuote, calibrationErrorType_ );
182248 optionBasket_.push_back (helper);
183249 helper->performCalculations ();
184250 expiryTimes.push_back (curve_->timeFromReference (helper->option ()->exercise ()->date (0 )));
0 commit comments