| 1 | /* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
| 2 | |
| 3 | /* |
| 4 | Copyright (C) 2008 J. Erik Radmall |
| 5 | |
| 6 | This file is part of QuantLib, a free-software/open-source library |
| 7 | for financial quantitative analysts and developers - http://quantlib.org/ |
| 8 | |
| 9 | QuantLib is free software: you can redistribute it and/or modify it |
| 10 | under the terms of the QuantLib license. You should have received a |
| 11 | copy of the license along with this program; if not, please email |
| 12 | <quantlib-dev@lists.sf.net>. The license is also available online at |
| 13 | <http://quantlib.org/license.shtml>. |
| 14 | |
| 15 | This program is distributed in the hope that it will be useful, but WITHOUT |
| 16 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
| 17 | FOR A PARTICULAR PURPOSE. See the license for more details. |
| 18 | */ |
| 19 | |
| 20 | /*! \file commodityindex.hpp |
| 21 | \brief Commodity index |
| 22 | */ |
| 23 | |
| 24 | #ifndef quantlib_commodity_index_hpp |
| 25 | #define quantlib_commodity_index_hpp |
| 26 | |
| 27 | #include <ql/experimental/commodities/commoditycurve.hpp> |
| 28 | #include <ql/indexes/indexmanager.hpp> |
| 29 | |
| 30 | namespace QuantLib { |
| 31 | |
| 32 | class TermStructure; |
| 33 | |
| 34 | //! base class for commodity indexes |
| 35 | class CommodityIndex : public Observable, |
| 36 | public Observer { |
| 37 | public: |
| 38 | CommodityIndex(const std::string& name, |
| 39 | CommodityType commodityType, |
| 40 | Currency currency, |
| 41 | UnitOfMeasure unitOfMeasure, |
| 42 | Calendar calendar, |
| 43 | Real lotQuantity, |
| 44 | ext::shared_ptr<CommodityCurve> forwardCurve, |
| 45 | ext::shared_ptr<ExchangeContracts> exchangeContracts, |
| 46 | int nearbyOffset); |
| 47 | //! \name Index interface |
| 48 | //@{ |
| 49 | std::string name() const; |
| 50 | //@} |
| 51 | //! \name Observer interface |
| 52 | //@{ |
| 53 | void update() override; |
| 54 | //@} |
| 55 | //! \name Inspectors |
| 56 | //@{ |
| 57 | const CommodityType& commodityType() const; |
| 58 | const Currency& currency() const; |
| 59 | const UnitOfMeasure& unitOfMeasure() const; |
| 60 | const Calendar& calendar() const; |
| 61 | const ext::shared_ptr<CommodityCurve>& forwardCurve() const; |
| 62 | Real lotQuantity() const; |
| 63 | |
| 64 | Real price(const Date& date); |
| 65 | Real forwardPrice(const Date& date) const; |
| 66 | Date lastQuoteDate() const; |
| 67 | //@} |
| 68 | void addQuote(const Date& quoteDate, Real quote); |
| 69 | |
| 70 | void addQuotes(const std::map<Date, Real>& quotes) { |
| 71 | std::string tag = name(); |
| 72 | quotes_ = IndexManager::instance().getHistory(name: tag); |
| 73 | for (auto quote : quotes) { |
| 74 | quotes_[quote.first] = quote.second; |
| 75 | } |
| 76 | IndexManager::instance().setHistory(name: tag, history: quotes_); |
| 77 | } |
| 78 | |
| 79 | void clearQuotes() const; |
| 80 | //! returns TRUE if the quote date is valid |
| 81 | bool isValidQuoteDate(const Date& quoteDate) const; |
| 82 | bool empty() const; |
| 83 | bool forwardCurveEmpty() const; |
| 84 | const TimeSeries<Real>& quotes() const; |
| 85 | |
| 86 | friend std::ostream& operator<<(std::ostream&, const CommodityIndex&); |
| 87 | protected: |
| 88 | std::string name_; |
| 89 | CommodityType commodityType_; |
| 90 | UnitOfMeasure unitOfMeasure_; |
| 91 | Currency currency_; |
| 92 | Calendar calendar_; |
| 93 | Real lotQuantity_; |
| 94 | TimeSeries<Real> quotes_; |
| 95 | ext::shared_ptr<CommodityCurve> forwardCurve_; |
| 96 | Real forwardCurveUomConversionFactor_ = 1; |
| 97 | ext::shared_ptr<ExchangeContracts> exchangeContracts_; |
| 98 | Integer nearbyOffset_; |
| 99 | }; |
| 100 | |
| 101 | |
| 102 | // inline definitions |
| 103 | |
| 104 | inline bool operator==(const CommodityIndex& i1, const CommodityIndex& i2) { |
| 105 | return i1.name() == i2.name(); |
| 106 | } |
| 107 | |
| 108 | inline void CommodityIndex::update() { |
| 109 | notifyObservers(); |
| 110 | } |
| 111 | |
| 112 | inline std::string CommodityIndex::name() const { |
| 113 | return name_; |
| 114 | } |
| 115 | |
| 116 | inline const CommodityType& CommodityIndex::commodityType() const { |
| 117 | return commodityType_; |
| 118 | } |
| 119 | |
| 120 | inline const UnitOfMeasure& CommodityIndex::unitOfMeasure() const { |
| 121 | return unitOfMeasure_; |
| 122 | } |
| 123 | |
| 124 | inline const Currency& CommodityIndex::currency() const { |
| 125 | return currency_; |
| 126 | } |
| 127 | |
| 128 | inline const Calendar& CommodityIndex::calendar() const { |
| 129 | return calendar_; |
| 130 | } |
| 131 | |
| 132 | inline Real CommodityIndex::lotQuantity() const { |
| 133 | return lotQuantity_; |
| 134 | } |
| 135 | |
| 136 | inline const ext::shared_ptr<CommodityCurve>& |
| 137 | CommodityIndex::forwardCurve() const { |
| 138 | return forwardCurve_; |
| 139 | } |
| 140 | |
| 141 | inline const TimeSeries<Real>& CommodityIndex::quotes() const { |
| 142 | return quotes_; |
| 143 | } |
| 144 | |
| 145 | inline Real CommodityIndex::price(const Date& date) { |
| 146 | auto hq = quotes_.find(d: date); |
| 147 | if (hq->second == Null<Real>()) { |
| 148 | ++hq; |
| 149 | if (hq == quotes_.end()) |
| 150 | //if (hq->second == Null<Real>()) |
| 151 | return Null<Real>(); |
| 152 | } |
| 153 | return hq->second; |
| 154 | } |
| 155 | |
| 156 | inline Real CommodityIndex::forwardPrice(const Date& date) const { |
| 157 | try { |
| 158 | Real forwardPrice = |
| 159 | forwardCurve_->price(d: date, exchangeContracts: exchangeContracts_, nearbyOffset: nearbyOffset_); |
| 160 | return forwardPrice * forwardCurveUomConversionFactor_; |
| 161 | } catch (const std::exception& e) { |
| 162 | QL_FAIL("error fetching forward price for index " << name_ |
| 163 | << ": " << e.what()); |
| 164 | } |
| 165 | } |
| 166 | |
| 167 | inline Date CommodityIndex::lastQuoteDate() const { |
| 168 | if (quotes_.empty()) |
| 169 | return Date::minDate(); |
| 170 | return quotes_.lastDate(); |
| 171 | } |
| 172 | |
| 173 | inline bool CommodityIndex::empty() const { |
| 174 | return quotes_.empty(); |
| 175 | } |
| 176 | |
| 177 | inline bool CommodityIndex::forwardCurveEmpty() const { |
| 178 | if (forwardCurve_ != nullptr) |
| 179 | return forwardCurve_->empty(); |
| 180 | return false; |
| 181 | } |
| 182 | |
| 183 | inline void CommodityIndex::addQuote(const Date& quoteDate, Real quote) { |
| 184 | //QL_REQUIRE(isValidQuoteDate(quoteDate), |
| 185 | // "Quote date " << quoteDate.weekday() << ", " << |
| 186 | // quoteDate << " is not valid"); |
| 187 | std::string tag = name(); |
| 188 | quotes_ = IndexManager::instance().getHistory(name: tag); |
| 189 | quotes_[quoteDate] = quote; |
| 190 | IndexManager::instance().setHistory(name: tag, history: quotes_); |
| 191 | } |
| 192 | |
| 193 | inline void CommodityIndex::clearQuotes() const { |
| 194 | IndexManager::instance().clearHistory(name: name()); |
| 195 | } |
| 196 | |
| 197 | inline bool CommodityIndex::isValidQuoteDate(const Date& quoteDate) const { |
| 198 | return calendar().isBusinessDay(d: quoteDate); |
| 199 | } |
| 200 | |
| 201 | } |
| 202 | |
| 203 | #endif |
| 204 | |