/src/quantlib/ql/discretizedasset.hpp
Line | Count | Source |
1 | | /* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | |
3 | | /* |
4 | | Copyright (C) 2001, 2002, 2003 Sadruddin Rejeb |
5 | | Copyright (C) 2004, 2005, 2006 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 | | <https://www.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 discretizedasset.hpp |
22 | | \brief Discretized asset classes |
23 | | */ |
24 | | |
25 | | #ifndef quantlib_discretized_asset_hpp |
26 | | #define quantlib_discretized_asset_hpp |
27 | | |
28 | | #include <ql/exercise.hpp> |
29 | | #include <ql/math/comparison.hpp> |
30 | | #include <ql/numericalmethod.hpp> |
31 | | #include <utility> |
32 | | |
33 | | namespace QuantLib { |
34 | | |
35 | | //! Discretized asset class used by numerical methods |
36 | | class DiscretizedAsset { |
37 | | public: |
38 | | DiscretizedAsset() |
39 | 0 | : latestPreAdjustment_(QL_MAX_REAL), |
40 | 0 | latestPostAdjustment_(QL_MAX_REAL) {} |
41 | 0 | virtual ~DiscretizedAsset() = default; |
42 | | |
43 | | //! \name inspectors |
44 | | //@{ |
45 | 0 | Time time() const { return time_; } |
46 | 0 | Time& time() { return time_; } |
47 | | |
48 | 0 | const Array& values() const { return values_; } |
49 | 0 | Array& values() { return values_; } |
50 | | |
51 | 0 | const ext::shared_ptr<Lattice>& method() const { |
52 | 0 | return method_; |
53 | 0 | } |
54 | | //@} |
55 | | |
56 | | /*! \name High-level interface |
57 | | |
58 | | Users of discretized assets should use these methods in |
59 | | order to initialize, evolve and take the present value of |
60 | | the assets. They call the corresponding methods in the |
61 | | Lattice interface, to which we refer for |
62 | | documentation. |
63 | | |
64 | | @{ |
65 | | */ |
66 | | void initialize(const ext::shared_ptr<Lattice>&, |
67 | | Time t); |
68 | | void rollback(Time to); |
69 | | void partialRollback(Time to); |
70 | | Real presentValue(); |
71 | | //@} |
72 | | |
73 | | /*! \name Low-level interface |
74 | | |
75 | | These methods (that developers should override when |
76 | | deriving from DiscretizedAsset) are to be used by |
77 | | numerical methods and not directly by users, with the |
78 | | exception of adjustValues(), preAdjustValues() and |
79 | | postAdjustValues() that can be used together with |
80 | | partialRollback(). |
81 | | |
82 | | @{ |
83 | | */ |
84 | | |
85 | | /*! This method should initialize the asset values to an Array |
86 | | of the given size and with values depending on the |
87 | | particular asset. |
88 | | */ |
89 | | virtual void reset(Size size) = 0; |
90 | | |
91 | | /*! This method will be invoked after rollback and before any |
92 | | other asset (i.e., an option on this one) has any chance to |
93 | | look at the values. For instance, payments happening at times |
94 | | already spanned by the rollback will be added here. |
95 | | |
96 | | This method is not virtual; derived classes must override |
97 | | the protected preAdjustValuesImpl() method instead. |
98 | | */ |
99 | | void preAdjustValues(); |
100 | | |
101 | | /*! This method will be invoked after rollback and after any |
102 | | other asset had their chance to look at the values. For |
103 | | instance, payments happening at the present time (and therefore |
104 | | not included in an option to be exercised at this time) will be |
105 | | added here. |
106 | | |
107 | | This method is not virtual; derived classes must override |
108 | | the protected postAdjustValuesImpl() method instead. |
109 | | */ |
110 | | void postAdjustValues(); |
111 | | |
112 | | /*! This method performs both pre- and post-adjustment */ |
113 | 0 | void adjustValues() { |
114 | 0 | preAdjustValues(); |
115 | 0 | postAdjustValues(); |
116 | 0 | } |
117 | | |
118 | | /*! This method returns the times at which the numerical |
119 | | method should stop while rolling back the asset. Typical |
120 | | examples include payment times, exercise times and such. |
121 | | |
122 | | \note The returned values are not guaranteed to be sorted. |
123 | | */ |
124 | | virtual std::vector<Time> mandatoryTimes() const = 0; |
125 | | //@} |
126 | | protected: |
127 | | /*! Indicates if a coupon should be adjusted in preAdjustValues() or postAdjustValues(). */ |
128 | | enum class CouponAdjustment { pre, post }; |
129 | | |
130 | | /*! This method checks whether the asset was rolled at the |
131 | | given time. */ |
132 | | bool isOnTime(Time t) const; |
133 | | /*! This method performs the actual pre-adjustment */ |
134 | 0 | virtual void preAdjustValuesImpl() {} |
135 | | /*! This method performs the actual post-adjustment */ |
136 | 0 | virtual void postAdjustValuesImpl() {} |
137 | | |
138 | | Time time_; |
139 | | Time latestPreAdjustment_, latestPostAdjustment_; |
140 | | Array values_; |
141 | | private: |
142 | | ext::shared_ptr<Lattice> method_; |
143 | | }; |
144 | | |
145 | | |
146 | | //! Useful discretized discount bond asset |
147 | | class DiscretizedDiscountBond : public DiscretizedAsset { |
148 | | public: |
149 | 0 | DiscretizedDiscountBond() = default; |
150 | 0 | void reset(Size size) override { values_ = Array(size, 1.0); } |
151 | 0 | std::vector<Time> mandatoryTimes() const override { return std::vector<Time>(); } |
152 | | }; |
153 | | |
154 | | |
155 | | //! Discretized option on a given asset |
156 | | /*! \warning it is advised that derived classes take care of |
157 | | creating and initializing themselves an instance of |
158 | | the underlying. |
159 | | */ |
160 | | class DiscretizedOption : public DiscretizedAsset { |
161 | | public: |
162 | | DiscretizedOption(ext::shared_ptr<DiscretizedAsset> underlying, |
163 | | Exercise::Type exerciseType, |
164 | | std::vector<Time> exerciseTimes) |
165 | 0 | : underlying_(std::move(underlying)), exerciseType_(exerciseType), |
166 | 0 | exerciseTimes_(std::move(exerciseTimes)) {} |
167 | | void reset(Size size) override; |
168 | | std::vector<Time> mandatoryTimes() const override; |
169 | | |
170 | | protected: |
171 | | void postAdjustValuesImpl() override; |
172 | | void applyExerciseCondition(); |
173 | | ext::shared_ptr<DiscretizedAsset> underlying_; |
174 | | Exercise::Type exerciseType_; |
175 | | std::vector<Time> exerciseTimes_; |
176 | | }; |
177 | | |
178 | | |
179 | | |
180 | | // inline definitions |
181 | | |
182 | | inline void DiscretizedAsset::initialize( |
183 | | const ext::shared_ptr<Lattice>& method, |
184 | 0 | Time t) { |
185 | 0 | method_ = method; |
186 | 0 | method_->initialize(*this, t); |
187 | 0 | } |
188 | | |
189 | 0 | inline void DiscretizedAsset::rollback(Time to) { |
190 | 0 | method_->rollback(*this, to); |
191 | 0 | } |
192 | | |
193 | 0 | inline void DiscretizedAsset::partialRollback(Time to) { |
194 | 0 | method_->partialRollback(*this, to); |
195 | 0 | } |
196 | | |
197 | 0 | inline Real DiscretizedAsset::presentValue() { |
198 | 0 | return method_->presentValue(*this); |
199 | 0 | } |
200 | | |
201 | 0 | inline void DiscretizedAsset::preAdjustValues() { |
202 | 0 | if (!close_enough(time(),latestPreAdjustment_)) { |
203 | 0 | preAdjustValuesImpl(); |
204 | 0 | latestPreAdjustment_ = time(); |
205 | 0 | } |
206 | 0 | } |
207 | | |
208 | 0 | inline void DiscretizedAsset::postAdjustValues() { |
209 | 0 | if (!close_enough(time(),latestPostAdjustment_)) { |
210 | 0 | postAdjustValuesImpl(); |
211 | 0 | latestPostAdjustment_ = time(); |
212 | 0 | } |
213 | 0 | } |
214 | | |
215 | 0 | inline bool DiscretizedAsset::isOnTime(Time t) const { |
216 | 0 | const TimeGrid& grid = method()->timeGrid(); |
217 | 0 | return close_enough(grid[grid.index(t)],time()); |
218 | 0 | } |
219 | | |
220 | | |
221 | 0 | inline void DiscretizedOption::reset(Size size) { |
222 | 0 | QL_REQUIRE(method() == underlying_->method(), |
223 | 0 | "option and underlying were initialized on " |
224 | 0 | "different methods"); |
225 | 0 | values_ = Array(size, 0.0); |
226 | 0 | adjustValues(); |
227 | 0 | } |
228 | | |
229 | 0 | inline std::vector<Time> DiscretizedOption::mandatoryTimes() const { |
230 | 0 | std::vector<Time> times = underlying_->mandatoryTimes(); |
231 | | // discard negative times... |
232 | 0 | auto i = std::find_if(exerciseTimes_.begin(), exerciseTimes_.end(), |
233 | 0 | [](Time t){ return t >= 0.0; }); |
234 | | // and add the positive ones |
235 | 0 | times.insert(times.end(), i, exerciseTimes_.end()); |
236 | 0 | return times; |
237 | 0 | } |
238 | | |
239 | 0 | inline void DiscretizedOption::applyExerciseCondition() { |
240 | 0 | for (Size i=0; i<values_.size(); i++) |
241 | 0 | values_[i] = std::max(underlying_->values()[i], values_[i]); |
242 | 0 | } |
243 | | |
244 | | |
245 | | } |
246 | | |
247 | | |
248 | | #endif |