Coverage Report

Created: 2025-08-28 06:30

/src/quantlib/ql/termstructures/yieldtermstructure.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3
/*
4
 Copyright (C) 2004, 2009 Ferdinando Ametrano
5
 Copyright (C) 2000, 2001, 2002, 2003 RiskMap srl
6
 Copyright (C) 2003, 2004, 2005, 2006 StatPro Italia srl
7
8
 This file is part of QuantLib, a free-software/open-source library
9
 for financial quantitative analysts and developers - http://quantlib.org/
10
11
 QuantLib is free software: you can redistribute it and/or modify it
12
 under the terms of the QuantLib license.  You should have received a
13
 copy of the license along with this program; if not, please email
14
 <quantlib-dev@lists.sf.net>. The license is also available online at
15
 <http://quantlib.org/license.shtml>.
16
17
 This program is distributed in the hope that it will be useful, but WITHOUT
18
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
19
 FOR A PARTICULAR PURPOSE.  See the license for more details.
20
*/
21
22
#include <ql/termstructures/yieldtermstructure.hpp>
23
#include <ql/utilities/dataformatters.hpp>
24
#include <utility>
25
26
namespace QuantLib {
27
28
    namespace {
29
        // time interval used in finite differences
30
        const Time dt = 0.0001;
31
    }
32
33
0
    YieldTermStructure::YieldTermStructure(const DayCounter& dc) : TermStructure(dc) {}
34
35
    YieldTermStructure::YieldTermStructure(const Date& referenceDate,
36
                                           const Calendar& cal,
37
                                           const DayCounter& dc,
38
                                           std::vector<Handle<Quote> > jumps,
39
                                           const std::vector<Date>& jumpDates)
40
2.04k
    : TermStructure(referenceDate, cal, dc), jumps_(std::move(jumps)), jumpDates_(jumpDates),
41
2.04k
      jumpTimes_(jumpDates.size()), nJumps_(jumps_.size()) {
42
2.04k
        setJumps(YieldTermStructure::referenceDate());
43
2.04k
        for (Size i=0; i<nJumps_; ++i)
44
0
            registerWith(jumps_[i]);
45
2.04k
    }
46
47
    YieldTermStructure::YieldTermStructure(Natural settlementDays,
48
                                           const Calendar& cal,
49
                                           const DayCounter& dc,
50
                                           std::vector<Handle<Quote> > jumps,
51
                                           const std::vector<Date>& jumpDates)
52
0
    : TermStructure(settlementDays, cal, dc), jumps_(std::move(jumps)), jumpDates_(jumpDates),
53
0
      jumpTimes_(jumpDates.size()), nJumps_(jumps_.size()) {
54
0
        setJumps(YieldTermStructure::referenceDate());
55
0
        for (Size i=0; i<nJumps_; ++i)
56
0
            registerWith(jumps_[i]);
57
0
    }
58
59
2.04k
    void YieldTermStructure::setJumps(const Date& referenceDate) {
60
2.04k
        if (jumpDates_.empty() && !jumps_.empty()) { // turn of year dates
61
0
            jumpDates_.resize(nJumps_);
62
0
            jumpTimes_.resize(nJumps_);
63
0
            Year y = referenceDate.year();
64
0
            for (Size i=0; i<nJumps_; ++i)
65
0
                jumpDates_[i] = Date(31, December, y+i);
66
2.04k
        } else { // fixed dates
67
2.04k
            QL_REQUIRE(jumpDates_.size()==nJumps_,
68
2.04k
                       "mismatch between number of jumps (" << nJumps_ <<
69
2.04k
                       ") and jump dates (" << jumpDates_.size() << ")");
70
2.04k
        }
71
2.04k
        for (Size i=0; i<nJumps_; ++i)
72
0
            jumpTimes_[i] = timeFromReference(jumpDates_[i]);
73
2.04k
        latestReference_ = referenceDate;
74
2.04k
    }
75
76
    DiscountFactor YieldTermStructure::discount(Time t,
77
0
                                                bool extrapolate) const {
78
0
        checkRange(t, extrapolate);
79
80
0
        if (jumps_.empty())
81
0
            return discountImpl(t);
82
83
0
        DiscountFactor jumpEffect = 1.0;
84
0
        for (Size i=0; i<nJumps_; ++i) {
85
0
            if (jumpTimes_[i]>0 && jumpTimes_[i]<t) {
86
0
                QL_REQUIRE(jumps_[i]->isValid(),
87
0
                           "invalid " << io::ordinal(i+1) << " jump quote");
88
0
                DiscountFactor thisJump = jumps_[i]->value();
89
0
                QL_REQUIRE(thisJump > 0.0,
90
0
                           "invalid " << io::ordinal(i+1) << " jump value: " <<
91
0
                           thisJump);
92
0
                jumpEffect *= thisJump;
93
0
            }
94
0
        }
95
0
        return jumpEffect * discountImpl(t);
96
0
    }
97
98
    InterestRate YieldTermStructure::zeroRate(const Date& d,
99
                                              const DayCounter& dayCounter,
100
                                              Compounding comp,
101
                                              Frequency freq,
102
0
                                              bool extrapolate) const {
103
0
        Time t = timeFromReference(d);
104
0
        if (t == 0) {
105
0
            Real compound = 1.0/discount(dt, extrapolate);
106
            // t has been calculated with a possibly different daycounter
107
            // but the difference should not matter for very small times
108
0
            return InterestRate::impliedRate(compound,
109
0
                                             dayCounter, comp, freq,
110
0
                                             dt);
111
0
        }
112
0
        Real compound = 1.0/discount(t, extrapolate);
113
0
        return InterestRate::impliedRate(compound,
114
0
                                         dayCounter, comp, freq,
115
0
                                         referenceDate(), d);
116
0
    }
117
118
    InterestRate YieldTermStructure::zeroRate(Time t,
119
                                              Compounding comp,
120
                                              Frequency freq,
121
0
                                              bool extrapolate) const {
122
0
        if (t==0.0) t = dt;
123
0
        Real compound = 1.0/discount(t, extrapolate);
124
0
        return InterestRate::impliedRate(compound,
125
0
                                         dayCounter(), comp, freq,
126
0
                                         t);
127
0
    }
128
129
    InterestRate YieldTermStructure::forwardRate(const Date& d1,
130
                                                 const Date& d2,
131
                                                 const DayCounter& dayCounter,
132
                                                 Compounding comp,
133
                                                 Frequency freq,
134
0
                                                 bool extrapolate) const {
135
0
        if (d1==d2) {
136
0
            checkRange(d1, extrapolate);
137
0
            Time t1 = std::max(timeFromReference(d1) - dt/2.0, 0.0);
138
0
            Time t2 = t1 + dt;
139
0
            Real compound =
140
0
                discount(t1, true)/discount(t2, true);
141
            // times have been calculated with a possibly different daycounter
142
            // but the difference should not matter for very small times
143
0
            return InterestRate::impliedRate(compound,
144
0
                                             dayCounter, comp, freq,
145
0
                                             dt);
146
0
        }
147
0
        QL_REQUIRE(d1 < d2,  d1 << " later than " << d2);
148
0
        Real compound = discount(d1, extrapolate)/discount(d2, extrapolate);
149
0
        return InterestRate::impliedRate(compound,
150
0
                                         dayCounter, comp, freq,
151
0
                                         d1, d2);
152
0
    }
153
154
    InterestRate YieldTermStructure::forwardRate(Time t1,
155
                                                 Time t2,
156
                                                 Compounding comp,
157
                                                 Frequency freq,
158
0
                                                 bool extrapolate) const {
159
0
        Real compound;
160
0
        if (t2==t1) {
161
0
            checkRange(t1, extrapolate);
162
0
            t1 = std::max(t1 - dt/2.0, 0.0);
163
0
            t2 = t1 + dt;
164
0
            compound = discount(t1, true)/discount(t2, true);
165
0
        } else {
166
0
            QL_REQUIRE(t2>t1, "t2 (" << t2 << ") < t1 (" << t2 << ")");
167
0
            compound = discount(t1, extrapolate)/discount(t2, extrapolate);
168
0
        }
169
0
        return InterestRate::impliedRate(compound,
170
0
                                         dayCounter(), comp, freq,
171
0
                                         t2-t1);
172
0
    }
173
174
367k
    void YieldTermStructure::update() {
175
367k
        TermStructure::update();
176
367k
        Date newReference = Date();
177
367k
        try {
178
367k
            newReference = referenceDate();
179
367k
            if (newReference != latestReference_)
180
0
                setJumps(newReference);
181
367k
        } catch (Error&) {
182
0
            if (newReference == Date()) {
183
                // the curve couldn't calculate the reference
184
                // date. Most of the times, this is because some
185
                // underlying handle wasn't set, so we can just absorb
186
                // the exception and continue; the jumps will be set
187
                // correctly when a valid underlying is set.
188
0
                return;
189
0
            } else {
190
                // something else happened during the call to
191
                // setJumps(), so we let the exception bubble up.
192
0
                throw;
193
0
            }
194
0
        }
195
367k
    }
196
197
}