@@ -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
184199XMLNode* 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
0 commit comments