Coverage Report

Created: 2025-08-28 06:30

/src/quantlib/ql/instruments/inflationcapfloor.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 Chris Kenyon
5
6
 This file is part of QuantLib, a free-software/open-source library
7
 for financial quantitative analysts and developers - http://quantlib.org/
8
9
 QuantLib is free software: you can redistribute it and/or modify it
10
 under the terms of the QuantLib license.  You should have received a
11
 copy of the license along with this program; if not, please email
12
 <quantlib-dev@lists.sf.net>. The license is also available online at
13
 <http://quantlib.org/license.shtml>.
14
15
 This program is distributed in the hope that it will be useful, but WITHOUT
16
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17
 FOR A PARTICULAR PURPOSE.  See the license for more details.
18
 */
19
20
#include <ql/cashflows/cashflows.hpp>
21
#include <ql/instruments/inflationcapfloor.hpp>
22
#include <ql/math/solvers1d/newtonsafe.hpp>
23
#include <ql/quotes/simplequote.hpp>
24
#include <ql/utilities/dataformatters.hpp>
25
#include <utility>
26
27
namespace QuantLib {
28
29
30
    std::ostream& operator<<(std::ostream& out,
31
0
                             YoYInflationCapFloor::Type t) {
32
0
        switch (t) {
33
0
            case YoYInflationCapFloor::Cap:
34
0
                return out << "YoYInflationCap";
35
0
            case YoYInflationCapFloor::Floor:
36
0
                return out << "YoYInflationFloor";
37
0
            case YoYInflationCapFloor::Collar:
38
0
                return out << "YoYInflationCollar";
39
0
            default:
40
0
                QL_FAIL("unknown YoYInflationCapFloor::Type (" << Integer(t) << ")");
41
0
        }
42
0
    }
43
44
    YoYInflationCapFloor::YoYInflationCapFloor(YoYInflationCapFloor::Type type,
45
                                               Leg yoyLeg,
46
                                               std::vector<Rate> capRates,
47
                                               std::vector<Rate> floorRates)
48
0
    : type_(type), yoyLeg_(std::move(yoyLeg)), capRates_(std::move(capRates)),
49
0
      floorRates_(std::move(floorRates)) {
50
0
        if (type_ == Cap || type_ == Collar) {
51
0
            QL_REQUIRE(!capRates_.empty(), "no cap rates given");
52
0
            capRates_.reserve(yoyLeg_.size());
53
0
            while (capRates_.size() < yoyLeg_.size())
54
0
                capRates_.push_back(capRates_.back());
55
0
        }
56
0
        if (type_ == Floor || type_ == Collar) {
57
0
            QL_REQUIRE(!floorRates_.empty(), "no floor rates given");
58
0
            floorRates_.reserve(yoyLeg_.size());
59
0
            while (floorRates_.size() < yoyLeg_.size())
60
0
                floorRates_.push_back(floorRates_.back());
61
0
        }
62
0
        Leg::const_iterator i;
63
0
        for (i = yoyLeg_.begin(); i != yoyLeg_.end(); ++i)
64
0
            registerWith(*i);
65
66
0
        registerWith(Settings::instance().evaluationDate());
67
0
    }
Unexecuted instantiation: QuantLib::YoYInflationCapFloor::YoYInflationCapFloor(QuantLib::YoYInflationCapFloor::Type, std::__1::vector<boost::shared_ptr<QuantLib::CashFlow>, std::__1::allocator<boost::shared_ptr<QuantLib::CashFlow> > >, std::__1::vector<double, std::__1::allocator<double> >, std::__1::vector<double, std::__1::allocator<double> >)
Unexecuted instantiation: QuantLib::YoYInflationCapFloor::YoYInflationCapFloor(QuantLib::YoYInflationCapFloor::Type, std::__1::vector<boost::shared_ptr<QuantLib::CashFlow>, std::__1::allocator<boost::shared_ptr<QuantLib::CashFlow> > >, std::__1::vector<double, std::__1::allocator<double> >, std::__1::vector<double, std::__1::allocator<double> >)
68
69
    YoYInflationCapFloor::YoYInflationCapFloor(YoYInflationCapFloor::Type type,
70
                                               Leg yoyLeg,
71
                                               const std::vector<Rate>& strikes)
72
0
    : type_(type), yoyLeg_(std::move(yoyLeg)) {
73
0
        QL_REQUIRE(!strikes.empty(), "no strikes given");
74
0
        if (type_ == Cap) {
75
0
            capRates_ = strikes;
76
0
            capRates_.reserve(yoyLeg_.size());
77
0
            while (capRates_.size() < yoyLeg_.size())
78
0
                capRates_.push_back(capRates_.back());
79
0
        } else if (type_ == Floor) {
80
0
            floorRates_ = strikes;
81
0
            floorRates_.reserve(yoyLeg_.size());
82
0
            while (floorRates_.size() < yoyLeg_.size())
83
0
                floorRates_.push_back(floorRates_.back());
84
0
        } else
85
0
            QL_FAIL("only Cap/Floor types allowed in this constructor");
86
87
0
        Leg::const_iterator i;
88
0
        for (i = yoyLeg_.begin(); i != yoyLeg_.end(); ++i)
89
0
            registerWith(*i);
90
91
0
        registerWith(Settings::instance().evaluationDate());
92
0
    }
Unexecuted instantiation: QuantLib::YoYInflationCapFloor::YoYInflationCapFloor(QuantLib::YoYInflationCapFloor::Type, std::__1::vector<boost::shared_ptr<QuantLib::CashFlow>, std::__1::allocator<boost::shared_ptr<QuantLib::CashFlow> > >, std::__1::vector<double, std::__1::allocator<double> > const&)
Unexecuted instantiation: QuantLib::YoYInflationCapFloor::YoYInflationCapFloor(QuantLib::YoYInflationCapFloor::Type, std::__1::vector<boost::shared_ptr<QuantLib::CashFlow>, std::__1::allocator<boost::shared_ptr<QuantLib::CashFlow> > >, std::__1::vector<double, std::__1::allocator<double> > const&)
93
94
0
    bool YoYInflationCapFloor::isExpired() const {
95
0
        for (Size i=yoyLeg_.size(); i>0; --i)
96
0
            if (!yoyLeg_[i-1]->hasOccurred())
97
0
                return false;
98
0
        return true;
99
0
    }
100
101
0
    Date YoYInflationCapFloor::startDate() const {
102
0
        return CashFlows::startDate(yoyLeg_);
103
0
    }
104
105
0
    Date YoYInflationCapFloor::maturityDate() const {
106
0
        return CashFlows::maturityDate(yoyLeg_);
107
0
    }
108
109
    ext::shared_ptr<YoYInflationCoupon>
110
0
    YoYInflationCapFloor::lastYoYInflationCoupon() const {
111
0
        ext::shared_ptr<CashFlow> lastCF(yoyLeg_.back());
112
0
        ext::shared_ptr<YoYInflationCoupon> lastYoYInflationCoupon =
113
0
        ext::dynamic_pointer_cast<YoYInflationCoupon>(lastCF);
114
0
        return lastYoYInflationCoupon;
115
0
    }
116
117
0
    ext::shared_ptr<YoYInflationCapFloor> YoYInflationCapFloor::optionlet(const Size i) const {
118
0
        QL_REQUIRE(i < yoyLeg().size(),
119
0
                   io::ordinal(i+1) << " optionlet does not exist, only " <<
120
0
                   yoyLeg().size());
121
0
        Leg cf(1, yoyLeg()[i]);
122
123
0
        std::vector<Rate> cap, floor;
124
0
        if (type() == Cap || type() == Collar)
125
0
            cap.push_back(capRates()[i]);
126
0
        if (type() == Floor || type() == Collar)
127
0
            floor.push_back(floorRates()[i]);
128
129
0
        return ext::make_shared<YoYInflationCapFloor>(type(),
130
0
                                                    cf, cap, floor);
131
0
    }
132
133
0
    void YoYInflationCapFloor::setupArguments(PricingEngine::arguments* args) const {
134
0
        auto* arguments = dynamic_cast<YoYInflationCapFloor::arguments*>(args);
135
0
        QL_REQUIRE(arguments != nullptr, "wrong argument type");
136
137
0
        Size n = yoyLeg_.size();
138
139
0
        arguments->startDates.resize(n);
140
0
        arguments->fixingDates.resize(n);
141
0
        arguments->payDates.resize(n);
142
0
        arguments->accrualTimes.resize(n);
143
0
        arguments->nominals.resize(n);
144
0
        arguments->gearings.resize(n);
145
0
        arguments->capRates.resize(n);
146
0
        arguments->floorRates.resize(n);
147
0
        arguments->spreads.resize(n);
148
149
0
        arguments->type = type_;
150
151
0
        for (Size i=0; i<n; ++i) {
152
0
            ext::shared_ptr<YoYInflationCoupon> coupon =
153
0
            ext::dynamic_pointer_cast<YoYInflationCoupon>(
154
0
                                                            yoyLeg_[i]);
155
0
            QL_REQUIRE(coupon, "non-YoYInflationCoupon given");
156
0
            arguments->startDates[i] = coupon->accrualStartDate();
157
0
            arguments->fixingDates[i] = coupon->fixingDate();
158
0
            arguments->payDates[i] = coupon->date();
159
160
            // this is passed explicitly for precision
161
0
            arguments->accrualTimes[i] = coupon->accrualPeriod();
162
163
0
            arguments->nominals[i] = coupon->nominal();
164
0
            Spread spread = coupon->spread();
165
0
            Real gearing = coupon->gearing();
166
0
            arguments->gearings[i] = gearing;
167
0
            arguments->spreads[i] = spread;
168
169
0
            if (type_ == Cap || type_ == Collar)
170
0
                arguments->capRates[i] = (capRates_[i]-spread)/gearing;
171
0
            else
172
0
                arguments->capRates[i] = Null<Rate>();
173
174
0
            if (type_ == Floor || type_ == Collar)
175
0
                arguments->floorRates[i] = (floorRates_[i]-spread)/gearing;
176
0
            else
177
0
                arguments->floorRates[i] = Null<Rate>();
178
0
        }
179
0
    }
180
181
0
    void YoYInflationCapFloor::arguments::validate() const {
182
0
        QL_REQUIRE(payDates.size() == startDates.size(),
183
0
                   "number of start dates (" << startDates.size()
184
0
                   << ") different from that of pay dates ("
185
0
                   << payDates.size() << ")");
186
0
        QL_REQUIRE(accrualTimes.size() == startDates.size(),
187
0
                   "number of start dates (" << startDates.size()
188
0
                   << ") different from that of accrual times ("
189
0
                   << accrualTimes.size() << ")");
190
0
        QL_REQUIRE(type == YoYInflationCapFloor::Floor ||
191
0
                   capRates.size() == startDates.size(),
192
0
                   "number of start dates (" << startDates.size()
193
0
                   << ") different from that of cap rates ("
194
0
                   << capRates.size() << ")");
195
0
        QL_REQUIRE(type == YoYInflationCapFloor::Cap ||
196
0
                   floorRates.size() == startDates.size(),
197
0
                   "number of start dates (" << startDates.size()
198
0
                   << ") different from that of floor rates ("
199
0
                   << floorRates.size() << ")");
200
0
        QL_REQUIRE(gearings.size() == startDates.size(),
201
0
                   "number of start dates (" << startDates.size()
202
0
                   << ") different from that of gearings ("
203
0
                   << gearings.size() << ")");
204
0
        QL_REQUIRE(spreads.size() == startDates.size(),
205
0
                   "number of start dates (" << startDates.size()
206
0
                   << ") different from that of spreads ("
207
0
                   << spreads.size() << ")");
208
0
        QL_REQUIRE(nominals.size() == startDates.size(),
209
0
                   "number of start dates (" << startDates.size()
210
0
                   << ") different from that of nominals ("
211
0
                   << nominals.size() << ")");
212
0
    }
213
214
0
    Rate YoYInflationCapFloor::atmRate(const YieldTermStructure& discountCurve) const {
215
0
        return CashFlows::atmRate(yoyLeg_, discountCurve,
216
0
                                  false, discountCurve.referenceDate());
217
0
    }
218
219
220
}