Coverage Report

Created: 2025-09-04 07:11

/src/quantlib/ql/models/shortrate/calibrationhelpers/swaptionhelper.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) 2001, 2002, 2003 Sadruddin Rejeb
5
 Copyright (C) 2007 StatPro Italia srl
6
 Copyright (C) 2015 Peter Caspers
7
8
 This file is part of QuantLib, a free-software/open-source library
9
 for financial quantitative analysts and developers - http://quantlib.org/
10
11
 QuantLib is free software: you can redistribute it and/or modify it
12
 under the terms of the QuantLib license.  You should have received a
13
 copy of the license along with this program; if not, please email
14
 <quantlib-dev@lists.sf.net>. The license is also available online at
15
 <https://www.quantlib.org/license.shtml>.
16
17
 This program is distributed in the hope that it will be useful, but WITHOUT
18
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
19
 FOR A PARTICULAR PURPOSE.  See the license for more details.
20
*/
21
22
#include <ql/indexes/iborindex.hpp>
23
#include <ql/instruments/overnightindexedswap.hpp>
24
#include <ql/instruments/vanillaswap.hpp>
25
#include <ql/models/shortrate/calibrationhelpers/swaptionhelper.hpp>
26
#include <ql/pricingengines/swap/discountingswapengine.hpp>
27
#include <ql/pricingengines/swaption/blackswaptionengine.hpp>
28
#include <ql/pricingengines/swaption/discretizedswaption.hpp>
29
#include <ql/quotes/simplequote.hpp>
30
#include <ql/time/schedule.hpp>
31
#include <utility>
32
33
namespace QuantLib {
34
35
    SwaptionHelper::SwaptionHelper(const Period& maturity,
36
                                   const Period& length,
37
                                   const Handle<Quote>& volatility,
38
                                   ext::shared_ptr<IborIndex> index,
39
                                   const Period& fixedLegTenor,
40
                                   DayCounter fixedLegDayCounter,
41
                                   DayCounter floatingLegDayCounter,
42
                                   Handle<YieldTermStructure> termStructure,
43
                                   CalibrationErrorType errorType,
44
                                   const Real strike,
45
                                   const Real nominal,
46
                                   const VolatilityType type,
47
                                   const Real shift,
48
                                   Natural settlementDays,
49
                                   RateAveraging::Type averagingMethod)
50
0
    : BlackCalibrationHelper(volatility, errorType, type, shift),
51
0
      maturity_(maturity), length_(length), fixedLegTenor_(fixedLegTenor),
52
0
      index_(std::move(index)), termStructure_(std::move(termStructure)),
53
0
      fixedLegDayCounter_(std::move(fixedLegDayCounter)),
54
0
      floatingLegDayCounter_(std::move(floatingLegDayCounter)), strike_(strike), nominal_(nominal),
55
0
      settlementDays_(settlementDays), averagingMethod_(averagingMethod) {
56
0
        registerWith(index_);
57
0
        registerWith(termStructure_);
58
0
    }
Unexecuted instantiation: QuantLib::SwaptionHelper::SwaptionHelper(QuantLib::Period const&, QuantLib::Period const&, QuantLib::Handle<QuantLib::Quote> const&, boost::shared_ptr<QuantLib::IborIndex>, QuantLib::Period const&, QuantLib::DayCounter, QuantLib::DayCounter, QuantLib::Handle<QuantLib::YieldTermStructure>, QuantLib::BlackCalibrationHelper::CalibrationErrorType, double, double, QuantLib::VolatilityType, double, unsigned int, QuantLib::RateAveraging::Type)
Unexecuted instantiation: QuantLib::SwaptionHelper::SwaptionHelper(QuantLib::Period const&, QuantLib::Period const&, QuantLib::Handle<QuantLib::Quote> const&, boost::shared_ptr<QuantLib::IborIndex>, QuantLib::Period const&, QuantLib::DayCounter, QuantLib::DayCounter, QuantLib::Handle<QuantLib::YieldTermStructure>, QuantLib::BlackCalibrationHelper::CalibrationErrorType, double, double, QuantLib::VolatilityType, double, unsigned int, QuantLib::RateAveraging::Type)
59
60
    SwaptionHelper::SwaptionHelper(const Date& exerciseDate,
61
                                   const Period& length,
62
                                   const Handle<Quote>& volatility,
63
                                   ext::shared_ptr<IborIndex> index,
64
                                   const Period& fixedLegTenor,
65
                                   DayCounter fixedLegDayCounter,
66
                                   DayCounter floatingLegDayCounter,
67
                                   Handle<YieldTermStructure> termStructure,
68
                                   CalibrationErrorType errorType,
69
                                   const Real strike,
70
                                   const Real nominal,
71
                                   const VolatilityType type,
72
                                   const Real shift,
73
                                   Natural settlementDays,
74
                                   RateAveraging::Type averagingMethod)
75
0
    : BlackCalibrationHelper(volatility, errorType, type, shift), exerciseDate_(exerciseDate),
76
0
      maturity_(0 * Days), length_(length), fixedLegTenor_(fixedLegTenor),
77
0
      index_(std::move(index)), termStructure_(std::move(termStructure)),
78
0
      fixedLegDayCounter_(std::move(fixedLegDayCounter)),
79
0
      floatingLegDayCounter_(std::move(floatingLegDayCounter)), strike_(strike), nominal_(nominal),
80
0
      settlementDays_(settlementDays), averagingMethod_(averagingMethod) {
81
0
        registerWith(index_);
82
0
        registerWith(termStructure_);
83
0
    }
Unexecuted instantiation: QuantLib::SwaptionHelper::SwaptionHelper(QuantLib::Date const&, QuantLib::Period const&, QuantLib::Handle<QuantLib::Quote> const&, boost::shared_ptr<QuantLib::IborIndex>, QuantLib::Period const&, QuantLib::DayCounter, QuantLib::DayCounter, QuantLib::Handle<QuantLib::YieldTermStructure>, QuantLib::BlackCalibrationHelper::CalibrationErrorType, double, double, QuantLib::VolatilityType, double, unsigned int, QuantLib::RateAveraging::Type)
Unexecuted instantiation: QuantLib::SwaptionHelper::SwaptionHelper(QuantLib::Date const&, QuantLib::Period const&, QuantLib::Handle<QuantLib::Quote> const&, boost::shared_ptr<QuantLib::IborIndex>, QuantLib::Period const&, QuantLib::DayCounter, QuantLib::DayCounter, QuantLib::Handle<QuantLib::YieldTermStructure>, QuantLib::BlackCalibrationHelper::CalibrationErrorType, double, double, QuantLib::VolatilityType, double, unsigned int, QuantLib::RateAveraging::Type)
84
85
    SwaptionHelper::SwaptionHelper(const Date& exerciseDate,
86
                                   const Date& endDate,
87
                                   const Handle<Quote>& volatility,
88
                                   ext::shared_ptr<IborIndex> index,
89
                                   const Period& fixedLegTenor,
90
                                   DayCounter fixedLegDayCounter,
91
                                   DayCounter floatingLegDayCounter,
92
                                   Handle<YieldTermStructure> termStructure,
93
                                   CalibrationErrorType errorType,
94
                                   const Real strike,
95
                                   const Real nominal,
96
                                   const VolatilityType type,
97
                                   const Real shift,
98
                                   Natural settlementDays,
99
                                   RateAveraging::Type averagingMethod)
100
0
    : BlackCalibrationHelper(volatility, errorType, type, shift), exerciseDate_(exerciseDate),
101
0
      endDate_(endDate), maturity_(0 * Days), length_(0 * Days), fixedLegTenor_(fixedLegTenor),
102
0
      index_(std::move(index)), termStructure_(std::move(termStructure)),
103
0
      fixedLegDayCounter_(std::move(fixedLegDayCounter)),
104
0
      floatingLegDayCounter_(std::move(floatingLegDayCounter)), strike_(strike), nominal_(nominal),
105
0
      settlementDays_(settlementDays), averagingMethod_(averagingMethod) {
106
0
        registerWith(index_);
107
0
        registerWith(termStructure_);
108
0
    }
Unexecuted instantiation: QuantLib::SwaptionHelper::SwaptionHelper(QuantLib::Date const&, QuantLib::Date const&, QuantLib::Handle<QuantLib::Quote> const&, boost::shared_ptr<QuantLib::IborIndex>, QuantLib::Period const&, QuantLib::DayCounter, QuantLib::DayCounter, QuantLib::Handle<QuantLib::YieldTermStructure>, QuantLib::BlackCalibrationHelper::CalibrationErrorType, double, double, QuantLib::VolatilityType, double, unsigned int, QuantLib::RateAveraging::Type)
Unexecuted instantiation: QuantLib::SwaptionHelper::SwaptionHelper(QuantLib::Date const&, QuantLib::Date const&, QuantLib::Handle<QuantLib::Quote> const&, boost::shared_ptr<QuantLib::IborIndex>, QuantLib::Period const&, QuantLib::DayCounter, QuantLib::DayCounter, QuantLib::Handle<QuantLib::YieldTermStructure>, QuantLib::BlackCalibrationHelper::CalibrationErrorType, double, double, QuantLib::VolatilityType, double, unsigned int, QuantLib::RateAveraging::Type)
109
110
111
0
    void SwaptionHelper::addTimesTo(std::list<Time>& times) const {
112
0
        calculate();
113
0
        Swaption::arguments args;
114
0
        swaption_->setupArguments(&args);
115
0
        std::vector<Time> swaptionTimes =
116
0
            DiscretizedSwaption(args,
117
0
                                termStructure_->referenceDate(),
118
0
                                termStructure_->dayCounter()).mandatoryTimes();
119
0
        times.insert(times.end(),
120
0
                     swaptionTimes.begin(), swaptionTimes.end());
121
0
    }
122
123
0
    Real SwaptionHelper::modelValue() const {
124
0
        calculate();
125
0
        swaption_->setPricingEngine(engine_);
126
0
        return swaption_->NPV();
127
0
    }
128
129
0
    Real SwaptionHelper::blackPrice(Volatility sigma) const {
130
0
        calculate();
131
0
        Handle<Quote> vol(ext::shared_ptr<Quote>(new SimpleQuote(sigma)));
132
0
        ext::shared_ptr<PricingEngine> engine;
133
0
        switch(volatilityType_) {
134
0
        case ShiftedLognormal:
135
0
            engine = ext::make_shared<BlackSwaptionEngine>(
136
0
                termStructure_, vol, Actual365Fixed(), shift_);
137
0
            break;
138
0
        case Normal:
139
0
            engine = ext::make_shared<BachelierSwaptionEngine>(
140
0
                termStructure_, vol, Actual365Fixed());
141
0
            break;
142
0
        default:
143
0
            QL_FAIL("can not construct engine: " << volatilityType_);
144
0
            break;
145
0
        }
146
0
        swaption_->setPricingEngine(engine);
147
0
        Real value = swaption_->NPV();
148
0
        swaption_->setPricingEngine(engine_);
149
0
        return value;
150
0
    }
151
152
0
    void SwaptionHelper::performCalculations() const {
153
154
0
        Calendar calendar = index_->fixingCalendar();
155
0
        Date exerciseDate = exerciseDate_;
156
0
        if (exerciseDate == Date())
157
0
            exerciseDate = calendar.advance(termStructure_->referenceDate(),
158
0
                                            maturity_,
159
0
                                            index_->businessDayConvention());
160
0
        Date startDate;
161
0
        if (settlementDays_ == Null<Size>()) {
162
0
            startDate = index_->valueDate(index_->fixingCalendar().adjust(exerciseDate));
163
0
        } else {
164
0
            startDate = calendar.advance(exerciseDate,
165
0
                                         index_->fixingDays(), Days,
166
0
                                         index_->businessDayConvention());
167
0
        }
168
169
0
        Date endDate = endDate_;
170
0
        if (endDate == Date())
171
0
            endDate = calendar.advance(startDate, length_,
172
0
                                       index_->businessDayConvention());
173
0
        Schedule fixedSchedule(startDate, endDate, fixedLegTenor_, calendar,
174
0
                               index_->businessDayConvention(),
175
0
                               index_->businessDayConvention(),
176
0
                               DateGeneration::Forward, false);
177
0
        Schedule floatSchedule(startDate, endDate, index_->tenor(), calendar,
178
0
                               index_->businessDayConvention(),
179
0
                               index_->businessDayConvention(),
180
0
                               DateGeneration::Forward, false);
181
182
0
        auto swapEngine = ext::make_shared<DiscountingSwapEngine>(termStructure_, false);
183
184
0
        Swap::Type type = Swap::Receiver;
185
0
        ext::shared_ptr<Exercise> exercise(new EuropeanExercise(exerciseDate));
186
0
        auto temp = makeSwap(fixedSchedule, floatSchedule, 0.0, type);
187
0
        temp->setPricingEngine(swapEngine);
188
0
        Real forward = temp->fairRate();
189
0
        if (strike_ == Null<Real>()) {
190
0
            exerciseRate_ = forward;
191
0
        } else {
192
0
            exerciseRate_ = strike_;
193
0
            type = strike_ <= forward ? Swap::Receiver : Swap::Payer;
194
0
        }
195
0
        swap_ = makeSwap(fixedSchedule, floatSchedule, exerciseRate_, type);
196
0
        swap_->setPricingEngine(swapEngine);
197
0
        swaption_ = ext::make_shared<Swaption>(swap_, exercise);
198
0
        BlackCalibrationHelper::performCalculations();
199
0
    }
200
201
    ext::shared_ptr<FixedVsFloatingSwap> SwaptionHelper::makeSwap(Schedule fixedSchedule,
202
                                                                  Schedule floatSchedule,
203
                                                                  Rate exerciseRate,
204
0
                                                                  Swap::Type type) const {
205
0
        auto onIndex = ext::dynamic_pointer_cast<OvernightIndex>(index_);
206
0
        if (onIndex) {
207
0
            return ext::make_shared<OvernightIndexedSwap>(
208
0
                type, nominal_, std::move(fixedSchedule), exerciseRate, fixedLegDayCounter_,
209
0
                std::move(floatSchedule), onIndex, 0.0, 0, Following,
210
0
                Calendar(), true, averagingMethod_);
211
0
        } else {
212
0
            return ext::make_shared<VanillaSwap>(type, nominal_, std::move(fixedSchedule), exerciseRate,
213
0
                                                 fixedLegDayCounter_, std::move(floatSchedule), index_, 0.0,
214
0
                                                 floatingLegDayCounter_);
215
0
        }
216
0
    }
217
218
}