Coverage Report

Created: 2025-08-11 06:28

/src/quantlib/ql/instruments/makeois.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) 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
 <http://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
        Date startDate;
50
0
        if (effectiveDate_ != Date())
51
0
            startDate = effectiveDate_;
52
0
        else {
53
            // settlement days: override if set, else fallback to default by index name
54
0
            Natural settlementDays = settlementDays_;
55
0
            if (settlementDays == Null<Natural>()) {
56
0
                if (ext::dynamic_pointer_cast<Sonia>(overnightIndex_)) {
57
0
                    settlementDays = 0; 
58
0
                }
59
0
                else if (ext::dynamic_pointer_cast<Corra>(overnightIndex_)) {
60
0
                    settlementDays = 1;
61
0
                }
62
0
                else {
63
0
                    settlementDays = 2;
64
0
                }
65
0
            }            
66
67
0
            Date refDate = Settings::instance().evaluationDate();
68
            // if the evaluation date is not a business day
69
            // then move to the next business day
70
0
            refDate = overnightCalendar_.adjust(refDate);
71
0
            Date spotDate = overnightCalendar_.advance(refDate,
72
0
                                                       settlementDays*Days);
73
0
            startDate = spotDate+forwardStart_;
74
0
            if (forwardStart_.length()<0)
75
0
                startDate = overnightCalendar_.adjust(startDate, Preceding);
76
0
            else
77
0
                startDate = overnightCalendar_.adjust(startDate, Following);
78
0
        }
79
80
        // OIS end of month default
81
0
        bool fixedEndOfMonth, overnightEndOfMonth;
82
0
        if (isDefaultEOM_)
83
0
            fixedEndOfMonth = overnightEndOfMonth = overnightCalendar_.isEndOfMonth(startDate);
84
0
        else {
85
0
            fixedEndOfMonth = fixedEndOfMonth_;
86
0
            overnightEndOfMonth = overnightEndOfMonth_;
87
0
        }
88
89
0
        Date endDate = terminationDate_;
90
0
        if (endDate == Date()) {
91
0
            if (overnightEndOfMonth)
92
0
                endDate = overnightCalendar_.advance(startDate,
93
0
                                                     swapTenor_,
94
0
                                                     ModifiedFollowing,
95
0
                                                     overnightEndOfMonth);
96
0
            else
97
0
                endDate = startDate + swapTenor_;
98
0
        }
99
100
0
        Frequency fixedPaymentFrequency, overnightPaymentFrequency;
101
0
        DateGeneration::Rule fixedRule, overnightRule;
102
0
        if (fixedPaymentFrequency_ == Once || fixedRule_ == DateGeneration::Zero) {
103
0
            fixedPaymentFrequency = Once;
104
0
            fixedRule = DateGeneration::Zero;
105
0
        } else {
106
0
            fixedPaymentFrequency = fixedPaymentFrequency_;
107
0
            fixedRule = fixedRule_;
108
0
        }
109
0
        if (overnightPaymentFrequency_ == Once || overnightRule_ == DateGeneration::Zero) {
110
0
            overnightPaymentFrequency = Once;
111
0
            overnightRule = DateGeneration::Zero;
112
0
        } else {
113
0
            overnightPaymentFrequency = overnightPaymentFrequency_;
114
0
            overnightRule = overnightRule_;
115
0
        }
116
117
0
        Schedule fixedSchedule(startDate, endDate,
118
0
                               Period(fixedPaymentFrequency),
119
0
                               fixedCalendar_,
120
0
                               fixedConvention_,
121
0
                               fixedTerminationDateConvention_,
122
0
                               fixedRule,
123
0
                               fixedEndOfMonth);
124
125
0
        Schedule overnightSchedule(startDate, endDate,
126
0
                                   Period(overnightPaymentFrequency),
127
0
                                   overnightCalendar_,
128
0
                                   overnightConvention_,
129
0
                                   overnightTerminationDateConvention_,
130
0
                                   overnightRule,
131
0
                                   overnightEndOfMonth);
132
133
0
        Rate usedFixedRate = fixedRate_;
134
0
        if (fixedRate_ == Null<Rate>()) {
135
0
            OvernightIndexedSwap temp(type_, nominal_,
136
0
                                      fixedSchedule,
137
0
                                      0.0, // fixed rate
138
0
                                      fixedDayCount_,
139
0
                                      overnightSchedule,
140
0
                                      overnightIndex_, overnightSpread_,
141
0
                                      paymentLag_, paymentAdjustment_,
142
0
                                      paymentCalendar_, telescopicValueDates_);
143
0
            if (engine_ == nullptr) {
144
0
                Handle<YieldTermStructure> disc =
145
0
                                    overnightIndex_->forwardingTermStructure();
146
0
                QL_REQUIRE(!disc.empty(),
147
0
                           "null term structure set to this instance of " <<
148
0
                           overnightIndex_->name());
149
0
                bool includeSettlementDateFlows = false;
150
0
                ext::shared_ptr<PricingEngine> engine(new
151
0
                    DiscountingSwapEngine(disc, includeSettlementDateFlows));
152
0
                temp.setPricingEngine(engine);
153
0
            } else
154
0
                temp.setPricingEngine(engine_);
155
156
0
            usedFixedRate = temp.fairRate();
157
0
        }
