Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
commodityschwartzmodelbuilder.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2022 Quaternion Risk Management Ltd
3 All rights reserved.
4
5 This file is part of ORE, a free-software/open-source library
6 for transparent pricing and risk analysis - http://opensourcerisk.org
7
8 ORE is free software: you can redistribute it and/or modify it
9 under the terms of the Modified BSD License. You should have received a
10 copy of the license along with this program.
11 The license is also available online at <http://opensourcerisk.org>
12
13 This program is distributed on the basis that it will form a useful
14 contribution to risk analytics and model standardisation, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the license for more details.
17*/
18
19#include <ql/math/optimization/levenbergmarquardt.hpp>
20#include <ql/quotes/simplequote.hpp>
21
25
32
33using namespace QuantLib;
34using namespace QuantExt;
35using namespace std;
36
37namespace ore {
38namespace data {
39
41 const QuantLib::ext::shared_ptr<ore::data::Market>& market, const QuantLib::ext::shared_ptr<CommoditySchwartzData>& data,
42 const QuantLib::Currency& baseCcy, const std::string& configuration,
43 const std::string& referenceCalibrationGrid)
44 : market_(market), configuration_(configuration), data_(data), referenceCalibrationGrid_(referenceCalibrationGrid),
45 baseCcy_(baseCcy) {
46
47 optionActive_ = std::vector<bool>(data_->optionExpiries().size(), false);
48 marketObserver_ = QuantLib::ext::make_shared<MarketObserver>();
49 QuantLib::Currency ccy = ore::data::parseCurrency(data->currency());
50 string name = data->name();
51
52 LOG("Start building CommoditySchwartz model for " << name);
53
54 // get market data
55 std::string fxCcyPair = ccy.code() + baseCcy_.code();
56 fxSpot_ = market_->fxRate(fxCcyPair, configuration_);
57 curve_ = market_->commodityPriceCurve(name, configuration_);
58 vol_ = market_->commodityVolatility(name, configuration_);
59
60 // register with market observables except vols
61 marketObserver_->registerWith(fxSpot_);
62 marketObserver_->registerWith(curve_);
63
64 // register the builder with the vol and the market observer
65 registerWith(vol_);
66 registerWith(marketObserver_);
67
68 // notify observers of all market data changes, not only when not calculated
69 alwaysForwardNotifications();
70
71 // build option basket and derive parametrization from it
72 if (data->calibrateSigma() || data->calibrateKappa())
74
75 parametrization_ = QuantLib::ext::make_shared<QuantExt::CommoditySchwartzParametrization>(ccy, name, curve_, fxSpot_,
76 data->sigmaValue(), data->kappaValue(),
77 data->driftFreeState());
78 model_ = QuantLib::ext::make_shared<QuantExt::CommoditySchwartzModel>(parametrization_);
79 params_ = model_->params();
80}
81
82QuantLib::ext::shared_ptr<QuantExt::CommoditySchwartzModel> CommoditySchwartzModelBuilder::model() const {
83 calculate();
84 return model_;
85}
86
88 calculate();
89 return error_;
90}
91
92QuantLib::ext::shared_ptr<QuantExt::CommoditySchwartzParametrization> CommoditySchwartzModelBuilder::parametrization() const {
93 calculate();
94 return parametrization_;
95}
96std::vector<QuantLib::ext::shared_ptr<BlackCalibrationHelper>> CommoditySchwartzModelBuilder::optionBasket() const {
97 calculate();
98 return optionBasket_;
99}
100
102 return (data_->calibrateSigma() || data_->calibrateKappa()) &&
103 (volSurfaceChanged(false) || marketObserver_->hasUpdated(false) || forceCalibration_);
104}
105
107 if (requiresRecalibration()) {
108 DLOG("COM model requires recalibration");
109
110 // reset market observer updated flag
111 marketObserver_->hasUpdated(true);
112 // build option basket
114 // update vol cache
115 volSurfaceChanged(true);
116
117 // attach pricing engine to helpers
118 QuantLib::ext::shared_ptr<QuantExt::CommoditySchwartzFutureOptionEngine> engine =
119 QuantLib::ext::make_shared<QuantExt::CommoditySchwartzFutureOptionEngine>(model_);
120 for (Size j = 0; j < optionBasket_.size(); j++)
121 optionBasket_[j]->setPricingEngine(engine);
122
123 QL_REQUIRE(data_->calibrationType() != CalibrationType::Bootstrap, "Bootstrap COM calibration not supported yet");
124
125 if (data_->calibrationType() == CalibrationType::None ||
126 (data_->calibrateSigma() == false && data_->calibrateKappa() == false)) {
127 LOG("COM calibration is deactivated in the CommoditySchwartzModelData for name " << data_->name());
128 return;
129 }
130
131 // check which parameters are kept fixed
132 std::vector<bool> fix(model_->parametrization()->numberOfParameters(), true);
133 std::vector<Real> weights;
134 Size freeParams = 0;
135 if (data_->calibrateSigma()) {
136 fix[0] = false;
137 freeParams++;
138 LOG("CommoditySchwartzModel: calibrate sigma for name " << data_->name());
139 }
140 if (data_->calibrateKappa()) {
141 fix[1] = false;
142 freeParams++;
143 LOG("CommoditySchwartzModel: calibrate kappa for name " << data_->name());
144 }
145 if (freeParams == 0) {
146 WLOG("CommoditySchwartzModel: skip calibration for name " << data_->name() << ", no free parameters");
147 error_ = 0.0;
148 return;
149 }
150
151 // use identical start values for each calibration to ensure identical results for identical baskets
152 model_->setParams(params_);
153
154 LOG("CommoditySchwartzModel for name " << data_->name() << " before calibration:"
155 << " sigma=" << parametrization_->sigmaParameter()
156 << " kappa=" << parametrization_->kappaParameter());
157
158 model_->calibrate(optionBasket_, *data_->optimizationMethod(), data_->endCriteria(), data_->constraint(), weights, fix);
159
160 LOG("CommoditySchwartzModel for name " << data_->name() << " after calibration:"
161 << " sigma=" << parametrization_->sigmaParameter()
162 << " kappa=" << parametrization_->kappaParameter());
163
165 LOG("CommoditySchwartzModel calibration rmse error " << error_ << " for name " << data_->name());
166 try {
168 DLOG(d);
169 } catch (const std::exception& e) {
170 WLOG("An error occurred: " << e.what());
171 }
172 }
173}
174
176 ore::data::Strike strike = ore::data::parseStrike(data_->optionStrikes()[j]);
177 Real strikeValue;
178 // TODO: Extend strike type coverage
180 strikeValue = Null<Real>();
181 else if (strike.type == ore::data::Strike::Type::Absolute)
182 strikeValue = strike.value;
183 else
184 QL_FAIL("strike type ATMF or Absolute expected");
185 return strikeValue;
186}
187
189 Date today = Settings::instance().evaluationDate();
190 std::string expiryString = data_->optionExpiries()[j];
191 bool expiryDateBased;
192 Period expiryPb;
193 Date expiryDb;
194 parseDateOrPeriod(expiryString, expiryDb, expiryPb, expiryDateBased);
195 Date expiryDate = expiryDateBased ? expiryDb : today + expiryPb;
196 return expiryDate;
197}
198
199bool CommoditySchwartzModelBuilder::volSurfaceChanged(const bool updateCache) const {
200 bool hasUpdated = false;
201
202 // if cache doesn't exist resize vector
203 if (volCache_.size() != optionBasket_.size())
204 volCache_ = vector<Real>(optionBasket_.size(), Null<Real>());
205
206 Size optionCounter = 0;
207 for (Size j = 0; j < data_->optionExpiries().size(); j++) {
208 if (!optionActive_[j])
209 continue;
210 Real vol = vol_->blackVol(optionExpiry(j), optionStrike(j));
211 if (!close_enough(volCache_[optionCounter], vol)) {
212 if (updateCache)
213 volCache_[optionCounter] = vol;
214 hasUpdated = true;
215 }
216 optionCounter++;
217 }
218 return hasUpdated;
219}
220
222
223 QL_REQUIRE(data_->optionExpiries().size() == data_->optionStrikes().size(), "Commodity option vector size mismatch");
224
225 optionActive_ = std::vector<bool>(data_->optionExpiries().size(), false);
226
227 DLOG("build reference date grid '" << referenceCalibrationGrid_ << "'");
228 Date lastRefCalDate = Date::minDate();
229 std::vector<Date> referenceCalibrationDates;
230 if (!referenceCalibrationGrid_.empty())
231 referenceCalibrationDates = DateGrid(referenceCalibrationGrid_).dates();
232
233 std::vector<Time> expiryTimes;
234 optionBasket_.clear();
235 for (Size j = 0; j < data_->optionExpiries().size(); j++) {
236 // may wish to calibrate against specific futures expiry dates...
237 Date expiryDate = optionExpiry(j);
238
239 // check if we want to keep the helper when a reference calibration grid is given
240 auto refCalDate =
241 std::lower_bound(referenceCalibrationDates.begin(), referenceCalibrationDates.end(), expiryDate);
242 if (refCalDate == referenceCalibrationDates.end() || *refCalDate > lastRefCalDate) {
243 optionActive_[j] = true;
244 Real strikeValue = optionStrike(j);
245 Handle<Quote> volQuote(QuantLib::ext::make_shared<SimpleQuote>(vol_->blackVol(expiryDate, strikeValue)));
246 QuantLib::ext::shared_ptr<QuantExt::FutureOptionHelper> helper = QuantLib::ext::make_shared<QuantExt::FutureOptionHelper>(
247 expiryDate, strikeValue, curve_, volQuote, data_->calibrationErrorType());
248 optionBasket_.push_back(helper);
249 helper->performCalculations();
250 expiryTimes.push_back(curve_->timeFromReference(helper->option()->exercise()->date(0)));
251 DLOG("Added FutureOptionHelper " << data_->name() << " " << QuantLib::io::iso_date(expiryDate) << " "
252 << volQuote->value());
253 if (refCalDate != referenceCalibrationDates.end())
254 lastRefCalDate = *refCalDate;
255 } else {
256 optionActive_[j] = false;
257 }
258 }
259
260 std::sort(expiryTimes.begin(), expiryTimes.end());
261 auto itExpiryTime = unique(expiryTimes.begin(), expiryTimes.end());
262 expiryTimes.resize(distance(expiryTimes.begin(), itExpiryTime));
263
264 optionExpiries_ = Array(expiryTimes.size());
265 for (Size j = 0; j < expiryTimes.size(); j++)
266 optionExpiries_[j] = expiryTimes[j];
267}
268
270 forceCalibration_ = true;
272 forceCalibration_ = false;
273}
274
275} // namespace data
276} // namespace ore
virtual void forceRecalculate()
bool volSurfaceChanged(const bool updateCache) const
QuantLib::ext::shared_ptr< QuantExt::MarketObserver > marketObserver_
QuantLib::ext::shared_ptr< QuantExt::CommoditySchwartzModel > model_
std::vector< QuantLib::ext::shared_ptr< BlackCalibrationHelper > > optionBasket() const
std::vector< QuantLib::ext::shared_ptr< BlackCalibrationHelper > > optionBasket_
CommoditySchwartzModelBuilder(const QuantLib::ext::shared_ptr< ore::data::Market > &market, const QuantLib::ext::shared_ptr< CommoditySchwartzData > &data, const QuantLib::Currency &baseCcy, const std::string &configuration=Market::defaultConfiguration, const std::string &referenceCalibrationGrid="")
Constructor.
const QuantLib::ext::shared_ptr< ore::data::Market > market_
const QuantLib::ext::shared_ptr< CommoditySchwartzData > data_
Handle< QuantExt::PriceTermStructure > curve_
QuantLib::ext::shared_ptr< QuantExt::CommoditySchwartzParametrization > parametrization() const
QuantLib::ext::shared_ptr< QuantExt::CommoditySchwartzParametrization > parametrization_
QuantLib::ext::shared_ptr< QuantExt::CommoditySchwartzModel > model() const
Simulation Date Grid.
Definition: dategrid.hpp:38
const std::vector< QuantLib::Date > & dates() const
Definition: dategrid.hpp:81
Builder for a Lognormal COM model component.
The date grid class.
Strike parseStrike(const std::string &s)
Convert text to Strike.
Definition: strike.cpp:30
boost::variant< QuantLib::Date, QuantLib::Period > parseDateOrPeriod(const string &s)
Convert text to QuantLib::Period or QuantLib::Date.
Definition: parsers.cpp:493
Currency parseCurrency(const string &s)
Convert text to QuantLib::Currency.
Definition: parsers.cpp:290
Classes and functions for log message handling.
@ data
Definition: log.hpp:77
#define LOG(text)
Logging Macro (Level = Notice)
Definition: log.hpp:552
#define DLOG(text)
Logging Macro (Level = Debug)
Definition: log.hpp:554
#define WLOG(text)
Logging Macro (Level = Warning)
Definition: log.hpp:550
Shared utilities for model building and calibration.
Filter close_enough(const RandomVariable &x, const RandomVariable &y)
Real getCalibrationError(const std::vector< QuantLib::ext::shared_ptr< Helper > > &basket)
Definition: utilities.hpp:47
Size size(const ValueType &v)
Definition: value.cpp:145
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
Serializable Credit Default Swap.
Definition: namespaces.docs:23
Map text representations to QuantLib/QuantExt types.
QuantLib::BootstrapHelper< QuantLib::OptionletVolatilityStructure > helper
QuantLib::Real value
Definition: strike.hpp:47
strike description