20#include <ql/time/daycounters/actualactual.hpp>
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>
132 if (!schedule.
empty())
133 return ext::shared_ptr<DayCounter::Impl>(
new ISMA_Impl(schedule));
139 return ext::shared_ptr<DayCounter::Impl>(
new ISDA_Impl);
142 return ext::shared_ptr<DayCounter::Impl>(
new AFB_Impl);
144 QL_FAIL(
"unknown act/act convention");
152 const Date& d4)
const {
155 }
else if (d2 < d1) {
159 std::vector<Date> couponDates =
160 getListOfPeriodDatesIncludingQuasiPayments(
schedule_);
162 Date firstDate = *std::min_element(couponDates.begin(), couponDates.end());
163 Date lastDate = *std::max_element(couponDates.begin(), couponDates.end());
165 QL_REQUIRE(d1 >= firstDate && d2 <= lastDate,
"Dates out of range of schedule: "
166 <<
"date 1: " << d1 <<
", date 2: " << d2 <<
", first date: "
167 << firstDate <<
", last date: " << lastDate);
169 Real yearFractionSum = 0.0;
170 for (
Size i = 0; i < couponDates.size() - 1; i++) {
171 Date startReferencePeriod = couponDates[i];
172 Date endReferencePeriod = couponDates[i + 1];
173 if (d1 < endReferencePeriod && d2 > startReferencePeriod) {
175 yearFractionWithReferenceDates(*
this,
176 std::max(d1, startReferencePeriod),
177 std::min(d2, endReferencePeriod),
178 startReferencePeriod,
182 return yearFractionSum;
189 const Date& d4)
const {
198 Date refPeriodStart = (d3 !=
Date() ? d3 : d1);
199 Date refPeriodEnd = (d4 !=
Date() ? d4 : d2);
201 QL_REQUIRE(refPeriodEnd > refPeriodStart && refPeriodEnd > d1,
202 "invalid reference period: "
204 <<
", date 2: " << d2
205 <<
", reference period start: " << refPeriodStart
206 <<
", reference period end: " << refPeriodEnd);
209 auto months = (
Integer)std::lround(12 *
Real(refPeriodEnd - refPeriodStart) / 365);
215 refPeriodEnd = d1 + 1*
Years;
221 if (d2 <= refPeriodEnd) {
223 if (d1 >= refPeriodStart) {
243 if (d2 > refPeriodStart)
254 QL_REQUIRE(refPeriodStart<=d1,
256 "d1 < refPeriodStart < refPeriodEnd < d2");
261 refPeriodStart, refPeriodEnd);
267 Date newRefStart, newRefEnd;
271 if (d2 < newRefEnd) {
278 sum +=
yearFraction(newRefStart,d2,newRefStart,newRefEnd);
298 Time sum = y2 - y1 - 1;
315 Date newD2=d2, temp=d2;
318 temp = newD2 - 1*
Years;
319 if (temp.dayOfMonth()==28 && temp.month()==2
333 if (newD2>temp && d1<=temp)
337 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, const 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.
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)