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,39 +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 ;
463- std::map<QuantLib::Date, size_t > dateIndexCache;
464- std::map<QuantLib::Date, double > dateTimeCache;
465+ std::map<QuantLib::Date, std::pair<double , size_t >> dateIndexCache;
465466 for (Size k = 0 ; k < sgd->getGrid ()->dates ().size (); ++k) {
466467 Real t = sgd->getGrid ()->timeGrid ()[k + 1 ];
467-
468+
468469 if (sgd->getGrid ()->isCloseOutDate ()[k]) {
469470 Date closeOutDate = sgd->getGrid ()->dates ()[k];
470471 Date valuationDate = sgd->getGrid ()->valuationDateFromCloseOutDate (closeOutDate);
471472 auto dateIndexIt = dateIndexCache.find (valuationDate);
472- QL_REQUIRE (dateIndexIt != dateIndexCache.end (), " first date in grid must be a valuation date" );
473- Real tm = dateTimeCache[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 ;
474478 for (Size i = 0 ; i < outputCube->samples (); ++i) {
475479 Real v = outputCube->get (tradeId[j], dateIndex, i, 1 );
476- outputCube->set (v + resLag[dateIndex + 1 ][i] * fx (fxBuffer, currencyIndex[j], k + 1 , i) *
477- num (model, irStateBuffer, currencyIndex[j], k + 1 , tm, i) *
478- effectiveMultiplier[j] +
479- resFee[dateIndex + 1 ][i],
480- tradeId[j], dateIndexIt->second , 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 );
481487 }
482488 }
483489 if (sgd->getGrid ()->isValuationDate ()[k]) {
484490 Date valuationDate = sgd->getGrid ()->dates ()[k];
485- dateIndexCache[valuationDate] = ++dateIndex;
486- dateTimeCache[valuationDate] = t;
491+ dateIndexCache[valuationDate] = std::make_pair (t, ++dateIndex);
487492 for (Size i = 0 ; i < outputCube->samples (); ++i) {
488493 Real v = outputCube->get (tradeId[j], dateIndex, i, 0 );
489- outputCube->set (v + res[dateIndex + 1 ][i] * fx (fxBuffer, currencyIndex[j], k + 1 , i) *
494+ outputCube->set (v +
495+ res[dateIndex + 1 ][i] * fx (fxBuffer, currencyIndex[j], k + 1 , i) *
490496 numRatio (model, irStateBuffer, currencyIndex[j], k + 1 , t, i) *
491497 effectiveMultiplier[j] +
492498 resFee[dateIndex + 1 ][i],
@@ -500,33 +506,39 @@ void runCoreEngine(const boost::shared_ptr<ore::data::Portfolio>& portfolio,
500506 tradeType[j]);
501507 Real v = outputCube->getT0 (tradeId[j], 0 );
502508 outputCube->setT0 (v + res[0 ].at (0 ) * fx (fxBuffer, currencyIndex[j], 0 , 0 ) *
503- numRatio (model, irStateBuffer, currencyIndex[j], 0 , 0.0 , 0 ) *
504- effectiveMultiplier[j],
509+ numRatio (model, irStateBuffer, currencyIndex[j], 0 , 0.0 , 0 ) *
510+ effectiveMultiplier[j],
505511 tradeId[j], 0 );
506- std::map<QuantLib::Date, size_t > dateIndexCache;
512+ std::map<QuantLib::Date, std::pair< double , size_t > > dateIndexCache;
507513 int dateIndex = -1 ;
508514 for (Size k = 1 ; k < res.size (); ++k) {
509515 Real t = sgd->getGrid ()->timeGrid ()[k];
510516 if (sgd->getGrid ()->isCloseOutDate ()[k - 1 ]) {
511- Date closeOutDate = sgd->getGrid ()->dates ()[k- 1 ];
517+ Date closeOutDate = sgd->getGrid ()->dates ()[k - 1 ];
512518 Date valuationDate = sgd->getGrid ()->valuationDateFromCloseOutDate (closeOutDate);
513519 auto dateIndexIt = dateIndexCache.find (valuationDate);
514- QL_REQUIRE (dateIndexIt != dateIndexCache.end (), " first date in grid must be a valuation date" );
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 ;
515525 for (Size i = 0 ; i < outputCube->samples (); ++i) {
516526 Real v = outputCube->get (tradeId[j], dateIndex, i, 1 );
517- 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) *
518529 num (model, irStateBuffer, currencyIndex[j], k, t, i) *
519530 effectiveMultiplier[j] +
520531 resFee[k][i],
521- tradeId[j], dateIndexIt-> second , i, 1 );
532+ tradeId[j], timeIndexValueDate , i, 1 );
522533 }
523534 }
524535 if (sgd->getGrid ()->isValuationDate ()[k - 1 ]) {
525- Date valuationDate = sgd->getGrid ()->dates ()[k- 1 ];
536+ Date valuationDate = sgd->getGrid ()->dates ()[k - 1 ];
526537 dateIndexCache[valuationDate] = ++dateIndex;
527538 for (Size i = 0 ; i < outputCube->samples (); ++i) {
528539 Real v = outputCube->get (tradeId[j], dateIndex, i, 0 );
529- 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) *
530542 numRatio (model, irStateBuffer, currencyIndex[j], k, t, i) *
531543 effectiveMultiplier[j] +
532544 resFee[k][i],
0 commit comments