158
159
0
        ext::shared_ptr<OvernightIndexedSwap> ois(new
160
0
            OvernightIndexedSwap(type_, nominal_,
161
0
                                 fixedSchedule,
162
0
                                 usedFixedRate, fixedDayCount_,
163
0
                                 overnightSchedule,
164
0
                                 overnightIndex_, overnightSpread_,
165
0
                                 paymentLag_, paymentAdjustment_,
166
0
                                 paymentCalendar_, telescopicValueDates_, 
167
0
                                 averagingMethod_, lookbackDays_,
168
0
                                 lockoutDays_, applyObservationShift_));
169
170
0
        if (engine_ == nullptr) {
171
0
            Handle<YieldTermStructure> disc =
172
0
                                overnightIndex_->forwardingTermStructure();
173
0
            bool includeSettlementDateFlows = false;
174
0
            ext::shared_ptr<PricingEngine> engine(new
175
0
                DiscountingSwapEngine(disc, includeSettlementDateFlows));
176
0
            ois->setPricingEngine(engine);
177
0
        } else
178
0
            ois->setPricingEngine(engine_);
179
180
0
        return ois;
181
0
    }
182
183
0
    MakeOIS& MakeOIS::receiveFixed(bool flag) {
184
0
        type_ = flag ? Swap::Receiver : Swap::Payer ;
185
0
        return *this;
186
0
    }
187
188
0
    MakeOIS& MakeOIS::withType(Swap::Type type) {
189
0
        type_ = type;
190
0
        return *this;
191
0
    }
192
193
0
    MakeOIS& MakeOIS::withNominal(Real n) {
194
0
        nominal_ = n;
195
0
        return *this;
196
0
    }
197
198
0
    MakeOIS& MakeOIS::withSettlementDays(Natural settlementDays) {
199
0
        settlementDays_ = settlementDays;
200
0
        effectiveDate_ = Date();
201
0
        return *this;
202
0
    }
203
204
0
    MakeOIS& MakeOIS::withEffectiveDate(const Date& effectiveDate) {
205
0
        effectiveDate_ = effectiveDate;
206
0
        return *this;
207
0
    }
208
209
0
    MakeOIS& MakeOIS::withTerminationDate(const Date& terminationDate) {
210
0
        terminationDate_ = terminationDate;
211
0
        if (terminationDate != Date())
212
0
            swapTenor_ = Period();
213
0
        return *this;
214
0
    }
215
216
0
    MakeOIS& MakeOIS::withPaymentFrequency(Frequency f) {
217
0
        return withFixedLegPaymentFrequency(f).withOvernightLegPaymentFrequency(f);
218
0
    }
219
220
0
    MakeOIS& MakeOIS::withFixedLegPaymentFrequency(Frequency f) {
221
0
        fixedPaymentFrequency_ = f;
222
0
        return *this;
223
0
    }
224
225
0
    MakeOIS& MakeOIS::withOvernightLegPaymentFrequency(Frequency f) {
226
0
        overnightPaymentFrequency_ = f;
227
0
        return *this;
228
0
    }
229
230
0
    MakeOIS& MakeOIS::withPaymentAdjustment(BusinessDayConvention convention) {
231
0
        paymentAdjustment_ = convention;
232
0
        return *this;
233
0
    }
234
235
0
    MakeOIS& MakeOIS::withPaymentLag(Integer lag) {
236
0
        paymentLag_ = lag;
237
0
        return *this;
238
0
    }
239
240
0
    MakeOIS& MakeOIS::withPaymentCalendar(const Calendar& cal) {
241
0
        paymentCalendar_ = cal;
242
0
        return *this;
243
0
    }
244
245
0
    MakeOIS& MakeOIS::withCalendar(const Calendar& cal) {
246
0
        return withFixedLegCalendar(cal).withOvernightLegCalendar(cal);
247
0
    }
248
249
0
    MakeOIS& MakeOIS::withFixedLegCalendar(const Calendar& cal) {
250
0
        fixedCalendar_ = cal;
251
0
        return *this;
252
0
    }
253
254
0
    MakeOIS& MakeOIS::withOvernightLegCalendar(const Calendar& cal) {
255
0
        overnightCalendar_ = cal;
256
0
        return *this;
257
0
    }
