@@ -208,69 +208,80 @@ void runCoreEngine(const boost::shared_ptr<ore::data::Portfolio>& portfolio,
208208 Size progressCounter = 0 ;
209209
210210 auto extractAmcCalculator = [&amcCalculators, &tradeId, &tradeLabel, &tradeType, &effectiveMultiplier,
211- ¤cyIndex, &tradeFees, &model, &outputCube](
212- const std::pair<std::string, boost::shared_ptr<Trade>>& trade,
213- boost::shared_ptr<AmcCalculator> amcCalc, Real multiplier) {
211+ ¤cyIndex, &tradeFees, &model,
212+ &outputCube]( const std::pair<std::string, boost::shared_ptr<Trade>>& trade,
213+ boost::shared_ptr<AmcCalculator> amcCalc, Real multiplier, bool addFees ) {
214214 LOG (" AMCCalculator extracted for \" " << trade.first << " \" " );
215215 amcCalculators.push_back (amcCalc);
216216 effectiveMultiplier.push_back (multiplier);
217217 currencyIndex.push_back (model->ccyIndex (amcCalc->npvCurrency ()));
218-
219218 if (auto id = outputCube->idsAndIndexes ().find (trade.first ); id != outputCube->idsAndIndexes ().end ()) {
220219 tradeId.push_back (id->second );
221220 } else {
222221 QL_FAIL (" AMCValuationEngine: trade id '" << trade.first
223222 << " ' is not present in output cube - internal error." );
224223 }
225-
226224 tradeLabel.push_back (trade.first );
227225 tradeType.push_back (trade.second ->tradeType ());
228226 tradeFees.push_back ({});
229- for (Size i = 0 ; i < trade.second ->instrument ()->additionalInstruments ().size (); ++i) {
230- if (auto p = boost::dynamic_pointer_cast<QuantExt::Payment>(
231- trade.second ->instrument ()->additionalInstruments ()[i])) {
232- tradeFees.back ().push_back (std::make_tuple (model->ccyIndex (p->currency ()), p->cashFlow ()->amount (),
233- p->cashFlow ()->date ()));
234- } else {
235- ALOG (StructuredTradeErrorMessage (trade.second , " Additional instrument is ignored in AMC simulation" ,
236- " only QuantExt::Payment is handled as additional instrument." ));
227+ if (addFees) {
228+ for (Size i = 0 ; i < trade.second ->instrument ()->additionalInstruments ().size (); ++i) {
229+ if (auto p = boost::dynamic_pointer_cast<QuantExt::Payment>(
230+ trade.second ->instrument ()->additionalInstruments ()[i])) {
231+ tradeFees.back ().push_back (std::make_tuple (model->ccyIndex (p->currency ()), p->cashFlow ()->amount (),
232+ p->cashFlow ()->date ()));
233+ } else {
234+ ALOG (StructuredTradeErrorMessage (trade.second , " Additional instrument is ignored in AMC simulation" ,
235+ " only QuantExt::Payment is handled as additional instrument." ));
236+ }
237237 }
238238 }
239239 };
240+
240241 for (auto const & trade : portfolio->trades ()) {
241242 boost::shared_ptr<AmcCalculator> amcCalc;
242243 try {
243244 auto inst = trade.second ->instrument ()->qlInstrument (true );
244245 Real multiplier = trade.second ->instrument ()->multiplier () *
245246 trade.second ->instrument ()->multiplier2 ();
247+
248+ // handle composite trades
246249 if (auto cInst = boost::dynamic_pointer_cast<CompositeInstrument>(inst)) {
247250 auto addResults = cInst->additionalResults ();
248251 std::vector<Real> multipliers;
249- while (true ) {
252+ while (true ) {
250253 std::stringstream ss;
251254 ss << multipliers.size () + 1 << " _multiplier" ;
252255 if (addResults.find (ss.str ()) == addResults.end ())
253256 break ;
254257 multipliers.push_back (inst->result <Real>(ss.str ()));
255258 }
259+ std::vector<boost::shared_ptr<AmcCalculator>> amcCalcs;
256260 for (Size cmpIdx = 0 ; cmpIdx < multipliers.size (); ++cmpIdx) {
257261 std::stringstream ss;
258262 ss << cmpIdx + 1 << " _amcCalculator" ;
259263 if (addResults.find (ss.str ()) != addResults.end ()) {
260- amcCalc = inst->result <boost::shared_ptr<AmcCalculator>>(ss.str ());
261- extractAmcCalculator (trade, amcCalc, multiplier * multipliers[cmpIdx]);
264+ amcCalcs.push_back (inst->result <boost::shared_ptr<AmcCalculator>>(ss.str ()));
262265 }
263266 }
267+ QL_REQUIRE (amcCalcs.size () == multipliers.size (),
268+ " Did not find amc calculators for all components of composite trade." );
269+ for (Size cmpIdx = 0 ; cmpIdx < multipliers.size (); ++cmpIdx) {
270+ extractAmcCalculator (trade, amcCalc, multiplier * multipliers[cmpIdx], cmpIdx == 0 );
271+ }
264272 continue ;
265273 }
266- amcCalc = inst->result <boost::shared_ptr<AmcCalculator>>(
267- " amcCalculator" );
268- extractAmcCalculator (trade, amcCalc, multiplier);
274+
275+ // handle non-composite trades
276+ amcCalc = inst->result <boost::shared_ptr<AmcCalculator>>(" amcCalculator" );
277+ extractAmcCalculator (trade, amcCalc, multiplier, true );
278+
269279 } catch (const std::exception& e) {
270280 ALOG (StructuredTradeErrorMessage (trade.second , " Error building trade for AMC simulation" , e.what ()));
271281 }
272282 progressIndicator->updateProgress (++progressCounter, portfolio->size () + 1 );
273283 }
284+
274285 timer.stop ();
275286 calibrationTime += timer.elapsed ().wall * 1e-9 ;
276287 LOG (" Extracted " << amcCalculators.size () << " AMCCalculators for " << portfolio->size () << " source trades" );
0 commit comments