Skip to content

Commit aee657c

Browse files
committed
Merge branch 'QPR-11232-payment-dates' into 'master'
QPR-11232 Add explicit payment date lists for Libor legs See merge request qs/quantlib!49
2 parents b0e143c + bb3124b commit aee657c

5 files changed

Lines changed: 50 additions & 7 deletions

File tree

ql/cashflows/cashflowvectors.hpp

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,8 @@ namespace QuantLib {
7575
Period exCouponPeriod = Period(),
7676
Calendar exCouponCalendar = Calendar(),
7777
BusinessDayConvention exCouponAdjustment = Unadjusted,
78-
bool exCouponEndOfMonth = false) {
78+
bool exCouponEndOfMonth = false,
79+
const std::vector<Date>& paymentDates = {}) {
7980

8081
Size n = schedule.size()-1;
8182
QL_REQUIRE(!nominals.empty(), "no notional given");
@@ -94,6 +95,11 @@ namespace QuantLib {
9495
QL_REQUIRE(floors.size()<=n,
9596
"too many floors (" << floors.size() <<
9697
"), only " << n << " required");
98+
QL_REQUIRE(paymentDates.empty() || paymentDates.size() == n,
99+
"Expected the number of explicit payment dates (" <<
100+
paymentDates.size() <<
101+
") to equal the number of calculation periods ("
102+
<< n << ")");
97103
QL_REQUIRE(!isZero || !isInArrears,
98104
"in-arrears and zero features are not compatible");
99105

@@ -112,8 +118,17 @@ namespace QuantLib {
112118
for (Size i=0; i<n; ++i) {
113119
refStart = start = schedule.date(i);
114120
refEnd = end = schedule.date(i+1);
115-
Date paymentDate =
116-
isZero ? lastPaymentDate : paymentCalendar.advance(end, paymentLag, Days, paymentAdj);
121+
Date paymentDate;
122+
if (isZero) {
123+
paymentDate = lastPaymentDate;
124+
} else {
125+
// If explicit payment dates provided, use them.
126+
if (!paymentDates.empty()) {
127+
paymentDate = paymentDates[i];
128+
} else {
129+
paymentDate = paymentCalendar.advance(end, paymentLag, Days, paymentAdj);
130+
}
131+
}
117132
if (i==0 && (schedule.hasIsRegular() && schedule.hasTenor() && !schedule.isRegular(i+1))) {
118133
BusinessDayConvention bdc = schedule.businessDayConvention();
119134
refStart = calendar.adjust(end - schedule.tenor(), bdc);

ql/cashflows/fixedratecoupon.cpp

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -169,17 +169,29 @@ namespace QuantLib {
169169
return *this;
170170
}
171171

172+
FixedRateLeg& FixedRateLeg::withPaymentDates(const std::vector<Date>& paymentDates) {
173+
paymentDates_ = paymentDates;
174+
return *this;
175+
}
176+
177+
172178
FixedRateLeg::operator Leg() const {
173179

174180
QL_REQUIRE(!couponRates_.empty(), "no coupon rates given");
175181
QL_REQUIRE(!notionals_.empty(), "no notional given");
182+
QL_REQUIRE(paymentDates_.empty() || paymentDates_.size() == schedule_.size() - 1,
183+
"Expected the number of explicit payment dates ("
184+
<< paymentDates_.size() << ") to equal the number of calculation periods ("
185+
<< schedule_.size() - 1 << ")");
176186

177187
Leg leg;
178188
leg.reserve(schedule_.size()-1);
179189

180190
// first period might be short or long
181191
Date start = schedule_.date(0), end = schedule_.date(1);
182-
Date paymentDate = paymentCalendar_.advance(end, paymentLag_, Days, paymentAdjustment_);
192+
Date paymentDate = paymentDates_.empty() ? paymentCalendar_.advance(end, paymentLag_, Days,
193+
paymentAdjustment_) :
194+
paymentDates_[0];
183195
Date exCouponDate;
184196
InterestRate rate = couponRates_[0];
185197
Real nominal = notionals_[0];
@@ -208,7 +220,10 @@ namespace QuantLib {
208220
// regular periods
209221
for (Size i=2; i<schedule_.size()-1; ++i) {
210222
start = end; end = schedule_.date(i);
211-
Date paymentDate = paymentCalendar_.advance(end, paymentLag_, Days, paymentAdjustment_);
223+
Date paymentDate =
224+
paymentDates_.empty() ?
225+
paymentCalendar_.advance(end, paymentLag_, Days, paymentAdjustment_) :
226+
paymentDates_[i - 1];
212227
if (exCouponPeriod_ != Period())
213228
{
214229
exCouponDate = exCouponCalendar_.advance(paymentDate,
@@ -232,7 +247,10 @@ namespace QuantLib {
232247
// last period might be short or long
233248
Size N = schedule_.size();
234249
start = end; end = schedule_.date(N-1);
235-
Date paymentDate = paymentCalendar_.advance(end, paymentLag_, Days, paymentAdjustment_);
250+
Date paymentDate =
251+
paymentDates_.empty() ?
252+
paymentCalendar_.advance(end, paymentLag_, Days, paymentAdjustment_) :
253+
paymentDates_[N - 2];
236254
if (exCouponPeriod_ != Period())
237255
{
238256
exCouponDate = exCouponCalendar_.advance(paymentDate,

ql/cashflows/fixedratecoupon.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ namespace QuantLib {
106106
const Calendar&,
107107
BusinessDayConvention,
108108
bool endOfMonth = false);
109+
FixedRateLeg& withPaymentDates(const std::vector<Date>& paymentDates);
109110
operator Leg() const;
110111
private:
111112
Schedule schedule_;
@@ -119,6 +120,7 @@ namespace QuantLib {
119120
Calendar exCouponCalendar_;
120121
BusinessDayConvention exCouponAdjustment_ = Following;
121122
bool exCouponEndOfMonth_ = false;
123+
std::vector<Date> paymentDates_;
122124
};
123125

124126
inline void FixedRateCoupon::accept(AcyclicVisitor& v) {

ql/cashflows/iborcoupon.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -265,13 +265,19 @@ namespace QuantLib {
265265
return *this;
266266
}
267267

268+
IborLeg& IborLeg::withPaymentDates(const std::vector<Date>& paymentDates) {
269+
paymentDates_ = paymentDates;
270+
return *this;
271+
}
272+
268273
IborLeg::operator Leg() const {
269274

270275
Leg leg = FloatingLeg<IborIndex, IborCoupon, CappedFlooredIborCoupon>(
271276
schedule_, notionals_, index_, paymentDayCounter_,
272277
paymentAdjustment_, fixingDays_, gearings_, spreads_,
273278
caps_, floors_, inArrears_, zeroPayments_, paymentLag_, paymentCalendar_,
274-
exCouponPeriod_, exCouponCalendar_, exCouponAdjustment_, exCouponEndOfMonth_);
279+
exCouponPeriod_, exCouponCalendar_, exCouponAdjustment_, exCouponEndOfMonth_,
280+
paymentDates_);
275281

276282
if (caps_.empty() && floors_.empty() && !inArrears_) {
277283
ext::shared_ptr<IborCouponPricer> pricer = ext::make_shared<BlackIborCouponPricer>(

ql/cashflows/iborcoupon.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ namespace QuantLib {
156156
bool endOfMonth = false);
157157
IborLeg& withIndexedCoupons(boost::optional<bool> b = true);
158158
IborLeg& withAtParCoupons(bool b = true);
159+
IborLeg& withPaymentDates(const std::vector<Date>& paymentDates);
159160
operator Leg() const;
160161

161162
private:
@@ -176,6 +177,7 @@ namespace QuantLib {
176177
BusinessDayConvention exCouponAdjustment_ = Unadjusted;
177178
bool exCouponEndOfMonth_ = false;
178179
boost::optional<bool> useIndexedCoupons_;
180+
std::vector<Date> paymentDates_;
179181
};
180182

181183
}

0 commit comments

Comments
 (0)