Coverage Report

Created: 2025-10-14 06:32

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/quantlib/ql/cashflows/cashflowvectors.hpp
Line
Count
Source
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 StatPro Italia srl
6
 Copyright (C) 2006, 2007 Cristina Duminuco
7
 Copyright (C) 2006, 2007 Giorgio Facchinetti
8
 Copyright (C) 2006 Mario Pucci
9
 Copyright (C) 2007 Ferdinando Ametrano
10
 Copyright (C) 2017 Joseph Jeisman
11
 Copyright (C) 2017 Fabrice Lecuyer
12
13
 This file is part of QuantLib, a free-software/open-source library
14
 for financial quantitative analysts and developers - http://quantlib.org/
15
16
 QuantLib is free software: you can redistribute it and/or modify it
17
 under the terms of the QuantLib license.  You should have received a
18
 copy of the license along with this program; if not, please email
19
 <quantlib-dev@lists.sf.net>. The license is also available online at
20
 <https://www.quantlib.org/license.shtml>.
21
22
 This program is distributed in the hope that it will be useful, but WITHOUT
23
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
24
 FOR A PARTICULAR PURPOSE.  See the license for more details.
25
*/
26
27
/*! \file cashflowvectors.hpp
28
    \brief Cash flow vector builders
29
*/
30
31
#ifndef quantlib_cash_flow_vectors_hpp
32
#define quantlib_cash_flow_vectors_hpp
33
34
#include <ql/cashflows/fixedratecoupon.hpp>
35
#include <ql/cashflows/replication.hpp>
36
#include <ql/time/schedule.hpp>
37
#include <ql/utilities/null.hpp>
38
#include <ql/utilities/vectors.hpp>
39
#include <ql/position.hpp>
40
#include <ql/indexes/swapindex.hpp>
41
42
namespace QuantLib {
43
44
    namespace detail {
45
46
        Rate effectiveFixedRate(const std::vector<Spread>& spreads,
47
                                const std::vector<Rate>& caps,
48
                                const std::vector<Rate>& floors,
49
                                Size i);
50
51
        bool noOption(const std::vector<Rate>& caps,
52
                      const std::vector<Rate>& floors,
53
                      Size i);
54
55
    }
56
57
58
    template <typename InterestRateIndexType,
59
              typename FloatingCouponType,
60
              typename CappedFlooredCouponType>
61
    Leg FloatingLeg(const Schedule& schedule,
62
                    const std::vector<Real>& nominals,
63
                    const ext::shared_ptr<InterestRateIndexType>& index,
64
                    const DayCounter& paymentDayCounter,
65
                    BusinessDayConvention paymentAdj,
66
                    const std::vector<Natural>& fixingDays,
67
                    const std::vector<Real>& gearings,
68
                    const std::vector<Spread>& spreads,
69
                    const std::vector<Rate>& caps,
70
                    const std::vector<Rate>& floors,
71
                    bool isInArrears,
72
                    bool isZero,
73
                    Integer paymentLag = 0,
74
                    Calendar paymentCalendar = Calendar(),
75
                    Period exCouponPeriod = Period(),
76
                    Calendar exCouponCalendar = Calendar(),
77
                    BusinessDayConvention exCouponAdjustment = Unadjusted,
78
0
                    bool exCouponEndOfMonth = false) {
79
80
0
        Size n = schedule.size()-1;
81
0
        QL_REQUIRE(!nominals.empty(), "no notional given");
82
0
        QL_REQUIRE(nominals.size() <= n,
83
0
                   "too many nominals (" << nominals.size() <<
84
0
                   "), only " << n << " required");
85
0
        QL_REQUIRE(gearings.size()<=n,
86
0
                   "too many gearings (" << gearings.size() <<
87
0
                   "), only " << n << " required");
88
0
        QL_REQUIRE(spreads.size()<=n,
89
0
                   "too many spreads (" << spreads.size() <<
90
0
                   "), only " << n << " required");
91
0
        QL_REQUIRE(caps.size()<=n,
92
0
                   "too many caps (" << caps.size() <<
93
0
                   "), only " << n << " required");
94
0
        QL_REQUIRE(floors.size()<=n,
95
0
                   "too many floors (" << floors.size() <<
96
0
                   "), only " << n << " required");
97
0
        QL_REQUIRE(!isZero || !isInArrears,
98
0
                   "in-arrears and zero features are not compatible");
99
100
0
        Leg leg; leg.reserve(n);
101
102
        // the following is not always correct
103
0
        const Calendar& calendar = schedule.calendar();
104
105
0
        if (paymentCalendar.empty()) {
106
0
            paymentCalendar = calendar;
107
0
        }
108
0
        Date refStart, start, refEnd, end;
109
0
        Date exCouponDate;
110
0
        Date lastPaymentDate = paymentCalendar.advance(schedule.date(n), paymentLag, Days, paymentAdj);
111
112
0
        for (Size i=0; i<n; ++i) {
113
0
            refStart = start = schedule.date(i);
114
0
            refEnd   =   end = schedule.date(i+1);
115
0
            Date paymentDate =
116
0
                isZero ? lastPaymentDate : paymentCalendar.advance(end, paymentLag, Days, paymentAdj);
117
0
            if (i==0   && (schedule.hasIsRegular() && schedule.hasTenor() && !schedule.isRegular(i+1))) {
118
0
                BusinessDayConvention bdc = schedule.businessDayConvention();
119
0
                refStart = calendar.adjust(end - schedule.tenor(), bdc);
120
0
            }
121
0
            if (i==n-1 && (schedule.hasIsRegular() && schedule.hasTenor() && !schedule.isRegular(i+1))) {
122
0
                BusinessDayConvention bdc = schedule.businessDayConvention();
123
0
                refEnd = calendar.adjust(start + schedule.tenor(), bdc);
124
0
            }
125
0
            if (exCouponPeriod != Period()) {
126
0
                if (exCouponCalendar.empty()) {
127
0
                    exCouponCalendar = calendar;
128
0
                }
129
0
                exCouponDate = exCouponCalendar.advance(paymentDate, -exCouponPeriod,
130
0
                                                         exCouponAdjustment, exCouponEndOfMonth);
131
0
            }
132
0
            if (detail::get(gearings, i, 1.0) == 0.0) { // fixed coupon
133
0
                leg.push_back(ext::shared_ptr<CashFlow>(new
134
0
                    FixedRateCoupon(paymentDate,
135
0
                                    detail::get(nominals, i, 1.0),
136
0
                                    detail::effectiveFixedRate(spreads,caps,
137
0
                                                               floors,i),
138
0
                                    paymentDayCounter,
139
0
                                    start, end, refStart, refEnd, 
140
0
                        exCouponDate)));
141
0
            } else { // floating coupon
142
0
                if (detail::noOption(caps, floors, i))
143
0
                    leg.push_back(ext::shared_ptr<CashFlow>(new
144
0
                        FloatingCouponType(
145
0
                            paymentDate,
146
0
                            detail::get(nominals, i, 1.0),
147
0
                            start, end,
148
0
                            detail::get(fixingDays, i, index->fixingDays()),
149
0
                            index,
150
0
                            detail::get(gearings, i, 1.0),
151
0
                            detail::get(spreads, i, 0.0),
152
0
                            refStart, refEnd,
153
0
                            paymentDayCounter, isInArrears, exCouponDate)));
154
0
                else {
155
0
                    leg.push_back(ext::shared_ptr<CashFlow>(new
156
0
                        CappedFlooredCouponType(
157
0
                               paymentDate,
158
0
                               detail::get(nominals, i, 1.0),
159
0
                               start, end,
160
0
                               detail::get(fixingDays, i, index->fixingDays()),
161
0
                               index,
162
0
                               detail::get(gearings, i, 1.0),
163
0
                               detail::get(spreads, i, 0.0),
164
0
                               detail::get(caps,   i, Null<Rate>()),
165
0
                               detail::get(floors, i, Null<Rate>()),
166
0
                               refStart, refEnd,
167
0
                               paymentDayCounter,
168
0
                               isInArrears, exCouponDate)));
169
0
                }
170
0
            }
171
0
        }
172
0
        return leg;
173
0
    }
Unexecuted instantiation: std::__1::vector<boost::shared_ptr<QuantLib::CashFlow>, std::__1::allocator<boost::shared_ptr<QuantLib::CashFlow> > > QuantLib::FloatingLeg<QuantLib::SwapIndex, QuantLib::CmsCoupon, QuantLib::CappedFlooredCmsCoupon>(QuantLib::Schedule const&, std::__1::vector<double, std::__1::allocator<double> > const&, boost::shared_ptr<QuantLib::SwapIndex> const&, QuantLib::DayCounter const&, QuantLib::BusinessDayConvention, std::__1::vector<unsigned int, std::__1::allocator<unsigned int> > const&, std::__1::vector<double, std::__1::allocator<double> > const&, std::__1::vector<double, std::__1::allocator<double> > const&, std::__1::vector<double, std::__1::allocator<double> > const&, std::__1::vector<double, std::__1::allocator<double> > const&, bool, bool, int, QuantLib::Calendar, QuantLib::Period, QuantLib::Calendar, QuantLib::BusinessDayConvention, bool)
Unexecuted instantiation: std::__1::vector<boost::shared_ptr<QuantLib::CashFlow>, std::__1::allocator<boost::shared_ptr<QuantLib::CashFlow> > > QuantLib::FloatingLeg<QuantLib::IborIndex, QuantLib::IborCoupon, QuantLib::CappedFlooredIborCoupon>(QuantLib::Schedule const&, std::__1::vector<double, std::__1::allocator<double> > const&, boost::shared_ptr<QuantLib::IborIndex> const&, QuantLib::DayCounter const&, QuantLib::BusinessDayConvention, std::__1::vector<unsigned int, std::__1::allocator<unsigned int> > const&, std::__1::vector<double, std::__1::allocator<double> > const&, std::__1::vector<double, std::__1::allocator<double> > const&, std::__1::vector<double, std::__1::allocator<double> > const&, std::__1::vector<double, std::__1::allocator<double> > const&, bool, bool, int, QuantLib::Calendar, QuantLib::Period, QuantLib::Calendar, QuantLib::BusinessDayConvention, bool)
Unexecuted instantiation: std::__1::vector<boost::shared_ptr<QuantLib::CashFlow>, std::__1::allocator<boost::shared_ptr<QuantLib::CashFlow> > > QuantLib::FloatingLeg<QuantLib::SwapSpreadIndex, QuantLib::CmsSpreadCoupon, QuantLib::CappedFlooredCmsSpreadCoupon>(QuantLib::Schedule const&, std::__1::vector<double, std::__1::allocator<double> > const&, boost::shared_ptr<QuantLib::SwapSpreadIndex> const&, QuantLib::DayCounter const&, QuantLib::BusinessDayConvention, std::__1::vector<unsigned int, std::__1::allocator<unsigned int> > const&, std::__1::vector<double, std::__1::allocator<double> > const&, std::__1::vector<double, std::__1::allocator<double> > const&, std::__1::vector<double, std::__1::allocator<double> > const&, std::__1::vector<double, std::__1::allocator<double> > const&, bool, bool, int, QuantLib::Calendar, QuantLib::Period, QuantLib::Calendar, QuantLib::BusinessDayConvention, bool)
174
175
176
    template <typename InterestRateIndexType,
177
              typename FloatingCouponType,
178
              typename DigitalCouponType>
179
    Leg FloatingDigitalLeg(
180
                        const Schedule& schedule,
181
                        const std::vector<Real>& nominals,
182
                        const ext::shared_ptr<InterestRateIndexType>& index,
183
                        const DayCounter& paymentDayCounter,
184
                        BusinessDayConvention paymentAdj,
185
                        const std::vector<Natural>& fixingDays,
186
                        const std::vector<Real>& gearings,
187
                        const std::vector<Spread>& spreads,
188
                        bool isInArrears,
189
                        const std::vector<Rate>& callStrikes,
190
                        Position::Type callPosition,
191
                        bool isCallATMIncluded,
192
                        const std::vector<Rate>& callDigitalPayoffs,
193
                        const std::vector<Rate>& putStrikes,
194
                        Position::Type putPosition,
195
                        bool isPutATMIncluded,
196
                        const std::vector<Rate>& putDigitalPayoffs,
197
                        const ext::shared_ptr<DigitalReplication>& replication,
198
0
                        bool nakedOption = false) {
199
0
        Size n = schedule.size()-1;
200
0
        QL_REQUIRE(!nominals.empty(), "no notional given");
201
0
        QL_REQUIRE(nominals.size() <= n,
202
0
                   "too many nominals (" << nominals.size() <<
203
0
                   "), only " << n << " required");
204
0
        QL_REQUIRE(gearings.size()<=n,
205
0
                   "too many gearings (" << gearings.size() <<
206
0
                   "), only " << n << " required");
207
0
        QL_REQUIRE(spreads.size()<=n,
208
0
                   "too many spreads (" << spreads.size() <<
209
0
                   "), only " << n << " required");
210
0
        QL_REQUIRE(callStrikes.size()<=n,
211
0
                   "too many call rates (" << callStrikes.size() <<
212
0
                   "), only " << n << " required");
213
0
        QL_REQUIRE(putStrikes.size()<=n,
214
0
                   "too many put rates (" << putStrikes.size() <<
215
0
                   "), only " << n << " required");
216
217
0
        Leg leg; leg.reserve(n);
218
219
        // the following is not always correct
220
0
        const Calendar& calendar = schedule.calendar();
221
222
0
        Date refStart, start, refEnd, end;
223
0
        Date paymentDate;
224
225
0
        for (Size i=0; i<n; ++i) {
226
0
            refStart = start = schedule.date(i);
227
0
            refEnd   =   end = schedule.date(i+1);
228
0
            paymentDate = calendar.adjust(end, paymentAdj);
229
0
            if (i==0 && (schedule.hasIsRegular() && schedule.hasTenor() && !schedule.isRegular(i+1))) {
230
0
                BusinessDayConvention bdc = schedule.businessDayConvention();
231
0
                refStart = calendar.adjust(end - schedule.tenor(), bdc);
232
0
            }
233
0
            if (i==n-1 && (schedule.hasIsRegular() && schedule.hasTenor() && !schedule.isRegular(i+1))) {
234
0
                BusinessDayConvention bdc = schedule.businessDayConvention();
235
0
                refEnd = calendar.adjust(start + schedule.tenor(), bdc);
236
0
            }
237
0
            if (detail::get(gearings, i, 1.0) == 0.0) { // fixed coupon
238
0
                leg.push_back(ext::shared_ptr<CashFlow>(new
239
0
                    FixedRateCoupon(paymentDate,
240
0
                                    detail::get(nominals, i, 1.0),
241
0
                                    detail::get(spreads, i, 1.0),
242
0
                                    paymentDayCounter,
243
0
                                    start, end, refStart, refEnd)));
244
0
            } else { // floating digital coupon
245
0
                ext::shared_ptr<FloatingCouponType> underlying(new
246
0
                    FloatingCouponType(paymentDate,
247
0
                                       detail::get(nominals, i, 1.0),
248
0
                                       start, end,
249
0
                                       detail::get(fixingDays, i, index->fixingDays()),
250
0
                                       index,
251
0
                                       detail::get(gearings, i, 1.0),
252
0
                                       detail::get(spreads, i, 0.0),
253
0
                                       refStart, refEnd,
254
0
                                       paymentDayCounter, isInArrears));
255
0
                leg.push_back(ext::shared_ptr<CashFlow>(new
256
0
                    DigitalCouponType(
257
0
                             underlying,
258
0
                             detail::get(callStrikes, i, Null<Real>()),
259
0
                             callPosition,
260
0
                             isCallATMIncluded,
261
0
                             detail::get(callDigitalPayoffs, i, Null<Real>()),
262
0
                             detail::get(putStrikes, i, Null<Real>()),
263
0
                             putPosition,
264
0
                             isPutATMIncluded,
265
0
                             detail::get(putDigitalPayoffs, i, Null<Real>()),
266
0
                             replication, nakedOption)));
267
0
            }
268
0
        }
269
0
        return leg;
270
0
    }
Unexecuted instantiation: std::__1::vector<boost::shared_ptr<QuantLib::CashFlow>, std::__1::allocator<boost::shared_ptr<QuantLib::CashFlow> > > QuantLib::FloatingDigitalLeg<QuantLib::SwapIndex, QuantLib::CmsCoupon, QuantLib::DigitalCmsCoupon>(QuantLib::Schedule const&, std::__1::vector<double, std::__1::allocator<double> > const&, boost::shared_ptr<QuantLib::SwapIndex> const&, QuantLib::DayCounter const&, QuantLib::BusinessDayConvention, std::__1::vector<unsigned int, std::__1::allocator<unsigned int> > const&, std::__1::vector<double, std::__1::allocator<double> > const&, std::__1::vector<double, std::__1::allocator<double> > const&, bool, std::__1::vector<double, std::__1::allocator<double> > const&, QuantLib::Position::Type, bool, std::__1::vector<double, std::__1::allocator<double> > const&, std::__1::vector<double, std::__1::allocator<double> > const&, QuantLib::Position::Type, bool, std::__1::vector<double, std::__1::allocator<double> > const&, boost::shared_ptr<QuantLib::DigitalReplication> const&, bool)
Unexecuted instantiation: std::__1::vector<boost::shared_ptr<QuantLib::CashFlow>, std::__1::allocator<boost::shared_ptr<QuantLib::CashFlow> > > QuantLib::FloatingDigitalLeg<QuantLib::IborIndex, QuantLib::IborCoupon, QuantLib::DigitalIborCoupon>(QuantLib::Schedule const&, std::__1::vector<double, std::__1::allocator<double> > const&, boost::shared_ptr<QuantLib::IborIndex> const&, QuantLib::DayCounter const&, QuantLib::BusinessDayConvention, std::__1::vector<unsigned int, std::__1::allocator<unsigned int> > const&, std::__1::vector<double, std::__1::allocator<double> > const&, std::__1::vector<double, std::__1::allocator<double> > const&, bool, std::__1::vector<double, std::__1::allocator<double> > const&, QuantLib::Position::Type, bool, std::__1::vector<double, std::__1::allocator<double> > const&, std::__1::vector<double, std::__1::allocator<double> > const&, QuantLib::Position::Type, bool, std::__1::vector<double, std::__1::allocator<double> > const&, boost::shared_ptr<QuantLib::DigitalReplication> const&, bool)
Unexecuted instantiation: std::__1::vector<boost::shared_ptr<QuantLib::CashFlow>, std::__1::allocator<boost::shared_ptr<QuantLib::CashFlow> > > QuantLib::FloatingDigitalLeg<QuantLib::SwapSpreadIndex, QuantLib::CmsSpreadCoupon, QuantLib::DigitalCmsSpreadCoupon>(QuantLib::Schedule const&, std::__1::vector<double, std::__1::allocator<double> > const&, boost::shared_ptr<QuantLib::SwapSpreadIndex> const&, QuantLib::DayCounter const&, QuantLib::BusinessDayConvention, std::__1::vector<unsigned int, std::__1::allocator<unsigned int> > const&, std::__1::vector<double, std::__1::allocator<double> > const&, std::__1::vector<double, std::__1::allocator<double> > const&, bool, std::__1::vector<double, std::__1::allocator<double> > const&, QuantLib::Position::Type, bool, std::__1::vector<double, std::__1::allocator<double> > const&, std::__1::vector<double, std::__1::allocator<double> > const&, QuantLib::Position::Type, bool, std::__1::vector<double, std::__1::allocator<double> > const&, boost::shared_ptr<QuantLib::DigitalReplication> const&, bool)
271
272
}
273
274
#endif