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 <boost/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,boost::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; 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 virtual void performCalculations() const; 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,boost::any> additionalResults_; 109 //@} 110 ext::shared_ptr<PricingEngine> engine_; 111 }; 112 113 class Instrument::results : public virtual PricingEngine::results { 114 public: reset()115 void reset() { 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,boost::any> additionalResults; 124 }; 125 126 127 // inline definitions 128 Instrument()129 inline Instrument::Instrument() 130 : NPV_(Null<Real>()), errorEstimate_(Null<Real>()), 131 valuationDate_(Date()) {} 132 setPricingEngine(const ext::shared_ptr<PricingEngine> & e)133 inline void Instrument::setPricingEngine( 134 const ext::shared_ptr<PricingEngine>& e) { 135 if (engine_ != 0) 136 unregisterWith(engine_); 137 engine_ = e; 138 if (engine_ != 0) 139 registerWith(engine_); 140 // trigger (lazy) recalculation and notify observers 141 update(); 142 } 143 setupArguments(PricingEngine::arguments *) const144 inline void Instrument::setupArguments(PricingEngine::arguments*) const { 145 QL_FAIL("Instrument::setupArguments() not implemented"); 146 } 147 calculate() const148 inline void Instrument::calculate() const { 149 if (!calculated_) { 150 if (isExpired()) { 151 setupExpired(); 152 calculated_ = true; 153 } else { 154 LazyObject::calculate(); 155 } 156 } 157 } 158 setupExpired() const159 inline void Instrument::setupExpired() const { 160 NPV_ = errorEstimate_ = 0.0; 161 valuationDate_ = Date(); 162 additionalResults_.clear(); 163 } 164 performCalculations() const165 inline void Instrument::performCalculations() const { 166 QL_REQUIRE(engine_, "null pricing engine"); 167 engine_->reset(); 168 setupArguments(engine_->getArguments()); 169 engine_->getArguments()->validate(); 170 engine_->calculate(); 171 fetchResults(engine_->getResults()); 172 } 173 fetchResults(const PricingEngine::results * r) const174 inline void Instrument::fetchResults( 175 const PricingEngine::results* r) const { 176 const Instrument::results* results = 177 dynamic_cast<const Instrument::results*>(r); 178 QL_ENSURE(results != 0, 179 "no results returned from pricing engine"); 180 181 NPV_ = results->value; 182 errorEstimate_ = results->errorEstimate; 183 valuationDate_ = results->valuationDate; 184 185 additionalResults_ = results->additionalResults; 186 } 187 NPV() const188 inline Real Instrument::NPV() const { 189 calculate(); 190 QL_REQUIRE(NPV_ != Null<Real>(), "NPV not provided"); 191 return NPV_; 192 } 193 errorEstimate() const194 inline Real Instrument::errorEstimate() const { 195 calculate(); 196 QL_REQUIRE(errorEstimate_ != Null<Real>(), 197 "error estimate not provided"); 198 return errorEstimate_; 199 } 200 valuationDate() const201 inline const Date& Instrument::valuationDate() const { 202 calculate(); 203 QL_REQUIRE(valuationDate_ != Date(), 204 "valuation date not provided"); 205 return valuationDate_; 206 } 207 208 template <class T> result(const std::string & tag) const209 inline T Instrument::result(const std::string& tag) const { 210 calculate(); 211 std::map<std::string,boost::any>::const_iterator value = 212 additionalResults_.find(tag); 213 QL_REQUIRE(value != additionalResults_.end(), 214 tag << " not provided"); 215 return boost::any_cast<T>(value->second); 216 } 217 218 inline const std::map<std::string,boost::any>& additionalResults() const219 Instrument::additionalResults() const { 220 return additionalResults_; 221 } 222 223 } 224 225 #endif 226