Skip to content

Commit 4c8d7e6

Browse files
Sebastien Bouvardjenkins
authored andcommitted
Merge branch 'master' into QPR-12223
1 parent a5fd0ca commit 4c8d7e6

8 files changed

Lines changed: 350 additions & 63 deletions

File tree

Docs/UserGuide/tradedata/compositetrade.tex

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,16 @@ \subsubsection{Composite Trade}
2121
\end{minted}
2222
\caption{Composite trade data}
2323
\label{lst:compositetrade_data}
24+
\begin{minted}[fontsize=\footnotesize]{xml}
25+
<CompositeTradeData>
26+
<Currency>USD</Currency>
27+
<NotionalCalculation>Sum</NotionalCalculation>
28+
<PortfolioBasket>true</PortfolioBasket>
29+
<BasketName>NAME</BasketName>
30+
</CompositeTradeData>
31+
\end{minted}
32+
\caption{Composite trade data with Reference Data}
33+
\label{lst:compositetrade_data_refdata}
2434
\end{listing}
2535
2636
The meanings and allowable values of the elements in the \lstinline!CompositeTradeData! node follow below.
@@ -43,4 +53,8 @@ \subsubsection{Composite Trade}
4353
Allowable values: Any non-negative real number.
4454
\item Components: The portfolio of trades that make up the composite trade. \\
4555
Allowable values: These trades should be valid xmls that could otherwise be entered into the portfolio, with the exception that they can have empty ids.
56+
\item PortfolioBasket [Optional]: Indicate if the Component represent a portfolio basket. \\
57+
Allowable values: Boolean true or false.
58+
\item BasketName [Optional]: The portfolio Id. \\
59+
Allowable values: Any string. Note that if PortfolioBasket is True then there must be a BasketName. We look up the Basket within the reference data.
4660
\end{itemize}

OREData/ored/portfolio/compositetrade.cpp

