/src/quantlib/ql/cashflows/fixedratecoupon.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) 2000, 2001, 2002, 2003 RiskMap srl |
5 | | Copyright (C) 2003, 2004, 2007 StatPro Italia srl |
6 | | Copyright (C) 2007 Piter Dias |
7 | | Copyright (C) 2010 Ferdinando Ametrano |
8 | | Copyright (C) 2017 Joseph Jeisman |
9 | | Copyright (C) 2017 Fabrice Lecuyer |
10 | | |
11 | | This file is part of QuantLib, a free-software/open-source library |
12 | | for financial quantitative analysts and developers - http://quantlib.org/ |
13 | | |
14 | | QuantLib is free software: you can redistribute it and/or modify it |
15 | | under the terms of the QuantLib license. You should have received a |
16 | | copy of the license along with this program; if not, please email |
17 | | <quantlib-dev@lists.sf.net>. The license is also available online at |
18 | | <http://quantlib.org/license.shtml>. |
19 | | |
20 | | This program is distributed in the hope that it will be useful, but WITHOUT |
21 | | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
22 | | FOR A PARTICULAR PURPOSE. See the license for more details. |
23 | | */ |
24 | | |
25 | | #include <ql/cashflows/fixedratecoupon.hpp> |
26 | | #include <utility> |
27 | | |
28 | | using std::vector; |
29 | | |
30 | | namespace QuantLib { |
31 | | |
32 | | FixedRateCoupon::FixedRateCoupon(const Date& paymentDate, |
33 | | Real nominal, |
34 | | Rate rate, |
35 | | const DayCounter& dayCounter, |
36 | | const Date& accrualStartDate, |
37 | | const Date& accrualEndDate, |
38 | | const Date& refPeriodStart, |
39 | | const Date& refPeriodEnd, |
40 | | const Date& exCouponDate) |
41 | 0 | : Coupon(paymentDate, nominal, accrualStartDate, accrualEndDate, |
42 | 0 | refPeriodStart, refPeriodEnd, exCouponDate), |
43 | 0 | rate_(InterestRate(rate, dayCounter, Simple, Annual)) {} Unexecuted instantiation: QuantLib::FixedRateCoupon::FixedRateCoupon(QuantLib::Date const&, double, double, QuantLib::DayCounter const&, QuantLib::Date const&, QuantLib::Date const&, QuantLib::Date const&, QuantLib::Date const&, QuantLib::Date const&) Unexecuted instantiation: QuantLib::FixedRateCoupon::FixedRateCoupon(QuantLib::Date const&, double, double, QuantLib::DayCounter const&, QuantLib::Date const&, QuantLib::Date const&, QuantLib::Date const&, QuantLib::Date const&, QuantLib::Date const&) |
44 | | |
45 | | FixedRateCoupon::FixedRateCoupon(const Date& paymentDate, |
46 | | Real nominal, |
47 | | InterestRate interestRate, |
48 | | const Date& accrualStartDate, |
49 | | const Date& accrualEndDate, |
50 | | const Date& refPeriodStart, |
51 | | const Date& refPeriodEnd, |
52 | | const Date& exCouponDate) |
53 | 28.7M | : Coupon(paymentDate, |
54 | 28.7M | nominal, |
55 | 28.7M | accrualStartDate, |
56 | 28.7M | accrualEndDate, |
57 | 28.7M | refPeriodStart, |
58 | 28.7M | refPeriodEnd, |
59 | 28.7M | exCouponDate), |
60 | 28.7M | rate_(std::move(interestRate)) {} Unexecuted instantiation: QuantLib::FixedRateCoupon::FixedRateCoupon(QuantLib::Date const&, double, QuantLib::InterestRate, QuantLib::Date const&, QuantLib::Date const&, QuantLib::Date const&, QuantLib::Date const&, QuantLib::Date const&) QuantLib::FixedRateCoupon::FixedRateCoupon(QuantLib::Date const&, double, QuantLib::InterestRate, QuantLib::Date const&, QuantLib::Date const&, QuantLib::Date const&, QuantLib::Date const&, QuantLib::Date const&) Line | Count | Source | 53 | 28.7M | : Coupon(paymentDate, | 54 | 28.7M | nominal, | 55 | 28.7M | accrualStartDate, | 56 | 28.7M | accrualEndDate, | 57 | 28.7M | refPeriodStart, | 58 | 28.7M | refPeriodEnd, | 59 | 28.7M | exCouponDate), | 60 | 28.7M | rate_(std::move(interestRate)) {} |
|
61 | | |
62 | 28.7M | Real FixedRateCoupon::amount() const { |
63 | 28.7M | calculate(); |
64 | 28.7M | return amount_; |
65 | 28.7M | } |
66 | | |
67 | 28.7M | void FixedRateCoupon::performCalculations() const { |
68 | 28.7M | amount_ = nominal() * (rate_.compoundFactor(accrualStartDate_, accrualEndDate_, |
69 | 28.7M | refPeriodStart_, refPeriodEnd_) - |
70 | 28.7M | 1.0); |
71 | 28.7M | } |
72 | | |
73 | 0 | Real FixedRateCoupon::accruedAmount(const Date& d) const { |
74 | 0 | if (d <= accrualStartDate_ || d > paymentDate_) { |
75 | | // out of coupon range |
76 | 0 | return 0.0; |
77 | 0 | } else if (tradingExCoupon(d)) { |
78 | 0 | return -nominal()*(rate_.compoundFactor(d, |
79 | 0 | std::max(d, accrualEndDate_), |
80 | 0 | refPeriodStart_, |
81 | 0 | refPeriodEnd_) - 1.0); |
82 | 0 | } else { |
83 | | // usual case |
84 | 0 | return nominal()*(rate_.compoundFactor(accrualStartDate_, |
85 | 0 | std::min(d,accrualEndDate_), |
86 | 0 | refPeriodStart_, |
87 | 0 | refPeriodEnd_) - 1.0); |
88 | 0 | } |
89 | 0 | } |
90 | | |
91 | | |
92 | | FixedRateLeg::FixedRateLeg(Schedule schedule) |
93 | 79.8k | : schedule_(std::move(schedule)), paymentCalendar_(schedule_.calendar()) {} |
94 | | |
95 | 0 | FixedRateLeg& FixedRateLeg::withNotionals(Real notional) { |
96 | 0 | notionals_ = vector<Real>(1,notional); |
97 | 0 | return *this; |
98 | 0 | } |
99 | | |
100 | 79.8k | FixedRateLeg& FixedRateLeg::withNotionals(const vector<Real>& notionals) { |
101 | 79.8k | notionals_ = notionals; |
102 | 79.8k | return *this; |
103 | 79.8k | } |
104 | | |
105 | | FixedRateLeg& FixedRateLeg::withCouponRates(Rate rate, |
106 | | const DayCounter& dc, |
107 | | Compounding comp, |
108 | 0 | Frequency freq) { |
109 | 0 | couponRates_.resize(1); |
110 | 0 | couponRates_[0] = InterestRate(rate, dc, comp, freq); |
111 | 0 | return *this; |
112 | 0 | } |
113 | | |
114 | 0 | FixedRateLeg& FixedRateLeg::withCouponRates(const InterestRate& i) { |
115 | 0 | couponRates_.resize(1); |
116 | 0 | couponRates_[0] = i; |
117 | 0 | return *this; |
118 | 0 | } |
119 | | |
120 | | FixedRateLeg& FixedRateLeg::withCouponRates(const vector<Rate>& rates, |
121 | | const DayCounter& dc, |
122 | | Compounding comp, |
123 | 79.8k | Frequency freq) { |
124 | 79.8k | couponRates_.resize(rates.size()); |
125 | 159k | for (Size i=0; i<rates.size(); ++i) |
126 | 79.8k | couponRates_[i] = InterestRate(rates[i], dc, comp, freq); |
127 | 79.8k | return *this; |
128 | 79.8k | } |
129 | | |
130 | | FixedRateLeg& FixedRateLeg::withCouponRates( |
131 | 0 | const vector<InterestRate>& interestRates) { |
132 | 0 | couponRates_ = interestRates; |
133 | 0 | return *this; |
134 | 0 | } |
135 | | |
136 | | FixedRateLeg& FixedRateLeg::withPaymentAdjustment( |
137 | 79.8k | BusinessDayConvention convention) { |
138 | 79.8k | paymentAdjustment_ = convention; |
139 | 79.8k | return *this; |
140 | 79.8k | } |
141 | | |
142 | | FixedRateLeg& FixedRateLeg::withFirstPeriodDayCounter( |
143 | 0 | const DayCounter& dayCounter) { |
144 | 0 | firstPeriodDC_ = dayCounter; |
145 | 0 | return *this; |
146 | 0 | } |
147 | | |
148 | | FixedRateLeg& FixedRateLeg::withLastPeriodDayCounter( |
149 | 0 | const DayCounter& dayCounter) { |
150 | 0 | lastPeriodDC_ = dayCounter; |
151 | 0 | return *this; |
152 | 0 | } |
153 | | |
154 | 0 | FixedRateLeg& FixedRateLeg::withPaymentCalendar(const Calendar& cal) { |
155 | 0 | paymentCalendar_ = cal; |
156 | 0 | return *this; |
157 | 0 | } |
158 | | |
159 | 79.8k | FixedRateLeg& FixedRateLeg::withPaymentLag(Integer lag) { |
160 | 79.8k | paymentLag_ = lag; |
161 | 79.8k | return *this; |
162 | 79.8k | } |
163 | | |
164 | | FixedRateLeg& FixedRateLeg::withExCouponPeriod( |
165 | | const Period& period, |
166 | | const Calendar& cal, |
167 | | BusinessDayConvention convention, |
168 | 79.8k | bool endOfMonth) { |
169 | 79.8k | exCouponPeriod_ = period; |
170 | 79.8k | exCouponCalendar_ = cal; |
171 | 79.8k | exCouponAdjustment_ = convention; |
172 | 79.8k | exCouponEndOfMonth_ = endOfMonth; |
173 | 79.8k | return *this; |
174 | 79.8k | } |
175 | | |
176 | 79.8k | FixedRateLeg::operator Leg() const { |
177 | | |
178 | 79.8k | QL_REQUIRE(!couponRates_.empty(), "no coupon rates given"); |
179 | 79.8k | QL_REQUIRE(!notionals_.empty(), "no notional given"); |
180 | | |
181 | 79.8k | Leg leg; |
182 | 79.8k | leg.reserve(schedule_.size()-1); |
183 | | |
184 | | // first period might be short or long |
185 | 79.8k | Date start = schedule_.date(0), end = schedule_.date(1); |
186 | 79.8k | Date paymentDate = paymentCalendar_.advance(end, paymentLag_, Days, paymentAdjustment_); |
187 | 79.8k | Date exCouponDate; |
188 | 79.8k | InterestRate rate = couponRates_[0]; |
189 | 79.8k | Real nominal = notionals_[0]; |
190 | | |
191 | 79.8k | if (exCouponPeriod_ != Period()) |
192 | 0 | { |
193 | 0 | exCouponDate = exCouponCalendar_.advance(paymentDate, |
194 | 0 | -exCouponPeriod_, |
195 | 0 | exCouponAdjustment_, |
196 | 0 | exCouponEndOfMonth_); |
197 | 0 | } |
198 | 79.8k | Date ref = schedule_.hasTenor() && |
199 | 79.8k | schedule_.hasIsRegular() && !schedule_.isRegular(1) ? |
200 | 0 | schedule_.calendar().advance(end, |
201 | 0 | -schedule_.tenor(), |
202 | 0 | schedule_.businessDayConvention(), |
203 | 0 | schedule_.endOfMonth()) |
204 | 79.8k | : start; |
205 | 79.8k | InterestRate r(rate.rate(), |
206 | 79.8k | firstPeriodDC_.empty() ? rate.dayCounter() |
207 | 79.8k | : firstPeriodDC_, |
208 | 79.8k | rate.compounding(), rate.frequency()); |
209 | 79.8k | leg.push_back(ext::shared_ptr<CashFlow>(new |
210 | 79.8k | FixedRateCoupon(paymentDate, nominal, r, |
211 | 79.8k | start, end, ref, end, exCouponDate))); |
212 | | // regular periods |
213 | 28.6M | for (Size i=2; i<schedule_.size()-1; ++i) { |
214 | 28.5M | start = end; end = schedule_.date(i); |
215 | 28.5M | Date paymentDate = paymentCalendar_.advance(end, paymentLag_, Days, paymentAdjustment_); |
216 | 28.5M | if (exCouponPeriod_ != Period()) |
217 | 0 | { |
218 | 0 | exCouponDate = exCouponCalendar_.advance(paymentDate, |
219 | 0 | -exCouponPeriod_, |
220 | 0 | exCouponAdjustment_, |
221 | 0 | exCouponEndOfMonth_); |
222 | 0 | } |
223 | 28.5M | if ((i-1) < couponRates_.size()) |
224 | 0 | rate = couponRates_[i-1]; |
225 | 28.5M | else |
226 | 28.5M | rate = couponRates_.back(); |
227 | 28.5M | if ((i-1) < notionals_.size()) |
228 | 28.5M | nominal = notionals_[i-1]; |
229 | 0 | else |
230 | 0 | nominal = notionals_.back(); |
231 | 28.5M | leg.push_back(ext::shared_ptr<CashFlow>(new |
232 | 28.5M | FixedRateCoupon(paymentDate, nominal, rate, |
233 | 28.5M | start, end, start, end, exCouponDate))); |
234 | 28.5M | } |
235 | 79.8k | if (schedule_.size() > 2) { |
236 | | // last period might be short or long |
237 | 79.8k | Size N = schedule_.size(); |
238 | 79.8k | start = end; end = schedule_.date(N-1); |
239 | 79.8k | Date paymentDate = paymentCalendar_.advance(end, paymentLag_, Days, paymentAdjustment_); |
240 | 79.8k | if (exCouponPeriod_ != Period()) |
241 | 0 | { |
242 | 0 | exCouponDate = exCouponCalendar_.advance(paymentDate, |
243 | 0 | -exCouponPeriod_, |
244 | 0 | exCouponAdjustment_, |
245 | 0 | exCouponEndOfMonth_); |
246 | 0 | } |
247 | 79.8k | if ((N-2) < couponRates_.size()) |
248 | 0 | rate = couponRates_[N-2]; |
249 | 79.8k | else |
250 | 79.8k | rate = couponRates_.back(); |
251 | 79.8k | if ((N-2) < notionals_.size()) |
252 | 79.8k | nominal = notionals_[N-2]; |
253 | 0 | else |
254 | 0 | nominal = notionals_.back(); |
255 | 79.8k | InterestRate r( rate.rate(), lastPeriodDC_.empty() ? |
256 | 79.8k | rate.dayCounter() : |
257 | 79.8k | lastPeriodDC_ , rate.compounding(), rate.frequency() ); |
258 | 79.8k | if ((schedule_.hasIsRegular() && schedule_.isRegular(N - 1)) || |
259 | 79.8k | !schedule_.hasTenor()) { |
260 | 79.8k | leg.push_back(ext::shared_ptr<CashFlow>(new |
261 | 79.8k | FixedRateCoupon(paymentDate, nominal, r, |
262 | 79.8k | start, end, start, end, exCouponDate))); |
263 | 79.8k | } else { |
264 | 0 | Date ref = schedule_.calendar().advance( |
265 | 0 | start, |
266 | 0 | schedule_.tenor(), |
267 | 0 | schedule_.businessDayConvention(), |
268 | 0 | schedule_.endOfMonth()); |
269 | 0 | leg.push_back(ext::shared_ptr<CashFlow>(new |
270 | 0 | FixedRateCoupon(paymentDate, nominal, r, |
271 | 0 | start, end, start, ref, exCouponDate))); |
272 | 0 | } |
273 | 79.8k | } |
274 | 79.8k | return leg; |
275 | 79.8k | } |
276 | | |
277 | | } |