/src/quantlib/ql/instruments/yearonyearinflationswap.cpp
Line | Count | Source |
1 | | /* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | |
3 | | /* |
4 | | Copyright (C) 2007, 2009 Chris Kenyon |
5 | | Copyright (C) 2009 StatPro Italia srl |
6 | | |
7 | | This file is part of QuantLib, a free-software/open-source library |
8 | | for financial quantitative analysts and developers - http://quantlib.org/ |
9 | | |
10 | | QuantLib is free software: you can redistribute it and/or modify it |
11 | | under the terms of the QuantLib license. You should have received a |
12 | | copy of the license along with this program; if not, please email |
13 | | <quantlib-dev@lists.sf.net>. The license is also available online at |
14 | | <https://www.quantlib.org/license.shtml>. |
15 | | |
16 | | This program is distributed in the hope that it will be useful, but WITHOUT |
17 | | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
18 | | FOR A PARTICULAR PURPOSE. See the license for more details. |
19 | | */ |
20 | | |
21 | | #include <ql/cashflows/cashflows.hpp> |
22 | | #include <ql/cashflows/cashflowvectors.hpp> |
23 | | #include <ql/cashflows/couponpricer.hpp> |
24 | | #include <ql/cashflows/fixedratecoupon.hpp> |
25 | | #include <ql/cashflows/yoyinflationcoupon.hpp> |
26 | | #include <ql/indexes/inflationindex.hpp> |
27 | | #include <ql/instruments/yearonyearinflationswap.hpp> |
28 | | #include <ql/termstructures/yieldtermstructure.hpp> |
29 | | #include <ql/time/schedule.hpp> |
30 | | #include <utility> |
31 | | |
32 | | namespace QuantLib { |
33 | | |
34 | | YearOnYearInflationSwap::YearOnYearInflationSwap(Type type, |
35 | | Real nominal, |
36 | | Schedule fixedSchedule, |
37 | | Rate fixedRate, |
38 | | DayCounter fixedDayCount, |
39 | | Schedule yoySchedule, |
40 | | ext::shared_ptr<YoYInflationIndex> yoyIndex, |
41 | | const Period& observationLag, |
42 | | CPI::InterpolationType interpolation, |
43 | | Spread spread, |
44 | | DayCounter yoyDayCount, |
45 | | Calendar paymentCalendar, |
46 | | BusinessDayConvention paymentConvention) |
47 | 0 | : Swap(2), type_(type), nominal_(nominal), fixedSchedule_(std::move(fixedSchedule)), |
48 | 0 | fixedRate_(fixedRate), fixedDayCount_(std::move(fixedDayCount)), |
49 | 0 | yoySchedule_(std::move(yoySchedule)), yoyIndex_(std::move(yoyIndex)), |
50 | 0 | observationLag_(observationLag), spread_(spread), yoyDayCount_(std::move(yoyDayCount)), |
51 | 0 | paymentCalendar_(std::move(paymentCalendar)), paymentConvention_(paymentConvention) { |
52 | | // N.B. fixed leg gets its calendar from the schedule! |
53 | 0 | Leg fixedLeg = FixedRateLeg(fixedSchedule_) |
54 | 0 | .withNotionals(nominal_) |
55 | 0 | .withCouponRates(fixedRate_, fixedDayCount_) // Simple compounding by default |
56 | 0 | .withPaymentAdjustment(paymentConvention_); |
57 | |
|
58 | 0 | Leg yoyLeg = yoyInflationLeg(yoySchedule_, paymentCalendar_, yoyIndex_, |
59 | 0 | observationLag_, interpolation) |
60 | 0 | .withNotionals(nominal_) |
61 | 0 | .withPaymentDayCounter(yoyDayCount_) |
62 | 0 | .withPaymentAdjustment(paymentConvention_) |
63 | 0 | .withSpreads(spread_); |
64 | |
|
65 | 0 | Leg::const_iterator i; |
66 | 0 | for (i = yoyLeg.begin(); i < yoyLeg.end(); ++i) |
67 | 0 | registerWith(*i); |
68 | |
|
69 | 0 | legs_[0] = fixedLeg; |
70 | 0 | legs_[1] = yoyLeg; |
71 | 0 | if (type_==Payer) { |
72 | 0 | payer_[0] = -1.0; |
73 | 0 | payer_[1] = +1.0; |
74 | 0 | } else { |
75 | 0 | payer_[0] = +1.0; |
76 | 0 | payer_[1] = -1.0; |
77 | 0 | } |
78 | 0 | } Unexecuted instantiation: QuantLib::YearOnYearInflationSwap::YearOnYearInflationSwap(QuantLib::Swap::Type, double, QuantLib::Schedule, double, QuantLib::DayCounter, QuantLib::Schedule, boost::shared_ptr<QuantLib::YoYInflationIndex>, QuantLib::Period const&, QuantLib::CPI::InterpolationType, double, QuantLib::DayCounter, QuantLib::Calendar, QuantLib::BusinessDayConvention) Unexecuted instantiation: QuantLib::YearOnYearInflationSwap::YearOnYearInflationSwap(QuantLib::Swap::Type, double, QuantLib::Schedule, double, QuantLib::DayCounter, QuantLib::Schedule, boost::shared_ptr<QuantLib::YoYInflationIndex>, QuantLib::Period const&, QuantLib::CPI::InterpolationType, double, QuantLib::DayCounter, QuantLib::Calendar, QuantLib::BusinessDayConvention) |
79 | | |
80 | 0 | void YearOnYearInflationSwap::setupArguments(PricingEngine::arguments* args) const { |
81 | |
|
82 | 0 | Swap::setupArguments(args); |
83 | |
|
84 | 0 | auto* arguments = dynamic_cast<YearOnYearInflationSwap::arguments*>(args); |
85 | |
|
86 | 0 | if (arguments == nullptr) // it's a swap engine... |
87 | 0 | return; |
88 | | |
89 | 0 | arguments->type = type_; |
90 | 0 | arguments->nominal = nominal_; |
91 | |
|
92 | 0 | const Leg& fixedCoupons = fixedLeg(); |
93 | |
|
94 | 0 | arguments->fixedResetDates = arguments->fixedPayDates = |
95 | 0 | std::vector<Date>(fixedCoupons.size()); |
96 | 0 | arguments->fixedCoupons = std::vector<Real>(fixedCoupons.size()); |
97 | |
|
98 | 0 | for (Size i=0; i<fixedCoupons.size(); ++i) { |
99 | 0 | ext::shared_ptr<FixedRateCoupon> coupon = |
100 | 0 | ext::dynamic_pointer_cast<FixedRateCoupon>(fixedCoupons[i]); |
101 | |
|
102 | 0 | arguments->fixedPayDates[i] = coupon->date(); |
103 | 0 | arguments->fixedResetDates[i] = coupon->accrualStartDate(); |
104 | 0 | arguments->fixedCoupons[i] = coupon->amount(); |
105 | 0 | } |
106 | |
|
107 | 0 | const Leg& yoyCoupons = yoyLeg(); |
108 | |
|
109 | 0 | arguments->yoyResetDates = arguments->yoyPayDates = |
110 | 0 | arguments->yoyFixingDates = |
111 | 0 | std::vector<Date>(yoyCoupons.size()); |
112 | 0 | arguments->yoyAccrualTimes = |
113 | 0 | std::vector<Time>(yoyCoupons.size()); |
114 | 0 | arguments->yoySpreads = |
115 | 0 | std::vector<Spread>(yoyCoupons.size()); |
116 | 0 | arguments->yoyCoupons = std::vector<Real>(yoyCoupons.size()); |
117 | 0 | for (Size i=0; i<yoyCoupons.size(); ++i) { |
118 | 0 | ext::shared_ptr<YoYInflationCoupon> coupon = |
119 | 0 | ext::dynamic_pointer_cast<YoYInflationCoupon>(yoyCoupons[i]); |
120 | |
|
121 | 0 | arguments->yoyResetDates[i] = coupon->accrualStartDate(); |
122 | 0 | arguments->yoyPayDates[i] = coupon->date(); |
123 | |
|
124 | 0 | arguments->yoyFixingDates[i] = coupon->fixingDate(); |
125 | 0 | arguments->yoyAccrualTimes[i] = coupon->accrualPeriod(); |
126 | 0 | arguments->yoySpreads[i] = coupon->spread(); |
127 | 0 | try { |
128 | 0 | arguments->yoyCoupons[i] = coupon->amount(); |
129 | 0 | } catch (Error&) { |
130 | 0 | arguments->yoyCoupons[i] = Null<Real>(); |
131 | 0 | } |
132 | 0 | } |
133 | 0 | } |
134 | | |
135 | | |
136 | 0 | Rate YearOnYearInflationSwap::fairRate() const { |
137 | 0 | calculate(); |
138 | 0 | QL_REQUIRE(fairRate_ != Null<Rate>(), "result not available"); |
139 | 0 | return fairRate_; |
140 | 0 | } |
141 | | |
142 | 0 | Spread YearOnYearInflationSwap::fairSpread() const { |
143 | 0 | calculate(); |
144 | 0 | QL_REQUIRE(fairSpread_ != Null<Spread>(), "result not available"); |
145 | 0 | return fairSpread_; |
146 | 0 | } |
147 | | |
148 | | |
149 | 0 | Real YearOnYearInflationSwap::fixedLegNPV() const { |
150 | 0 | calculate(); |
151 | 0 | QL_REQUIRE(legNPV_[0] != Null<Real>(), "result not available"); |
152 | 0 | return legNPV_[0]; |
153 | 0 | } |
154 | | |
155 | 0 | Real YearOnYearInflationSwap::yoyLegNPV() const { |
156 | 0 | calculate(); |
157 | 0 | QL_REQUIRE(legNPV_[1] != Null<Real>(), "result not available"); |
158 | 0 | return legNPV_[1]; |
159 | 0 | } |
160 | | |
161 | 0 | void YearOnYearInflationSwap::setupExpired() const { |
162 | 0 | Swap::setupExpired(); |
163 | 0 | legBPS_[0] = legBPS_[1] = 0.0; |
164 | 0 | fairRate_ = Null<Rate>(); |
165 | 0 | fairSpread_ = Null<Spread>(); |
166 | 0 | } |
167 | | |
168 | 0 | void YearOnYearInflationSwap::fetchResults(const PricingEngine::results* r) const { |
169 | 0 | static const Spread basisPoint = 1.0e-4; |
170 | | |
171 | | // copy from VanillaSwap |
172 | | // works because similarly simple instrument |
173 | | // that we always expect to be priced with a swap engine |
174 | |
|
175 | 0 | Swap::fetchResults(r); |
176 | |
|
177 | 0 | const auto* results = dynamic_cast<const YearOnYearInflationSwap::results*>(r); |
178 | 0 | if (results != nullptr) { // might be a swap engine, so no error is thrown |
179 | 0 | fairRate_ = results->fairRate; |
180 | 0 | fairSpread_ = results->fairSpread; |
181 | 0 | } else { |
182 | 0 | fairRate_ = Null<Rate>(); |
183 | 0 | fairSpread_ = Null<Spread>(); |
184 | 0 | } |
185 | |
|
186 | 0 | if (fairRate_ == Null<Rate>()) { |
187 | | // calculate it from other results |
188 | 0 | if (legBPS_[0] != Null<Real>()) |
189 | 0 | fairRate_ = fixedRate_ - NPV_/(legBPS_[0]/basisPoint); |
190 | 0 | } |
191 | 0 | if (fairSpread_ == Null<Spread>()) { |
192 | | // ditto |
193 | 0 | if (legBPS_[1] != Null<Real>()) |
194 | 0 | fairSpread_ = spread_ - NPV_/(legBPS_[1]/basisPoint); |
195 | 0 | } |
196 | |
|
197 | 0 | } |
198 | | |
199 | 0 | void YearOnYearInflationSwap::arguments::validate() const { |
200 | 0 | Swap::arguments::validate(); |
201 | 0 | QL_REQUIRE(nominal != Null<Real>(), "nominal null or not set"); |
202 | 0 | QL_REQUIRE(fixedResetDates.size() == fixedPayDates.size(), |
203 | 0 | "number of fixed start dates different from " |
204 | 0 | "number of fixed payment dates"); |
205 | 0 | QL_REQUIRE(fixedPayDates.size() == fixedCoupons.size(), |
206 | 0 | "number of fixed payment dates different from " |
207 | 0 | "number of fixed coupon amounts"); |
208 | 0 | QL_REQUIRE(yoyResetDates.size() == yoyPayDates.size(), |
209 | 0 | "number of yoy start dates different from " |
210 | 0 | "number of yoy payment dates"); |
211 | 0 | QL_REQUIRE(yoyFixingDates.size() == yoyPayDates.size(), |
212 | 0 | "number of yoy fixing dates different from " |
213 | 0 | "number of yoy payment dates"); |
214 | 0 | QL_REQUIRE(yoyAccrualTimes.size() == yoyPayDates.size(), |
215 | 0 | "number of yoy accrual Times different from " |
216 | 0 | "number of yoy payment dates"); |
217 | 0 | QL_REQUIRE(yoySpreads.size() == yoyPayDates.size(), |
218 | 0 | "number of yoy spreads different from " |
219 | 0 | "number of yoy payment dates"); |
220 | 0 | QL_REQUIRE(yoyPayDates.size() == yoyCoupons.size(), |
221 | 0 | "number of yoy payment dates different from " |
222 | 0 | "number of yoy coupon amounts"); |
223 | 0 | } |
224 | | |
225 | 0 | void YearOnYearInflationSwap::results::reset() { |
226 | 0 | Swap::results::reset(); |
227 | 0 | fairRate = Null<Rate>(); |
228 | 0 | fairSpread = Null<Spread>(); |
229 | 0 | } |
230 | | |
231 | | } |
232 | | |