Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
commodityposition.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2023 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
24namespace ore {
25namespace data {
26
28 XMLUtils::checkNode(node, "CommodityPositionData");
29 quantity_ = XMLUtils::getChildValueAsDouble(node, "Quantity", true);
30 auto c = XMLUtils::getChildrenNodes(node, "Underlying");
31 underlyings_.clear();
32 for (auto const n : c) {
34 underlyings_.back().fromXML(n);
35 }
36}
37
39 XMLNode* n = doc.allocNode("CommodityPositionData");
40 XMLUtils::addChild(doc, n, "Quantity", quantity_);
41 for (auto& u : underlyings_) {
42 XMLUtils::appendNode(n, u.toXML(doc));
43 }
44 return n;
45}
46
47void CommodityPosition::build(const QuantLib::ext::shared_ptr<ore::data::EngineFactory>& engineFactory) {
48
49 // ISDA taxonomy: not a derivative, but define the asset class at least
50 // so that we can determine a TRS asset class that has an EQ position underlying
51 additionalData_["isdaAssetClass"] = string("Commodity");
52 additionalData_["isdaBaseProduct"] = string("");
53 additionalData_["isdaSubProduct"] = string("");
54 additionalData_["isdaTransaction"] = string("");
55
56 DLOG("CommodityPosition::build() called for " << id());
57 QL_REQUIRE(!data_.underlyings().empty(), "CommodityPosition::build(): no underlyings given");
58 indices_.clear();
59 weights_.clear();
60 fxConversion_.clear();
61
62 std::vector<std::string> currencies;
63 for (auto const& u : data_.underlyings()) {
64 auto pts = engineFactory->market()->commodityPriceCurve(u.name(), engineFactory->configuration(MarketContext::pricing));
65 QL_REQUIRE(!pts.empty() && *pts != nullptr, "CommodityPosition, curve missing for '"<<u.name()<<"'");
66 QL_REQUIRE(!pts->currency().empty(),
67 "CommodityPosition, Currency not set in curve config for commodity curve'" << u.name() << "'. Skip this trade.");
68 auto index = parseCommodityIndex(u.name(), false, pts, NullCalendar(), u.priceType() == "FutureSettlement");
69 QuantLib::ext::shared_ptr<Conventions> conventions = InstrumentConventions::instance().conventions();
70 pair<bool, QuantLib::ext::shared_ptr<Convention>> p = conventions->get(u.name(), Convention::Type::CommodityFuture);
71 if (u.priceType() == "FutureSettlement" && p.first) {
72 auto convention = QuantLib::ext::dynamic_pointer_cast<CommodityFutureConvention>(p.second);
73 ConventionsBasedFutureExpiry feCalc(*convention);
74 Date expiry = Settings::instance().evaluationDate();
75 Size nOffset = u.futureMonthOffset() == Null<Size>() ? 0 : u.futureMonthOffset();
76 if (u.deliveryRollDays() != Null<Size>()) {
77 auto cal =
78 u.deliveryRollCalendar().empty() ? convention->calendar() : parseCalendar(u.deliveryRollCalendar());
79 expiry = cal.advance(expiry, u.deliveryRollDays() * Days, convention->businessDayConvention());
80 }
81 expiry = feCalc.nextExpiry(true, expiry, nOffset);
82 if (!u.futureContractMonth().empty()) {
83 QL_REQUIRE(u.futureContractMonth().size() == 7,
84 "FutureContractMonth has invalid format, please use MonYYYY, where 'Mon' is a 3 letter "
85 "month abbreviation.");
86 auto month = parseMonth(u.futureContractMonth().substr(0, 3));
87 auto year = parseInteger(u.futureContractMonth().substr(3, 4));
88 Date contractDate(1, month, year);
89 expiry = feCalc.expiryDate(contractDate, nOffset, false);
90 } else if (!u.futureExpiryDate().empty()) {
91 expiry = parseDate(u.futureExpiryDate());
92 expiry = feCalc.nextExpiry(true, expiry, nOffset, false);
93 }
94 index = index->clone(expiry, pts);
95 }
96 indices_.push_back(index);
97 weights_.push_back(u.weight());
98 currencies.push_back(pts->currency().code());
99 }
100
101 // get fx quotes
102
103 isSingleCurrency_ = true;
104 npvCurrency_ = currencies.front();
105 for (auto const& c : currencies) {
106 // we use fxSpot() as opposed to fxRate() here to ensure consistency between NPV() and the fixing of an
107 // equivalent index representing the same basket
108 fxConversion_.push_back(
109 engineFactory->market()->fxSpot(c + npvCurrency_, engineFactory->configuration(MarketContext::pricing)));
110 if (npvCurrency_ != c)
111 isSingleCurrency_ = false;
112 }
113
114 // set instrument
115 auto qlInstr =
116 QuantLib::ext::make_shared<CommodityPositionInstrumentWrapper>(data_.quantity(), indices_, weights_, fxConversion_);
117 qlInstr->setPricingEngine(QuantLib::ext::make_shared<CommodityPositionInstrumentWrapperEngine>());
118 setSensitivityTemplate(std::string());
119 instrument_ = QuantLib::ext::make_shared<VanillaInstrument>(qlInstr);
120
121 // no sensible way to set these members
122 maturity_ = Date::maxDate();
123 notional_ = Null<Real>();
125
126 // leave legs empty
127}
128
129void CommodityPosition::setNpvCurrencyConversion(const std::string& ccy, const Handle<Quote>& conversion) {
130 npvCurrency_ = ccy;
131 QuantLib::ext::static_pointer_cast<CommodityPositionInstrumentWrapper>(instrument_->qlInstrument())
132 ->setNpvCurrencyConversion(conversion);
133}
134
136 Trade::fromXML(node);
137 data_.fromXML(XMLUtils::getChildNode(node, "CommodityPositionData"));
138}
139
141 XMLNode* node = Trade::toXML(doc);
142 XMLUtils::appendNode(node, data_.toXML(doc));
143 return node;
144}
145
146std::map<AssetClass, std::set<std::string>>
147CommodityPosition::underlyingIndices(const QuantLib::ext::shared_ptr<ReferenceDataManager>& referenceDataManager) const {
148 std::map<AssetClass, std::set<std::string>> result;
149 for (auto const& u : data_.underlyings()) {
150 result[AssetClass::COM].insert(u.name());
151 }
152 return result;
153}
154
156 const Real quantity, const std::vector<QuantLib::ext::shared_ptr<QuantExt::CommodityIndex>>& commodities,
157 const std::vector<Real>& weights, const std::vector<Handle<Quote>>& fxConversion)
158 : quantity_(quantity), commodities_(commodities), weights_(weights), fxConversion_(fxConversion) {
159 QL_REQUIRE(commodities_.size() == weights_.size(), "CommodityPositionInstrumentWrapper: commodities size ("
160 << commodities_.size() << ") must match weights size ("
161 << weights_.size() << ")");
162 QL_REQUIRE(fxConversion_.empty() || fxConversion_.size() == commodities_.size(),
163 "CommodityPositionInstrumentWrapper: fxConversion size ("
164 << fxConversion_.size() << ") must match commodities size (" << commodities_.size() << ")");
165 for (auto const& i : commodities_)
166 registerWith(i);
167 for (auto const& f : fxConversion_)
168 registerWith(f);
169 registerWith(npvCcyConversion_);
170}
171
172void CommodityPositionInstrumentWrapper::setNpvCurrencyConversion(const Handle<Quote>& npvCcyConversion) {
173 npvCcyConversion_ = npvCcyConversion;
174}
175
177
178void CommodityPositionInstrumentWrapper::setupExpired() const { Instrument::setupExpired(); }
179
180void CommodityPositionInstrumentWrapper::setupArguments(PricingEngine::arguments* args) const {
182 QL_REQUIRE(a != nullptr, "wrong argument type in CommodityPositionInstrumentWrapper");
183 a->quantity_ = quantity_;
185 a->weights_ = weights_;
188}
189
190void CommodityPositionInstrumentWrapper::fetchResults(const PricingEngine::results* r) const {
191 Instrument::fetchResults(r);
192}
193
195 Real result = 0.0;
196 Date today = Settings::instance().evaluationDate();
197 for (Size i = 0; i < arguments_.commodities_.size(); ++i) {
198 // TODO: if refering spot price need lookup the spot date instead of today
199 // for future settlement the fixing date is not relvant, always lookup future expiry date
200 Real tmp = arguments_.quantity_ * arguments_.commodities_[i]->fixing(today, true);
201 if (!arguments_.fxConversion_[i].empty()) {
202 tmp *= arguments_.fxConversion_[i]->value();
203 }
204 result += tmp * arguments_.weights_[i];
205 }
206 if (!arguments_.npvCcyConversion_.empty()) {
207 result *= arguments_.npvCcyConversion_->value();
208 }
209 results_.value = result;
210}
211
212} // namespace data
213} // namespace ore
const Instrument::results * results_
const std::vector< CommodityUnderlying > & underlyings() const
void fromXML(XMLNode *node) override
XMLNode * toXML(XMLDocument &doc) const override
std::vector< CommodityUnderlying > underlyings_
std::vector< QuantLib::ext::shared_ptr< QuantExt::CommodityIndex > > indices_
std::map< AssetClass, std::set< std::string > > underlyingIndices(const QuantLib::ext::shared_ptr< ReferenceDataManager > &referenceDataManager=nullptr) const override
void fromXML(XMLNode *node) override
std::vector< Handle< Quote > > fxConversion_
void setNpvCurrencyConversion(const std::string &ccy, const Handle< Quote > &conversion)
XMLNode * toXML(XMLDocument &doc) const override
void build(const QuantLib::ext::shared_ptr< ore::data::EngineFactory > &) override
std::vector< QuantLib::ext::shared_ptr< QuantExt::CommodityIndex > > commodities_
void fetchResults(const QuantLib::PricingEngine::results *) const override
std::vector< QuantLib::ext::shared_ptr< QuantExt::CommodityIndex > > commodities_
void setupArguments(QuantLib::PricingEngine::arguments *) const override
CommodityPositionInstrumentWrapper(const Real quantity, const std::vector< QuantLib::ext::shared_ptr< QuantExt::CommodityIndex > > &commodities, const std::vector< Real > &weights, const std::vector< Handle< Quote > > &fxConversion={})
void setNpvCurrencyConversion(const Handle< Quote > &npvCcyConversion)
Perform date calculations for future contracts based on conventions.
QuantLib::Date nextExpiry(bool includeExpiry=true, const QuantLib::Date &referenceDate=QuantLib::Date(), QuantLib::Natural offset=0, bool forOption=false) override
QuantLib::Date expiryDate(const QuantLib::Date &contractDate, QuantLib::Natural monthOffset=0, bool forOption=false) override
string npvCurrency_
Definition: trade.hpp:201
QuantLib::Real notional_
Definition: trade.hpp:202
virtual void fromXML(XMLNode *node) override
Definition: trade.cpp:34
void setSensitivityTemplate(const EngineBuilder &builder)
Definition: trade.cpp:295
virtual XMLNode * toXML(XMLDocument &doc) const override
Definition: trade.cpp:46
QuantLib::ext::shared_ptr< InstrumentWrapper > instrument_
Definition: trade.hpp:197
string notionalCurrency_
Definition: trade.hpp:203
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
static void checkNode(XMLNode *n, const string &expectedName)
Definition: xmlutils.cpp:175
static vector< XMLNode * > getChildrenNodes(XMLNode *node, const string &name)
Returns all the children with a given name.
Definition: xmlutils.cpp:428
static Real getChildValueAsDouble(XMLNode *node, const string &name, bool mandatory=false, double defaultValue=0.0)
Definition: xmlutils.cpp:286
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
Commodity Position trade data model and serialization.
Base class for classes that perform date calculations for future contracts.
Calendar parseCalendar(const string &s)
Convert text to QuantLib::Calendar.
Definition: parsers.cpp:157
Month parseMonth(const string &s)
Definition: parsers.cpp:613
Date parseDate(const string &s)
Convert std::string to QuantLib::Date.
Definition: parsers.cpp:51
Integer parseInteger(const string &s)
Convert text to QuantLib::Integer.
Definition: parsers.cpp:136
Map text representations to QuantLib/QuantExt types.
@ data
Definition: log.hpp:77
#define DLOG(text)
Logging Macro (Level = Debug)
Definition: log.hpp:554
QuantLib::ext::shared_ptr< QuantExt::CommodityIndex > parseCommodityIndex(const string &name, bool hasPrefix, const Handle< PriceTermStructure > &ts, const Calendar &cal, const bool enforceFutureIndex)
Serializable Credit Default Swap.
Definition: namespaces.docs:23
Swap::arguments * arguments_
Trade Factory.