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