Coverage Report

Created: 2026-09-28 06:23

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/quantlib/ql/interestrate.cpp
Line
Count
Source
1
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3
/*
4
 Copyright (C) 2004 Ferdinando Ametrano
5
6
 This file is part of QuantLib, a free-software/open-source library
7
 for financial quantitative analysts and developers - http://quantlib.org/
8
9
 QuantLib is free software: you can redistribute it and/or modify it
10
 under the terms of the QuantLib license.  You should have received a
11
 copy of the license along with this program; if not, please email
12
 <quantlib-dev@lists.sf.net>. The license is also available online at
13
 <https://www.quantlib.org/license.shtml>.
14
15
 This program is distributed in the hope that it will be useful, but WITHOUT
16
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17
 FOR A PARTICULAR PURPOSE.  See the license for more details.
18
*/
19
20
#include <ql/interestrate.hpp>
21
#include <ql/utilities/dataformatters.hpp>
22
#include <iomanip>
23
#include <sstream>
24
#include <utility>
25
26
namespace QuantLib {
27
28
    // constructors
29
30
    InterestRate::InterestRate()
31
86.1k
    : r_(Null<Real>()) {}
32
33
    InterestRate::InterestRate(Rate r, DayCounter dc, Compounding comp, Frequency freq)
34
5.05M
    : r_(r), dc_(std::move(dc)), comp_(comp), freqMakesSense_(false) {
35
36
5.05M
        if (comp_==Compounded || comp_==SimpleThenCompounded || comp_==CompoundedThenSimple) {
37
37.6k
            freqMakesSense_ = true;
38
37.6k
            QL_REQUIRE(freq!=Once && freq!=NoFrequency,
39
37.6k
                       "frequency not allowed for this interest rate");
40
37.6k
            freq_ = Real(freq);
41
37.6k
        }
42
5.05M
    }
43
44
36.9M
    Real InterestRate::compoundFactor(Time t) const {
45
46
36.9M
        QL_REQUIRE(t>=0.0, "negative time (" << t << ") not allowed");
47
36.9M
        QL_REQUIRE(r_ != Null<Rate>(), "null interest rate");
48
36.9M
        switch (comp_) {
49
25.8M
          case Simple:
50
25.8M
            return 1.0 + r_*t;
51
148k
          case Compounded:
52
148k
            return std::pow(1.0+r_/freq_, freq_*t);
53
10.9M
          case Continuous:
54
10.9M
            return std::exp(r_*t);
55
0
          case SimpleThenCompounded:
56
0
          case CompoundedThenSimple:
57
0
            QL_FAIL(comp_ << " is not supported for direct calculations: use the CashFlow methods");
58
0
          default:
59
0
            QL_FAIL("unknown compounding convention");
60
36.9M
        }
61
36.9M
    }
62
63
41.3k
    Real InterestRate::discountFactorFirstDerivative(Time t) const {
64
41.3k
        Real discount = discountFactor(t);
65
41.3k
        switch (comp_) {
66
9.30k
          case Simple:
67
9.30k
            return -t * discount * discount;
68
29.2k
          case Compounded: {
69
29.2k
              Real freq = Real(frequency());
70
29.2k
              Real compound = 1 + r_ / freq;
71
29.2k
              return -t * discount / compound;
72
0
          }
73
2.78k
          case Continuous:
74
2.78k
            return -t * discount;
75
0
          case SimpleThenCompounded:
76
0
          case CompoundedThenSimple:
77
0
            QL_FAIL(comp_ << " is not supported for direct calculations: use the CashFlow methods");
78
0
          default:
79
0
            QL_FAIL("unknown compounding convention");
80
41.3k
        }
81
41.3k
    }
82
83
5.61k
    Real InterestRate::discountFactorSecondDerivative(Time t) const {
84
5.61k
        Real discount = discountFactor(t);
85
5.61k
        switch (comp_) {
86
2.19k
          case Simple:
87
2.19k
            return 2.0 * t * t * discount * discount * discount;
88
2.84k
          case Compounded: {
89
2.84k
              Real freq = Real(frequency());
90
2.84k
              Real compound = 1 + r_ / freq;
91
2.84k
              return discount * t * (freq * t + 1.0) / (freq * compound * compound);
92
0
          }
93
568
          case Continuous:
94
568
            return t * t * discount;
95
0
          case SimpleThenCompounded:
96
0
          case CompoundedThenSimple:
97
0
            QL_FAIL(comp_ << " is not supported for direct calculations: use the CashFlow methods");
98
0
          default:
99
0
            QL_FAIL("unknown compounding convention");
100
5.61k
        }
101
5.61k
    }
102
103
    InterestRate InterestRate::impliedRate(Real compound,
104
                                           const DayCounter& resultDC,
105
                                           Compounding comp,
106
                                           Frequency freq,
107
4.77M
                                           Time t) {
108
109
4.77M
        QL_REQUIRE(compound>0.0, "positive compound factor required");
110
111
4.77M
        Rate r = Null<Rate>();
112
4.77M
        if (compound==1.0) {
113
413k
            QL_REQUIRE(t>=0.0, "non negative time (" << t << ") required");
114
413k
            r = 0.0;
115
4.35M
        } else {
116
4.35M
            QL_REQUIRE(t>0.0, "positive time (" << t << ") required");
117
4.35M
            switch (comp) {
118
0
              case Simple:
119
0
                r = (compound - 1.0)/t;
120
0
                break;
121
0
              case Compounded:
122
0
                r = (std::pow(compound, 1.0/(Real(freq)*t))-1.0)*Real(freq);
123
0
                break;
124
4.35M
              case Continuous:
125
4.35M
                r = std::log(compound)/t;
126
4.35M
                break;
127
0
              case SimpleThenCompounded:
128
0
              case CompoundedThenSimple:
129
0
                QL_FAIL(comp << " is not supported for direct calculations: use the CashFlow methods");
130
4.35M
            }
131
4.35M
        }
132
4.77M
        return InterestRate(r, resultDC, comp, freq);
133
4.77M
    }
134
135
136
0
    std::ostream& operator<<(std::ostream& out, const InterestRate& ir) {
137
0
        if (ir.rate() == Null<Rate>())
138
0
            return out << "null interest rate";
139
140
0
        out << io::rate(ir.rate()) << " " << ir.dayCounter().name() << " ";
141
0
        switch (ir.compounding()) {
142
0
          case Simple:
143
0
            out << "simple compounding";
144
0
            break;
145
0
          case Compounded:
146
0
            switch (ir.frequency()) {
147
0
              case NoFrequency:
148
0
              case Once:
149
0
                QL_FAIL(ir.frequency() << " frequency not allowed "
150
0
                        "for this interest rate");
151
0
              default:
152
0
                out << ir.frequency() <<" compounding";
153
0
            }
154
0
            break;
155
0
          case Continuous:
156
0
            out << "continuous compounding";
157
0
            break;
158
0
          case SimpleThenCompounded:
159
0
            switch (ir.frequency()) {
160
0
              case NoFrequency:
161
0
              case Once:
162
0
                QL_FAIL(ir.frequency() << " frequency not allowed "
163
0
                        "for this interest rate");
164
0
              default:
165
0
                out << "simple compounding up to "
166
0
                    << Integer(12/ir.frequency()) << " months, then "
167
0
                    << ir.frequency() << " compounding";
168
0
            }
169
0
            break;
170
0
          case CompoundedThenSimple:
171
0
            switch (ir.frequency()) {
172
0
              case NoFrequency:
173
0
              case Once:
174
0
                QL_FAIL(ir.frequency() << " frequency not allowed "
175
0
                        "for this interest rate");
176
0
              default:
177
0
                out << "compounding up to "
178
0
                    << Integer(12/ir.frequency()) << " months, then "
179
0
                    << ir.frequency() << " simple compounding";
180
0
            }
181
0
            break;
182
0
          default:
183
0
            QL_FAIL("unknown compounding convention ("
184
0
                    << Integer(ir.compounding()) << ")");
185
0
        }
186
0
        return out;
187
0
    }
188
189
}