Skip to content

Commit 105767c

Browse files
pcaspersjenkins
authored andcommitted
QPR-12097 remove unnecessary error about non-unique initial price currency, collect missing fx terms before throwing an error
1 parent 9bcf7e0 commit 105767c

2 files changed

Lines changed: 41 additions & 24 deletions

File tree

OREData/ored/portfolio/trs.cpp

Lines changed: 39 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -257,8 +257,8 @@ XMLNode* TRS::toXML(XMLDocument& doc) {
257257

258258
boost::shared_ptr<QuantExt::FxIndex>
259259
TRS::getFxIndex(const boost::shared_ptr<Market> market, const std::string& configuration, const std::string& domestic,
260-
const std::string& foreign,
261-
std::map<std::string, boost::shared_ptr<QuantExt::FxIndex>>& fxIndices) const {
260+
const std::string& foreign, std::map<std::string, boost::shared_ptr<QuantExt::FxIndex>>& fxIndices,
261+
std::set<std::string>& missingFxIndexPairs) const {
262262
if (domestic == foreign)
263263
return nullptr;
264264
std::set<std::string> requiredCcys = {domestic, foreign};
@@ -275,7 +275,15 @@ TRS::getFxIndex(const boost::shared_ptr<Market> market, const std::string& confi
275275
return fx;
276276
}
277277
}
278-
QL_FAIL("TRS:getFxIndex(): no fx terms for " << domestic << " vs " << foreign);
278+
279+
// build a fx index, so that the processing can continue, but add to the error messages,
280+
// which - if not empty - will fail the trade build eventually
281+
282+
std::string f("FX-GENERIC-" + domestic + "-" + foreign);
283+
auto fx = buildFxIndex(f, domestic, foreign, market, configuration, false);
284+
fxIndices[f] = fx;
285+
missingFxIndexPairs.insert(domestic + foreign);
286+
return fx;
279287
}
280288

281289
void TRS::build(const boost::shared_ptr<EngineFactory>& engineFactory) {
@@ -381,13 +389,16 @@ void TRS::build(const boost::shared_ptr<EngineFactory>& engineFactory) {
381389

382390
// get fx indices for conversion return and add cf ccy to funding ccy
383391

392+
std::set<std::string> missingFxIndexPairs;
393+
384394
auto fxIndexReturn = getFxIndex(engineFactory->market(), engineFactory->configuration(MarketContext::pricing),
385-
returnData_.currency(), fundingCurrency, initialFxIndices);
395+
returnData_.currency(), fundingCurrency, initialFxIndices, missingFxIndexPairs);
386396
auto fxIndexAdditionalCashflows =
387397
additionalCashflowData_.legData().currency().empty()
388398
? fxIndexReturn
389399
: getFxIndex(engineFactory->market(), engineFactory->configuration(MarketContext::pricing),
390-
additionalCashflowData_.legData().currency(), fundingCurrency, fxIndicesDummy);
400+
additionalCashflowData_.legData().currency(), fundingCurrency, fxIndicesDummy,
401+
missingFxIndexPairs);
391402

392403
Real initialPrice = returnData_.initialPrice();
393404

