/*
* (c) Copyright Christian P. Fries, Germany. All rights reserved. Contact: email@christianfries.com.
*
* Created on 07.09.2013
*/
package net.finmath.time.daycount;
import org.joda.time.DateTimeConstants;
import org.joda.time.LocalDate;
/**
* Implementation of ACT/ACT as in Excel (2013).
*
* Calculates the day count by calculating the actual number of days between startDate and endDate.
*
* A fractional day is rounded to the approximately nearest day.
*
* The day count fraction is calculated using ACT_ACT_YEARFRAC convention, that is, it is calculates the daycount fraction
* corresponding to the Excel (2013) function YEARFRAC(startDate, endDate, 1). The day count fraction is calculated by dividing
* the actual number of days between start and end date by a denominator, where the denominator is determines as follows:
* <ul>
* <li>If the interval from start to end spans more than one year fraction, denominator is the average number of days per year</li>
* <li>If the interval from start to end spans less or equal one year and if start and end fall in a leap year, denominator is 366.0</li>
* <li>If the interval from start to end spans less or equal one year and if either falls in a leap year and if February 29th of that leap year lies in between start and end (or is equal to start or end), denominator is 366.0</li>
* <li>If the interval from start to end spans less or equal one year and neither of the above applied denominator is 365.0</li>
* </ul>
*
* <p>
* <strong>
* This method is not identical to ACT/ACT ISDA. For ACT/ACT ISDA use {@link net.finmath.time.daycount.DayCountConvention_ACT_ACT_ISDA}.
* </strong>
* </p>
*
* <p>
* In addition the method has the defect, that it is not additive (if you consider small intervals). For example
* YEARFRAC(30.12.2011, 04.01.2012, 1) is not equal to YEARFRAC(30.12.2011, 01.01.2012, 1) + YEARFRAC(01.01.2012, 04.01.2012, 1).
* </p>
*
* @author Christian Fries
*/
public class DayCountConvention_ACT_ACT_YEARFRAC extends DayCountConvention_ACT {
/**
* Create an ACT/ACT YEARFRAC daycount convention.
*/
public DayCountConvention_ACT_ACT_YEARFRAC() {
}
/* (non-Javadoc)
* @see net.finmath.time.daycount.DayCountConventionInterface#getDaycountFraction(java.time.LocalDate, java.time.LocalDate)
*/
@Override
public double getDaycountFraction(LocalDate startDate, LocalDate endDate) {
if(startDate.isAfter(endDate)) return -getDaycountFraction(endDate,startDate);
/*
* Determine the denominator of act/act.
*/
double denominator;
LocalDate startDatePlusOneYear = startDate.plusYears(1);
if(endDate.isAfter(startDatePlusOneYear)) {
/*
* The following method applies, if the interval spans more than one year:
* fraction = actual number of days / average number of days per year.
*/
LocalDate startDateYearStart = startDate.withDayOfYear(1);
LocalDate endDateYearEnd = endDate.withDayOfYear(endDate.dayOfYear().getMaximumValue()).plusDays(1);
double spannedYears = endDate.getYear() - startDate.getYear() + 1;
denominator = getDaycount(startDateYearStart, endDateYearEnd) / spannedYears;
}
else {
boolean isStartLeapYear = startDate.year().isLeap();
boolean isEndLeapYear = endDate.year().isLeap();
/*
* If the start and end span less or equal one year:
* If start and end fall in a leap year, use ACT/366.
*/
if(isStartLeapYear && isEndLeapYear)
{
denominator = 366.0;
}
else
/*
* If the start and end span less or equal one year:
* If either falls in a leap year and Feb 29th of that leap year lies in between start and end (or is equal to start or end), use ACT/366.
*/
if(isStartLeapYear || isEndLeapYear)
{
// Get February 29th of the respective leap year
LocalDate leapYearsFeb29th = isStartLeapYear ?
new LocalDate(startDate.getYear(), DateTimeConstants.FEBRUARY, 29) :
new LocalDate(endDate.getYear(), DateTimeConstants.FEBRUARY, 29);
// Check position of February 29th
if(startDate.compareTo(leapYearsFeb29th) <= 0 && endDate.compareTo(leapYearsFeb29th) >= 0) {
denominator = 366.0;
}
else {
denominator = 365.0;
}
}
else {
/*
* If the start and end span less or equal one year:
* If none of the above applies, use denominator = ACT/365.
*/
denominator = 365.0;
}
}
double daycountFraction = getDaycount(startDate, endDate) / denominator;
return daycountFraction;
}
@Override
public String toString() {
return "DayCountConvention_ACT_ACT_YEARFRAC";
}
}