Skip to content

Commit 009282b

Browse files
pcaspersjenkins
authored andcommitted
QPR-12028 PoC XVA Sensis AAD
1 parent 44cb59e commit 009282b

51 files changed

Lines changed: 1492 additions & 739 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

OREData/ored/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,8 @@ scripting/models/blackscholescg.cpp
313313
scripting/models/blackscholescgbase.cpp
314314
scripting/models/fdblackscholesbase.cpp
315315
scripting/models/gaussiancam.cpp
316+
scripting/models/gaussiancamcg.cpp
317+
scripting/models/lgmcg.cpp
316318
scripting/models/localvol.cpp
317319
scripting/models/modelcgimpl.cpp
318320
scripting/models/modelimpl.cpp
@@ -684,13 +686,16 @@ scripting/engines/scriptedinstrumentpricingengine.hpp
684686
scripting/engines/scriptedinstrumentpricingenginecg.hpp
685687
scripting/grammar.hpp
686688
scripting/models/amcmodel.hpp
689+
scripting/models/amcmodelcg.hpp
687690
scripting/models/blackscholes.hpp
688691
scripting/models/blackscholesbase.hpp
689692
scripting/models/blackscholescg.hpp
690693
scripting/models/blackscholescgbase.hpp
691694
scripting/models/dummymodel.hpp
692695
scripting/models/fdblackscholesbase.hpp
693696
scripting/models/gaussiancam.hpp
697+
scripting/models/gaussiancamcg.hpp
698+
scripting/models/lgmcg.hpp
694699
scripting/models/localvol.hpp
695700
scripting/models/model.hpp
696701
scripting/models/modelcg.hpp

OREData/ored/ored.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,13 +334,16 @@
334334
#include <ored/scripting/engines/scriptedinstrumentpricingenginecg.hpp>
335335
#include <ored/scripting/grammar.hpp>
336336
#include <ored/scripting/models/amcmodel.hpp>
337+
#include <ored/scripting/models/amcmodelcg.hpp>
337338
#include <ored/scripting/models/blackscholes.hpp>
338339
#include <ored/scripting/models/blackscholesbase.hpp>
339340
#include <ored/scripting/models/blackscholescg.hpp>
340341
#include <ored/scripting/models/blackscholescgbase.hpp>
341342
#include <ored/scripting/models/dummymodel.hpp>
342343
#include <ored/scripting/models/fdblackscholesbase.hpp>
343344
#include <ored/scripting/models/gaussiancam.hpp>
345+
#include <ored/scripting/models/gaussiancamcg.hpp>
346+
#include <ored/scripting/models/lgmcg.hpp>
344347
#include <ored/scripting/models/localvol.hpp>
345348
#include <ored/scripting/models/model.hpp>
346349
#include <ored/scripting/models/modelcg.hpp>

