/** * Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.financial.convention.daycount; import org.apache.commons.lang.NotImplementedException; import org.apache.commons.lang.Validate; import org.threeten.bp.LocalDate; import org.threeten.bp.ZonedDateTime; import org.threeten.bp.temporal.JulianFields; import com.opengamma.financial.convention.StubType; /** * The 'Actual/Actual ICMA Normal' day count. */ public class ActualActualICMANormal extends ActualTypeDayCount { /** Serialization version. */ private static final long serialVersionUID = 1L; @Override public double getDayCountFraction(final LocalDate firstDate, final LocalDate secondDate) { throw new NotImplementedException("Cannot get daycount fraction; need information about the coupon and payment frequency"); } @Override public double getAccruedInterest(final LocalDate previousCouponDate, final LocalDate date, final LocalDate nextCouponDate, final double coupon, final double paymentsPerYear) { return getAccruedInterest(previousCouponDate, date, nextCouponDate, coupon, paymentsPerYear, StubType.NONE); } public double getAccruedInterest(final ZonedDateTime previousCouponDate, final ZonedDateTime date, final ZonedDateTime nextCouponDate, final double coupon, final double paymentsPerYear, final StubType stubType) { return getAccruedInterest(previousCouponDate.toLocalDate(), date.toLocalDate(), nextCouponDate.toLocalDate(), coupon, paymentsPerYear, stubType); } public double getAccruedInterest(final LocalDate previousCouponDate, final LocalDate date, final LocalDate nextCouponDate, final double coupon, final double paymentsPerYear, final StubType stubType) { testDates(previousCouponDate, date, nextCouponDate); Validate.notNull(stubType, "stub type"); long daysBetween, daysBetweenCoupons; final long previousCouponDateJulian = previousCouponDate.getLong(JulianFields.MODIFIED_JULIAN_DAY); final long nextCouponDateJulian = nextCouponDate.getLong(JulianFields.MODIFIED_JULIAN_DAY); final long dateJulian = date.getLong(JulianFields.MODIFIED_JULIAN_DAY); final int months = (int) (12 / paymentsPerYear); switch (stubType) { case NONE: { daysBetween = dateJulian - previousCouponDateJulian; daysBetweenCoupons = nextCouponDateJulian - previousCouponDateJulian; return coupon * daysBetween / daysBetweenCoupons / paymentsPerYear; } case SHORT_START: { final LocalDate notionalStart = nextCouponDate.minusMonths(months); daysBetweenCoupons = nextCouponDateJulian - notionalStart.getLong(JulianFields.MODIFIED_JULIAN_DAY); daysBetween = dateJulian - previousCouponDateJulian; return coupon * daysBetween / daysBetweenCoupons / paymentsPerYear; } case LONG_START: { final long firstNotionalJulian = nextCouponDate.minusMonths(months * 2).getLong(JulianFields.MODIFIED_JULIAN_DAY); final long secondNotionalJulian = nextCouponDate.minusMonths(months).getLong(JulianFields.MODIFIED_JULIAN_DAY); final long daysBetweenStub = secondNotionalJulian - previousCouponDateJulian; final double daysBetweenTwoNotionalCoupons = secondNotionalJulian - firstNotionalJulian; if (dateJulian > secondNotionalJulian) { daysBetween = dateJulian - secondNotionalJulian; return coupon * (daysBetweenStub / daysBetweenTwoNotionalCoupons + 1) / paymentsPerYear; } daysBetween = dateJulian - firstNotionalJulian; return coupon * (daysBetween / daysBetweenTwoNotionalCoupons) / paymentsPerYear; } case SHORT_END: { final LocalDate notionalEnd = previousCouponDate.plusMonths(months); daysBetweenCoupons = notionalEnd.getLong(JulianFields.MODIFIED_JULIAN_DAY) - previousCouponDateJulian; daysBetween = dateJulian - previousCouponDateJulian; return coupon * daysBetween / daysBetweenCoupons / paymentsPerYear; } case LONG_END: { final long firstNotionalJulian = previousCouponDate.plusMonths(months).getLong(JulianFields.MODIFIED_JULIAN_DAY); final long secondNotionalJulian = previousCouponDate.plusMonths(2 * months).getLong(JulianFields.MODIFIED_JULIAN_DAY); final long daysBetweenPreviousAndFirstNotional = firstNotionalJulian - previousCouponDateJulian; if (dateJulian < firstNotionalJulian) { daysBetween = dateJulian - previousCouponDateJulian; return coupon * daysBetween / daysBetweenPreviousAndFirstNotional / paymentsPerYear; } final long daysBetweenStub = dateJulian - firstNotionalJulian; final double daysBetweenTwoNotionalCoupons = secondNotionalJulian - firstNotionalJulian; return coupon * (1 + daysBetweenStub / daysBetweenTwoNotionalCoupons) / paymentsPerYear; } default: throw new IllegalArgumentException("Cannot handle stub type " + stubType); } } @Override public String getName() { return "Actual/Actual ICMA Normal"; } }