Lines changed: 102 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -38,20 +38,23 @@ void CompositeTrade::build(const QuantLib::ext::shared_ptr<EngineFactory>& engin
3838
fxRates_.clear();
3939
fxRatesNotional_.clear();
4040
legs_.clear();
41-
QL_REQUIRE(trades_.size() > 0, "Failed to build composite trade.");
42-
for (const QuantLib::ext::shared_ptr<Trade>& trade : trades_) {
4341

44-
trade->reset();
45-
trade->build(engineFactory);
46-
trade->validate();
42+
populateFromReferenceData(engineFactory->referenceData());
43+
44+
45+
for (const boost::shared_ptr<Trade>& trade : trades_) {
46+
47+
trade->reset();
48+
trade->build(engineFactory);
49+
trade->validate();
4750

4851
if (sensitivityTemplate_.empty())
4952
setSensitivityTemplate(trade->sensitivityTemplate());
5053

51-
Handle<Quote> fx = Handle<Quote>(QuantLib::ext::make_shared<SimpleQuote>(1.0));
52-
if (trade->npvCurrency() != npvCurrency_)
53-
fx = engineFactory->market()->fxRate(trade->npvCurrency() + npvCurrency_);
54-
fxRates_.push_back(fx);
54+
Handle<Quote> fx = Handle<Quote>(boost::make_shared<SimpleQuote>(1.0));
55+
if (trade->npvCurrency() != npvCurrency_)
56+
fx = engineFactory->market()->fxRate(trade->npvCurrency() + npvCurrency_);
57+
fxRates_.push_back(fx);
5558

5659
Handle<Quote> fxNotional = Handle<Quote>(QuantLib::ext::make_shared<SimpleQuote>(1.0));
5760
if (trade->notionalCurrency().empty()) {
@@ -69,22 +72,22 @@ void CompositeTrade::build(const QuantLib::ext::shared_ptr<EngineFactory>& engin
6972

7073
QuantLib::ext::shared_ptr<InstrumentWrapper> instrumentWrapper = trade->instrument();
7174
Real effectiveMultiplier = instrumentWrapper->multiplier();
72-
if (auto optionWrapper = QuantLib::ext::dynamic_pointer_cast<ore::data::OptionWrapper>(instrumentWrapper)) {
73-
effectiveMultiplier *= optionWrapper->isLong() ? 1.0 : -1.0;
74-
}
75-
76-
compositeInstrument->add(instrumentWrapper->qlInstrument(), effectiveMultiplier, fx);
77-
for (Size i = 0; i < instrumentWrapper->additionalInstruments().size(); ++i) {
78-
compositeInstrument->add(instrumentWrapper->additionalInstruments()[i],
79-
instrumentWrapper->additionalMultipliers()[i]);
80-
}
81-
82-
// For cashflows
83-
legs_.insert(legs_.end(), trade->legs().begin(), trade->legs().end());
84-
legPayers_.insert(legPayers_.end(), trade->legPayers().begin(), trade->legPayers().end());
85-
legCurrencies_.insert(legCurrencies_.end(), trade->legCurrencies().begin(), trade->legCurrencies().end());
86-
87-
maturity_ = std::max(maturity_, trade->maturity());
75+
if (auto optionWrapper = boost::dynamic_pointer_cast<ore::data::OptionWrapper>(instrumentWrapper)) {
76+
effectiveMultiplier *= optionWrapper->isLong() ? 1.0 : -1.0;
77+
}
78+
79+
compositeInstrument->add(instrumentWrapper->qlInstrument(), effectiveMultiplier, fx);
80+
for (Size i = 0; i < instrumentWrapper->additionalInstruments().size(); ++i) {
81+
compositeInstrument->add(instrumentWrapper->additionalInstruments()[i],
82+
instrumentWrapper->additionalMultipliers()[i]);
83+
}
84+
85+
// For cashflows
86+
legs_.insert(legs_.end(), trade->legs().begin(), trade->legs().end());
87+
legPayers_.insert(legPayers_.end(), trade->legPayers().begin(), trade->legPayers().end());
88+
legCurrencies_.insert(legCurrencies_.end(), trade->legCurrencies().begin(), trade->legCurrencies().end());
89+
90+
maturity_ = std::max(maturity_, trade->maturity());
8891
}
8992
instrument_ = QuantLib::ext::shared_ptr<InstrumentWrapper>(new VanillaInstrument(compositeInstrument));
9093

@@ -113,7 +116,6 @@ void CompositeTrade::fromXML(XMLNode* node) {
113116
"Wrong trade type in composite trade builder.");
114117
Trade::fromXML(node);
115118
this->id() = XMLUtils::getAttribute(node, "id");
116-
117119
// We read the data particular to composite trades
118120
XMLNode* compNode = XMLUtils::getChildNode(node, "CompositeTradeData");
119121
QL_REQUIRE(compNode, "Could not find CompositeTradeData node.");
@@ -133,45 +135,58 @@ void CompositeTrade::fromXML(XMLNode* node) {
133135
QL_REQUIRE(notionalCalculation_ != "Override", "Notional override value has not been provided.");
134136
}
135137

136-
XMLNode* tradesNode = XMLUtils::getChildNode(compNode, "Components");
137-
QL_REQUIRE(tradesNode, "Could not find Components node.");
138+
if (XMLUtils::getChildNode(compNode, "PortfolioBasket")) {
139+
portfolioBasket_ = XMLUtils::getChildValueAsBool(node, "PortfolioBasket", false);
140+
} else {
141+
portfolioBasket_ = false;
142+
}
138143

139-
vector<XMLNode*> nodes = XMLUtils::getChildrenNodes(tradesNode, "Trade");
140-
for (Size i = 0; i < nodes.size(); i++) {
141-
string tradeType = XMLUtils::getChildValue(nodes[i], "TradeType", true);
144+
portfolioId_ = XMLUtils::getChildValue(compNode, "BasketName", false);
142145

143-
string id = XMLUtils::getAttribute(nodes[i], "id");
144-
if (id == "") {
145-
WLOG("Empty component trade id being overwritten in composite trade " << this->id() << ".");
146-
}
147-
id = this->id() + "_" + std::to_string(i);
148-
DLOG("Parsing composite trade " << this->id() << " node " << i << " with id: " << id);
149-
150-
QuantLib::ext::shared_ptr<Trade> trade;
151-
try {
152-
trade = TradeFactory::instance().build(tradeType);
153-
trade->id() = id;
154-
Envelope componentEnvelope;
155-
if (XMLNode* envNode = XMLUtils::getChildNode(nodes[i], "Envelope")) {
156-
componentEnvelope.fromXML(envNode);
146+
XMLNode* tradesNode = XMLUtils::getChildNode(compNode, "Components");
147+
if (portfolioBasket_ && portfolioId_.empty()) {
148+
QL_REQUIRE(tradesNode, "Required a Portfolio Id or a Components Node.");
149+
}
150+
if ((portfolioBasket_ && portfolioId_.empty()) || (!portfolioBasket_)) {
151+
152+
vector<XMLNode*> nodes = XMLUtils::getChildrenNodes(tradesNode, "Trade");
153+
for (Size i = 0; i < nodes.size(); i++) {
154+
string tradeType = XMLUtils::getChildValue(nodes[i], "TradeType", true);
155+
string id = XMLUtils::getAttribute(nodes[i], "id");
156+
if (id == "") {
157+
WLOG("Empty component trade id being overwritten in composite trade " << this->id() << ".");
158+
}
159+
id = this->id() + "_" + std::to_string(i);
160+
DLOG("Parsing composite trade " << this->id() << " node " << i << " with id: " << id);
161+
162+
boost::shared_ptr<Trade> trade;
163+
try {
164+
trade = TradeFactory::instance().build(tradeType);
165+
trade->id() = id;
166+
Envelope componentEnvelope;
167+
if (XMLNode* envNode = XMLUtils::getChildNode(nodes[i], "Envelope")) {
168+
componentEnvelope.fromXML(envNode);
169+
}
170+
Envelope env = this->envelope();
171+
// the component trade's envelope is the main trade's envelope with possibly overwritten add fields
172+
for (auto const& [k, v] : componentEnvelope.fullAdditionalFields()) {
173+
env.setAdditionalField(k,v);
174+
}
175+
176+
trade->setEnvelope(env);
177+
trade->fromXML(nodes[i]);
178+
trades_.push_back(trade);
179+
DLOG("Added Trade " << id << " (" << trade->id() << ")"
180+
<< " type:" << tradeType << " to composite trade " << this->id() << ".");
181+
} catch (const std::exception& e) {
182+
StructuredTradeErrorMessage(
183+
id, this->tradeType(),
184+
"Failed to build subtrade with id '" + id + "' inside composite trade: ", e.what())
185+
.log();
157186
}
158-
Envelope env = this->envelope();
159-
// the component trade's envelope is the main trade's envelope with possibly overwritten add fields
160-
for (auto const& [k, v] : componentEnvelope.fullAdditionalFields())
161-
env.setAdditionalField(k,v);
162-
trade->setEnvelope(env);
163-
trade->fromXML(nodes[i]);
164-
trades_.push_back(trade);
165-
DLOG("Added Trade " << id << " (" << trade->id() << ")"
166-
<< " type:" << tradeType << " to composite trade " << this->id() << ".");
167-
} catch (const std::exception& e) {
168-
StructuredTradeErrorMessage(
169-
id, this->tradeType(),
170-
"Failed to build subtrade with id '" + id + "' inside composite trade: ", e.what())
171-
.log();
172187
}
188+
LOG("Finished Parsing XML doc");
173189
}
174-
LOG("Finished Parsing XML doc");
175190
}
176191

177192
XMLNode* CompositeTrade::toXML(XMLDocument& doc) const {
@@ -249,5 +264,32 @@ const std::map<std::string, boost::any>& CompositeTrade::additionalData() const
249264
return additionalData_;
250265
}
251266

267+
void CompositeTrade::populateFromReferenceData(const boost::shared_ptr<ReferenceDataManager>& referenceData) {
268+
269+
if (!portfolioId_.empty() && (referenceData->hasData(PortfolioBasketReferenceDatum::TYPE, portfolioId_))) {
270+
auto ptfRefData = boost::dynamic_pointer_cast<PortfolioBasketReferenceDatum>(
271+
referenceData->getData(PortfolioBasketReferenceDatum::TYPE, portfolioId_));
272+
QL_REQUIRE(ptfRefData, "could not cast to PortfolioBasketReferenceDatum, this is unexpected");
273+
getTradesFromReferenceData(ptfRefData);
274+
} else {
275+
DLOG("Could not get PortfolioBasketReferenceDatum for Id " << portfolioId_ << " leave data in trade unchanged");
276+
}
277+
278+
}
279+
280+
void CompositeTrade::getTradesFromReferenceData(const boost::shared_ptr<PortfolioBasketReferenceDatum>& ptfReferenceDatum) {
281+
282+
DLOG("populating portfolio basket data from reference data");
283+
QL_REQUIRE(ptfReferenceDatum, "populateFromReferenceData(): empty cbo reference datum given");
284+
285+
auto refData = ptfReferenceDatum->getTrades();
286+
trades_.clear();
287+
for (Size i = 0; i < refData.size(); i++) {
288+
trades_.push_back(refData[i]);
289+
}
290+
LOG("Finished Parsing XML doc");
291+
292+
}
293+
252294
} // namespace data
253295
} // namespace oreplus

OREData/ored/portfolio/compositetrade.hpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424

2525
#include <ored/portfolio/trade.hpp>
2626
#include <ored/portfolio/tradefactory.hpp>
27+
#include <ored/portfolio/referencedata.hpp>
2728
#include <ostream>
2829

2930
namespace ore {
@@ -70,6 +71,8 @@ class CompositeTrade : public Trade {
7071
//! \name Inspectors
7172
//@{
7273
const string& currency() const { return currency_; }
74+
const string& portfolioId() const { return portfolioId_; }
75+
const bool& portfolioBasket() const { return portfolioBasket_; }
7376
const string& notionalCalculation() const { return notionalCalculation_; }
7477
const vector<QuantLib::ext::shared_ptr<Trade>>& trades() const { return trades_; }
7578
//@}
@@ -97,11 +100,17 @@ class CompositeTrade : public Trade {
97100
//@}
98101

99102
private:
103+
104+
void populateFromReferenceData(const boost::shared_ptr<ReferenceDataManager>& referenceDataManager);
105+
void getTradesFromReferenceData(const boost::shared_ptr<PortfolioBasketReferenceDatum>& ptfReferenceDatum);
106+
100107
string currency_;
101108
Real notionalOverride_;
102109
string notionalCalculation_;
103110
vector<QuantLib::ext::shared_ptr<Trade>> trades_;
104111
vector<Handle<Quote>> fxRates_, fxRatesNotional_;
112+
string portfolioId_;
113+
bool portfolioBasket_;
105114
};
106115

107116
} // namespace data

0 commit comments

Comments
 (0)