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 ¤cyIndex, &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