Coverage Report

Created: 2025-08-05 06:45

/src/quantlib/ql/cashflows/fixedratecoupon.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) 2000, 2001, 2002, 2003 RiskMap srl
5
 Copyright (C) 2003, 2004, 2007 StatPro Italia srl
6
 Copyright (C) 2007 Piter Dias
7
 Copyright (C) 2010 Ferdinando Ametrano
8
 Copyright (C) 2017 Joseph Jeisman
9
 Copyright (C) 2017 Fabrice Lecuyer
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
 <http://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
#include <ql/cashflows/fixedratecoupon.hpp>
26
#include <utility>
27
28
using std::vector;
29
30
namespace QuantLib {
31
32
    FixedRateCoupon::FixedRateCoupon(const Date& paymentDate,
33
                                     Real nominal,
34
                                     Rate rate,
35
                                     const DayCounter& dayCounter,
36
                                     const Date& accrualStartDate,
37
                                     const Date& accrualEndDate,
38
                                     const Date& refPeriodStart,
39
                                     const Date& refPeriodEnd,
40
                                     const Date& exCouponDate)
41
0
    : Coupon(paymentDate, nominal, accrualStartDate, accrualEndDate,
42
0
             refPeriodStart, refPeriodEnd, exCouponDate),
43
0
      rate_(InterestRate(rate, dayCounter, Simple, Annual)) {}
Unexecuted instantiation: QuantLib::FixedRateCoupon::FixedRateCoupon(QuantLib::Date const&, double, double, QuantLib::DayCounter const&, QuantLib::Date const&, QuantLib::Date const&, QuantLib::Date const&, QuantLib::Date const&, QuantLib::Date const&)
Unexecuted instantiation: QuantLib::FixedRateCoupon::FixedRateCoupon(QuantLib::Date const&, double, double, QuantLib::DayCounter const&, QuantLib::Date const&, QuantLib::Date const&, QuantLib::Date const&, QuantLib::Date const&, QuantLib::Date const&)
44
45
    FixedRateCoupon::FixedRateCoupon(const Date& paymentDate,
46
                                     Real nominal,
47
                                     InterestRate interestRate,
48
                                     const Date& accrualStartDate,
49
                                     const Date& accrualEndDate,
50
                                     const Date& refPeriodStart,
51
                                     const Date& refPeriodEnd,
52
                                     const Date& exCouponDate)
53
28.7M
    : Coupon(paymentDate,
54
28.7M
             nominal,
55
28.7M
             accrualStartDate,
56
28.7M
             accrualEndDate,
57
28.7M
             refPeriodStart,
58
28.7M
             refPeriodEnd,
59
28.7M
             exCouponDate),
60
28.7M
      rate_(std::move(interestRate)) {}
Unexecuted instantiation: QuantLib::FixedRateCoupon::FixedRateCoupon(QuantLib::Date const&, double, QuantLib::InterestRate, QuantLib::Date const&, QuantLib::Date const&, QuantLib::Date const&, QuantLib::Date const&, QuantLib::Date const&)
QuantLib::FixedRateCoupon::FixedRateCoupon(QuantLib::Date const&, double, QuantLib::InterestRate, QuantLib::Date const&, QuantLib::Date const&, QuantLib::Date const&, QuantLib::Date const&, QuantLib::Date const&)
Line
Count
Source
53
28.7M
    : Coupon(paymentDate,
54
28.7M
             nominal,
55
28.7M
             accrualStartDate,
56
28.7M
             accrualEndDate,
57
28.7M
             refPeriodStart,
58
28.7M
             refPeriodEnd,
59
28.7M
             exCouponDate),
60
28.7M
      rate_(std::move(interestRate)) {}
61
62
28.7M
    Real FixedRateCoupon::amount() const {
63
28.7M
        calculate();
64
28.7M
        return amount_;
65
28.7M
    }
66
67
28.7M
    void FixedRateCoupon::performCalculations() const {
68
28.7M
        amount_ = nominal() * (rate_.compoundFactor(accrualStartDate_, accrualEndDate_,
69
28.7M
                                                    refPeriodStart_, refPeriodEnd_) -
70
28.7M
                               1.0);
71
28.7M
    }
72
73
0
    Real FixedRateCoupon::accruedAmount(const Date& d) const {
74
0
        if (d <= accrualStartDate_ || d > paymentDate_) {
75
            // out of coupon range
76
0
            return 0.0;
77
0
        } else if (tradingExCoupon(d)) {
78
0
            return -nominal()*(rate_.compoundFactor(d,
79
0
                                                    std::max(d, accrualEndDate_),
80
0
                                                    refPeriodStart_,
81
0
                                                    refPeriodEnd_) - 1.0);
82
0
        } else {
83
            // usual case
84
0
            return nominal()*(rate_.compoundFactor(accrualStartDate_,
85
0
                                                   std::min(d,accrualEndDate_),
86
0
                                                   refPeriodStart_,
87
0
                                                   refPeriodEnd_) - 1.0);
88
0
        }
89
0
    }
90
91
92
    FixedRateLeg::FixedRateLeg(Schedule schedule)
93
79.8k
    : schedule_(std::move(schedule)), paymentCalendar_(schedule_.calendar()) {}
94
95
0
    FixedRateLeg& FixedRateLeg::withNotionals(Real notional) {
96
0
        notionals_ = vector<Real>(1,notional);
97
0
        return *this;
98
0
    }
99
100
79.8k
    FixedRateLeg& FixedRateLeg::withNotionals(const vector<Real>& notionals) {
101
79.8k
        notionals_ = notionals;
102
79.8k
        return *this;
103
79.8k
    }
104
105
    FixedRateLeg& FixedRateLeg::withCouponRates(Rate rate,
106
                                                const DayCounter& dc,
107
                                                Compounding comp,
108
0
                                                Frequency freq) {
109
0
        couponRates_.resize(1);
110
0
        couponRates_[0] = InterestRate(rate, dc, comp, freq);
111
0
        return *this;
112
0
    }
113
114
0
    FixedRateLeg& FixedRateLeg::withCouponRates(const InterestRate& i) {
115
0
        couponRates_.resize(1);
116
0
        couponRates_[0] = i;
117
0
        return *this;
118
0
    }
119
120
    FixedRateLeg& FixedRateLeg::withCouponRates(const vector<Rate>& rates,
121
                                                const DayCounter& dc,
122
                                                Compounding comp,
123
79.8k
                                                Frequency freq) {
124
79.8k
        couponRates_.resize(rates.size());
125
159k
        for (Size i=0; i<rates.size(); ++i)
126
79.8k
            couponRates_[i] = InterestRate(rates[i], dc, comp, freq);
127
79.8k
        return *this;
128
79.8k
    }
129
130
    FixedRateLeg& FixedRateLeg::withCouponRates(
131
0
                                const vector<InterestRate>& interestRates) {
132
0
        couponRates_ = interestRates;
133
0
        return *this;
134
0
    }
135
136
    FixedRateLeg& FixedRateLeg::withPaymentAdjustment(
137
79.8k
                                           BusinessDayConvention convention) {
138
79.8k
        paymentAdjustment_ = convention;
139
79.8k
        return *this;
140
79.8k
    }
141
142
    FixedRateLeg& FixedRateLeg::withFirstPeriodDayCounter(
143
0
                                            const DayCounter& dayCounter) {
144
0
        firstPeriodDC_ = dayCounter;
145
0
        return *this;
146
0
    }
147
148
    FixedRateLeg& FixedRateLeg::withLastPeriodDayCounter(
149
0
                                               const DayCounter& dayCounter) {
150
0
        lastPeriodDC_ = dayCounter;
151
0
        return *this;
152
0
    }
153
154
0
    FixedRateLeg& FixedRateLeg::withPaymentCalendar(const Calendar& cal) {
155
0
        paymentCalendar_ = cal;
156
0
        return *this;
157
0
    }
158
159
79.8k
    FixedRateLeg& FixedRateLeg::withPaymentLag(Integer lag) {
160
79.8k
        paymentLag_ = lag;
161
79.8k
        return *this;
162
79.8k
    }
163
164
    FixedRateLeg& FixedRateLeg::withExCouponPeriod(
165
                                const Period& period,
166
                                const Calendar& cal,
167
                                BusinessDayConvention convention,
168
79.8k
                                bool endOfMonth) {
169
79.8k
        exCouponPeriod_ = period;
170
79.8k
        exCouponCalendar_ = cal;
171
79.8k
        exCouponAdjustment_ = convention;
172
79.8k
        exCouponEndOfMonth_ = endOfMonth;
173
79.8k
        return *this;
174
79.8k
    }
175
176
79.8k
    FixedRateLeg::operator Leg() const {
177
178
79.8k
        QL_REQUIRE(!couponRates_.empty(), "no coupon rates given");
179
79.8k
        QL_REQUIRE(!notionals_.empty(), "no notional given");
180
181
79.8k
        Leg leg;
182
79.8k
        leg.reserve(schedule_.size()-1);
183
184
        // first period might be short or long
185
79.8k
        Date start = schedule_.date(0), end = schedule_.date(1);
186
79.8k
        Date paymentDate = paymentCalendar_.advance(end, paymentLag_, Days, paymentAdjustment_);
187
79.8k
        Date exCouponDate;
188
79.8k
        InterestRate rate = couponRates_[0];
189
79.8k
        Real nominal = notionals_[0];
190
191
79.8k
        if (exCouponPeriod_ != Period())
192
0
        {
193
0
            exCouponDate = exCouponCalendar_.advance(paymentDate,
194
0
                                                     -exCouponPeriod_,
195
0
                                                     exCouponAdjustment_,
196
0
                                                     exCouponEndOfMonth_);
197
0
        }
198
79.8k
        Date ref = schedule_.hasTenor() &&
199
79.8k
            schedule_.hasIsRegular() && !schedule_.isRegular(1) ?
200
0
            schedule_.calendar().advance(end,
201
0
                                         -schedule_.tenor(),
202
0
                                         schedule_.businessDayConvention(),
203
0
                                         schedule_.endOfMonth())
204
79.8k
            : start;
205
79.8k
        InterestRate r(rate.rate(),
206
79.8k
                       firstPeriodDC_.empty() ? rate.dayCounter()
207
79.8k
                       : firstPeriodDC_,
208
79.8k
                       rate.compounding(), rate.frequency());
209
79.8k
        leg.push_back(ext::shared_ptr<CashFlow>(new
210
79.8k
            FixedRateCoupon(paymentDate, nominal, r,
211
79.8k
                            start, end, ref, end, exCouponDate)));
212
        // regular periods
213
28.6M
        for (Size i=2; i<schedule_.size()-1; ++i) {
214
28.5M
            start = end; end = schedule_.date(i);
215
28.5M
            Date paymentDate = paymentCalendar_.advance(end, paymentLag_, Days, paymentAdjustment_);
216
28.5M
            if (exCouponPeriod_ != Period())
217
0
            {
218
0
                exCouponDate = exCouponCalendar_.advance(paymentDate,
219
0
                                                         -exCouponPeriod_,
220
0
                                                         exCouponAdjustment_,
221
0
                                                         exCouponEndOfMonth_);
222
0
            }
223
28.5M
            if ((i-1) < couponRates_.size())
224
0
                rate = couponRates_[i-1];
225
28.5M
            else
226
28.5M
                rate = couponRates_.back();
227
28.5M
            if ((i-1) < notionals_.size())
228
28.5M
                nominal = notionals_[i-1];
229
0
            else
230
0
                nominal = notionals_.back();
231
28.5M
            leg.push_back(ext::shared_ptr<CashFlow>(new
232
28.5M
                FixedRateCoupon(paymentDate, nominal, rate,
233
28.5M
                                start, end, start, end, exCouponDate)));
234
28.5M
        }
235
79.8k
        if (schedule_.size() > 2) {
236
            // last period might be short or long
237
79.8k
            Size N = schedule_.size();
238
79.8k
            start = end; end = schedule_.date(N-1);
239
79.8k
            Date paymentDate = paymentCalendar_.advance(end, paymentLag_, Days, paymentAdjustment_);
240
79.8k
            if (exCouponPeriod_ != Period())
241
0
            {
242
0
                exCouponDate = exCouponCalendar_.advance(paymentDate,
243
0
                                                         -exCouponPeriod_,
244
0
                                                         exCouponAdjustment_,
245
0
                                                         exCouponEndOfMonth_);
246
0
            }
247
79.8k
            if ((N-2) < couponRates_.size())
248
0
                rate = couponRates_[N-2];
249
79.8k
            else
250
79.8k
                rate = couponRates_.back();
251
79.8k
            if ((N-2) < notionals_.size())
252
79.8k
                nominal = notionals_[N-2];
253
0
            else
254
0
                nominal = notionals_.back();
255
79.8k
            InterestRate r( rate.rate(), lastPeriodDC_.empty() ?
256
79.8k
                rate.dayCounter() :
257
79.8k
                lastPeriodDC_ , rate.compounding(), rate.frequency() );
258
79.8k
            if ((schedule_.hasIsRegular() && schedule_.isRegular(N - 1)) ||
259
79.8k
                !schedule_.hasTenor()) {
260
79.8k
                leg.push_back(ext::shared_ptr<CashFlow>(new
261
79.8k
                    FixedRateCoupon(paymentDate, nominal, r,
262
79.8k
                                    start, end, start, end, exCouponDate)));
263
79.8k
            } else {
264
0
                Date ref = schedule_.calendar().advance(
265
0
                                            start,
266
0
                                            schedule_.tenor(),
267
0
                                            schedule_.businessDayConvention(),
268
0
                                            schedule_.endOfMonth());
269
0
                leg.push_back(ext::shared_ptr<CashFlow>(new
270
0
                    FixedRateCoupon(paymentDate, nominal, r,
271
0
                                    start, end, start, ref, exCouponDate)));
272
0
            }
273
79.8k
        }
274
79.8k
        return leg;
275
79.8k
    }
276
277
}