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