OREData/ored/portfolio/builders/scriptedtrade.cpp

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include <ored/scripting/models/blackscholescg.hpp>
2222
#include <ored/scripting/models/fdblackscholesbase.hpp>
2323
#include <ored/scripting/models/gaussiancam.hpp>
24+
#include <ored/scripting/models/gaussiancamcg.hpp>
2425
#include <ored/scripting/models/localvol.hpp>
2526
#include <ored/scripting/engines/scriptedinstrumentpricingengine.hpp>
2627
#include <ored/scripting/engines/scriptedinstrumentpricingenginecg.hpp>
@@ -1278,7 +1279,7 @@ void ScriptedTradeEngineBuilder::buildGaussianCam(const std::string& id, const I
12781279
std::vector<boost::shared_ptr<EqBsData>> eqConfigs;
12791280
std::vector<boost::shared_ptr<CommoditySchwartzData>> comConfigs;
12801281
// TODO: populate comConfigs
1281-
1282+
12821283
// calibration expiries and terms for IR, INF, FX, EQ parametrisations (this will only work for a fixed reference
12831284
// date, due to the way the cam builder and nested builders work, see ticket #940)
12841285
Date referenceDate = modelCurves_.front()->referenceDate();
@@ -1473,19 +1474,30 @@ void ScriptedTradeEngineBuilder::buildGaussianCam(const std::string& id, const I
14731474

14741475
std::string configurationInCcy = configuration(MarketContext::irCalibration);
14751476
std::string configurationXois = configuration(MarketContext::pricing);
1477+
auto discretization = useCg_ ? CrossAssetModel::Discretization::Euler : CrossAssetModel::Discretization::Exact;
14761478
auto camBuilder = boost::make_shared<CrossAssetModelBuilder>(
14771479
market_,
14781480
boost::make_shared<CrossAssetModelData>(irConfigs, fxConfigs, eqConfigs, infConfigs, crLgmConfigs, crCirConfigs,
1479-
comConfigs, 0, camCorrelations, bootstrapTolerance_),
1481+
comConfigs, 0, camCorrelations, bootstrapTolerance_, "LGM",
1482+
discretization),
14801483
configurationInCcy, configurationXois, configurationXois, configurationInCcy, configurationInCcy,
14811484
configurationXois, !calibrate_ || zeroVolatility_, continueOnCalibrationError_, referenceCalibrationGrid_,
14821485
SalvagingAlgorithm::Spectral, id);
14831486

1484-
// TODO hardcode timeStepsPerYear to 0 and exact discretisation (we might want Euler for AD...)
1485-
model_ = boost::make_shared<GaussianCam>(camBuilder->model(), modelSize_, modelCcys_, modelCurves_, modelFxSpots_,
1486-
modelIrIndices_, modelInfIndices_, modelIndices_, modelIndicesCurrencies_,
1487-
simulationDates_, mcParams_, 0, iborFallbackConfig, std::vector<Size>(),
1488-
conditionalExpectationModelStates);
1487+
// effective time steps per year: zero for exact evolution, otherwise the pricing engine parameter
1488+
if (useCg_) {
1489+
modelCG_ = boost::make_shared<GaussianCamCG>(
1490+
camBuilder->model(), modelSize_, modelCcys_, modelCurves_, modelFxSpots_, modelIrIndices_, modelInfIndices_,
1491+
modelIndices_, modelIndicesCurrencies_, simulationDates_,
1492+
camBuilder->model()->discretization() == CrossAssetModel::Discretization::Exact ? 0 : timeStepsPerYear_,
1493+
iborFallbackConfig, std::vector<Size>(), conditionalExpectationModelStates);
1494+
} else {
1495+
model_ = boost::make_shared<GaussianCam>(
1496+
camBuilder->model(), modelSize_, modelCcys_, modelCurves_, modelFxSpots_, modelIrIndices_, modelInfIndices_,
1497+
modelIndices_, modelIndicesCurrencies_, simulationDates_, mcParams_,
1498+
camBuilder->model()->discretization() == CrossAssetModel::Discretization::Exact ? 0 : timeStepsPerYear_,
1499+
iborFallbackConfig, std::vector<Size>(), conditionalExpectationModelStates);
1500+
}
14891501

14901502
modelBuilders_.insert(std::make_pair(id, camBuilder));
14911503
}
@@ -1526,11 +1538,20 @@ void ScriptedTradeEngineBuilder::buildGaussianCamAMC(
15261538
Handle<CrossAssetModel> projectedModel(
15271539
getProjectedCrossAssetModel(amcCam_, selectedComponents, projectedStateProcessIndices));
15281540

1529-
// TODO hardcode timeStepsPerYear to 1 and exact discretisation (we might want Euler for AD...)
1530-
model_ = boost::make_shared<GaussianCam>(projectedModel, modelSize_, modelCcys_, modelCurves_, modelFxSpots_,
1531-
modelIrIndices_, modelInfIndices_, modelIndices_, modelIndicesCurrencies_,
1532-
simulationDates_, mcParams_, 1, iborFallbackConfig,
1533-
projectedStateProcessIndices, conditionalExpectationModelStates);
1541+
// effective time steps per year: zero for exact evolution, otherwise the pricing engine parameter
1542+
if (useCg_) {
1543+
modelCG_ = boost::make_shared<GaussianCamCG>(
1544+
projectedModel, modelSize_, modelCcys_, modelCurves_, modelFxSpots_, modelIrIndices_, modelInfIndices_,
1545+
modelIndices_, modelIndicesCurrencies_, simulationDates_,
1546+
projectedModel->discretization() == CrossAssetModel::Discretization::Exact ? 0 : timeStepsPerYear_,
1547+
iborFallbackConfig, projectedStateProcessIndices, conditionalExpectationModelStates);
1548+
} else {
1549+
model_ = boost::make_shared<GaussianCam>(
1550+
projectedModel, modelSize_, modelCcys_, modelCurves_, modelFxSpots_, modelIrIndices_, modelInfIndices_,
1551+
modelIndices_, modelIndicesCurrencies_, simulationDates_, mcParams_,
1552+
projectedModel->discretization() == CrossAssetModel::Discretization::Exact ? 0 : timeStepsPerYear_,
1553+
iborFallbackConfig, projectedStateProcessIndices, conditionalExpectationModelStates);
1554+
}
15341555

15351556
DLOG("built GuassianCam model as projection of xva evolution model");
15361557
for (auto const& p : projectedStateProcessIndices)

OREData/ored/scripting/engines/scriptedinstrumentpricingenginecg.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,8 @@ void ScriptedInstrumentPricingEngineCG::calculate() const {
7373
QL_REQUIRE(!useExternalComputeFramework_ || !useCachedSensis_,
7474
"ScriptedInstrumentPricingEngineCG: when using external compute framework, usage of cached sensis is "
7575
"not supported yet");
76-
QL_REQUIRE(model_->trainingPaths() == Null<Size>(), "ScriptedInstrumentPricingEngineCG: separate training phase "
77-
"not supported, trainingSamples can not be specified.");
76+
QL_REQUIRE(model_->trainingSamples() == Null<Size>(), "ScriptedInstrumentPricingEngineCG: separate training phase "
77+
"not supported, trainingSamples can not be specified.");
7878

7979
lastCalculationWasValid_ = false;
8080

@@ -131,8 +131,8 @@ void ScriptedInstrumentPricingEngineCG::calculate() const {
131131
opsExternal_ = getExternalRandomVariableOps();
132132
gradsExternal_ = getExternalRandomVariableGradients();
133133
} else {
134-
ops_ = getRandomVariableOps(model_->size());
135-
grads_ = getRandomVariableGradients(model_->size());
134+
ops_ = getRandomVariableOps(model_->size(), mcParams_.regressionOrder, mcParams_.polynomType);
135+
grads_ = getRandomVariableGradients(model_->size(), mcParams_.regressionOrder, mcParams_.polynomType);
136136
}
137137

138138
// build graph
@@ -272,7 +272,8 @@ void ScriptedInstrumentPricingEngineCG::calculate() const {
272272
// extract npv result and set it
273273

274274
if (useExternalComputeFramework_) {
275-
ComputeEnvironment::instance().context().finalizeCalculation(externalOutputPtr_);
275+
ComputeEnvironment::instance().context().finalizeCalculation(externalOutputPtr_,
276+
{mcParams_.regressionOrder});
276277
baseNpv_ = results_.value = externalAverage(externalOutput_[0]);
277278
} else {
278279
baseNpv_ = results_.value = model_->extractT0Result(values[baseNpvNode]);

OREData/ored/scripting/models/amcmodel.hpp

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,23 +23,11 @@
2323

2424
#pragma once
2525

26-
#include <ored/scripting/value.hpp>
27-
28-
#include <qle/models/modelbuilder.hpp>
29-
30-
#include <qle/processes/crossassetstateprocess.hpp>
31-
32-
#include <ql/patterns/lazyobject.hpp>
33-
#include <ql/settings.hpp>
34-
#include <ql/time/daycounters/actualactual.hpp>
35-
36-
#include <boost/enable_shared_from_this.hpp>
26+
#include <qle/math/randomvariable.hpp>
3727

3828
namespace ore {
3929
namespace data {
4030

41-
using QuantLib::Date;
42-
4331
class AmcModel {
4432
public:
4533
virtual ~AmcModel() {}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
Copyright (C) 2023 Quaternion Risk Management Ltd
3+
All rights reserved.
4+
*/
5+
6+
/*! \file models/amcmodelcg.hpp
7+
\brief additional interface for amc enabled models
8+
\ingroup utilities
9+
*/
10+
11+
#pragma once
12+
13+
#include <qle/math/randomvariable.hpp>
14+
15+
namespace ore {
16+
namespace data {
17+
18+
class AmcModelCG {
19+
public:
20+
virtual ~AmcModelCG() {}
21+
virtual void injectPaths(const std::vector<QuantLib::Real>* pathTimes,
22+
const std::vector<std::vector<std::size_t>>* variates,
23+
const std::vector<bool>* isRelevantTime, const bool stickyCloseOutRun) = 0;
24+
};
25+
26+
} // namespace data
27+
} // namespace ore

OREData/ored/scripting/models/blackscholesbase.cpp

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -264,11 +264,10 @@ RandomVariable BlackScholesBase::npv(const RandomVariable& amount, const Date& o
264264
return expectation(amount);
265265
}
266266

267-
// generate basis if not yet done
267+
// get basis fns
268268

269-
if (basisFns_.find(state.size()) == basisFns_.end())
270-
basisFns_[state.size()] = multiPathBasisSystem(state.size(), mcParams_.regressionOrder, mcParams_.polynomType,
271-
std::min(size(), trainingSamples()));
269+
auto basisFns = multiPathBasisSystem(state.size(), mcParams_.regressionOrder, mcParams_.polynomType,
270+
std::min(trainingSamples(), Model::size()));
272271

273272
// if a memSlot is given and coefficients are stored, we use them
274273

@@ -288,8 +287,7 @@ RandomVariable BlackScholesBase::npv(const RandomVariable& amount, const Date& o
288287
// otherwise compute coefficients and store them if a memSlot is given
289288

290289
if (coeff.size() == 0) {
291-
coeff = regressionCoefficients(amount, state, basisFns_.at(state.size()), filter,
292-
RandomVariableRegressionMethod::QR);
290+
coeff = regressionCoefficients(amount, state, basisFns, filter, RandomVariableRegressionMethod::QR);
293291
DLOG("BlackScholesBase::npv(" << ore::data::to_string(obsdate) << "): regression coefficients are " << coeff
294292
<< " (got model state size " << nModelStates << " and " << nAddReg
295293
<< " additional regressors)");
@@ -299,7 +297,7 @@ RandomVariable BlackScholesBase::npv(const RandomVariable& amount, const Date& o
299297

300298
// compute conditional expectation and return the result
301299

302-
return conditionalExpectation(state, basisFns_.at(state.size()), coeff);
300+
return conditionalExpectation(state, basisFns, coeff);
303301
}
304302

305303
void BlackScholesBase::releaseMemory() {

OREData/ored/scripting/models/blackscholesbase.hpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,6 @@ class BlackScholesBase : public ModelImpl {
103103
const std::vector<Date> simulationDates_;
104104

105105
// these all except underlyingPaths_ are initialised when the interface functions above are called
106-
mutable std::map<Size, std::vector<std::function<RandomVariable(const std::vector<const RandomVariable*>&)>>>
107-
basisFns_;
108106
mutable Date referenceDate_; // the model reference date
109107
mutable std::set<Date> effectiveSimulationDates_; // the dates effectively simulated (including today)
110108
mutable TimeGrid timeGrid_; // the (possibly refined) time grid for the simulation

OREData/ored/scripting/models/blackscholescg.cpp

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ void BlackScholesCG::performCalculations() const {
247247
if (indices_.empty() || !underlyingPaths_.empty())
248248
return;
249249

250-
// exit if only one simulation date in the future
250+
// exit if there are no future simulation dates (i.e. only the reference date)
251251

252252
if (effectiveSimulationDates_.size() == 1)
253253
return;
@@ -302,11 +302,10 @@ void BlackScholesCG::performCalculations() const {
302302
for (Size j = 0; j < indices_.size(); ++j) {
303303
for (Size k = 0; k < indices_.size(); ++k) {
304304
std::string id = "__sqrtCov_" + std::to_string(j) + "_" + std::to_string(k) + "_" + std::to_string(i);
305-
addModelParameter(id, [sqrtCovCalc, i, j, k] { return sqrtCovCalc->sqrtCov(i, j, k); });
306-
sqrtCov[i][j][k] = cg_var(*g_, id);
305+
sqrtCov[i][j][k] =
306+
addModelParameter(id, [sqrtCovCalc, i, j, k] { return sqrtCovCalc->sqrtCov(i, j, k); });
307307
id = "__cov_" + std::to_string(j) + "_" + std::to_string(k) + "_" + std::to_string(i);
308-
addModelParameter(id, [sqrtCovCalc, i, j, k] { return sqrtCovCalc->cov(i, j, k); });
309-
cov[i][j][k] = cg_var(*g_, id);
308+
cov[i][j][k] = addModelParameter(id, [sqrtCovCalc, i, j, k] { return sqrtCovCalc->cov(i, j, k); });
310309
}
311310
}
312311
}
@@ -333,9 +332,9 @@ void BlackScholesCG::performCalculations() const {
333332
for (Size j = 0; j < indices_.size(); ++j) {
334333
auto p = model_->processes().at(j);
335334
std::string id = std::to_string(j) + "_" + ore::data::to_string(d);
336-
addModelParameter("__div_" + id, [p, d]() { return p->dividendYield()->discount(d); });
337-
addModelParameter("__rfr_" + id, [p, d]() { return p->riskFreeRate()->discount(d); });
338-
std::size_t tmp = cg_div(*g_, cg_var(*g_, "__rfr_" + id), cg_var(*g_, "__div_" + id));
335+
std::size_t div= addModelParameter("__div_" + id, [p, d]() { return p->dividendYield()->discount(d); });
336+
std::size_t rfr = addModelParameter("__rfr_" + id, [p, d]() { return p->riskFreeRate()->discount(d); });
337+
std::size_t tmp = cg_div(*g_, rfr, div);
339338
drift[i][j] = cg_subtract(*g_, cg_negative(*g_, cg_log(*g_, cg_div(*g_, tmp, discountRatio[j]))),
340339
cg_mult(*g_, cg_const(*g_, 0.5), cov[i][j][j]));
341340
discountRatio[j] = tmp;
@@ -353,7 +352,8 @@ void BlackScholesCG::performCalculations() const {
353352

354353
for (Size j = 0; j < indices_.size(); ++j) {
355354
for (Size i = 0; i < effectiveSimulationDates_.size() - 1; ++i) {
356-
randomVariates_[j][i] = cg_var(*g_, "__rv_" + std::to_string(j) + "_" + std::to_string(i), true);
355+
randomVariates_[j][i] = cg_var(*g_, "__rv_" + std::to_string(j) + "_" + std::to_string(i),
356+
ComputationGraph::VarDoesntExist::Create);
357357
}
358358
}
359359

@@ -363,8 +363,7 @@ void BlackScholesCG::performCalculations() const {
363363
for (Size j = 0; j < indices_.size(); ++j) {
364364
std::string id = "__x0_" + std::to_string(j);
365365
auto p = model_->processes().at(j);
366-
addModelParameter(id, [p] { return std::log(p->x0()); });
367-
logState[j] = cg_var(*g_, id);
366+
logState[j] = addModelParameter(id, [p] { return std::log(p->x0()); });
368367
underlyingPaths_[*effectiveSimulationDates_.begin()][j] = cg_exp(*g_, logState[j]);
369368
}
370369

0 commit comments

Comments
 (0)