Coverage Report

Created: 2026-06-08 06:47

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/quantlib/ql/instruments/makeois.cpp
Line
Count
Source
1
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3
/*
4
 Copyright (C) 2009, 2014, 2015 Ferdinando Ametrano
5
 Copyright (C) 2015 Paolo Mazzocchi
6
 Copyright (C) 2017 Joseph Jeisman
7
 Copyright (C) 2017 Fabrice Lecuyer
8
9
 This file is part of QuantLib, a free-software/open-source library
10
 for financial quantitative analysts and developers - http://quantlib.org/
11
12
 QuantLib is free software: you can redistribute it and/or modify it
13
 under the terms of the QuantLib license.  You should have received a
14
 copy of the license along with this program; if not, please email
15
 <quantlib-dev@lists.sf.net>. The license is also available online at
16
 <https://www.quantlib.org/license.shtml>.
17
18
 This program is distributed in the hope that it will be useful, but WITHOUT
19
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
20
 FOR A PARTICULAR PURPOSE.  See the license for more details.
21
*/
22
23
#include <ql/instruments/makeois.hpp>
24
#include <ql/pricingengines/swap/discountingswapengine.hpp>
25
#include <ql/indexes/iborindex.hpp>
26
#include <ql/time/schedule.hpp>
27
#include <ql/indexes/ibor/sonia.hpp>
28
#include <ql/indexes/ibor/corra.hpp>
29
30
namespace QuantLib {
31
32
    MakeOIS::MakeOIS(const Period& swapTenor,
33
                     const ext::shared_ptr<OvernightIndex>& overnightIndex,
34
                     Rate fixedRate,
35
                     const Period& forwardStart)
36
0
    : swapTenor_(swapTenor), overnightIndex_(overnightIndex), fixedRate_(fixedRate),
37
0
      forwardStart_(forwardStart),
38
0
      fixedCalendar_(overnightIndex->fixingCalendar()),
39
0
      overnightCalendar_(overnightIndex->fixingCalendar()),
40
0
      fixedDayCount_(overnightIndex->dayCounter()) {}
41
42
0
    MakeOIS::operator OvernightIndexedSwap() const {
43
0
        ext::shared_ptr<OvernightIndexedSwap> ois = *this;
44
0
        return *ois;
45
0
    }
46
47
0
    MakeOIS::operator ext::shared_ptr<OvernightIndexedSwap>() const {
48
49
0
        QL_REQUIRE(effectiveDate_ == Date() || settlementDays_ == Null<Natural>(),
50
0
                   "cannot set both an explicit effective date and settlement days; "
51
0
                   "use one or the other");
52
53
0
        Date startDate;
54
0
        if (effectiveDate_ != Date())
55
0
            startDate = effectiveDate_;
56
0
        else {
57
            // settlement days: override if set, else fallback to default by index name
58
0
            Natural settlementDays = settlementDays_;
59
0
            if (settlementDays == Null<Natural>()) {
60
0
                if (ext::dynamic_pointer_cast<Sonia>(overnightIndex_)) {
61
0
                    settlementDays = 0; 
62
0
                }
63
0
                else if (ext::dynamic_pointer_cast<Corra>(overnightIndex_)) {
64
0
                    settlementDays = 1;
65
0
                }
66
0
                else {
67
0
                    settlementDays = 2;
68
0
                }
69
0
            }            
70
71
0
            Date refDate = Settings::instance().evaluationDate();
72
            // if the evaluation date is not a business day
73
            // then move to the next business day
74
0
            refDate = overnightCalendar_.adjust(refDate);
75
0
            Date spotDate = overnightCalendar_.advance(refDate,
76
0
                                                       settlementDays*Days);
77
0
            startDate = spotDate+forwardStart_;
78
0
            if (forwardStart_.length()<0)
79
0
                startDate = overnightCalendar_.adjust(startDate, Preceding);
80
0
            else
81
0
                startDate = overnightCalendar_.adjust(startDate, Following);
82
0
        }
83
84
0
        bool fixedEndOfMonth, overnightEndOfMonth, maturityEndOfMonth;
85
0
        if (isDefaultEOM_)
86
0
            fixedEndOfMonth = overnightEndOfMonth = maturityEndOfMonth =
87
0
                overnightCalendar_.isEndOfMonth(startDate);
88
0
        else {
89
0
            fixedEndOfMonth = fixedEndOfMonth_;
90
0
            overnightEndOfMonth = overnightEndOfMonth_;
91
0
            maturityEndOfMonth = maturityEndOfMonth_ ? *maturityEndOfMonth_ : overnightEndOfMonth_;
92
0
        }
93
94
0
        Date endDate = terminationDate_;
95
0
        if (endDate == Date()) {
96
0
            endDate = startDate + swapTenor_;
97
0
            if (maturityEndOfMonth && allowsEndOfMonth(swapTenor_) &&
98
0
                overnightCalendar_.isEndOfMonth(startDate))
99
0
                endDate = overnightCalendar_.endOfMonth(endDate);
100
0
        }
101
102
0
        Frequency fixedPaymentFrequency, overnightPaymentFrequency;
103
0
        DateGeneration::Rule fixedRule, overnightRule;
104
0
        if (fixedPaymentFrequency_ == Once || fixedRule_ == DateGeneration::Zero) {
105
0
            fixedPaymentFrequency = Once;
106
0
            fixedRule = DateGeneration::Zero;
107
0
        } else {
108
0
            fixedPaymentFrequency = fixedPaymentFrequency_;
109
0
            fixedRule = fixedRule_;
110
0
        }
111
0
        if (overnightPaymentFrequency_ == Once || overnightRule_ == DateGeneration::Zero) {
112
0
            overnightPaymentFrequency = Once;
113
0
            overnightRule = DateGeneration::Zero;
114
0
        } else {
115
0
            overnightPaymentFrequency = overnightPaymentFrequency_;
116
0
            overnightRule = overnightRule_;
117
0
        }
118
119
0
        Schedule fixedSchedule(startDate, endDate,
120
0
                               Period(fixedPaymentFrequency),
121
0
                               fixedCalendar_,
122
0
                               fixedConvention_,
123
0
                               fixedTerminationDateConvention_,
124
0
                               fixedRule,
125
0
                               fixedEndOfMonth);
126
127
0
        Schedule overnightSchedule(startDate, endDate,
128
0
                                   Period(overnightPaymentFrequency),
129
0
                                   overnightCalendar_,
130
0
                                   overnightConvention_,
131
0
                                   overnightTerminationDateConvention_,
132
0
                                   overnightRule,
133
0
                                   overnightEndOfMonth);
134
135
0
        Rate usedFixedRate = fixedRate_;
136
0
        if (fixedRate_ == Null<Rate>()) {
137
0
            OvernightIndexedSwap temp(type_, nominal_,
138
0
                                      fixedSchedule,
139
0
                                      0.0, // fixed rate
140
0
                                      fixedDayCount_,
141
0
                                      overnightSchedule,
142
0
                                      overnightIndex_, overnightSpread_,
143
0
                                      paymentLag_, paymentAdjustment_,
144
0
                                      paymentCalendar_, telescopicValueDates_);
145
0
            if (engine_ == nullptr) {
146
0
                Handle<YieldTermStructure> disc =
147
0
                                    overnightIndex_->forwardingTermStructure();
148
0
                QL_REQUIRE(!disc.empty(),
149
0
                           "null term structure set to this instance of " <<
150
0
                           overnightIndex_->name());
151
0
                bool includeSettlementDateFlows = false;
152
0
                ext::shared_ptr<PricingEngine> engine(new
153
0
                    DiscountingSwapEngine(disc, includeSettlementDateFlows));
154
0
                temp.setPricingEngine(engine);
155
0
            } else
156
0
                temp.setPricingEngine(engine_);
157
158
0
            usedFixedRate = temp.fairRate();
159
0
        }
160
161
0
        ext::shared_ptr<OvernightIndexedSwap> ois(new
162
0
            OvernightIndexedSwap(type_, nominal_,
163
0
                                 fixedSchedule,
164
0
                                 usedFixedRate, fixedDayCount_,
165
0
                                 overnightSchedule,
166
0
                                 overnightIndex_, overnightSpread_,
167
0
                                 paymentLag_, paymentAdjustment_,
168
0
                                 paymentCalendar_, telescopicValueDates_, 
169
0
                                 averagingMethod_, lookbackDays_,
170
0
                                 lockoutDays_, applyObservationShift_));
171
172
0
        if (engine_ == nullptr) {
173
0
            Handle<YieldTermStructure> disc =
174
0
                                overnightIndex_->forwardingTermStructure();
175
0
            bool includeSettlementDateFlows = false;
176
0
            ext::shared_ptr<PricingEngine> engine(new
177
0
                DiscountingSwapEngine(disc, includeSettlementDateFlows));
178
0
            ois->setPricingEngine(engine);
179
0
        } else
180
0
            ois->setPricingEngine(engine_);
181
182
0
        return ois;
183
0
    }
184
185
0
    MakeOIS& MakeOIS::receiveFixed(bool flag) {
186
0
        type_ = flag ? Swap::Receiver : Swap::Payer ;
187
0
        return *this;
188
0
    }
189
190
0
    MakeOIS& MakeOIS::withType(Swap::Type type) {
191
0
        type_ = type;
192
0
        return *this;
193
0
    }
194
195
0
    MakeOIS& MakeOIS::withNominal(Real n) {
196
0
        nominal_ = n;
197
0
        return *this;
198
0
    }
199
200
0
    MakeOIS& MakeOIS::withSettlementDays(Natural settlementDays) {
201
0
        settlementDays_ = settlementDays;
202
0
        return *this;
203
0
    }
204
205
0
    MakeOIS& MakeOIS::withEffectiveDate(const Date& effectiveDate) {
206
0
        effectiveDate_ = effectiveDate;
207
0
        return *this;
208
0
    }
209
210
0
    MakeOIS& MakeOIS::withTerminationDate(const Date& terminationDate) {
211
0
        terminationDate_ = terminationDate;
212
0
        if (terminationDate != Date())
213
0
            swapTenor_ = Period();
214
0
        return *this;
215
0
    }
216
217
0
    MakeOIS& MakeOIS::withPaymentFrequency(Frequency f) {
218
0
        return withFixedLegPaymentFrequency(f).withOvernightLegPaymentFrequency(f);
219
0
    }
220
221
0
    MakeOIS& MakeOIS::withFixedLegPaymentFrequency(Frequency f) {
222
0
        fixedPaymentFrequency_ = f;
223
0
        return *this;
224
0
    }
225
226
0
    MakeOIS& MakeOIS::withOvernightLegPaymentFrequency(Frequency f) {
227
0
        overnightPaymentFrequency_ = f;
228
0
        return *this;
229
0
    }
230
231
0
    MakeOIS& MakeOIS::withPaymentAdjustment(BusinessDayConvention convention) {
232
0
        paymentAdjustment_ = convention;
233
0
        return *this;
234
0
    }
235
236
0
    MakeOIS& MakeOIS::withPaymentLag(Integer lag) {
237
0
        paymentLag_ = lag;
238
0
        return *this;
239
0
    }
240
241
0
    MakeOIS& MakeOIS::withPaymentCalendar(const Calendar& cal) {
242
0
        paymentCalendar_ = cal;
243
0
        return *this;
244
0
    }
245
246
0
    MakeOIS& MakeOIS::withCalendar(const Calendar& cal) {
247
0
        return withFixedLegCalendar(cal).withOvernightLegCalendar(cal);
248
0
    }
249
250
0
    MakeOIS& MakeOIS::withFixedLegCalendar(const Calendar& cal) {
251
0
        fixedCalendar_ = cal;
252
0
        return *this;
253
0
    }
254
255
0
    MakeOIS& MakeOIS::withOvernightLegCalendar(const Calendar& cal) {
256
0
        overnightCalendar_ = cal;
257
0
        return *this;
258
0
    }
259
260
0
    MakeOIS& MakeOIS::withRule(DateGeneration::Rule r) {
261
0
        return withFixedLegRule(r).withOvernightLegRule(r);
262
0
    }
263
264
0
    MakeOIS& MakeOIS::withFixedLegRule(DateGeneration::Rule r) {
265
0
        fixedRule_ = r;
266
0
        return *this;
267
0
    }
268
269
0
    MakeOIS& MakeOIS::withOvernightLegRule(DateGeneration::Rule r) {
270
0
        overnightRule_ = r;
271
0
        return *this;
272
0
    }
273
274
    MakeOIS& MakeOIS::withDiscountingTermStructure(
275
0
                                        const Handle<YieldTermStructure>& d) {
276
0
        bool includeSettlementDateFlows = false;
277
0
        engine_ = ext::shared_ptr<PricingEngine>(new
278
0
            DiscountingSwapEngine(d, includeSettlementDateFlows));
279
0
        return *this;
280
0
    }
281
282
    MakeOIS& MakeOIS::withPricingEngine(
283
0
                             const ext::shared_ptr<PricingEngine>& engine) {
284
0
        engine_ = engine;
285
0
        return *this;
286
0
    }
287
288
0
    MakeOIS& MakeOIS::withFixedLegDayCount(const DayCounter& dc) {
289
0
        fixedDayCount_ = dc;
290
0
        return *this;
291
0
    }
292
293
0
    MakeOIS& MakeOIS::withConvention(BusinessDayConvention bdc) {
294
0
        return withFixedLegConvention(bdc).withOvernightLegConvention(bdc);
295
0
    }
296
297
0
    MakeOIS& MakeOIS::withFixedLegConvention(BusinessDayConvention bdc) {
298
0
        fixedConvention_ = bdc;
299
0
        return *this;
300
0
    }
301
302
0
    MakeOIS& MakeOIS::withOvernightLegConvention(BusinessDayConvention bdc) {
303
0
        overnightConvention_ = bdc;
304
0
        return *this;
305
0
    }
306
307
0
    MakeOIS& MakeOIS::withTerminationDateConvention(BusinessDayConvention bdc) {
308
0
        withFixedLegTerminationDateConvention(bdc);
309
0
        return withOvernightLegTerminationDateConvention(bdc);
310
0
    }
311
312
0
    MakeOIS& MakeOIS::withFixedLegTerminationDateConvention(BusinessDayConvention bdc) {
313
0
        fixedTerminationDateConvention_ = bdc;
314
0
        return *this;
315
0
    }
316
317
0
    MakeOIS& MakeOIS::withOvernightLegTerminationDateConvention(BusinessDayConvention bdc) {
318
0
        overnightTerminationDateConvention_ = bdc;
319
0
        return *this;
320
0
    }
321
322
0
    MakeOIS& MakeOIS::withEndOfMonth(bool flag) {
323
0
        return withFixedLegEndOfMonth(flag).withOvernightLegEndOfMonth(flag);
324
0
    }
325
326
0
    MakeOIS& MakeOIS::withFixedLegEndOfMonth(bool flag) {
327
0
        fixedEndOfMonth_ = flag;
328
0
        isDefaultEOM_ = false;
329
0
        return *this;
330
0
    }
331
332
0
    MakeOIS& MakeOIS::withOvernightLegEndOfMonth(bool flag) {
333
0
        overnightEndOfMonth_ = flag;
334
0
        isDefaultEOM_ = false;
335
0
        return *this;
336
0
    }
337
338
0
    MakeOIS& MakeOIS::withMaturityEndOfMonth(bool flag) {
339
0
        maturityEndOfMonth_ = flag;
340
0
        isDefaultEOM_ = false;
341
0
        return *this;
342
0
    }
343
344
0
    MakeOIS& MakeOIS::withOvernightLegSpread(Spread sp) {
345
0
        overnightSpread_ = sp;
346
0
        return *this;
347
0
    }
348
349
0
    MakeOIS& MakeOIS::withTelescopicValueDates(bool telescopicValueDates) {
350
0
        telescopicValueDates_ = telescopicValueDates;
351
0
        return *this;
352
0
    }
353
354
0
    MakeOIS& MakeOIS::withAveragingMethod(RateAveraging::Type averagingMethod) {
355
0
        averagingMethod_ = averagingMethod;
356
0
        return *this;
357
0
    }
358
359
0
    MakeOIS& MakeOIS::withLookbackDays(Natural lookbackDays) {
360
0
        lookbackDays_ = lookbackDays;
361
0
        return *this;
362
0
    }
363
364
0
    MakeOIS& MakeOIS::withLockoutDays(Natural lockoutDays) {
365
0
        lockoutDays_ = lockoutDays;
366
0
        return *this;
367
0
    }
368
369
0
    MakeOIS& MakeOIS::withObservationShift(bool applyObservationShift) {
370
0
        applyObservationShift_ = applyObservationShift;
371
0
        return *this;
372
0
    }
373
374
}