Skip to content

Commit e8710fa

Browse files
pcaspersjenkins
authored andcommitted
Resolve QPR-9859
1 parent a6bbbd7 commit e8710fa

6 files changed

Lines changed: 202 additions & 122 deletions

File tree

OREAnalytics/orea/engine/amcvaluationengine.cpp

Lines changed: 50 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,14 @@
2727
#include <ored/model/crossassetmodelbuilder.hpp>
2828
#include <ored/portfolio/enginefactory.hpp>
2929
#include <ored/portfolio/structuredtradeerror.hpp>
30+
#include <ored/utilities/to_string.hpp>
3031

3132
#include <qle/indexes/fallbackiborindex.hpp>
3233
#include <qle/instruments/payment.hpp>
3334
#include <qle/methods/multipathgeneratorbase.hpp>
3435
#include <qle/methods/multipathvariategenerator.hpp>
35-
#include <qle/pricingengines/mcmultilegbaseengine.hpp>
3636
#include <qle/models/lgmimpliedyieldtermstructure.hpp>
37+
#include <qle/pricingengines/mcmultilegbaseengine.hpp>
3738

3839
#include <ql/instruments/compositeinstrument.hpp>
3940

@@ -222,7 +223,6 @@ void runCoreEngine(const boost::shared_ptr<ore::data::Portfolio>& portfolio,
222223
McEngineStats::instance().calc_timer.start();
223224
McEngineStats::instance().calc_timer.stop();
224225

225-
226226
auto extractAmcCalculator = [&amcCalculators, &tradeId, &tradeLabel, &tradeType, &effectiveMultiplier,
227227
&currencyIndex, &tradeFees, &model,
228228
&outputCube](const std::pair<std::string, boost::shared_ptr<Trade>>& trade,
@@ -235,7 +235,7 @@ void runCoreEngine(const boost::shared_ptr<ore::data::Portfolio>& portfolio,
235235
tradeId.push_back(id->second);
236236
} else {
237237
QL_FAIL("AMCValuationEngine: trade id '" << trade.first
238-
<< "' is not present in output cube - internal error.");
238+
<< "' is not present in output cube - internal error.");
239239
}
240240
tradeLabel.push_back(trade.first);
241241
tradeType.push_back(trade.second->tradeType());
@@ -261,8 +261,7 @@ void runCoreEngine(const boost::shared_ptr<ore::data::Portfolio>& portfolio,
261261
auto inst = trade.second->instrument()->qlInstrument(true);
262262
QL_REQUIRE(inst != nullptr,
263263
"instrument has no ql instrument, this is not supported by the amc valuation engine.");
264-
Real multiplier = trade.second->instrument()->multiplier() *
265-
trade.second->instrument()->multiplier2();
264+
Real multiplier = trade.second->instrument()->multiplier() * trade.second->instrument()->multiplier2();
266265

267266
// handle composite trades
268267
if (auto cInst = boost::dynamic_pointer_cast<CompositeInstrument>(inst)) {
@@ -428,7 +427,8 @@ void runCoreEngine(const boost::shared_ptr<ore::data::Portfolio>& portfolio,
428427
auto res = simulatePathInterface2(amcCalculators[j], pathTimes, paths, allTimes, false, tradeLabel[j],
429428
tradeType[j]);
430429
Real v = outputCube->getT0(tradeId[j], 0);
431-
outputCube->setT0(v + res[0].at(0) * fx(fxBuffer, currencyIndex[j], 0, 0) *
430+
outputCube->setT0(v +
431+
res[0].at(0) * fx(fxBuffer, currencyIndex[j], 0, 0) *
432432
numRatio(model, irStateBuffer, currencyIndex[j], 0, 0.0, 0) *
433433
effectiveMultiplier[j] +
434434
resFee[0][0],
@@ -437,7 +437,8 @@ void runCoreEngine(const boost::shared_ptr<ore::data::Portfolio>& portfolio,
437437
Real t = sgd->getGrid()->timeGrid()[k];
438438
for (Size i = 0; i < outputCube->samples(); ++i) {
439439
Real v = outputCube->get(tradeId[j], k - 1, i, 0);
440-
outputCube->set(v + res[k][i] * fx(fxBuffer, currencyIndex[j], k, i) *
440+
outputCube->set(v +
441+
res[k][i] * fx(fxBuffer, currencyIndex[j], k, i) *
441442
numRatio(model, irStateBuffer, currencyIndex[j], k, t, i) *
442443
effectiveMultiplier[j] +
443444
resFee[k][i],
@@ -454,31 +455,44 @@ void runCoreEngine(const boost::shared_ptr<ore::data::Portfolio>& portfolio,
454455
auto resLag = simulatePathInterface2(amcCalculators[j], pathTimes, paths, closeOutTimes, true,
455456
tradeLabel[j], tradeType[j]);
456457
Real v = outputCube->getT0(tradeId[j], 0);
457-
outputCube->setT0(v + res[0].at(0) * fx(fxBuffer, currencyIndex[j], 0, 0) *
458+
outputCube->setT0(v +
459+
res[0].at(0) * fx(fxBuffer, currencyIndex[j], 0, 0) *
458460
numRatio(model, irStateBuffer, currencyIndex[j], 0, 0.0, 0) *
459461
effectiveMultiplier[j] +
460462
resFee[0][0],
461463
tradeId[j], 0);
462464
int dateIndex = -1;
465+
std::map<QuantLib::Date, std::pair<double, size_t>> dateIndexCache;
463466
for (Size k = 0; k < sgd->getGrid()->dates().size(); ++k) {
464467
Real t = sgd->getGrid()->timeGrid()[k + 1];
465-
Real tm = sgd->getGrid()->timeGrid()[k];
468+
466469
if (sgd->getGrid()->isCloseOutDate()[k]) {
467-
QL_REQUIRE(dateIndex >= 0, "first date in grid must be a valuation date");
470+
Date closeOutDate = sgd->getGrid()->dates()[k];
471+
Date valuationDate = sgd->getGrid()->valuationDateFromCloseOutDate(closeOutDate);
472+
auto dateIndexIt = dateIndexCache.find(valuationDate);
473+
QL_REQUIRE(dateIndexIt != dateIndexCache.end(),
474+
"The valuation date (" << ore::data::to_string(valuationDate)
475+
<< ") needs to before the corresponding close out date ("
476+
<< ore::data::to_string(closeOutDate) << ")");
477+
auto [timeValueDate, timeIndexValueDate] = dateIndexIt->second;
468478
for (Size i = 0; i < outputCube->samples(); ++i) {
469479
Real v = outputCube->get(tradeId[j], dateIndex, i, 1);
470-
outputCube->set(v + resLag[dateIndex + 1][i] * fx(fxBuffer, currencyIndex[j], k + 1, i) *
471-
num(model, irStateBuffer, currencyIndex[j], k + 1, tm, i) *
472-
effectiveMultiplier[j] +
473-
resFee[dateIndex + 1][i],
474-
tradeId[j], dateIndex, i, 1);
480+
outputCube->set(
481+
v +
482+
resLag[dateIndex + 1][i] * fx(fxBuffer, currencyIndex[j], k + 1, i) *
483+
num(model, irStateBuffer, currencyIndex[j], k + 1, timeValueDate, i) *
484+
effectiveMultiplier[j] +
485+
resFee[dateIndex + 1][i],
486+
tradeId[j], timeIndexValueDate, i, 1);
475487
}
476488
}
477489
if (sgd->getGrid()->isValuationDate()[k]) {
478-
++dateIndex;
490+
Date valuationDate = sgd->getGrid()->dates()[k];
491+
dateIndexCache[valuationDate] = std::make_pair(t, ++dateIndex);
479492
for (Size i = 0; i < outputCube->samples(); ++i) {
480-
Real v = outputCube->get(tradeId[j], dateIndex, i, 1);
481-
outputCube->set(v + res[dateIndex + 1][i] * fx(fxBuffer, currencyIndex[j], k + 1, i) *
493+
Real v = outputCube->get(tradeId[j], dateIndex, i, 0);
494+
outputCube->set(v +
495+
res[dateIndex + 1][i] * fx(fxBuffer, currencyIndex[j], k + 1, i) *
482496
numRatio(model, irStateBuffer, currencyIndex[j], k + 1, t, i) *
483497
effectiveMultiplier[j] +
484498
resFee[dateIndex + 1][i],
@@ -492,28 +506,39 @@ void runCoreEngine(const boost::shared_ptr<ore::data::Portfolio>& portfolio,
492506
tradeType[j]);
493507
Real v = outputCube->getT0(tradeId[j], 0);
494508
outputCube->setT0(v + res[0].at(0) * fx(fxBuffer, currencyIndex[j], 0, 0) *
495-
numRatio(model, irStateBuffer, currencyIndex[j], 0, 0.0, 0) *
496-
effectiveMultiplier[j],
509+
numRatio(model, irStateBuffer, currencyIndex[j], 0, 0.0, 0) *
510+
effectiveMultiplier[j],
497511
tradeId[j], 0);
512+
std::map<QuantLib::Date, std::pair<double, size_t>> dateIndexCache;
498513
int dateIndex = -1;
499514
for (Size k = 1; k < res.size(); ++k) {
500515
Real t = sgd->getGrid()->timeGrid()[k];
501516
if (sgd->getGrid()->isCloseOutDate()[k - 1]) {
502-
QL_REQUIRE(dateIndex >= 0, "first date in grid must be a valuation date");
517+
Date closeOutDate = sgd->getGrid()->dates()[k - 1];
518+
Date valuationDate = sgd->getGrid()->valuationDateFromCloseOutDate(closeOutDate);
519+
auto dateIndexIt = dateIndexCache.find(valuationDate);
520+
QL_REQUIRE(dateIndexIt != dateIndexCache.end(),
521+
"The valuation date (" << ore::data::to_string(valuationDate)
522+
<< ") needs to before the corresponding close out date ("
523+
<< ore::data::to_string(closeOutDate) << ")");
524+
auto [_, timeIndexValueDate] = dateIndexIt->second;
503525
for (Size i = 0; i < outputCube->samples(); ++i) {
504526
Real v = outputCube->get(tradeId[j], dateIndex, i, 1);
505-
outputCube->set(v + res[k][i] * fx(fxBuffer, currencyIndex[j], k, i) *
527+
outputCube->set(v +
528+
res[k][i] * fx(fxBuffer, currencyIndex[j], k, i) *
506529
num(model, irStateBuffer, currencyIndex[j], k, t, i) *
507530
effectiveMultiplier[j] +
508531
resFee[k][i],
509-
tradeId[j], dateIndex, i, 1);
532+
tradeId[j], timeIndexValueDate, i, 1);
510533
}
511534
}
512535
if (sgd->getGrid()->isValuationDate()[k - 1]) {
513-
++dateIndex;
536+
Date valuationDate = sgd->getGrid()->dates()[k - 1];
537+
dateIndexCache[valuationDate] = std::make_pair(t, ++dateIndex);
514538
for (Size i = 0; i < outputCube->samples(); ++i) {
515539
Real v = outputCube->get(tradeId[j], dateIndex, i, 0);
516-
outputCube->set(v + res[k][i] * fx(fxBuffer, currencyIndex[j], k, i) *
540+
outputCube->set(v +
541+
res[k][i] * fx(fxBuffer, currencyIndex[j], k, i) *
517542
numRatio(model, irStateBuffer, currencyIndex[j], k, t, i) *
518543
effectiveMultiplier[j] +
519544
resFee[k][i],

0 commit comments

Comments
 (0)