Skip to content

Commit fd87547

Browse files
author
jenkins
committed
git subrepo pull (merge) ore
subrepo: subdir: "ore" merged: "9a48f18cf1" upstream: origin: "git@gitlab.acadiasoft.net:qs/ore.git" branch: "master" commit: "e9e7a78680" git-subrepo: version: "0.4.6" origin: "https://github.com/ingydotnet/git-subrepo" commit: "73a0129"
2 parents 49f943a + e9e7a78 commit fd87547

10 files changed

Lines changed: 529 additions & 66 deletions

File tree

Docs/UserGuide/tradedata/compositetrade.tex

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,19 @@ \subsubsection{Composite Trade}
2323
\label{lst:compositetrade_data}
2424
\end{listing}
2525
26+
\begin{listing}[H]
27+
%\hrule\medskip
28+
\begin{minted}[fontsize=\footnotesize]{xml}
29+
<CompositeTradeData>
30+
<Currency>USD</Currency>
31+
<NotionalCalculation>Sum</NotionalCalculation>
32+
<PortfolioBasket>true</PortfolioBasket>
33+
<BasketName>NAME</BasketName>
34+
</CompositeTradeData>
35+
\end{minted}
36+
\caption{Composite trade data with Reference Data}
37+
\end{listing}
38+
2639
The meanings and allowable values of the elements in the \lstinline!CompositeTradeData! node follow below.
2740
2841
\begin{itemize}
@@ -43,4 +56,8 @@ \subsubsection{Composite Trade}
4356
Allowable values: Any non-negative real number.
4457
\item Components: The portfolio of trades that make up the composite trade. \\
4558
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.
59+
\item PortfolioBasket [Optional]: Indicate if the Component represent a portfolio basket. \\
60+
Allowable values: Boolean true or false.
61+
\item BasketName [Optional]: The portfolio Id. \\
62+
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.
4663
\end{itemize}

OREData/ored/portfolio/compositetrade.cpp

Lines changed: 108 additions & 64 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.");
41+
42+
populateFromReferenceData(engineFactory->referenceData());
43+
44+
4245
for (const QuantLib::ext::shared_ptr<Trade>& trade : trades_) {
4346

44-
trade->reset();
45-
trade->build(engineFactory);
46-
trade->validate();
47+
trade->reset();
48+
trade->build(engineFactory);
49+
trade->validate();
4750

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

5154
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);
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,29 +72,29 @@ 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-
bool isDuplicate = false;
83-
try {
84-
if (instrumentWrapper->additionalResults().find("cashFlowResults") != trade->instrument()->additionalResults().end())
85-
isDuplicate = true;
86-
} catch (...) {}
87-
if (!isDuplicate) {
88-
// For cashflows
89-
legs_.insert(legs_.end(), trade->legs().begin(), trade->legs().end());
90-
legPayers_.insert(legPayers_.end(), trade->legPayers().begin(), trade->legPayers().end());
91-
legCurrencies_.insert(legCurrencies_.end(), trade->legCurrencies().begin(), trade->legCurrencies().end());
92-
}
75+
if (auto optionWrapper = QuantLib::ext::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+
bool isDuplicate = false;
86+
try {
87+
if (instrumentWrapper->additionalResults().find("cashFlowResults") != trade->instrument()->additionalResults().end())
88+
isDuplicate = true;
89+
} catch (...) {}
90+
if (!isDuplicate) {
91+
// For cashflows
92+
legs_.insert(legs_.end(), trade->legs().begin(), trade->legs().end());
93+
legPayers_.insert(legPayers_.end(), trade->legPayers().begin(), trade->legPayers().end());
94+
legCurrencies_.insert(legCurrencies_.end(), trade->legCurrencies().begin(), trade->legCurrencies().end());
95+
}
9396

94-
maturity_ = std::max(maturity_, trade->maturity());
97+
maturity_ = std::max(maturity_, trade->maturity());
9598
}
9699
instrument_ = QuantLib::ext::shared_ptr<InstrumentWrapper>(new VanillaInstrument(compositeInstrument));
97100

@@ -120,7 +123,6 @@ void CompositeTrade::fromXML(XMLNode* node) {
120123
"Wrong trade type in composite trade builder.");
121124
Trade::fromXML(node);
122125
this->id() = XMLUtils::getAttribute(node, "id");
123-
124126
// We read the data particular to composite trades
125127
XMLNode* compNode = XMLUtils::getChildNode(node, "CompositeTradeData");
126128
QL_REQUIRE(compNode, "Could not find CompositeTradeData node.");
@@ -140,45 +142,58 @@ void CompositeTrade::fromXML(XMLNode* node) {
140142
QL_REQUIRE(notionalCalculation_ != "Override", "Notional override value has not been provided.");
141143
}
142144

143-
XMLNode* tradesNode = XMLUtils::getChildNode(compNode, "Components");
144-
QL_REQUIRE(tradesNode, "Could not find Components node.");
145+
if (XMLUtils::getChildNode(compNode, "PortfolioBasket")) {
146+
portfolioBasket_ = XMLUtils::getChildValueAsBool(node, "PortfolioBasket", false);
147+
} else {
148+
portfolioBasket_ = false;
149+
}
145150

146-
vector<XMLNode*> nodes = XMLUtils::getChildrenNodes(tradesNode, "Trade");
147-
for (Size i = 0; i < nodes.size(); i++) {
148-
string tradeType = XMLUtils::getChildValue(nodes[i], "TradeType", true);
151+
portfolioId_ = XMLUtils::getChildValue(compNode, "BasketName", false);
149152

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

184199
XMLNode* CompositeTrade::toXML(XMLDocument& doc) const {
@@ -256,5 +271,34 @@ const std::map<std::string, boost::any>& CompositeTrade::additionalData() const
256271
return additionalData_;
257272
}
258273

274+
void CompositeTrade::populateFromReferenceData(const QuantLib::ext::shared_ptr<ReferenceDataManager>& referenceData) {
275+
276+
if (!portfolioId_.empty() && referenceData != nullptr &&
277+
(referenceData->hasData(PortfolioBasketReferenceDatum::TYPE, portfolioId_))) {
278+
auto ptfRefData = QuantLib::ext::dynamic_pointer_cast<PortfolioBasketReferenceDatum>(
279+
referenceData->getData(PortfolioBasketReferenceDatum::TYPE, portfolioId_));
280+
QL_REQUIRE(ptfRefData, "could not cast to PortfolioBasketReferenceDatum, this is unexpected");
281+
getTradesFromReferenceData(ptfRefData);
282+
} else {
283+
DLOG("Could not get PortfolioBasketReferenceDatum for Id " << portfolioId_ << " leave data in trade unchanged");
284+
}
285+
286+
}
287+
288+
void CompositeTrade::getTradesFromReferenceData(
289+
const QuantLib::ext::shared_ptr<PortfolioBasketReferenceDatum>& ptfReferenceDatum) {
290+
291+
DLOG("populating portfolio basket data from reference data");
292+
QL_REQUIRE(ptfReferenceDatum, "populateFromReferenceData(): empty cbo reference datum given");
293+
294+
auto refData = ptfReferenceDatum->getTrades();
295+
trades_.clear();
296+
for (Size i = 0; i < refData.size(); i++) {
297+
trades_.push_back(refData[i]);
298+
}
299+
LOG("Finished Parsing XML doc");
300+
301+
}
302+
259303
} // namespace data
260304
} // 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 QuantLib::ext::shared_ptr<ReferenceDataManager>& referenceDataManager);
105+
void getTradesFromReferenceData(const QuantLib::ext::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)