@@ -411,13 +422,13 @@ void TRS::build(const boost::shared_ptr<EngineFactory>& engineFactory) {
411422
std::vector<Leg> returnLegs;
412423
auto builder = TrsUnderlyingBuilderFactory::instance().getBuilder(
413424
underlyingDerivativeId_[i].empty() ? underlying_[i]->tradeType() : "Derivative");
414-
builder->build(id(), underlying_[i], valuationDates, paymentDates, fundingCurrency,
415-
engineFactory, underlyingIndex[i], underlyingMultiplier[i],
416-
localIndexNamesAndQuantities, localFxIndices,
417-
underlying_.size() == 1 ? initialPrice : dummyInitialPrice,
418-
assetCurrency[i], localCreditRiskCurrency, creditQualifierMapping_, localMaturity,
425+
builder->build(id(), underlying_[i], valuationDates, paymentDates, fundingCurrency, engineFactory,
426+
underlyingIndex[i], underlyingMultiplier[i], localIndexNamesAndQuantities, localFxIndices,
427+
underlying_.size() == 1 ? initialPrice : dummyInitialPrice, assetCurrency[i],
428+
localCreditRiskCurrency, creditQualifierMapping_, localMaturity,
419429
std::bind(&TRS::getFxIndex, this, std::placeholders::_1, std::placeholders::_2,
420-
std::placeholders::_3, std::placeholders::_4, std::placeholders::_5),
430+
std::placeholders::_3, std::placeholders::_4, std::placeholders::_5,
431+
std::ref(missingFxIndexPairs)),
421432
underlyingDerivativeId_[i], requiredFixings_, returnLegs);
422433

423434
addTRSRequiredFixings(requiredFixings_, returnLegs, fxIndexReturn);
@@ -442,7 +453,7 @@ void TRS::build(const boost::shared_ptr<EngineFactory>& engineFactory) {
442453
<< fundingCurrency << ", return ccy is " << returnData_.currency());
443454

444455
fxIndexAsset[i] = getFxIndex(engineFactory->market(), engineFactory->configuration(MarketContext::pricing),
445-
assetCurrency[i], fundingCurrency, localFxIndices);
456+
assetCurrency[i], fundingCurrency, localFxIndices, missingFxIndexPairs);
446457
DLOG("underlying #" << (i + 1) << " index (" << underlyingIndex[i]->name() << ") built.");
447458
DLOG("underlying #" << (i + 1) << " multiplier is " << underlyingMultiplier[i]);
448459

@@ -455,18 +466,24 @@ void TRS::build(const boost::shared_ptr<EngineFactory>& engineFactory) {
455466
fxIndices.insert(localFxIndices.begin(), localFxIndices.end());
456467
}
457468

469+
// check that we have all fx terms that we needed to build the fx indices
470+
471+
QL_REQUIRE(missingFxIndexPairs.empty(), "TRS::build(): missing FXTerms for the following pairs: "
472+
<< boost::algorithm::join(missingFxIndexPairs, ", "));
473+
458474
// set initial price currency
459475

460-
std::string initialPriceCurrency;
461-
if (returnData_.initialPrice() != Null<Real>() && !returnData_.initialPriceCurrency().empty())
462-
initialPriceCurrency = returnData_.initialPriceCurrency();
463-
else {
464-
initialPriceCurrency = assetCurrency.front();
465-
for (Size i = 1; i < assetCurrency.size(); ++i) {
466-
QL_REQUIRE(assetCurrency[i] == initialPriceCurrency,
467-
"TRS::build(): can not determine unique initial price currency, since it is not given in the "
468-
"trade data and the underlyings have different asset currencies (e.g. '"
469-
<< assetCurrency[i] << ", " << initialPriceCurrency << ")");
476+
QL_REQUIRE(!assetCurrency.empty(), "TRS::build(): no underlying given.");
477+
478+
std::string initialPriceCurrency =
479+
returnData_.initialPriceCurrency().empty() ? assetCurrency.front() : returnData_.initialPriceCurrency();
480+
481+
if (initialPrice != Null<Real>() && returnData_.initialPriceCurrency().empty()) {
482+
for (auto const& ccy : assetCurrency) {
483+
QL_REQUIRE(ccy == initialPriceCurrency, "TRS::build(): can not determine unique initial price currency "
484+
"from asset currencies for initial price ("
485+
<< returnData_.initialPrice()
486+
<< "), please add the initial price currency to the trade xml");
470487
}
471488
}
472489

OREData/ored/portfolio/trs.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,8 +159,8 @@ class TRS : public Trade {
159159
protected:
160160
boost::shared_ptr<QuantExt::FxIndex>
161161
getFxIndex(const boost::shared_ptr<Market> market, const std::string& configuration, const std::string& domestic,
162-
const std::string& foreign,
163-
std::map<std::string, boost::shared_ptr<QuantExt::FxIndex>>& fxIndices) const;
162+
const std::string& foreign, std::map<std::string, boost::shared_ptr<QuantExt::FxIndex>>& fxIndices,
163+
std::set<std::string>& missingFxIndexPairs) const;
164164

165165
mutable std::vector<boost::shared_ptr<Trade>> underlying_;
166166
// empty if underlying is not from a Derivative subnode of UnderlyingData

0 commit comments

Comments
 (0)