258
259
0
    MakeOIS& MakeOIS::withRule(DateGeneration::Rule r) {
260
0
        return withFixedLegRule(r).withOvernightLegRule(r);
261
0
    }
262
263
0
    MakeOIS& MakeOIS::withFixedLegRule(DateGeneration::Rule r) {
264
0
        fixedRule_ = r;
265
0
        return *this;
266
0
    }
267
268
0
    MakeOIS& MakeOIS::withOvernightLegRule(DateGeneration::Rule r) {
269
0
        overnightRule_ = r;
270
0
        return *this;
271
0
    }
272
273
    MakeOIS& MakeOIS::withDiscountingTermStructure(
274
0
                                        const Handle<YieldTermStructure>& d) {
275
0
        bool includeSettlementDateFlows = false;
276
0
        engine_ = ext::shared_ptr<PricingEngine>(new
277
0
            DiscountingSwapEngine(d, includeSettlementDateFlows));
278
0
        return *this;
279
0
    }
280
281
    MakeOIS& MakeOIS::withPricingEngine(
282
0
                             const ext::shared_ptr<PricingEngine>& engine) {
283
0
        engine_ = engine;
284
0
        return *this;
285
0
    }
286
287
0
    MakeOIS& MakeOIS::withFixedLegDayCount(const DayCounter& dc) {
288
0
        fixedDayCount_ = dc;
289
0
        return *this;
290
0
    }
291
292
0
    MakeOIS& MakeOIS::withConvention(BusinessDayConvention bdc) {
293
0
        return withFixedLegConvention(bdc).withOvernightLegConvention(bdc);
294
0
    }
295
296
0
    MakeOIS& MakeOIS::withFixedLegConvention(BusinessDayConvention bdc) {
297
0
        fixedConvention_ = bdc;
298
0
        return *this;
299
0
    }
300
301
0
    MakeOIS& MakeOIS::withOvernightLegConvention(BusinessDayConvention bdc) {
302
0
        overnightConvention_ = bdc;
303
0
        return *this;
304
0
    }
305
306
0
    MakeOIS& MakeOIS::withTerminationDateConvention(BusinessDayConvention bdc) {
307
0
        withFixedLegTerminationDateConvention(bdc);
308
0
        return withOvernightLegTerminationDateConvention(bdc);
309
0
    }
310
311
0
    MakeOIS& MakeOIS::withFixedLegTerminationDateConvention(BusinessDayConvention bdc) {
312
0
        fixedTerminationDateConvention_ = bdc;
313
0
        return *this;
314
0
    }
315
316
0
    MakeOIS& MakeOIS::withOvernightLegTerminationDateConvention(BusinessDayConvention bdc) {
317
0
        overnightTerminationDateConvention_ = bdc;
318
0
        return *this;
319
0
    }
320
321
0
    MakeOIS& MakeOIS::withEndOfMonth(bool flag) {
322
0
        return withFixedLegEndOfMonth(flag).withOvernightLegEndOfMonth(flag);
323
0
    }
324
325
0
    MakeOIS& MakeOIS::withFixedLegEndOfMonth(bool flag) {
326
0
        fixedEndOfMonth_ = flag;
327
0
        isDefaultEOM_ = false;
328
0
        return *this;
329
0
    }
330
331
0
    MakeOIS& MakeOIS::withOvernightLegEndOfMonth(bool flag) {
332
0
        overnightEndOfMonth_ = flag;
333
0
        isDefaultEOM_ = false;
334
0
        return *this;
335
0
    }
336
337
0
    MakeOIS& MakeOIS::withOvernightLegSpread(Spread sp) {
338
0
        overnightSpread_ = sp;
339
0
        return *this;
340
0
    }
341
342
0
    MakeOIS& MakeOIS::withTelescopicValueDates(bool telescopicValueDates) {
343
0
        telescopicValueDates_ = telescopicValueDates;
344
0
        return *this;
345
0
    }
346
347
0
    MakeOIS& MakeOIS::withAveragingMethod(RateAveraging::Type averagingMethod) {
348
0
        averagingMethod_ = averagingMethod;
349
0
        return *this;
350
0
    }
351
352
0
    MakeOIS& MakeOIS::withLookbackDays(Natural lookbackDays) {
353
0
        lookbackDays_ = lookbackDays;
354
0
        return *this;
355
0
    }
356
357
0
    MakeOIS& MakeOIS::withLockoutDays(Natural lockoutDays) {
358
0
        lockoutDays_ = lockoutDays;
359
0
        return *this;
360
0
    }
361
362
0
    MakeOIS& MakeOIS::withObservationShift(bool applyObservationShift) {
363
0
        applyObservationShift_ = applyObservationShift;
364
0
        return *this;
365
0
    }
366
367
}