Skip to content

Commit d9bc39c

Browse files
pcaspersjenkins
authored andcommitted
QPR-12398 enable commodity components in scripted trade GCam model
1 parent 027a175 commit d9bc39c

8 files changed

Lines changed: 48 additions & 25 deletions

File tree

OREData/ored/model/commodityschwartzmodelbuilder.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -148,13 +148,13 @@ void CommoditySchwartzModelBuilder::performCalculations() const {
148148
return;
149149
}
150150

151+
// use identical start values for each calibration to ensure identical results for identical baskets
152+
model_->setParams(params_);
153+
151154
LOG("CommoditySchwartzModel for name " << data_->name() << " before calibration:"
152155
<< " sigma=" << parametrization_->sigmaParameter()
153156
<< " kappa=" << parametrization_->kappaParameter());
154157

155-
// use identical start values for each calibration to ensure identical results for identical baskets
156-
model_->setParams(params_);
157-
158158
model_->calibrate(optionBasket_, *data_->optimizationMethod(), data_->endCriteria(), data_->constraint(), weights, fix);
159159

160160
LOG("CommoditySchwartzModel for name " << data_->name() << " after calibration:"

OREData/ored/model/crossassetmodelbuilder.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -485,6 +485,8 @@ void CrossAssetModelBuilder::buildModel() const {
485485
}
486486
auto builder = QuantLib::ext::dynamic_pointer_cast<CommoditySchwartzModelBuilder>(
487487
subBuilders_[CrossAssetModel::AssetType::COM][i]);
488+
if (dontCalibrate_)
489+
builder->freeze();
488490
csBuilder.push_back(builder);
489491
QuantLib::ext::shared_ptr<QuantExt::CommoditySchwartzParametrization> parametrization = builder->parametrization();
490492
comOptionBaskets_[i] = builder->optionBasket();

OREData/ored/portfolio/builders/scriptedtrade.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1301,8 +1301,8 @@ void ScriptedTradeEngineBuilder::buildGaussianCam(const std::string& id, const I
13011301

13021302
map<CorrelationKey, Handle<Quote>> camCorrelations;
13031303
for (auto const& c : tmpCorrelations) {
1304-
CorrelationFactor f_1 = parseCorrelationFactor(c.first.first);
1305-
CorrelationFactor f_2 = parseCorrelationFactor(c.first.second);
1304+
CorrelationFactor f_1 = parseCorrelationFactor(c.first.first, '#');
1305+
CorrelationFactor f_2 = parseCorrelationFactor(c.first.second, '#');
13061306
// update index for JY from 0 to 1 (i.e. to the factor driving the inf index ("fx") process)
13071307
// in all other cases the index 0 is fine, since there is only one driving factor always
13081308
if (infModelType_ == "JY") {
@@ -1321,11 +1321,11 @@ void ScriptedTradeEngineBuilder::buildGaussianCam(const std::string& id, const I
13211321
std::set<CorrelationFactor> allCorrRiskFactors;
13221322

13231323
for (auto const& m : modelIndices_)
1324-
allCorrRiskFactors.insert(parseCorrelationFactor(convertIndexToCamCorrelationEntry(m).first));
1324+
allCorrRiskFactors.insert(parseCorrelationFactor(convertIndexToCamCorrelationEntry(m).first, '#'));
13251325
for (auto const& m : modelIrIndices_)
1326-
allCorrRiskFactors.insert(parseCorrelationFactor(convertIndexToCamCorrelationEntry(m.first).first));
1326+
allCorrRiskFactors.insert(parseCorrelationFactor(convertIndexToCamCorrelationEntry(m.first).first, '#'));
13271327
for (auto const& m : modelInfIndices_)
1328-
allCorrRiskFactors.insert(parseCorrelationFactor(convertIndexToCamCorrelationEntry(m.first).first));
1328+
allCorrRiskFactors.insert(parseCorrelationFactor(convertIndexToCamCorrelationEntry(m.first).first, '#'));
13291329
for (auto const& ccy : modelCcys_)
13301330
allCorrRiskFactors.insert({CrossAssetModel::AssetType::IR, ccy, 0});
13311331

OREData/ored/scripting/models/gaussiancam.cpp

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,8 @@ void GaussianCam::performCalculations() const {
197197
}
198198

199199
indexPositionInProcess_.clear();
200+
eqIndexInCam_.clear();
201+
comIndexInCam_.clear();
200202
for (Size i = 0; i < indices_.size(); ++i) {
201203
if (indices_[i].isFx()) {
202204
// FX
@@ -209,8 +211,14 @@ void GaussianCam::performCalculations() const {
209211
Size eqIdx = cam_->eqIndex(indices_[i].eq()->name());
210212
indexPositionInProcess_.push_back(cam_->pIdx(CrossAssetModel::AssetType::EQ, eqIdx));
211213
eqIndexInCam_.push_back(eqIdx);
214+
} else if(indices_[i].isComm()) {
215+
// COM
216+
Size comIdx = cam_->comIndex(indices_[i].commName());
217+
indexPositionInProcess_.push_back(cam_->pIdx(CrossAssetModel::AssetType::COM, comIdx));
218+
comIndexInCam_.push_back(comIdx);
212219
} else {
213-
QL_FAIL("index '" << indices_[i].name() << "' expected to be FX or EQ");
220+
QL_FAIL("GuassianCam::performCalculations(): index '" << indices_[i].name()
221+
<< "' expected to be FX, EQ, COMM");
214222
}
215223
}
216224

@@ -233,7 +241,7 @@ void GaussianCam::populatePathValues(const Size nSamples, std::map<Date, std::ve
233241

234242
// set reference date values, if there are no future simulation dates, we are done
235243

236-
// FX and EQ indcies
244+
// FX, EQ, COMM indcies
237245
for (Size k = 0; k < indices_.size(); ++k) {
238246
paths[referenceDate_][k].setAll(process->initialValues().at(indexPositionInProcess_[k]));
239247
}
@@ -351,7 +359,7 @@ void GaussianCam::populatePathValues(const Size nSamples, std::map<Date, std::ve
351359
}
352360
}
353361

354-
// FX and EQ indcies
362+
// FX, EQ, COMM indices
355363
std::vector<std::vector<RandomVariable*>> rvs(
356364
indices_.size(), std::vector<RandomVariable*>(effectiveSimulationDates_.size() - 1));
357365
auto date = effectiveSimulationDates_.begin();
@@ -417,8 +425,17 @@ void GaussianCam::populatePathValues(const Size nSamples, std::map<Date, std::ve
417425

418426
RandomVariable GaussianCam::getIndexValue(const Size indexNo, const Date& d, const Date& fwd) const {
419427
auto res = underlyingPaths_.at(d).at(indexNo);
420-
// compute forwarding factor
421-
if (fwd != Null<Date>()) {
428+
if (comIndexInCam_[indexNo] != Null<Size>()) {
429+
// handle com (TODO: performace optimization via vectorized version of com model)
430+
RandomVariable tmp(res.size());
431+
for (Size i = 0; i < tmp.size(); ++i) {
432+
tmp.set(i, cam_->comModel(comIndexInCam_[indexNo])
433+
->forwardPrice(timeFromReference(d), timeFromReference(fwd != Null<Date>() ? fwd : d),
434+
Array(1, std::log(res[i]))));
435+
}
436+
return tmp;
437+
} else if (fwd != Null<Date>()) {
438+
// handle fx, eq -> incorporate forwarding factor if applicable
422439
auto ccy = std::find(currencies_.begin(), currencies_.end(), indexCurrencies_[indexNo]);
423440
QL_REQUIRE(ccy != currencies_.end(), "GaussianCam::getIndexValue(): can not get currency for index #"
424441
<< indexNo << "(" << indices_.at(indexNo) << ")");
@@ -430,9 +447,11 @@ RandomVariable GaussianCam::getIndexValue(const Size indexNo, const Date& d, con
430447
res *= RandomVariable(size(), div->discount(fwd) / div->discount(d)) /
431448
getDiscount(std::distance(currencies_.begin(), ccy), d, fwd,
432449
cam_->eqbs(eqIndexInCam_[indexNo])->equityIrCurveToday());
450+
} else if (comIndexInCam_[indexNo] != Null<Size>()) {
451+
433452
} else {
434-
QL_FAIL("GaussianGam::getIndexValue(): did not recognise index #" << indexNo << "(" << indices_.at(indexNo)
435-
<< ")");
453+
QL_FAIL("GaussianGam::getIndexValue(): did not recognise index #" << indexNo << "("
454+
<< indices_.at(indexNo));
436455
}
437456
}
438457
return res;

OREData/ored/scripting/models/gaussiancam.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ class GaussianCam : public ModelImpl, public AmcModel {
130130
mutable std::vector<Size> infIndexPositionInCam_; // maps inf index no to inf idx in cam
131131
mutable std::vector<Size> currencyPositionInCam_; // maps currency no to position in cam parametrizations
132132
mutable std::vector<Size> eqIndexInCam_; // maps index no to eq position in cam (or null, if not an eq index)
133+
mutable std::vector<Size> comIndexInCam_; // maps index no to com position in cam (or null, if not a com index)
133134
mutable bool conditionalExpectationUseIr_; // derived from input conditionalExpectationModelState
134135
mutable bool conditionalExpectationUseInf_; // derived from input conditionalExpectationModelState
135136
mutable bool conditionalExpectationUseAsset_; // derived from input conditionalExpectationModelState

OREData/ored/scripting/utilities.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -138,16 +138,16 @@ ASTNodePtr parseScript(const std::string& code) {
138138
std::pair<std::string, Period> convertIndexToCamCorrelationEntry(const std::string& i) {
139139
IndexInfo info(i);
140140
if (info.isIr()) {
141-
return std::make_pair("IR:" + info.ir()->currency().code(), info.ir()->tenor());
141+
return std::make_pair("IR#" + info.ir()->currency().code(), info.ir()->tenor());
142142
} else if (info.isInf()) {
143-
return std::make_pair("INF:" + info.infName(), 0 * Days);
143+
return std::make_pair("INF#" + info.infName(), 0 * Days);
144144
} else if (info.isFx()) {
145-
return std::make_pair("FX:" + info.fx()->sourceCurrency().code() + info.fx()->targetCurrency().code(),
145+
return std::make_pair("FX#" + info.fx()->sourceCurrency().code() + info.fx()->targetCurrency().code(),
146146
0 * Days);
147147
} else if (info.isEq()) {
148-
return std::make_pair("EQ:" + info.eq()->name(), 0 * Days);
148+
return std::make_pair("EQ#" + info.eq()->name(), 0 * Days);
149149
} else if (info.isComm()) {
150-
return std::make_pair("COMM:" + info.commName(), 0 * Days);
150+
return std::make_pair("COM#" + info.commName(), 0 * Days);
151151
} else {
152152
QL_FAIL("convertIndextoCamCorrelationEntry(): index '" << i << "' not recognised");
153153
}

OREData/ored/utilities/correlationmatrix.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,14 +55,15 @@ ostream& operator<<(ostream& out, const CorrelationFactor& f) {
5555
return out << f.type << ":" << f.name << ":" << f.index;
5656
}
5757

58-
CorrelationFactor parseCorrelationFactor(const string& name) {
58+
CorrelationFactor parseCorrelationFactor(const string& name, const char separator) {
5959

60+
std::string sep(1, separator);
6061
vector<string> tokens;
61-
boost::split(tokens, name, boost::is_any_of(":"));
62+
boost::split(tokens, name, boost::is_any_of(sep));
6263

6364
QL_REQUIRE(tokens.size() == 2 || tokens.size() == 3,
64-
"parseCorrelationFactor(" << name
65-
<< "): expected 2 or 3 tokens separated by ':', e.g. 'IR:USD' or 'INF:UKRPI:0'");
65+
"parseCorrelationFactor(" << name << "): expected 2 or 3 tokens separated by separator ('" << sep
66+
<< "'), e.g. 'IR" << sep << "USD' or 'INF" << sep << "UKRPI" << sep << "0'");
6667

6768
return {parseCamAssetType(tokens[0]), tokens[1],
6869
static_cast<Size>(tokens.size() == 3 ? parseInteger(tokens[3]) : 0)};

OREData/ored/utilities/correlationmatrix.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ std::ostream& operator<<(std::ostream& out, const CorrelationFactor& f);
5454
\c type, \c name and \c index set to \c IR, \c EUR and \c 0 respectively. Note that the name is of the form
5555
\c type:name and the index is always set to 0 initially. The actual index is set separately.
5656
*/
57-
CorrelationFactor parseCorrelationFactor(const std::string& name);
57+
CorrelationFactor parseCorrelationFactor(const std::string& name, const char separator = ':');
5858

5959
/*! The key for storing the correlation data is the pair of factors.
6060
*/

0 commit comments

Comments
 (0)