Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
trade.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2016 Quaternion Risk Management Ltd
3 All rights reserved.
4
5 This file is part of ORE, a free-software/open-source library
6 for transparent pricing and risk analysis - http://opensourcerisk.org
7
8 ORE is free software: you can redistribute it and/or modify it
9 under the terms of the Modified BSD License. You should have received a
10 copy of the license along with this program.
11 The license is also available online at <http://opensourcerisk.org>
12
13 This program is distributed on the basis that it will form a useful
14 contribution to risk analytics and model standardisation, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the license for more details.
17*/
18
23
28
30
31namespace ore {
32namespace data {
33
35 XMLUtils::checkNode(node, "Trade");
36 tradeType_ = XMLUtils::getChildValue(node, "TradeType", true);
37 if (XMLNode* envNode = XMLUtils::getChildNode(node, "Envelope")) {
38 envelope_.fromXML(envNode);
39 }
41 XMLNode* taNode = XMLUtils::getChildNode(node, "TradeActions");
42 if (taNode)
43 tradeActions_.fromXML(taNode);
44}
45
47 // Crete Trade Node with Id attribute.
48 XMLNode* node = doc.allocNode("Trade");
49 QL_REQUIRE(node, "Failed to create trade node");
50 XMLUtils::addAttribute(doc, node, "id", id_);
51 XMLUtils::addChild(doc, node, "TradeType", tradeType_);
53 if (!tradeActions_.empty())
55 return node;
56}
57
58Date Trade::addPremiums(std::vector<QuantLib::ext::shared_ptr<Instrument>>& addInstruments, std::vector<Real>& addMultipliers,
59 const Real tradeMultiplier, const PremiumData& premiumData, const Real premiumMultiplier,
60 const Currency& tradeCurrency, const QuantLib::ext::shared_ptr<EngineFactory>& factory,
61 const string& configuration) {
62
63 Date latestPremiumPayDate = Date::minDate();
64
65 for (auto const& d : premiumData.premiumData()) {
66 QL_REQUIRE(d.amount != Null<Real>(), "Trade contains invalid premium data.");
67
68 Currency premiumCurrency = parseCurrencyWithMinors(d.ccy);
69 Real premiumAmount = convertMinorToMajorCurrency(d.ccy, d.amount);
70 auto fee = QuantLib::ext::make_shared<QuantExt::Payment>(premiumAmount, premiumCurrency, d.payDate);
71
72 addMultipliers.push_back(premiumMultiplier);
73
74 Handle<YieldTermStructure> yts = factory->market()->discountCurve(d.ccy, configuration);
75 Handle<Quote> fx;
76 if (tradeCurrency.code() != d.ccy) {
77 fx = factory->market()->fxRate(d.ccy + tradeCurrency.code(), configuration);
78 }
79 QuantLib::ext::shared_ptr<PricingEngine> discountingEngine(new QuantExt::PaymentDiscountingEngine(yts, fx));
80 fee->setPricingEngine(discountingEngine);
81
82 // 1) Add to additional instruments for pricing
83 addInstruments.push_back(fee);
84
85 // 2) Add a trade leg for cash flow reporting, divide the amount by the multiplier, because the leg entries
86 // are multiplied with the trade multiplier in the cashflow report (and if used elsewhere)
87 legs_.push_back(
88 Leg(1, QuantLib::ext::make_shared<SimpleCashFlow>(fee->cashFlow()->amount() * premiumMultiplier / tradeMultiplier,
89 fee->cashFlow()->date())));
90 legCurrencies_.push_back(fee->currency().code());
91
92 // premium * premiumMultiplier reflects the correct pay direction, set payer to false therefore
93 legPayers_.push_back(false);
94
95 // update latest premium pay date
96 latestPremiumPayDate = std::max(latestPremiumPayDate, d.payDate);
97
98 DLOG("added fee " << d.amount << " " << d.ccy << " payable on " << d.payDate << " to trade");
99 }
100
101 return latestPremiumPayDate;
102}
103
104void Trade::validate() const {
105 QL_REQUIRE(id_ != "", "Trade id has not been set.");
106 QL_REQUIRE(tradeType_ != "", "Trade id has not been set.");
107 QL_REQUIRE(instrument_ || legs_.size() > 0,
108 "Trade " << id_ << " requires either QuantLib instruments or legs to be created.");
109 QL_REQUIRE(npvCurrency_ != "", "NPV currency has not been set for trade " << id_ << ".");
110 // QL_REQUIRE(notional_ != Null<Real>(), "Notional has not been set for trade " << id_ << ".");
111 // QL_REQUIRE(notionalCurrency_ != "", "Notional currency has not been set for trade " << id_ << ".");
112 QL_REQUIRE(maturity_ != Null<Date>(), "Maturity not set for trade " << id_ << ".");
113 QL_REQUIRE(envelope_.initialized(), "Envelope not set for trade " << id_ << ".");
114 if (legs_.size() > 0) {
115 QL_REQUIRE(legs_.size() == legPayers_.size(),
116 "Inconsistent number of pay/receive indicators for legs in trade " << id_ << ".");
117 QL_REQUIRE(legs_.size() == legCurrencies_.size(),
118 "Inconsistent number of leg currencies for legs in trade " << id_ << ".");
119 }
120}
121
122void Trade::setEnvelope(const Envelope& envelope) {
124}
125
126void Trade::setAdditionalData(const std::map<std::string, boost::any>& additionalData) {
128}
129
131 // save accumulated timings from wrapper to trade before resetting
132 if (instrument_ != nullptr) {
133 savedNumberOfPricings_ += instrument_->getNumberOfPricings();
134 savedCumulativePricingTime_ += instrument_->getCumulativePricingTime();
135 }
136 // reset members
137 instrument_ = QuantLib::ext::shared_ptr<InstrumentWrapper>();
138 legs_.clear();
139 legCurrencies_.clear();
140 legPayers_.clear();
141 npvCurrency_.clear();
142 notional_ = Null<Real>();
143 notionalCurrency_.clear();
144 maturity_ = Date();
145 issuer_.clear();
147 sensitivityTemplate_.clear();
149}
150
151const std::map<std::string, boost::any>& Trade::additionalData() const { return additionalData_; }
152
153void Trade::setLegBasedAdditionalData(const Size i, Size resultLegId) const {
154 if (legs_.size() < i + 1)
155 return;
156 Date asof = Settings::instance().evaluationDate();
157 string legID = std::to_string(resultLegId == Null<Size>() ? i + 1 : resultLegId);
158 for (Size j = 0; j < legs_[i].size(); ++j) {
159 QuantLib::ext::shared_ptr<CashFlow> flow = legs_[i][j];
160 // pick flow with earliest future payment date on this leg
161 if (flow->date() > asof) {
162 Real flowAmount = 0.0;
163 try {
164 flowAmount = flow->amount();
165 } catch (std::exception& e) {
166 ALOG("flow amount could not be determined for trade " << id() << ", set to zero: " << e.what());
167 }
168 additionalData_["amount[" + legID + "]"] = flowAmount;
169 additionalData_["paymentDate[" + legID + "]"] = ore::data::to_string(flow->date());
170 QuantLib::ext::shared_ptr<Coupon> coupon = QuantLib::ext::dynamic_pointer_cast<Coupon>(flow);
171 if (coupon) {
172 Real currentNotional = 0;
173 try {
174 currentNotional = coupon->nominal();
175 } catch (std::exception& e) {
176 ALOG("current notional could not be determined for trade " << id()
177 << ", set to zero: " << e.what());
178 }
179 additionalData_["currentNotional[" + legID + "]"] = currentNotional;
180
181 Real rate = 0;
182 try {
183 rate = coupon->rate();
184 } catch (std::exception& e) {
185 ALOG("coupon rate could not be determined for trade " << id() << ", set to zero: " << e.what());
186 }
187 additionalData_["rate[" + legID + "]"] = rate;
188
189 if (auto frc = QuantLib::ext::dynamic_pointer_cast<FloatingRateCoupon>(flow)) {
190 additionalData_["index[" + legID + "]"] = frc->index()->name();
191 additionalData_["spread[" + legID + "]"] = frc->spread();
192 }
193
194 if (auto eqc = QuantLib::ext::dynamic_pointer_cast<QuantExt::EquityCoupon>(flow)) {
195 auto arc = eqc->pricer()->additionalResultCache();
196 additionalData_["initialPrice[" + legID + "]"] = arc.initialPrice;
197 additionalData_["endEquityFixing[" + legID + "]"] = arc.endFixing;
198 if (arc.startFixing != Null<Real>())
199 additionalData_["startEquityFixing[" + legID + "]"] = arc.startFixing;
200 if (arc.startFixingTotal != Null<Real>())
201 additionalData_["startEquityFixingTotal[" + legID + "]"] =
202 arc.startFixingTotal;
203 if (arc.endFixingTotal != Null<Real>())
204 additionalData_["endEquityFixingTotal[" + legID + "]"] = arc.endFixingTotal;
205 if (arc.startFxFixing != Null<Real>())
206 additionalData_["startFxFixing[" + legID + "]"] = arc.startFxFixing;
207 if (arc.endFxFixing != Null<Real>())
208 additionalData_["endFxFixing[" + legID + "]"] = arc.endFxFixing;
209 if (arc.pastDividends != Null<Real>())
210 additionalData_["pastDividends[" + legID + "]"] = arc.pastDividends;
211 if (arc.forecastDividends != Null<Real>())
212 additionalData_["forecastDividends[" + legID + "]"] = arc.forecastDividends;
213 }
214
215 if (auto cpic = QuantLib::ext::dynamic_pointer_cast<QuantExt::CPICoupon>(flow)) {
216 Real baseCPI;
217 baseCPI = cpic->baseCPI();
218 if (baseCPI == Null<Real>()) {
219 try {
220 baseCPI =
221 QuantLib::CPI::laggedFixing(cpic->cpiIndex(), cpic->baseDate() + cpic->observationLag(),
222 cpic->observationLag(), cpic->observationInterpolation());
223 } catch (std::exception& e) {
224 ALOG("CPICoupon baseCPI could not be interpolated for additional results for trade " << id()
225 << ".")
226 }
227 }
228
229 additionalData_["baseCPI[" + legID + "]"] = baseCPI;
230 } else if (auto cpicf = QuantLib::ext::dynamic_pointer_cast<QuantLib::CPICashFlow>(flow)) {
231 Real baseCPI;
232 baseCPI = cpicf->baseFixing();
233 if (baseCPI == Null<Real>()) {
234 try {
235 baseCPI = QuantLib::CPI::laggedFixing(cpicf->cpiIndex(),
236 cpicf->baseDate() + cpicf->observationLag(),
237 cpicf->observationLag(), cpicf->interpolation());
238 } catch (std::exception& e) {
239 ALOG("CPICashFlow baseCPI could not be interpolated for additional results for trade " << id()
240 << ".")
241 }
242 }
243
244 additionalData_["baseCPI[" + legID + "]"] = baseCPI;
245 }
246 }
247 break;
248 }
249 }
250 if (legs_[i].size() > 0) {
251 QuantLib::ext::shared_ptr<Coupon> coupon = QuantLib::ext::dynamic_pointer_cast<Coupon>(legs_[i][0]);
252 if (coupon) {
253 Real originalNotional = 0.0;
254 try {
255 originalNotional = coupon->nominal();
256 } catch (std::exception& e) {
257 ALOG("original nominal could not be determined for trade " << id() << ", set to zero: " << e.what());
258 }
259 additionalData_["originalNotional[" + legID + "]"] = originalNotional;
260 if (auto eqc = QuantLib::ext::dynamic_pointer_cast<QuantExt::EquityCoupon>(coupon)) {
261 Real quantity = eqc->quantity();
262 if (quantity == Null<Real>()) {
263 if (eqc->legInitialNotional() != Null<Real>() && eqc->initialPrice() != Null<Real>()) {
264 quantity = eqc->legInitialNotional() / eqc->initialPrice();
265 }
266 }
267 additionalData_["initialQuantity[" + legID + "]"] = quantity;
268
269 Real currentPrice = Null<Real>();
270 if (eqc->equityCurve()->isValidFixingDate(asof)) {
271 currentPrice = eqc->equityCurve()->equitySpot()->value();
272 }
273 if (currentPrice != Null<Real>() && originalNotional != Null<Real>()) {
274 additionalData_["currentQuantity" + legID + "]"] = originalNotional / currentPrice;
275 }
276 }
277 }
278 }
279 for (Size j = 0; j < legs_[i].size(); ++j) {
280 QuantLib::ext::shared_ptr<CashFlow> flow = legs_[i][j];
281 if (flow->date() > asof) {
282 Size k = 0;
283 for (auto const& [fixingDate, index, multiplier] :
285 auto label = "[" + legID + "][" + std::to_string(j) + "][" + std::to_string(k) + "]";
286 additionalData_["indexingFixingDate" + label] = fixingDate;
287 additionalData_["indexingIndex" + label] =
288 index == nullptr ? "na" : IndexNameTranslator::instance().oreName(index->name());
289 additionalData_["indexingMultiplier" + label] = multiplier;
290 }
291 }
292 }
293}
294
296 sensitivityTemplate_ = builder.engineParameter("SensitivityTemplate", {}, false, std::string());
298}
299
300void Trade::setSensitivityTemplate(const std::string& id) {
303}
304
305const std::string& Trade::sensitivityTemplate() const {
308 id(), tradeType(), "No valid sensitivty template.",
309 "Either build() was not called, or the trade builder did not set the sensitivity template.")
310 .log();
311 }
313}
314
315} // namespace data
316} // namespace ore
Base PricingEngine Builder class for a specific model and engine.
std::string engineParameter(const std::string &p, const std::vector< std::string > &qualifiers={}, const bool mandatory=true, const std::string &defaultValue="") const
Serializable object holding generic trade data, reporting dimensions.
Definition: envelope.hpp:51
virtual void fromXML(XMLNode *node) override
Definition: envelope.cpp:27
virtual XMLNode * toXML(XMLDocument &doc) const override
Definition: envelope.cpp:75
bool initialized() const
Check if the envelope is initialized.
Definition: envelope.hpp:116
void log() const
generate Boost log record to pass to corresponding sinks
Definition: log.cpp:491
Serializable object holding premium data.
Definition: premiumdata.hpp:37
const std::vector< PremiumDatum > & premiumData() const
Definition: premiumdata.hpp:57
Utility classes for Structured warnings, contains the Trade ID and Type.
bool empty() const
Returns true of this set of actions is empty.
virtual void fromXML(XMLNode *node) override
virtual XMLNode * toXML(XMLDocument &doc) const override
void clear()
Clear the trade actions.
string npvCurrency_
Definition: trade.hpp:201
void setEnvelope(const Envelope &envelope)
Set the envelope with counterparty and portfolio info.
Definition: trade.cpp:122
const std::string & sensitivityTemplate() const
Definition: trade.cpp:305
std::vector< bool > legPayers_
Definition: trade.hpp:200
string sensitivityTemplate_
Definition: trade.hpp:206
std::vector< string > legCurrencies_
Definition: trade.hpp:199
string issuer_
Definition: trade.hpp:205
std::vector< QuantLib::Leg > legs_
Definition: trade.hpp:198
TradeActions tradeActions_
Definition: trade.hpp:238
QuantLib::Real notional_
Definition: trade.hpp:202
virtual void fromXML(XMLNode *node) override
Definition: trade.cpp:34
Date addPremiums(std::vector< QuantLib::ext::shared_ptr< Instrument > > &instruments, std::vector< Real > &multipliers, const Real tradeMultiplier, const PremiumData &premiumData, const Real premiumMultiplier, const Currency &tradeCurrency, const QuantLib::ext::shared_ptr< EngineFactory > &factory, const string &configuration)
Definition: trade.cpp:58
void setSensitivityTemplate(const EngineBuilder &builder)
Definition: trade.cpp:295
virtual XMLNode * toXML(XMLDocument &doc) const override
Definition: trade.cpp:46
string & id()
Set the trade id.
Definition: trade.hpp:118
string tradeType_
Definition: trade.hpp:196
bool sensitivityTemplateSet_
Definition: trade.hpp:207
virtual const std::map< std::string, boost::any > & additionalData() const
returns all additional data returned by the trade once built
Definition: trade.cpp:151
void setAdditionalData(const std::map< std::string, boost::any > &additionalData)
Definition: trade.cpp:126
RequiredFixings requiredFixings_
Definition: trade.hpp:223
void validate() const
Utility to validate that everything that needs to be set in this base class is actually set.
Definition: trade.cpp:104
const Envelope & envelope() const
Definition: trade.hpp:135
boost::timer::nanosecond_type savedCumulativePricingTime_
Definition: trade.hpp:210
QuantLib::ext::shared_ptr< InstrumentWrapper > instrument_
Definition: trade.hpp:197
Envelope envelope_
Definition: trade.hpp:237
void reset()
Reset trade, clear all base class data. This does not reset accumulated timings for this trade.
Definition: trade.cpp:130
std::size_t savedNumberOfPricings_
Definition: trade.hpp:209
string notionalCurrency_
Definition: trade.hpp:203
const string & tradeType() const
Definition: trade.hpp:133
void setLegBasedAdditionalData(const Size legNo, Size resultLegId=Null< Size >()) const
Definition: trade.cpp:153
std::map< std::string, boost::any > additionalData_
Definition: trade.hpp:224
Small XML Document wrapper class.
Definition: xmlutils.hpp:65
XMLNode * allocNode(const string &nodeName)
util functions that wrap rapidxml
Definition: xmlutils.cpp:132
XML Utilities Class.
Definition: xmlutils.hpp:119
static void addAttribute(XMLDocument &doc, XMLNode *node, const string &attrName, const string &attrValue)
Definition: xmlutils.cpp:412
static void checkNode(XMLNode *n, const string &expectedName)
Definition: xmlutils.cpp:175
static string getChildValue(XMLNode *node, const string &name, bool mandatory=false, const string &defaultValue=string())
Definition: xmlutils.cpp:277
static XMLNode * getChildNode(XMLNode *n, const string &name="")
Definition: xmlutils.cpp:387
static XMLNode * addChild(XMLDocument &doc, XMLNode *n, const string &name)
Definition: xmlutils.cpp:181
static void appendNode(XMLNode *parent, XMLNode *child)
Definition: xmlutils.cpp:406
Currency parseCurrencyWithMinors(const string &s)
Convert text to QuantLib::Currency.
Definition: parsers.cpp:310
QuantLib::Real convertMinorToMajorCurrency(const std::string &s, QuantLib::Real value)
Convert a value from a minor ccy to major.
Definition: parsers.cpp:324
translates between QuantLib::Index::name() and ORE names
@ data
Definition: log.hpp:77
#define DLOG(text)
Logging Macro (Level = Debug)
Definition: log.hpp:554
#define ALOG(text)
Logging Macro (Level = Alert)
Definition: log.hpp:544
QuantLib::Date fixingDate(const QuantLib::Date &d, const QuantLib::Period obsLag, const QuantLib::Frequency freq, bool interpolated)
std::vector< std::tuple< Date, boost::shared_ptr< Index >, Real > > getIndexedCouponOrCashFlowFixingDetails(const boost::shared_ptr< CashFlow > &c)
Real currentNotional(const Leg &leg)
Definition: legdata.cpp:2435
Size size(const ValueType &v)
Definition: value.cpp:145
Real originalNotional(const Leg &leg)
Definition: legdata.cpp:2449
std::string to_string(const LocationInfo &l)
Definition: ast.cpp:28
Serializable Credit Default Swap.
Definition: namespaces.docs:23
Classes for structured trade warnings.
string conversion utilities
base trade data model and serialization