21#include <ql/cashflows/fixedratecoupon.hpp>
22#include <ql/cashflows/iborcoupon.hpp>
29 const std::vector<Date>& payDatesInput,
const std::vector<Date>& fixingDatesInput,
30 const std::vector<Date>& resetDatesInput,
const Size fixingDays,
31 const std::vector<Real>& notionals,
const std::vector<Date>& notionalDatesInput,
32 const std::vector<Real>& spreadsInput,
const std::vector<Date>& spreadDatesInput,
33 const std::vector<Real>& gearingsInput,
const std::vector<Date>& gearingDatesInput,
34 const bool strictNotionalDates,
const DayCounter& dayCounter,
const Calendar& payCalendar,
35 const BusinessDayConvention payConv,
const Period& payLag,
const bool isInArrears) {
39 std::vector<Real> spreads = spreadsInput, gearings = gearingsInput;
41 if (spreads.empty()) {
42 spreads.push_back(0.0);
45 if (gearings.empty()) {
46 gearings.push_back(1.0);
51 QL_REQUIRE(calcDates.size() >= 2,
52 "makeNonStandardIborLeg(): calc dates size (" << calcDates.size() <<
") >= 2 required");
53 QL_REQUIRE(!notionals.empty(),
"makeNonStandardIborLeg(): empty notinoals");
54 QL_REQUIRE(notionalDatesInput.empty() || notionalDatesInput.size() == notionals.size() - 1,
55 "makeNonStandardIborLeg(): notional dates (" << notionalDatesInput.size() <<
") must match notional ("
56 << notionals.size() <<
") minus 1");
57 QL_REQUIRE(spreadDatesInput.empty() || spreadDatesInput.size() == spreads.size() - 1,
58 "makeNonStandardIborLeg(): spread dates (" << spreadDatesInput.size() <<
") must match spread ("
59 << spreads.size() <<
") minus 1");
60 QL_REQUIRE(gearingDatesInput.empty() || gearingDatesInput.size() == gearings.size() - 1,
61 "makeNonStandardIborLeg(): gearing dates (" << gearingDatesInput.size() <<
") must match gearing ("
62 << gearings.size() <<
") minus 1");
66 std::vector<Date> payDates(payDatesInput);
67 std::vector<Date> resetDates(resetDatesInput);
68 std::vector<Date> fixingDates(fixingDatesInput);
69 std::vector<Date> notionalDates(notionalDatesInput);
70 std::vector<Date> spreadDates(spreadDatesInput);
71 std::vector<Date> gearingDates(gearingDatesInput);
73 if (payDates.empty()) {
74 for (Size i = 1; i < calcDates.size(); ++i) {
75 payDates.push_back(payCalendar.advance(calcDates[i], payLag, payConv));
79 if (resetDates.empty() && fixingDates.empty()) {
80 for (Size i = 0; i < calcDates.size() - 1; ++i) {
81 resetDates.push_back(calcDates[i]);
82 fixingDates.push_back(index->fixingCalendar().advance(isInArrears ? calcDates[i + 1] : calcDates[i],
83 -
static_cast<int>(fixingDays) * Days, Preceding));
85 }
else if (resetDates.empty()) {
86 for (Size i = 0; i < fixingDates.size(); ++i) {
87 resetDates.push_back(index->fixingCalendar().advance(fixingDates[i], fixingDays * Days, Following));
89 }
else if (fixingDates.empty()) {
90 for (Size i = 0; i < resetDates.size(); ++i) {
91 fixingDates.push_back(
92 index->fixingCalendar().advance(resetDates[i], -
static_cast<int>(fixingDays) * Days, Preceding));
96 if (notionalDates.empty()) {
97 for (Size i = 1; i < notionals.size(); ++i)
98 notionalDates.push_back(calcDates[i]);
101 if (spreadDates.empty()) {
102 for (Size i = 1; i < spreads.size(); ++i)
103 spreadDates.push_back(calcDates[i]);
106 if (gearingDates.empty()) {
107 for (Size i = 1; i < gearings.size(); ++i)
108 gearingDates.push_back(calcDates[i]);
113 QL_REQUIRE(payDates.size() == calcDates.size() - 1,
"makeNonStandardIborLeg(): pay dates size ("
114 << payDates.size() <<
") = calc dates size ("
115 << calcDates.size() <<
") minus 1 required");
116 QL_REQUIRE(fixingDates.size() == resetDates.size(),
"makeNonStandardIborLeg(): fixing dates ("
117 << fixingDates.size() <<
") must match reset dates ("
118 << resetDates.size() <<
")");
120 for (Size i = 0; i < fixingDates.size(); ++i) {
121 QL_REQUIRE(resetDates[i] <= calcDates.back(),
"makeNonStandardIborLeg(): reset date at "
122 << i <<
" (" << resetDates[i]
123 <<
") must be less or equal last calculation date ("
124 << calcDates.back());
127 for (Size i = 0; i < calcDates.size() - 1; ++i) {
128 QL_REQUIRE(calcDates[i] <= calcDates[i + 1],
"makeNonStandardIborLeg(): calc date at "
129 << i <<
" (" << calcDates[i]
130 <<
") must be less or equal calc date at " << (i + 1) <<
" ("
131 << calcDates[i + 1]);
134 for (Size i = 0; i < fixingDates.size() - 1; ++i) {
135 QL_REQUIRE(fixingDates[i] <= fixingDates[i + 1],
"makeNonStandardIborLeg(): fixing date at "
136 << i <<
" (" << fixingDates[i]
137 <<
") must be less or equal fixing date at " << (i + 1)
138 <<
" (" << fixingDates[i + 1] <<
")");
141 for (Size i = 0; i < resetDates.size() - 1; ++i) {
142 QL_REQUIRE(resetDates[i] <= resetDates[i + 1],
"makeNonStandardIborLeg(): reset date at "
143 << i <<
" (" << resetDates[i]
144 <<
") must be less or equal reset date at " << (i + 1)
145 <<
" (" << resetDates[i + 1] <<
")");
150 std::set<Date> effCalcDates;
152 for (
auto const& d : calcDates)
153 effCalcDates.insert(d);
155 for (
auto const& d : resetDates) {
156 if (d >= calcDates.front() && d < calcDates.back())
157 effCalcDates.insert(d);
160 if (strictNotionalDates) {
161 for (
auto const& d : notionalDates) {
162 if (d >= calcDates.front() && d < calcDates.back())
163 effCalcDates.insert(d);
171 for (
auto startDate = effCalcDates.begin(); startDate != std::next(effCalcDates.end(), -1); ++startDate) {
174 Date endDate = *std::next(startDate, 1);
176 if (endDate > calcDates.back())
181 auto nextCalcDate = std::lower_bound(calcDates.begin(), calcDates.end(), endDate);
182 Date payDate = payDates[std::max<Size>(1, std::distance(calcDates.begin(), nextCalcDate)) - 1];
186 auto nextReset = std::upper_bound(resetDates.begin(), resetDates.end(), *startDate);
187 QL_REQUIRE(nextReset != resetDates.begin(),
188 "makeNonStandardIborLeg(): calc start date "
189 << *startDate <<
" is before first reset date " << *resetDates.begin()
190 <<
". Ensure that there is a reset date on or before the calc start date.");
191 Date
fixingDate = fixingDates[std::distance(resetDates.begin(), nextReset) - 1];
195 auto notionalDate = std::upper_bound(notionalDates.begin(), notionalDates.end(), *startDate);
197 notionals[std::min<Size>(notionals.size() - 1, std::distance(notionalDates.begin(), notionalDate))];
201 auto spreadDate = std::upper_bound(spreadDates.begin(), spreadDates.end(), *startDate);
202 Real spread = spreads[std::min<Size>(spreads.size() - 1, std::distance(spreadDates.begin(), spreadDate))];
206 auto gearingDate = std::upper_bound(gearingDates.begin(), gearingDates.end(), *startDate);
207 Real gearing = gearings[std::min<Size>(gearings.size() - 1, std::distance(gearingDates.begin(), gearingDate))];
211 leg.push_back(QuantLib::ext::make_shared<IborCoupon>(payDate, notional, *startDate, endDate,
fixingDate, index, gearing,
212 spread, Date(), Date(), dayCounter));
219 const std::vector<Real>& notionals,
const std::vector<Date>& notionalDatesInput,
220 const std::vector<Real>& rates,
const std::vector<Date>& rateDatesInput,
221 const bool strictNotionalDates,
const DayCounter& dayCounter,
const Calendar& payCalendar,
222 const BusinessDayConvention payConv,
const Period& payLag) {
226 QL_REQUIRE(calcDates.size() >= 2,
227 "makeNonStandardFixedLeg(): calc dates size (" << calcDates.size() <<
") >= 2 required");
228 QL_REQUIRE(!notionals.empty(),
"makeNonStandardFixedLeg(): empty notinoals");
229 QL_REQUIRE(!rates.empty(),
"makeNonStandardFixedLeg(): empty rates");
230 QL_REQUIRE(notionalDatesInput.empty() || notionalDatesInput.size() == notionals.size() - 1,
231 "makeNonStandardFixedLeg(): notional dates (" << notionalDatesInput.size() <<
") must match notional ("
232 << notionals.size() <<
") minus 1");
233 QL_REQUIRE(rateDatesInput.empty() || rateDatesInput.size() == rates.size() - 1,
234 "makeNonStandardIborLeg(): rate dates (" << rateDatesInput.size() <<
") must match rate ("
235 << rates.size() <<
") minus 1");
237 for (Size i = 0; i < calcDates.size() - 1; ++i) {
238 QL_REQUIRE(calcDates[i] <= calcDates[i + 1],
"makeNonStandardFixedLeg(): calc date at "
239 << i <<
" (" << calcDates[i]
240 <<
") must be less or equal calc date at " << (i + 1) <<
" ("
241 << calcDates[i + 1] <<
")");
246 std::vector<Date> payDates(payDatesInput);
247 std::vector<Date> notionalDates(notionalDatesInput);
248 std::vector<Date> rateDates(rateDatesInput);
250 if (payDates.empty()) {
251 for (Size i = 1; i < calcDates.size(); ++i) {
252 payDates.push_back(payCalendar.advance(calcDates[i], payLag, payConv));
256 if (notionalDates.empty()) {
257 for (Size i = 1; i < notionals.size(); ++i)
258 notionalDates.push_back(calcDates[i]);
261 if (rateDates.empty()) {
262 for (Size i = 1; i < rates.size(); ++i)
263 rateDates.push_back(calcDates[i]);
268 QL_REQUIRE(payDates.size() == calcDates.size() - 1,
"makeNonStandardFixedLeg(): pay dates size ("
269 << payDates.size() <<
") = calc dates size ("
270 << calcDates.size() <<
") minus 1 required");
274 std::set<Date> effCalcDates;
276 for (
auto const& d : calcDates)
277 effCalcDates.insert(d);
279 if (strictNotionalDates)
280 for (
auto const& d : notionalDates) {
281 if (d >= calcDates.front() && d < calcDates.back())
282 effCalcDates.insert(d);
289 for (
auto startDate = effCalcDates.begin(); startDate != std::next(effCalcDates.end(), -1); ++startDate) {
293 Date endDate = *std::next(startDate, 1);
295 if (endDate >= calcDates.back())
300 auto nextCalcDate = std::lower_bound(calcDates.begin(), calcDates.end(), endDate);
301 Date payDate = payDates[std::max<Size>(1, std::distance(calcDates.begin(), nextCalcDate)) - 1];
305 auto notionalDate = std::upper_bound(notionalDates.begin(), notionalDates.end(), *startDate);
307 notionals[std::min<Size>(notionals.size() - 1, std::distance(notionalDates.begin(), notionalDate))];
311 auto rateDate = std::upper_bound(rateDates.begin(), rateDates.end(), *startDate);
312 Real rate = rates[std::min<Size>(rates.size() - 1, std::distance(rateDates.begin(), rateDate))];
316 leg.push_back(QuantLib::ext::make_shared<FixedRateCoupon>(payDate, notional, rate, dayCounter, *startDate, endDate,
make functions for non-standard ibor and fixed legs
QuantLib::Date fixingDate(const QuantLib::Date &d, const QuantLib::Period obsLag, const QuantLib::Frequency freq, bool interpolated)
Leg makeNonStandardIborLeg(const QuantLib::ext::shared_ptr< IborIndex > &index, const std::vector< Date > &calcDates, const std::vector< Date > &payDatesInput, const std::vector< Date > &fixingDatesInput, const std::vector< Date > &resetDatesInput, const Size fixingDays, const std::vector< Real > ¬ionals, const std::vector< Date > ¬ionalDatesInput, const std::vector< Real > &spreadsInput, const std::vector< Date > &spreadDatesInput, const std::vector< Real > &gearingsInput, const std::vector< Date > &gearingDatesInput, const bool strictNotionalDates, const DayCounter &dayCounter, const Calendar &payCalendar, const BusinessDayConvention payConv, const Period &payLag, const bool isInArrears)
Leg makeNonStandardFixedLeg(const std::vector< Date > &calcDates, const std::vector< Date > &payDatesInput, const std::vector< Real > ¬ionals, const std::vector< Date > ¬ionalDatesInput, const std::vector< Real > &rates, const std::vector< Date > &rateDatesInput, const bool strictNotionalDates, const DayCounter &dayCounter, const Calendar &payCalendar, const BusinessDayConvention payConv, const Period &payLag)