31 Integer findCouponsPerYear(
const T& impl,
32 Date refStart, Date refEnd) {
34 auto months = (
Integer)std::lround(12 *
Real(impl.dayCount(refStart, refEnd)) / 365.0);
43 Time yearFractionGuess(
const T& impl,
44 const Date& start,
const Date& end) {
46 return Real(impl.dayCount(start, end)) / 365.0;
49 std::vector<Date> getListOfPeriodDatesIncludingQuasiPayments(
50 const Schedule& schedule) {
52 Date issueDate = schedule.date(0);
53 std::vector<Date> newDates = schedule.dates();
55 if (!schedule.hasIsRegular() || !schedule.isRegular(1))
57 Date firstCoupon = schedule.date(1);
59 Date notionalFirstCoupon =
60 schedule.calendar().advance(firstCoupon,
62 schedule.businessDayConvention(),
63 schedule.endOfMonth());
65 newDates[0] = notionalFirstCoupon;
68 if (notionalFirstCoupon > issueDate) {
69 Date priorNotionalCoupon =
70 schedule.calendar().advance(notionalFirstCoupon,
72 schedule.businessDayConvention(),
73 schedule.endOfMonth());
74 newDates.insert(newDates.begin(),
79 if (!schedule.hasIsRegular() || !schedule.isRegular(schedule.size() - 1))
81 Date notionalLastCoupon =
82 schedule.calendar().advance(schedule.date(schedule.size() - 2),
84 schedule.businessDayConvention(),
85 schedule.endOfMonth());
87 newDates[schedule.size() - 1] = notionalLastCoupon;
89 if (notionalLastCoupon < schedule.endDate())
91 Date nextNotionalCoupon =
92 schedule.calendar().advance(notionalLastCoupon,
94 schedule.businessDayConvention(),
95 schedule.endOfMonth());
96 newDates.push_back(nextNotionalCoupon);
104 Time yearFractionWithReferenceDates(
const T& impl,
105 const Date& d1,
const Date& d2,
106 const Date& d3,
const Date& d4) {
108 "This function is only correct if d1 <= d2\n"
109 "d1: " << d1 <<
" d2: " << d2);
111 Real referenceDayCount =
Real(impl.dayCount(d3, d4));
114 if (referenceDayCount < 16) {
116 referenceDayCount = impl.dayCount(d1, d1 + 1 *
Years);
119 couponsPerYear = findCouponsPerYear(impl, d3, d4);
121 return Real(impl.dayCount(d1, d2)) / (referenceDayCount*couponsPerYear);
126 ext::shared_ptr<DayCounter::Impl>
131 if (!schedule.
empty())
132 return ext::shared_ptr<DayCounter::Impl>(
new ISMA_Impl(std::move(schedule)));
138 return ext::shared_ptr<DayCounter::Impl>(
new ISDA_Impl);
141 return ext::shared_ptr<DayCounter::Impl>(
new AFB_Impl);
143 QL_FAIL(
"unknown act/act convention");
151 const Date& d4)
const {
154 }
else if (d2 < d1) {
158 std::vector<Date> couponDates =
159 getListOfPeriodDatesIncludingQuasiPayments(
schedule_);
161 Date firstDate = *std::min_element(couponDates.begin(), couponDates.end());
162 Date lastDate = *std::max_element(couponDates.begin(), couponDates.end());
164 QL_REQUIRE(d1 >= firstDate && d2 <= lastDate,
"Dates out of range of schedule: "
165 <<
"date 1: " << d1 <<
", date 2: " << d2 <<
", first date: "
166 << firstDate <<
", last date: " << lastDate);
168 Real yearFractionSum = 0.0;
169 for (
Size i = 0; i < couponDates.size() - 1; i++) {
170 Date startReferencePeriod = couponDates[i];
171 Date endReferencePeriod = couponDates[i + 1];
172 if (d1 < endReferencePeriod && d2 > startReferencePeriod) {
174 yearFractionWithReferenceDates(*
this,
175 std::max(d1, startReferencePeriod),
176 std::min(d2, endReferencePeriod),
177 startReferencePeriod,
181 return yearFractionSum;
188 const Date& d4)
const {
197 Date refPeriodStart = (d3 !=
Date() ? d3 : d1);
198 Date refPeriodEnd = (d4 !=
Date() ? d4 : d2);
200 QL_REQUIRE(refPeriodEnd > refPeriodStart && refPeriodEnd > d1,
201 "invalid reference period: "
203 <<
", date 2: " << d2
204 <<
", reference period start: " << refPeriodStart
205 <<
", reference period end: " << refPeriodEnd);
208 auto months = (
Integer)std::lround(12 *
Real(refPeriodEnd - refPeriodStart) / 365);
214 refPeriodEnd = d1 + 1*
Years;
220 if (d2 <= refPeriodEnd) {
222 if (d1 >= refPeriodStart) {
242 if (d2 > refPeriodStart)
255 "d1 < refPeriodStart < refPeriodEnd < d2");
260 refPeriodStart, refPeriodEnd);
266 Date newRefStart, newRefEnd;
270 if (d2 < newRefEnd) {
277 sum +=
yearFraction(newRefStart,d2,newRefStart,newRefEnd);
297 Time sum = y2 - y1 - 1;
314 Date newD2=d2, temp=d2;
317 temp = newD2 - 1*
Years;
318 if (temp.dayOfMonth()==28 && temp.month()==2
332 if (newD2>temp && d1<=temp)
336 if (newD2>temp && d1<=temp)
Time yearFraction(const Date &d1, const Date &d2, const Date &, const Date &) const override
Time yearFraction(const Date &d1, const Date &d2, const Date &, const Date &) const override
Time yearFraction(const Date &d1, const Date &d2, const Date &refPeriodStart, const Date &refPeriodEnd) const override
Time yearFraction(const Date &d1, const Date &d2, const Date &refPeriodStart, const Date &refPeriodEnd) const override
static ext::shared_ptr< DayCounter::Impl > implementation(Convention c, Schedule schedule)
static bool isLeap(Year y)
whether the given year is a leap one
Time yearFraction(const Date &, const Date &, const Date &refPeriodStart=Date(), const Date &refPeriodEnd=Date()) const
Returns the period between two dates as a fraction of year.
#define QL_REQUIRE(condition, message)
throw an error if the given pre-condition is not verified
#define QL_FAIL(message)
throw an error (possibly with file and line information)
Real Time
continuous quantity with 1-year units
QL_INTEGER Integer
integer number
std::size_t Size
size of a container
Real months(const Period &p)
Time daysBetween(const Date &d1, const Date &d2)