Coverage Report

Created: 2025-11-04 06:12

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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