Skip to content

Commit 5b7b938

Browse files
Merge remote-tracking branch 'origin/master' into github_modules
2 parents c88784c + 4898537 commit 5b7b938

1 file changed

Lines changed: 61 additions & 18 deletions

File tree

OREData/ored/portfolio/crosscurrencyswap.cpp

Lines changed: 61 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717
*/
1818

1919
#include <ored/portfolio/crosscurrencyswap.hpp>
20+
#include <ored/portfolio/structuredtradewarning.hpp>
21+
#include <ored/utilities/indexparser.hpp>
22+
2023

2124
namespace ore {
2225
namespace data {
@@ -27,6 +30,37 @@ CrossCurrencySwap::CrossCurrencySwap(const Envelope& env, const LegData& leg0, c
2730
: Swap(env, leg0, leg1, "CrossCurrencySwap") {}
2831

2932
void CrossCurrencySwap::checkCrossCurrencySwap() {
33+
// This function will attempt to set legIndexCcy to the other ccy from the first Indexing index.
34+
auto getIndexingCurrency = [this](const LegData& legData, const Currency& legCcy, Currency& legIndexCcy) {
35+
vector<Indexing> indexings = legData.indexing();
36+
if (!indexings.empty() && indexings.front().hasData()) {
37+
Indexing indexing = indexings.front();
38+
if (!boost::starts_with(indexing.index(), "FX-")) {
39+
WLOG(StructuredTradeWarningMessage(
40+
tradeType(), id(), "Trade validation (checkCrossCurrencySwap)",
41+
"Could not set fixed leg currency to Indexing currency for trade validation. Index (" +
42+
indexing.index() + ") should start with 'FX-'"));
43+
return;
44+
}
45+
46+
auto index = parseFxIndex(indexing.index());
47+
Currency srcCurrency = index->sourceCurrency();
48+
Currency tgtCurrency = index->targetCurrency();
49+
50+
if (legCcy != srcCurrency && legCcy != tgtCurrency) {
51+
WLOG(StructuredTradeWarningMessage(tradeType(), id(), "Trade validation (checkCrossCurrencySwap)",
52+
"Could not set fixed leg currency to Indexing currency for trade "
53+
"validation. Expected the leg currency (" +
54+
legCcy.code() +
55+
") be equal to either of the currencies in the index (" +
56+
indexing.index() + ")"));
57+
return;
58+
}
59+
60+
legIndexCcy = legCcy == srcCurrency ? tgtCurrency : srcCurrency;
61+
}
62+
};
63+
3064
// Cross Currency Swap legs must be either Fixed, Floating or Cashflow and exactly two of Fixed and/or Floating
3165
vector<Size> legDataIdx;
3266
for (Size i = 0; i < legData_.size(); i++) {
@@ -40,28 +74,37 @@ void CrossCurrencySwap::checkCrossCurrencySwap() {
4074
QL_REQUIRE(legDataIdx.size() == 2,
4175
"A Cross Currency Swap must have 2 legs that are either Fixed or Floating: " + id());
4276

77+
const LegData& legData0 = legData_[legDataIdx[0]];
78+
const LegData& legData1 = legData_[legDataIdx[1]];
79+
4380
// Check leg currencies
44-
Currency legCcy0 = parseCurrencyWithMinors(legData_[legDataIdx[0]].currency());
45-
Currency legIndexCcy0;
46-
if (legData_[legDataIdx[0]].legType() == "Fixed") {
47-
legIndexCcy0 = legCcy0;
48-
} else if (legData_[legDataIdx[0]].legType() == "Floating") {
49-
auto floatingLeg = boost::dynamic_pointer_cast<FloatingLegData>(legData_[legDataIdx[0]].concreteLegData());
50-
legIndexCcy0 = parseIborIndex(floatingLeg->index())->currency();
51-
}
81+
const Currency legCcy0 = parseCurrencyWithMinors(legData0.currency());
82+
const Currency legCcy1 = parseCurrencyWithMinors(legData1.currency());
5283

53-
Currency legCcy1;
54-
legCcy1 = parseCurrencyWithMinors(legData_[legDataIdx[1]].currency());
55-
// Require leg currencies to be different. If they are the same, we do a further check of FloatingLeg
56-
// underlying currencies, in which case we still call this a cross currency swap.
84+
// Require leg currencies to be different. If they are the same, we do a further check of the underlying currencies
85+
// (Indexings for Fixed leg; Floating leg index for Floating leg) and compare these.
5786
if (legCcy0 == legCcy1) {
58-
Currency legIndexCcy1;
59-
if (legData_[legDataIdx[1]].legType() == "Fixed") {
60-
legIndexCcy1 = legCcy1;
61-
} else if (legData_[legDataIdx[1]].legType() == "Floating") {
62-
auto floatingLeg = boost::dynamic_pointer_cast<FloatingLegData>(legData_[legDataIdx[1]].concreteLegData());
63-
legIndexCcy1 = parseIborIndex(floatingLeg->index()) ->currency();
87+
88+
// Get relevant index currency for the first leg - defaults to the leg ccy
89+
Currency legIndexCcy0 = legCcy0;
90+
if (legData0.legType() == "Fixed") {
91+
getIndexingCurrency(legData0, legCcy0, legIndexCcy0);
92+
} else if (legData0.legType() == "Floating") {
93+
auto floatingLeg = boost::dynamic_pointer_cast<FloatingLegData>(legData0.concreteLegData());
94+
if (floatingLeg)
95+
legIndexCcy0 = parseIborIndex(floatingLeg->index())->currency();
6496
}
97+
98+
// Get relevant index currency for the second leg - defaults to the leg ccy
99+
Currency legIndexCcy1 = legCcy1;
100+
if (legData1.legType() == "Fixed") {
101+
getIndexingCurrency(legData1, legCcy1, legIndexCcy1);
102+
} else if (legData1.legType() == "Floating") {
103+
auto floatingLeg = boost::dynamic_pointer_cast<FloatingLegData>(legData1.concreteLegData());
104+
if (floatingLeg)
105+
legIndexCcy1 = parseIborIndex(floatingLeg->index()) ->currency();
106+
}
107+
65108
QL_REQUIRE(legIndexCcy0 != legIndexCcy1, "Cross currency swap legs must have different currencies.");
66109
}
67110
}

0 commit comments

Comments
 (0)