Skip to content

Commit 2ecd0c6

Browse files
pcaspersjenkins
authored andcommitted
Merge remote-tracking branch 'origin/master' into QPR-12275
1 parent 6f9bec3 commit 2ecd0c6

17 files changed

Lines changed: 132 additions & 58 deletions

OREData/ored/portfolio/builders/swap.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,9 @@ boost::shared_ptr<PricingEngine> CamAmcSwapEngineBuilder::buildMcEngine(const bo
4848
parseRegressorModel(engineParameter("RegressorModel", {}, false, "Simple")));
4949
}
5050

51-
boost::shared_ptr<PricingEngine> CamAmcSwapEngineBuilder::engineImpl(const Currency& ccy) {
51+
boost::shared_ptr<PricingEngine> CamAmcSwapEngineBuilder::engineImpl(const Currency& ccy,
52+
const std::string& discountCurveName,
53+
const std::string& securitySpread) {
5254
DLOG("Building AMC Swap engine for ccy " << ccy << " (from externally given CAM)");
5355

5456
QL_REQUIRE(cam_ != nullptr, "LgmAmcSwapEngineBuilder::engineImpl: cam is null");

OREData/ored/portfolio/builders/swap.hpp

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,20 @@
2323

2424
#pragma once
2525

26-
#include <boost/make_shared.hpp>
2726
#include <ored/portfolio/builders/cachingenginebuilder.hpp>
2827
#include <ored/portfolio/enginefactory.hpp>
2928
#include <ored/utilities/log.hpp>
3029
#include <ored/utilities/marketdata.hpp>
31-
#include <ql/pricingengines/swap/discountingswapengine.hpp>
30+
31+
#include <qle/models/crossassetmodel.hpp>
3232
#include <qle/pricingengines/discountingcurrencyswapengine.hpp>
3333
#include <qle/pricingengines/discountingswapenginemulticurve.hpp>
3434
#include <qle/pricingengines/mclgmswaptionengine.hpp>
35-
#include <qle/models/crossassetmodel.hpp>
35+
36+
#include <ql/pricingengines/swap/discountingswapengine.hpp>
37+
#include <ql/termstructures/yield/zerospreadedtermstructure.hpp>
38+
39+
#include <boost/make_shared.hpp>
3640

3741
namespace ore {
3842
namespace data {
@@ -41,13 +45,17 @@ namespace data {
4145
/*! Pricing engines are cached by currency
4246
\ingroup builders
4347
*/
44-
class SwapEngineBuilderBase : public CachingPricingEngineBuilder<string, const Currency&> {
48+
class SwapEngineBuilderBase
49+
: public CachingPricingEngineBuilder<string, const Currency&, const std::string&, const std::string&> {
4550
public:
4651
SwapEngineBuilderBase(const std::string& model, const std::string& engine)
4752
: CachingEngineBuilder(model, engine, {"Swap"}) {}
4853

4954
protected:
50-
virtual string keyImpl(const Currency& ccy) override { return ccy.code(); }
55+
virtual string keyImpl(const Currency& ccy, const std::string& discountCurve,
56+
const std::string& securitySpread) override {
57+
return ccy.code() + discountCurve + securitySpread;
58+
}
5159
};
5260

5361
//! Engine Builder for Single Currency Swaps
@@ -59,9 +67,14 @@ class SwapEngineBuilder : public SwapEngineBuilderBase {
5967
SwapEngineBuilder() : SwapEngineBuilderBase("DiscountedCashflows", "DiscountingSwapEngine") {}
6068

6169
protected:
62-
virtual boost::shared_ptr<PricingEngine> engineImpl(const Currency& ccy) override {
63-
64-
Handle<YieldTermStructure> yts = market_->discountCurve(ccy.code(), configuration(MarketContext::pricing));
70+
virtual boost::shared_ptr<PricingEngine> engineImpl(const Currency& ccy, const std::string& discountCurve,
71+
const std::string& securitySpread) override {
72+
Handle<YieldTermStructure> yts =
73+
discountCurve.empty() ? market_->discountCurve(ccy.code(), configuration(MarketContext::pricing))
74+
: indexOrYieldCurve(market_, discountCurve, configuration(MarketContext::pricing));
75+
if (!securitySpread.empty())
76+
yts = Handle<YieldTermStructure>(boost::make_shared<ZeroSpreadedTermStructure>(
77+
yts, market_->securitySpread(securitySpread, configuration(MarketContext::pricing))));
6578
return boost::make_shared<QuantLib::DiscountingSwapEngine>(yts);
6679
}
6780
};
@@ -75,9 +88,15 @@ class SwapEngineBuilderOptimised : public SwapEngineBuilderBase {
7588
SwapEngineBuilderOptimised() : SwapEngineBuilderBase("DiscountedCashflows", "DiscountingSwapEngineOptimised") {}
7689

7790
protected:
78-
virtual boost::shared_ptr<PricingEngine> engineImpl(const Currency& ccy) override {
79-
80-
Handle<YieldTermStructure> yts = market_->discountCurve(ccy.code(), configuration(MarketContext::pricing));
91+
virtual boost::shared_ptr<PricingEngine> engineImpl(const Currency& ccy, const std::string& discountCurve,
92+
const std::string& securitySpread) override {
93+
94+
Handle<YieldTermStructure> yts =
95+
discountCurve.empty() ? market_->discountCurve(ccy.code(), configuration(MarketContext::pricing))
96+
: indexOrYieldCurve(market_, discountCurve, configuration(MarketContext::pricing));
97+
if (!securitySpread.empty())
98+
yts = Handle<YieldTermStructure>(boost::make_shared<ZeroSpreadedTermStructure>(
99+
yts, market_->securitySpread(securitySpread, configuration(MarketContext::pricing))));
81100
return boost::make_shared<QuantExt::DiscountingSwapEngineMultiCurve>(yts);
82101
}
83102
};
@@ -139,7 +158,8 @@ class CamAmcSwapEngineBuilder : public SwapEngineBuilderBase {
139158

140159
protected:
141160
// the pricing engine depends on the ccy only, can use the caching from SwapEngineBuilderBase
142-
virtual boost::shared_ptr<PricingEngine> engineImpl(const Currency& ccy) override;
161+
virtual boost::shared_ptr<PricingEngine> engineImpl(const Currency& ccy, const std::string& discountCurve,
162+
const std::string& securitySpread) override;
143163

144164
private:
145165
boost::shared_ptr<PricingEngine> buildMcEngine(const boost::shared_ptr<QuantExt::LGM>& lgm,

OREData/ored/portfolio/capfloor.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ void CapFloor::build(const boost::shared_ptr<EngineFactory>& engineFactory) {
116116
boost::shared_ptr<SwapEngineBuilderBase> swapBuilder =
117117
boost::dynamic_pointer_cast<SwapEngineBuilderBase>(builder);
118118
QL_REQUIRE(swapBuilder, "No Builder found for Swap " << id());
119-
qlInstrument->setPricingEngine(swapBuilder->engine(parseCurrency(legData_.currency())));
119+
qlInstrument->setPricingEngine(swapBuilder->engine(parseCurrency(legData_.currency()), std::string(), std::string()));
120120
setSensitivityTemplate(*swapBuilder);
121121
} else {
122122
qlInstrument->setPricingEngine(
@@ -193,7 +193,7 @@ void CapFloor::build(const boost::shared_ptr<EngineFactory>& engineFactory) {
193193
boost::shared_ptr<SwapEngineBuilderBase> swapBuilder =
194194
boost::dynamic_pointer_cast<SwapEngineBuilderBase>(builder);
195195
QL_REQUIRE(swapBuilder, "No Builder found for Swap " << id());
196-
qlInstrument->setPricingEngine(swapBuilder->engine(parseCurrency(legData_.currency())));
196+
qlInstrument->setPricingEngine(swapBuilder->engine(parseCurrency(legData_.currency()), std::string(), std::string()));
197197
setSensitivityTemplate(*swapBuilder);
198198
} else {
199199
qlInstrument->setPricingEngine(
@@ -222,7 +222,7 @@ void CapFloor::build(const boost::shared_ptr<EngineFactory>& engineFactory) {
222222
boost::shared_ptr<SwapEngineBuilderBase> swapBuilder =
223223
boost::dynamic_pointer_cast<SwapEngineBuilderBase>(builder);
224224
QL_REQUIRE(swapBuilder, "No Builder found for Swap " << id());
225-
qlInstrument->setPricingEngine(swapBuilder->engine(parseCurrency(legData_.currency())));
225+
qlInstrument->setPricingEngine(swapBuilder->engine(parseCurrency(legData_.currency()), std::string(), std::string()));
226226
setSensitivityTemplate(*swapBuilder);
227227
} else {
228228
qlInstrument->setPricingEngine(
@@ -252,7 +252,7 @@ void CapFloor::build(const boost::shared_ptr<EngineFactory>& engineFactory) {
252252
boost::shared_ptr<SwapEngineBuilderBase> swapBuilder =
253253
boost::dynamic_pointer_cast<SwapEngineBuilderBase>(builder);
254254
QL_REQUIRE(swapBuilder, "No Builder found for Swap " << id());
255-
qlInstrument->setPricingEngine(swapBuilder->engine(parseCurrency(legData_.currency())));
255+
qlInstrument->setPricingEngine(swapBuilder->engine(parseCurrency(legData_.currency()), std::string(), std::string()));
256256
setSensitivityTemplate(*swapBuilder);
257257
} else {
258258
qlInstrument->setPricingEngine(

OREData/ored/portfolio/compositetrade.cpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -150,14 +150,19 @@ void CompositeTrade::fromXML(XMLNode* node) {
150150
try {
151151
trade = TradeFactory::instance().build(tradeType);
152152
trade->id() = id;
153-
// we prefer that the component trades don't have envelopes, but we need one for validation
154-
trade->envelope() = this->envelope();
155153
trade->fromXML(nodes[i]);
154+
// if a sub trade does not have an envelope, we provide the main trade's one
155+
if (!trade->envelope().initialized())
156+
trade->envelope() = this->envelope();
156157
trades_.push_back(trade);
157158
DLOG("Added Trade " << id << " (" << trade->id() << ")"
158159
<< " type:" << tradeType << " to composite trade " << this->id() << ".");
159-
} catch (std::exception& ex) {
160-
ALOG("Failed to build subtrade with id '" << id << "' inside composite trade: " << ex.what());
160+
std::cout << "adding trade:\n" << trade->toXMLString() << std::endl;
161+
} catch (const std::exception& e) {
162+
StructuredTradeErrorMessage(
163+
id, this->tradeType(),
164+
"Failed to build subtrade with id '" + id + "' inside composite trade: ", e.what())
165+
.log();
161166
}
162167
}
163168
LOG("Finished Parsing XML doc");

OREData/ored/portfolio/envelope.cpp

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ namespace data {
2626

2727
void Envelope::fromXML(XMLNode* node) {
2828
XMLUtils::checkNode(node, "Envelope");
29-
counterparty_ = XMLUtils::getChildValue(node, "CounterParty", true);
29+
counterparty_ = XMLUtils::getChildValue(node, "CounterParty", false);
3030

3131
XMLNode* nettingSetDetailsNode = XMLUtils::getChildNode(node, "NettingSetDetails");
3232
if (nettingSetDetailsNode) {
@@ -69,6 +69,7 @@ void Envelope::fromXML(XMLNode* node) {
6969
additionalFields_[XMLUtils::getNodeName(child)] = getValue(child);
7070
}
7171
}
72+
initialized_ = true;
7273
}
7374

7475
XMLNode* Envelope::toXML(XMLDocument& doc) {
@@ -106,5 +107,28 @@ XMLNode* Envelope::toXML(XMLDocument& doc) {
106107
return node;
107108
}
108109

110+
const map<string, string> Envelope::additionalFields() const {
111+
map<string, string> stringAddFields;
112+
for (const auto& f : additionalFields_)
113+
if (f.second.type() == typeid(string))
114+
stringAddFields[f.first] = boost::any_cast<string>(f.second);
115+
return stringAddFields;
116+
}
117+
118+
string Envelope::additionalField(const std::string& name, const bool mandatory, const std::string& defaultValue) const {
119+
auto af = additionalFields();
120+
auto it = af.find(name);
121+
QL_REQUIRE(it != af.end() || !mandatory,
122+
"Envelope::additionalField(): Mandatory field '" << name << "' not found.");
123+
return it == af.end() ? defaultValue : it->second;
124+
}
125+
126+
boost::any Envelope::additionalAnyField(const std::string& name, const bool mandatory, const boost::any& defaultValue) const {
127+
auto it = additionalFields_.find(name);
128+
QL_REQUIRE(it != additionalFields_.end() || !mandatory,
129+
"Envelope::additionalField(): Mandatory field '" << name << "' not found.");
130+
return it == additionalFields_.end() ? defaultValue : it->second;
131+
}
132+
109133
} // namespace data
110134
} // namespace ore

OREData/ored/portfolio/envelope.hpp

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -23,17 +23,20 @@
2323

2424
#pragma once
2525

26-
#include <map>
26+
#include <ored/portfolio/nettingsetdetails.hpp>
2727
#include <ored/utilities/xmlutils.hpp>
28+
29+
#include <boost/any.hpp>
30+
#include <boost/none.hpp>
2831
#include <boost/tuple/tuple.hpp>
2932
#include <boost/tuple/tuple_comparison.hpp>
30-
#include <boost/any.hpp>
33+
34+
#include <map>
3135
#include <set>
32-
#include <ored/portfolio/nettingsetdetails.hpp>
3336

37+
using ore::data::NettingSetDetails;
3438
using ore::data::XMLNode;
3539
using ore::data::XMLSerializable;
36-
using ore::data::NettingSetDetails;
3740
using std::map;
3841
using std::set;
3942
using std::string;
@@ -51,35 +54,37 @@ class Envelope : public XMLSerializable {
5154
Envelope() {}
5255

5356
//! Constructor with netting set id and portfolio ids, without additional fields
54-
Envelope(const string& counterparty, const string& nettingSetId,
55-
const set<string>& portfolioIds = set<string>())
56-
: counterparty_(counterparty), nettingSetDetails_(NettingSetDetails(nettingSetId)),
57-
portfolioIds_(portfolioIds) {}
57+
Envelope(const string& counterparty, const string& nettingSetId, const set<string>& portfolioIds = set<string>())
58+
: counterparty_(counterparty), nettingSetDetails_(NettingSetDetails(nettingSetId)), portfolioIds_(portfolioIds),
59+
initialized_(true) {}
5860

5961
//! Constructor with netting set details and portfolio ids, without additional fields
6062
Envelope(const string& counterparty, const NettingSetDetails& nettingSetDetails = NettingSetDetails(),
6163
const set<string>& portfolioIds = set<string>())
62-
: counterparty_(counterparty), nettingSetDetails_(nettingSetDetails), portfolioIds_(portfolioIds) {}
64+
: counterparty_(counterparty), nettingSetDetails_(nettingSetDetails), portfolioIds_(portfolioIds),
65+
initialized_(true) {}
6366

6467
//! Constructor without netting set / portfolio ids, with additional fields
6568
Envelope(const string& counterparty, const map<string, string>& additionalFields)
66-
: counterparty_(counterparty), nettingSetDetails_(NettingSetDetails()) {
69+
: counterparty_(counterparty), nettingSetDetails_(NettingSetDetails()), initialized_(true) {
6770
for (const auto& addField : additionalFields)
6871
additionalFields_[addField.first] = addField.second;
6972
}
7073

7174
//! Constructor with netting set, with additional fields
7275
Envelope(const string& counterparty, const string& nettingSetId, const map<string, string>& additionalFields,
7376
const set<string>& portfolioIds = set<string>())
74-
: counterparty_(counterparty), nettingSetDetails_(NettingSetDetails(nettingSetId)), portfolioIds_(portfolioIds) {
77+
: counterparty_(counterparty), nettingSetDetails_(NettingSetDetails(nettingSetId)), portfolioIds_(portfolioIds),
78+
initialized_(true) {
7579
for (const auto& addField : additionalFields)
7680
additionalFields_[addField.first] = addField.second;
7781
}
7882

7983
//! Constructor with netting set details, with additional fields
8084
Envelope(const string& counterparty, const NettingSetDetails& nettingSetDetails,
8185
const map<string, string>& additionalFields, const set<string>& portfolioIds = set<string>())
82-
: counterparty_(counterparty), nettingSetDetails_(nettingSetDetails), portfolioIds_(portfolioIds) {
86+
: counterparty_(counterparty), nettingSetDetails_(nettingSetDetails), portfolioIds_(portfolioIds),
87+
initialized_(true) {
8388
for (const auto& addField : additionalFields)
8489
additionalFields_[addField.first] = addField.second;
8590
}
@@ -96,20 +101,18 @@ class Envelope : public XMLSerializable {
96101
const string& nettingSetId() const { return nettingSetDetails_.nettingSetId(); }
97102
const NettingSetDetails nettingSetDetails() { return nettingSetDetails_; }
98103
const set<string>& portfolioIds() const { return portfolioIds_; }
99-
const map<string, string> additionalFields() const {
100-
map<string, string> stringAddFields;
101-
for (const auto& f : additionalFields_)
102-
if (f.second.type() == typeid(string))
103-
stringAddFields[f.first] = boost::any_cast<string>(f.second);
104-
return stringAddFields;
105-
}
104+
const map<string, string> additionalFields() const;
106105
const map<string, boost::any>& fullAdditionalFields() const { return additionalFields_; }
106+
string additionalField(const std::string& name, const bool mandatory = true,
107+
const std::string& defaultValue = std::string()) const;
108+
boost::any additionalAnyField(const std::string& name, const bool mandatory = true,
109+
const boost::any& defaultValue = boost::none) const;
107110
//@}
108111

109112
//! \name Utility
110113
//@{
111-
//! Check if the envelope has been populated
112-
bool empty() const { return counterparty_ == ""; }
114+
//! Check if the envelope is initialized
115+
bool initialized() const { return initialized_; }
113116
//! Check if the netting set details have been populated
114117
bool hasNettingSetDetails() const { return !nettingSetDetails_.empty(); }
115118
//@}
@@ -119,6 +122,7 @@ class Envelope : public XMLSerializable {
119122
NettingSetDetails nettingSetDetails_;
120123
set<string> portfolioIds_;
121124
map<string, boost::any> additionalFields_;
125+
bool initialized_ = false;
122126
};
123127

124128
} // namespace data

OREData/ored/portfolio/equitydoubletouchoption.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ void EquityDoubleTouchOption::build(const boost::shared_ptr<EngineFactory>& engi
119119
QL_REQUIRE(builder, "No builder found for Swap");
120120
boost::shared_ptr<SwapEngineBuilderBase> swapBuilder =
121121
boost::dynamic_pointer_cast<SwapEngineBuilderBase>(builder);
122-
underlying->setPricingEngine(swapBuilder->engine(parseCurrency(payoffCurrency_)));
122+
underlying->setPricingEngine(swapBuilder->engine(parseCurrency(payoffCurrency_), std::string(), std::string()));
123123
}
124124

125125
bool isLong = (positionType == Position::Long) ? true : false;

OREData/ored/portfolio/equitytouchoption.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ void EquityTouchOption::build(const boost::shared_ptr<EngineFactory>& engineFact
139139
QL_REQUIRE(builder, "No builder found for Swap");
140140
boost::shared_ptr<SwapEngineBuilderBase> swapBuilder =
141141
boost::dynamic_pointer_cast<SwapEngineBuilderBase>(builder);
142-
underlying->setPricingEngine(swapBuilder->engine(ccy));
142+
underlying->setPricingEngine(swapBuilder->engine(ccy, std::string(), std::string()));
143143
}
144144

145145
bool isLong = (positionType == Position::Long) ? true : false;

OREData/ored/portfolio/forwardrateagreement.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ void ForwardRateAgreement::build(const boost::shared_ptr<EngineFactory>& engineF
6262
boost::shared_ptr<EngineBuilder> builder = engineFactory->builder("Swap");
6363
boost::shared_ptr<SwapEngineBuilderBase> swapBuilder = boost::dynamic_pointer_cast<SwapEngineBuilderBase>(builder);
6464
QL_REQUIRE(swapBuilder, "No Builder found for Swap " << id());
65-
swap->setPricingEngine(swapBuilder->engine(npvCcy));
65+
swap->setPricingEngine(swapBuilder->engine(npvCcy, std::string(), std::string()));
6666
setSensitivityTemplate(*swapBuilder);
6767
instrument_.reset(new VanillaInstrument(swap));
6868
maturity_ = endDate;

OREData/ored/portfolio/fxaverageforward.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ void FxAverageForward::build(const boost::shared_ptr<EngineFactory>& engineFacto
6464
boost::shared_ptr<EngineBuilder> builder = engineFactory->builder("Swap");
6565
boost::shared_ptr<SwapEngineBuilderBase> swapBuilder = boost::dynamic_pointer_cast<SwapEngineBuilderBase>(builder);
6666
QL_REQUIRE(swapBuilder, "No Builder found for Swap " << id());
67-
swap->setPricingEngine(swapBuilder->engine(payCcy));
67+
swap->setPricingEngine(swapBuilder->engine(payCcy, std::string(), std::string()));
6868
setSensitivityTemplate(*swapBuilder);
6969
instrument_.reset(new VanillaInstrument(swap));
7070

0 commit comments

Comments
 (0)