Coverage Report

Created: 2026-09-28 06:23

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/quantlib/ql/instruments/bond.hpp
Line
Count
Source
1
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3
/*
4
 Copyright (C) 2004 Jeff Yu
5
 Copyright (C) 2004 M-Dimension Consulting Inc.
6
 Copyright (C) 2005, 2006, 2007, 2008 StatPro Italia srl
7
 Copyright (C) 2007, 2008, 2009 Ferdinando Ametrano
8
 Copyright (C) 2007 Chiara Fornarola
9
 Copyright (C) 2008 Simon Ibbotson
10
11
 This file is part of QuantLib, a free-software/open-source library
12
 for financial quantitative analysts and developers - http://quantlib.org/
13
14
 QuantLib is free software: you can redistribute it and/or modify it
15
 under the terms of the QuantLib license.  You should have received a
16
 copy of the license along with this program; if not, please email
17
 <quantlib-dev@lists.sf.net>. The license is also available online at
18
 <https://www.quantlib.org/license.shtml>.
19
20
 This program is distributed in the hope that it will be useful, but WITHOUT
21
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
22
 FOR A PARTICULAR PURPOSE.  See the license for more details.
23
*/
24
25
/*! \file bond.hpp
26
    \brief concrete bond class
27
*/
28
29
#ifndef quantlib_bond_hpp
30
#define quantlib_bond_hpp
31
32
#include <ql/instrument.hpp>
33
34
#include <ql/time/calendar.hpp>
35
#include <ql/cashflow.hpp>
36
#include <ql/compounding.hpp>
37
38
#include <vector>
39
40
namespace QuantLib {
41
42
    class DayCounter;
43
44
    //! Base bond class
45
    /*! Derived classes must fill the uninitialized data members.
46
47
        \warning Most methods assume that the cash flows are stored
48
                 sorted by date, the redemption(s) being after any
49
                 cash flow at the same date. In particular, if there's
50
                 one single redemption, it must be the last cash flow,
51
52
        \note Pricing methods (cleanPrice, dirtyPrice, settlementValue, etc.)
53
              assume and return values as a percentage of par (per 100).
54
              For bonds with a face value other than 100 (e.g., 25), the actual
55
              cash price must be calculated by the user: `cash price = quote * face / 100`.
56
              Yield and Z-spread methods also expect prices to be passed per 100.
57
58
        \ingroup instruments
59
60
        \test
61
        - price/yield calculations are cross-checked for consistency.
62
        - price/yield calculations are checked against known good
63
          values.
64
    */
65
    class Bond : public Instrument {
66
      public:
67
        //! Bond price information
68
        class Price {
69
          public:
70
            enum Type { Dirty, Clean };
71
0
            Price() : amount_(Null<Real>()), type_(Bond::Price::Clean) {}
72
0
            Price(Real amount, Type type) : amount_(amount), type_(type) {}
73
0
            Real amount() const {
74
0
                QL_REQUIRE(amount_ != Null<Real>(), "no amount given");
75
0
                return amount_;
76
0
            }
Unexecuted instantiation: QuantLib::Bond::Price::amount() const
Unexecuted instantiation: QuantLib::Bond::Price::amount() const
77
0
            Type type() const { return type_; }
78
0
            bool isValid() const { return amount_ != Null<Real>(); }
79
          private:
80
            Real amount_;
81
            Type type_;
82
        };
83
84
        //! constructor for amortizing or non-amortizing bonds.
85
        /*! Redemptions and maturity are calculated from the coupon
86
            data, if available.  Therefore, redemptions must not be
87
            included in the passed cash flows.
88
        */
89
        Bond(Natural settlementDays,
90
             Calendar calendar,
91
             const Date& issueDate = Date(),
92
             const Leg& coupons = Leg());
93
94
        //! old constructor for non amortizing bonds.
95
        /*! \warning The last passed cash flow must be the bond
96
                     redemption. No other cash flow can have a date
97
                     later than the redemption date.
98
        */
99
        Bond(Natural settlementDays,
100
             Calendar calendar,
101
             Real faceAmount,
102
             const Date& maturityDate,
103
             const Date& issueDate = Date(),
104
             const Leg& cashflows = Leg());
105
106
        class arguments;
107
        class results;
108
        class engine;
109
110
        //! \name Instrument interface
111
        //@{
112
        bool isExpired() const override;
113
        //@}
114
        //! \name Observable interface
115
        //@{
116
        void deepUpdate() override;
117
        //@}
118
        //! \name Inspectors
119
        //@{
120
        Natural settlementDays() const;
121
        const Calendar& calendar() const;
122
123
        const std::vector<Real>& notionals() const;
124
        virtual Real notional(Date d = Date()) const;
125
126
        /*! \note returns all the cashflows, including the redemptions. */
127
        const Leg& cashflows() const;
128
        /*! returns just the redemption flows (not interest payments) */
129
        const Leg& redemptions() const;
130
        /*! returns the redemption, if only one is defined */
131
        const ext::shared_ptr<CashFlow>& redemption() const;
132
133
        Date startDate() const;
134
        Date maturityDate() const;
135
        Date issueDate() const;
136
137
        bool isTradable(Date d = Date()) const;
138
        Date settlementDate(Date d = Date()) const;
139
        //@}
140
141
        //! \name Calculations
142
        //@{
143
144
        //! theoretical clean price
145
        /*! The default bond settlement is used for calculation.
146
147
            \warning the theoretical price calculated from a flat term
148
                     structure might differ slightly from the price
149
                     calculated from the corresponding yield by means
150
                     of the other overload of this function. If the
151
                     price from a constant yield is desired, it is
152
                     advisable to use such other overload.
153
        */
154
        Real cleanPrice() const;
155
156
        //! theoretical dirty price
157
        /*! The default bond settlement is used for calculation.
158
159
            \warning the theoretical price calculated from a flat term
160
                     structure might differ slightly from the price
161
                     calculated from the corresponding yield by means
162
                     of the other overload of this function. If the
163
                     price from a constant yield is desired, it is
164
                     advisable to use such other overload.
165
        */
166
        Real dirtyPrice() const;
167
168
        //! theoretical settlement value
169
        /*! The default bond settlement date is used for calculation. */
170
        Real settlementValue() const;
171
172
        //! theoretical bond yield
173
        /*! The default bond settlement and theoretical price are used
174
            for calculation.
175
        */
176
        Rate yield(const DayCounter& dc,
177
                   Compounding comp,
178
                   Frequency freq,
179
                   Real accuracy = 1.0e-8,
180
                   Size maxEvaluations = 100,
181
                   Real guess = 0.05,
182
                   Bond::Price::Type priceType = Bond::Price::Clean) const;
183
184
        //! clean price given a yield and settlement date
185
        /*! The default bond settlement is used if no date is given. */
186
        Real cleanPrice(Rate yield,
187
                        const DayCounter& dc,
188
                        Compounding comp,
189
                        Frequency freq,
190
                        Date settlementDate = Date()) const;
191
192
        //! dirty price given a yield and settlement date
193
        /*! The default bond settlement is used if no date is given. */
194
        Real dirtyPrice(Rate yield,
195
                        const DayCounter& dc,
196
                        Compounding comp,
197
                        Frequency freq,
198
                        Date settlementDate = Date()) const;
199
200
        //! settlement value as a function of the clean price
201
        /*! The default bond settlement date is used for calculation. */
202
        Real settlementValue(Real cleanPrice) const;
203
204
        //! yield given a price and settlement date
205
        /*! The default bond settlement is used if no date is given. */
206
        Rate yield(Bond::Price price,
207
                   const DayCounter& dc,
208
                   Compounding comp,
209
                   Frequency freq,
210
                   Date settlementDate = Date(),
211
                   Real accuracy = 1.0e-8,
212
                   Size maxEvaluations = 100,
213
                   Real guess = 0.05) const;
214
215
        //! accrued amount at a given date
216
        /*! The default bond settlement is used if no date is given. */
217
        virtual Real accruedAmount(Date d = Date()) const;
218
        //@}
219
220
        /*! Expected next coupon: depending on (the bond and) the given date
221
            the coupon can be historic, deterministic or expected in a
222
            stochastic sense. When the bond settlement date is used the coupon
223
            is the already-fixed not-yet-paid one.
224
225
            The current bond settlement is used if no date is given.
226
        */
227
        virtual Rate nextCouponRate(Date d = Date()) const;
228
229
        //! Previous coupon already paid at a given date
230
        /*! Expected previous coupon: depending on (the bond and) the given
231
            date the coupon can be historic, deterministic or expected in a
232
            stochastic sense. When the bond settlement date is used the coupon
233
            is the last paid one.
234
235
            The current bond settlement is used if no date is given.
236
        */
237
        Rate previousCouponRate(Date d = Date()) const;
238
239
        Date nextCashFlowDate(Date d = Date()) const;
240
        Date previousCashFlowDate(Date d = Date()) const;
241
242
      protected:
243
        void setupExpired() const override;
244
        void setupArguments(PricingEngine::arguments*) const override;
245
        void fetchResults(const PricingEngine::results*) const override;
246
247
        /*! This method can be called by derived classes in order to
248
            build redemption payments from the existing cash flows.
249
            It must be called after setting up the cashflows_ vector
250
            and will fill the notionalSchedule_, notionals_, and
251
            redemptions_ data members.
252
253
            If given, the elements of the redemptions vector will
254
            multiply the amount of the redemption cash flow.  The
255
            elements will be taken in base 100, i.e., a redemption
256
            equal to 100 does not modify the amount.
257
258
            \pre The cashflows_ vector must contain at least one
259
                 coupon and must be sorted by date.
260
        */
261
        void addRedemptionsToCashflows(const std::vector<Real>& redemptions
262
                                                       = std::vector<Real>());
263
264
        /*! This method can be called by derived classes in order to
265
            build a bond with a single redemption payment.  It will
266
            fill the notionalSchedule_, notionals_, and redemptions_
267
            data members.
268
        */
269
        void setSingleRedemption(Real notional,
270
                                 Real redemption,
271
                                 const Date& date);
272
273
        /*! This method can be called by derived classes in order to
274
            build a bond with a single redemption payment.  It will
275
            fill the notionalSchedule_, notionals_, and redemptions_
276
            data members.
277
        */
278
        void setSingleRedemption(Real notional,
279
                                 const ext::shared_ptr<CashFlow>& redemption);
280
281
        /*! used internally to collect notional information from the
282
            coupons. It should not be called by derived classes,
283
            unless they already provide redemption cash flows (in
284
            which case they must set up the redemptions_ data member
285
            independently).  It will fill the notionalSchedule_ and
286
            notionals_ data members.
287
        */
288
        void calculateNotionalsFromCashflows();
289
290
        Natural settlementDays_;
291
        Calendar calendar_;
292
        std::vector<Date> notionalSchedule_;
293
        std::vector<Real> notionals_;
294
        Leg cashflows_; // all cashflows
295
        Leg redemptions_; // the redemptions
296
297
        Date maturityDate_, issueDate_;
298
        mutable Real settlementValue_;
299
    };
300
301
    class Bond::arguments : public PricingEngine::arguments {
302
      public:
303
        Date settlementDate;
304
        Leg cashflows;
305
        Calendar calendar;
306
        void validate() const override;
307
    };
308
309
    class Bond::results : public Instrument::results {
310
      public:
311
        Real settlementValue;
312
0
        void reset() override {
313
0
            settlementValue = Null<Real>();
314
0
            Instrument::results::reset();
315
0
        }
316
    };
317
318
    class Bond::engine : public GenericEngine<Bond::arguments,
319
                                              Bond::results> {};
320
321
322
    // inline definitions
323
324
0
    inline Natural Bond::settlementDays() const {
325
0
        return settlementDays_;
326
0
    }
327
328
0
    inline const Calendar& Bond::calendar() const {
329
0
        return calendar_;
330
0
    }
331
332
0
    inline const std::vector<Real>& Bond::notionals() const {
333
0
        return notionals_;
334
0
    }
335
336
143k
    inline const Leg& Bond::cashflows() const {
337
143k
        return cashflows_;
338
143k
    }
339
340
0
    inline const Leg& Bond::redemptions() const {
341
0
        return redemptions_;
342
0
    }
343
344
0
    inline Date Bond::issueDate() const {
345
0
        return issueDate_;
346
0
    }
347
348
}
349
350
#endif