| 1 | /* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
| 2 | |
| 3 | /* |
| 4 | Copyright (C) 2000, 2001, 2002, 2003 RiskMap srl |
| 5 | Copyright (C) 2003, 2004, 2005, 2006, 2007 StatPro Italia srl |
| 6 | |
| 7 | This file is part of QuantLib, a free-software/open-source library |
| 8 | for financial quantitative analysts and developers - http://quantlib.org/ |
| 9 | |
| 10 | QuantLib is free software: you can redistribute it and/or modify it |
| 11 | under the terms of the QuantLib license. You should have received a |
| 12 | copy of the license along with this program; if not, please email |
| 13 | <quantlib-dev@lists.sf.net>. The license is also available online at |
| 14 | <http://quantlib.org/license.shtml>. |
| 15 | |
| 16 | This program is distributed in the hope that it will be useful, but WITHOUT |
| 17 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
| 18 | FOR A PARTICULAR PURPOSE. See the license for more details. |
| 19 | */ |
| 20 | |
| 21 | /*! \file instrument.hpp |
| 22 | \brief Abstract instrument class |
| 23 | */ |
| 24 | |
| 25 | #ifndef quantlib_instrument_hpp |
| 26 | #define quantlib_instrument_hpp |
| 27 | |
| 28 | #include <ql/patterns/lazyobject.hpp> |
| 29 | #include <ql/pricingengine.hpp> |
| 30 | #include <ql/utilities/null.hpp> |
| 31 | #include <ql/time/date.hpp> |
| 32 | #include <ql/any.hpp> |
| 33 | #include <map> |
| 34 | #include <string> |
| 35 | |
| 36 | namespace QuantLib { |
| 37 | |
| 38 | //! Abstract instrument class |
| 39 | /*! This class is purely abstract and defines the interface of concrete |
| 40 | instruments which will be derived from this one. |
| 41 | |
| 42 | \test observability of class instances is checked. |
| 43 | */ |
| 44 | class Instrument : public LazyObject { |
| 45 | public: |
| 46 | class results; |
| 47 | Instrument(); |
| 48 | //! \name Inspectors |
| 49 | //@{ |
| 50 | |
| 51 | //! returns the net present value of the instrument. |
| 52 | Real NPV() const; |
| 53 | //! returns the error estimate on the NPV when available. |
| 54 | Real errorEstimate() const; |
| 55 | //! returns the date the net present value refers to. |
| 56 | const Date& valuationDate() const; |
| 57 | |
| 58 | //! returns any additional result returned by the pricing engine. |
| 59 | template <typename T> T result(const std::string& tag) const; |
| 60 | //! returns all additional result returned by the pricing engine. |
| 61 | const std::map<std::string, ext::any>& additionalResults() const; |
| 62 | |
| 63 | //! returns whether the instrument might have value greater than zero. |
| 64 | virtual bool isExpired() const = 0; |
| 65 | //@} |
| 66 | //! \name Modifiers |
| 67 | //@{ |
| 68 | //! set the pricing engine to be used. |
| 69 | /*! \warning calling this method will have no effects in |
| 70 | case the <b>performCalculation</b> method |
| 71 | was overridden in a derived class. |
| 72 | */ |
| 73 | void setPricingEngine(const ext::shared_ptr<PricingEngine>&); |
| 74 | //@} |
| 75 | /*! When a derived argument structure is defined for an |
| 76 | instrument, this method should be overridden to fill |
| 77 | it. This is mandatory in case a pricing engine is used. |
| 78 | */ |
| 79 | virtual void setupArguments(PricingEngine::arguments*) const; |
| 80 | /*! When a derived result structure is defined for an |
| 81 | instrument, this method should be overridden to read from |
| 82 | it. This is mandatory in case a pricing engine is used. |
| 83 | */ |
| 84 | virtual void fetchResults(const PricingEngine::results*) const; |
| 85 | protected: |
| 86 | //! \name Calculations |
| 87 | //@{ |
| 88 | void calculate() const override; |
| 89 | /*! This method must leave the instrument in a consistent |
| 90 | state when the expiration condition is met. |
| 91 | */ |
| 92 | virtual void setupExpired() const; |
| 93 | /*! In case a pricing engine is <b>not</b> used, this |
| 94 | method must be overridden to perform the actual |
| 95 | calculations and set any needed results. In case |
| 96 | a pricing engine is used, the default implementation |
| 97 | can be used. |
| 98 | */ |
| 99 | void performCalculations() const override; |
| 100 | //@} |
| 101 | /*! \name Results |
| 102 | The value of this attribute and any other that derived |
| 103 | classes might declare must be set during calculation. |
| 104 | */ |
| 105 | //@{ |
| 106 | mutable Real NPV_, errorEstimate_; |
| 107 | mutable Date valuationDate_; |
| 108 | mutable std::map<std::string, ext::any> additionalResults_; |
| 109 | //@} |
| 110 | ext::shared_ptr<PricingEngine> engine_; |
| 111 | }; |
| 112 | |
| 113 | class Instrument::results : public virtual PricingEngine::results { |
| 114 | public: |
| 115 | void reset() override { |
| 116 | value = errorEstimate = Null<Real>(); |
| 117 | valuationDate = Date(); |
| 118 | additionalResults.clear(); |
| 119 | } |
| 120 | Real value; |
| 121 | Real errorEstimate; |
| 122 | Date valuationDate; |
| 123 | std::map<std::string, ext::any> additionalResults; |
| 124 | }; |
| 125 | |
| 126 | |
| 127 | // inline definitions |
| 128 | |
| 129 | inline void Instrument::calculate() const { |
| 130 | if (!calculated_) { |
| 131 | if (isExpired()) { |
| 132 | setupExpired(); |
| 133 | calculated_ = true; |
| 134 | } else { |
| 135 | LazyObject::calculate(); |
| 136 | } |
| 137 | } |
| 138 | } |
| 139 | |
| 140 | inline void Instrument::setupExpired() const { |
| 141 | NPV_ = errorEstimate_ = 0.0; |
| 142 | valuationDate_ = Date(); |
| 143 | additionalResults_.clear(); |
| 144 | } |
| 145 | |
| 146 | inline void Instrument::performCalculations() const { |
| 147 | QL_REQUIRE(engine_, "null pricing engine" ); |
| 148 | engine_->reset(); |
| 149 | setupArguments(engine_->getArguments()); |
| 150 | engine_->getArguments()->validate(); |
| 151 | engine_->calculate(); |
| 152 | fetchResults(engine_->getResults()); |
| 153 | } |
| 154 | |
| 155 | inline void Instrument::fetchResults( |
| 156 | const PricingEngine::results* r) const { |
| 157 | const auto* results = dynamic_cast<const Instrument::results*>(r); |
| 158 | QL_ENSURE(results != nullptr, "no results returned from pricing engine" ); |
| 159 | |
| 160 | NPV_ = results->value; |
| 161 | errorEstimate_ = results->errorEstimate; |
| 162 | valuationDate_ = results->valuationDate; |
| 163 | |
| 164 | additionalResults_ = results->additionalResults; |
| 165 | } |
| 166 | |
| 167 | inline Real Instrument::NPV() const { |
| 168 | calculate(); |
| 169 | QL_REQUIRE(NPV_ != Null<Real>(), "NPV not provided" ); |
| 170 | return NPV_; |
| 171 | } |
| 172 | |
| 173 | inline Real Instrument::errorEstimate() const { |
| 174 | calculate(); |
| 175 | QL_REQUIRE(errorEstimate_ != Null<Real>(), |
| 176 | "error estimate not provided" ); |
| 177 | return errorEstimate_; |
| 178 | } |
| 179 | |
| 180 | inline const Date& Instrument::valuationDate() const { |
| 181 | calculate(); |
| 182 | QL_REQUIRE(valuationDate_ != Date(), |
| 183 | "valuation date not provided" ); |
| 184 | return valuationDate_; |
| 185 | } |
| 186 | |
| 187 | template <class T> |
| 188 | inline T Instrument::result(const std::string& tag) const { |
| 189 | calculate(); |
| 190 | std::map<std::string, ext::any>::const_iterator value = |
| 191 | additionalResults_.find(x: tag); |
| 192 | QL_REQUIRE(value != additionalResults_.end(), |
| 193 | tag << " not provided" ); |
| 194 | return ext::any_cast<T>(value->second); |
| 195 | } |
| 196 | |
| 197 | inline const std::map<std::string, ext::any>& |
| 198 | Instrument::additionalResults() const { |
| 199 | calculate(); |
| 200 | return additionalResults_; |
| 201 | } |
| 202 | |
| 203 | } |
| 204 | |
| 205 | #endif |
| 206 | |