Skip to content

Commit 903d83f

Browse files
pcaspersjenkins
authored andcommitted
QPR-11986 fix composite trade handling in amc val engine
1 parent 301db64 commit 903d83f

1 file changed

Lines changed: 30 additions & 19 deletions

File tree

OREAnalytics/orea/engine/amcvaluationengine.cpp

Lines changed: 30 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -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-
&currencyIndex, &tradeFees, &model, &outputCube](
212-
const std::pair<std::string, boost::shared_ptr<Trade>>& trade,
213-
boost::shared_ptr<AmcCalculator> amcCalc, Real multiplier) {
211+
&currencyIndex, &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

Comments
 (0)