1717*/
1818
1919#include < ored/portfolio/crosscurrencyswap.hpp>
20+ #include < ored/portfolio/structuredtradewarning.hpp>
21+ #include < ored/utilities/indexparser.hpp>
22+
2023
2124namespace ore {
2225namespace data {
@@ -27,6 +30,37 @@ CrossCurrencySwap::CrossCurrencySwap(const Envelope& env, const LegData& leg0, c
2730 : Swap(env, leg0, leg1, " CrossCurrencySwap" ) {}
2831
2932void 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