/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 | | } |