Coverage Report

Created: 2026-09-28 06:23

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/quantlib/ql/experimental/termstructures/basisswapratehelpers.hpp
Line
Count
Source
1
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3
/*
4
 Copyright (C) 2021 StatPro Italia srl
5
 Copyright (C) 2026 Kyrylo Protsenko
6
7
 This file is part of QuantLib, a free-software/open-source library
8
 for financial quantitative analysts and developers - http://quantlib.org/
9
10
 QuantLib is free software: you can redistribute it and/or modify it
11
 under the terms of the QuantLib license.  You should have received a
12
 copy of the license along with this program; if not, please email
13
 <quantlib-dev@lists.sf.net>. The license is also available online at
14
 <https://www.quantlib.org/license.shtml>.
15
16
 This program is distributed in the hope that it will be useful, but WITHOUT
17
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18
 FOR A PARTICULAR PURPOSE.  See the license for more details.
19
*/
20
21
/*! \file basisswapratehelpers.hpp
22
    \brief ibor-ibor, ois-ibor and ois-ois basis swap rate helpers
23
*/
24
25
#ifndef quantlib_basisswapratehelpers_hpp
26
#define quantlib_basisswapratehelpers_hpp
27
28
#include <ql/cashflows/iborcoupon.hpp>
29
#include <ql/cashflows/stubiborcoupon.hpp>
30
#include <ql/cashflows/rateaveraging.hpp>
31
#include <ql/termstructures/yield/ratehelpers.hpp>
32
#include <ql/time/dategenerationrule.hpp>
33
#include <optional>
34
35
namespace QuantLib {
36
37
    //! Rate helper for bootstrapping over ibor-ibor basis swaps
38
    /*! The swap is assumed to pay baseIndex + basis and receive
39
        otherIndex.  The helper can be used to bootstrap the forecast
40
        curve for baseIndex (in which case you'll have to pass
41
        bootstrapBaseCurve = true and provide otherIndex with a
42
        forecast curve) or the forecast curve for otherIndex (in which
43
        case bootstrapBaseCurve = false and baseIndex will need a
44
        forecast curve).
45
        In both cases, an exogenous discount curve is required.
46
47
        A payment lag can also be passed; it is applied to both legs.
48
49
        Limitation: we cannot bootstrap the forecasting curve with stubs
50
        computed off self for now.
51
    */
52
    class IborIborBasisSwapRateHelper : public RelativeDateRateHelper {
53
      public:
54
        IborIborBasisSwapRateHelper(const Handle<Quote>& basis,
55
                                    const Period& tenor,
56
                                    Natural settlementDays,
57
                                    Calendar calendar,
58
                                    BusinessDayConvention convention,
59
                                    bool endOfMonth,
60
                                    const ext::shared_ptr<IborIndex>& baseIndex,
61
                                    const ext::shared_ptr<IborIndex>& otherIndex,
62
                                    Handle<YieldTermStructure> discountHandle,
63
                                    bool bootstrapBaseCurve,
64
                                    std::optional<bool> useIndexedCoupons = std::nullopt,
65
                                    DateGeneration::Rule rule = DateGeneration::Backward,
66
                                    Integer paymentLag = 0,
67
                                    StubIndexSelection baseStubIndexSelection = {},
68
                                    StubIndexSelection otherStubIndexSelection = {});
69
70
        Real impliedQuote() const override;
71
        void accept(AcyclicVisitor&) override;
72
        // NOLINTNEXTLINE(cppcoreguidelines-noexcept-swap,performance-noexcept-swap)
73
0
        ext::shared_ptr<Swap> swap() const { return swap_; }
74
      private:
75
        void initializeDates() override;
76
        void setTermStructure(YieldTermStructure*) override;
77
78
        Period tenor_;
79
        Natural settlementDays_;
80
        Calendar calendar_;
81
        BusinessDayConvention convention_;
82
        bool endOfMonth_;
83
        ext::shared_ptr<IborIndex> baseIndex_;
84
        ext::shared_ptr<IborIndex> otherIndex_;
85
        Handle<YieldTermStructure> discountHandle_;
86
        bool bootstrapBaseCurve_;
87
        std::optional<bool> useIndexedCoupons_;
88
        DateGeneration::Rule rule_;
89
        Integer paymentLag_;
90
        StubIndexSelection baseStubIndexSelection_;
91
        StubIndexSelection otherStubIndexSelection_;
92
93
        ext::shared_ptr<Swap> swap_;
94
95
        RelinkableHandle<YieldTermStructure> termStructureHandle_;
96
    };
97
98
99
    //! Rate helper for bootstrapping over overnight-ibor basis swaps
100
    /*! The swap is assumed to pay overnight + basis and receive ibor.
101
        As a default, the helper is used to bootstrap the forecast
102
        curve for the ibor index; the overnight index will need an
103
        existing forecast curve. If bootstrapBaseCurve is set to true,
104
        instead, the helper will be used to bootstrap the forecast
105
        curve for the overnight index; in this case, the ibor index
106
        will need to be given a forecast curve.
107
108
        An exogenous discount curve can be passed; if not, the curve being
109
        bootstrapped is also used for discounting.
110
111
        A payment lag can also be passed; it is applied to both legs.
112
113
        The payment frequency of the overnight leg can be overridden.
114
        It defaults to the tenor of the ibor index.  The ibor leg
115
        always pays at the tenor of its own index.  Passing NoFrequency
116
        creates a single overnight coupon spanning the full swap tenor.
117
118
        The averaging method and use of telescopic value dates can be
119
        configured for the overnight leg.  Telescopic value dates are only
120
        applied to compounded coupons.
121
122
        The basis is quoted on the overnight (base) leg by default.  Setting
123
        basisOnIborLeg solves for a margin quoted on the ibor leg instead.
124
125
        A stub-index configuration can be passed for the ibor leg; it is
126
        applied to that leg's irregular coupons (see StubIndexSelection).
127
        Since the candidate indices keep their own forwarding curves,
128
        this is only allowed when bootstrapBaseCurve is true, i.e. when
129
        the ibor index has an exogenous forecast curve; otherwise the
130
        candidates could not track the curve under construction.
131
    */
132
    class OvernightIborBasisSwapRateHelper : public RelativeDateRateHelper {
133
      public:
134
        OvernightIborBasisSwapRateHelper(const Handle<Quote>& basis,
135
                                         const Period& tenor,
136
                                         Natural settlementDays,
137
                                         Calendar calendar,
138
                                         BusinessDayConvention convention,
139
                                         bool endOfMonth,
140
                                         const ext::shared_ptr<OvernightIndex>& baseIndex,
141
                                         const ext::shared_ptr<IborIndex>& otherIndex,
142
                                         Handle<YieldTermStructure> discountHandle = Handle<YieldTermStructure>(),
143
                                         bool bootstrapBaseCurve = false,
144
                                         Integer paymentLag = 0,
145
                                         std::optional<Frequency> overnightPaymentFrequency = std::nullopt,
146
                                         std::optional<bool> useIndexedCoupons = std::nullopt,
147
                                         DateGeneration::Rule rule = DateGeneration::Backward,
148
                                         RateAveraging::Type averagingMethod = RateAveraging::Compound,
149
                                         bool telescopicValueDates = false,
150
                                         bool basisOnIborLeg = false,
151
                                         StubIndexSelection iborStubIndexSelection = {});
152
153
        Real impliedQuote() const override;
154
        void accept(AcyclicVisitor&) override;
155
        // NOLINTNEXTLINE(cppcoreguidelines-noexcept-swap,performance-noexcept-swap)
156
0
        ext::shared_ptr<Swap> swap() const { return swap_; }
157
      private:
158
        void initializeDates() override;
159
        void setTermStructure(YieldTermStructure*) override;
160
161
        Period tenor_;
162
        Natural settlementDays_;
163
        Calendar calendar_;
164
        BusinessDayConvention convention_;
165
        bool endOfMonth_;
166
        ext::shared_ptr<OvernightIndex> baseIndex_;
167
        ext::shared_ptr<IborIndex> otherIndex_;
168
        Handle<YieldTermStructure> discountHandle_;
169
        bool bootstrapBaseCurve_;
170
        Integer paymentLag_;
171
        std::optional<Frequency> overnightPaymentFrequency_;
172
        std::optional<bool> useIndexedCoupons_;
173
        DateGeneration::Rule rule_;
174
        RateAveraging::Type averagingMethod_;
175
        bool telescopicValueDates_;
176
        bool basisOnIborLeg_;
177
        StubIndexSelection iborStubIndexSelection_;
178
179
        ext::shared_ptr<Swap> swap_;
180
181
        RelinkableHandle<YieldTermStructure> termStructureHandle_;
182
        RelinkableHandle<YieldTermStructure> discountRelinkableHandle_;
183
    };
184
185
186
    //! Rate helper for bootstrapping over overnight-overnight basis swaps
187
    /*! The swap is assumed to pay baseIndex + basis and receive otherIndex.
188
        The helper can be used to bootstrap the forecast curve for either
189
        index; the other index must have an existing forecast curve.
190
191
        An exogenous discount curve can be passed.  If none is passed, the
192
        curve being bootstrapped is also used for discounting.
193
194
        Both legs share the same schedule and payment lag, but their
195
        averaging methods can be configured independently.  This allows,
196
        for instance, an arithmetically averaged Fed Funds leg to be matched
197
        against a compounded SOFR leg.  Telescopic value dates are only
198
        applied to compounded legs. Arithmetically averaged legs retain their
199
        full value-date schedule so that they are priced exactly.
200
201
        Passing NoFrequency as the payment frequency creates one coupon on
202
        each leg spanning the full swap tenor.
203
    */
204
    class OvernightOvernightBasisSwapRateHelper : public RelativeDateRateHelper {
205
      public:
206
        OvernightOvernightBasisSwapRateHelper(
207
            const Handle<Quote>& basis,
208
            const Period& tenor,
209
            Natural settlementDays,
210
            Calendar calendar,
211
            BusinessDayConvention convention,
212
            bool endOfMonth,
213
            const ext::shared_ptr<OvernightIndex>& baseIndex,
214
            const ext::shared_ptr<OvernightIndex>& otherIndex,
215
            Handle<YieldTermStructure> discountHandle = Handle<YieldTermStructure>(),
216
            bool bootstrapBaseCurve = false,
217
            Integer paymentLag = 0,
218
            Frequency paymentFrequency = Annual,
219
            RateAveraging::Type baseAveragingMethod = RateAveraging::Compound,
220
            RateAveraging::Type otherAveragingMethod = RateAveraging::Compound,
221
            bool telescopicValueDates = false,
222
            DateGeneration::Rule rule = DateGeneration::Backward);
223
224
        Real impliedQuote() const override;
225
        void accept(AcyclicVisitor&) override;
226
        // NOLINTNEXTLINE(cppcoreguidelines-noexcept-swap,performance-noexcept-swap)
227
0
        ext::shared_ptr<Swap> swap() const { return swap_; }
228
      private:
229
        void initializeDates() override;
230
        void setTermStructure(YieldTermStructure*) override;
231
232
        Period tenor_;
233
        Natural settlementDays_;
234
        Calendar calendar_;
235
        BusinessDayConvention convention_;
236
        bool endOfMonth_;
237
        ext::shared_ptr<OvernightIndex> baseIndex_;
238
        ext::shared_ptr<OvernightIndex> otherIndex_;
239
        Handle<YieldTermStructure> discountHandle_;
240
        bool bootstrapBaseCurve_;
241
        Integer paymentLag_;
242
        Frequency paymentFrequency_;
243
        RateAveraging::Type baseAveragingMethod_;
244
        RateAveraging::Type otherAveragingMethod_;
245
        bool telescopicValueDates_;
246
        DateGeneration::Rule rule_;
247
248
        ext::shared_ptr<Swap> swap_;
249
250
        RelinkableHandle<YieldTermStructure> termStructureHandle_;
251
        RelinkableHandle<YieldTermStructure> discountRelinkableHandle_;
252
    };
253
254
}
255
256
#endif