Package com.opengamma.financial.convention.daycount

Source Code of com.opengamma.financial.convention.daycount.AccruedInterestCalculator

/**
* 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 java.util.Arrays;

import org.apache.commons.lang.Validate;
import org.threeten.bp.LocalDate;
import org.threeten.bp.ZoneOffset;
import org.threeten.bp.ZonedDateTime;

import com.opengamma.financial.convention.StubCalculator;
import com.opengamma.financial.convention.StubType;
import com.opengamma.financial.convention.calendar.Calendar;

/**
* Utility to calculate the accrued interest.
*/
public final class AccruedInterestCalculator {

  /**
   * Restricted constructor.
   */
  private AccruedInterestCalculator() {
  }

  /**
   * Calculates the accrued interest for a {@code ZonedDateTime}.
   *
   * @param dayCount  the day count convention, not null
   * @param settlementDate  the settlement date, not null
   * @param nominalDates  the nominalDates, not null, no null elements
   * @param coupon  the coupon value
   * @param paymentsPerYear  the number of payments per year, one, two, three, four, six or twelve
   * @param isEndOfMonthConvention  whether to use end of month rules
   * @param exDividendDays the number of ex-dividend days
   * @param calendar The working day calendar to be used in calculating ex-dividend dates, not null
   * @return the accrued interest
   */
  public static double getAccruedInterest(final DayCount dayCount, final ZonedDateTime settlementDate, final ZonedDateTime[] nominalDates, final double coupon, final int paymentsPerYear,
      final boolean isEndOfMonthConvention, final int exDividendDays, final Calendar calendar) {
    Validate.notNull(dayCount, "day-count");
    Validate.notNull(settlementDate, "date");
    Validate.noNullElements(nominalDates, "nominalDates");
    Validate.notNull(calendar, "calendar");
    Validate.isTrue(paymentsPerYear > 0);
    Validate.isTrue(exDividendDays >= 0);
    final int i = Arrays.binarySearch(nominalDates, settlementDate);
    if (i > 0) {
      return 0;
    }
    final int index = -i - 2;
    final int length = nominalDates.length;
    Validate.isTrue(index >= 0, "Settlement date is before first accrual date");
    Validate.isTrue(index < length, "Settlement date is after maturity date");
    final double accruedInterest = getAccruedInterest(dayCount, index, length, nominalDates[index], settlementDate, nominalDates[index + 1], coupon, paymentsPerYear, isEndOfMonthConvention);
    ZonedDateTime exDividendDate = nominalDates[index + 1];
    for (int j = 0; j < exDividendDays; j++) {
      while (!calendar.isWorkingDay(exDividendDate.toLocalDate())) {
        exDividendDate = exDividendDate.minusDays(1);
      }
      exDividendDate = exDividendDate.minusDays(1);
    }
    if (exDividendDays != 0 && exDividendDate.isBefore(settlementDate)) {
      return accruedInterest - coupon;
    }
    return accruedInterest;
  }

  /**
   * Calculates the accrued interest for a {@code ZonedDateTime}.
   *
   * @param dayCount  the day count convention, not null
   * @param settlementDate  the settlement date, not null
   * @param nominalDates  the nominalDates, not null, no null elements
   * @param coupon  the coupon value
   * @param paymentsPerYear  the number of payments per year, one, two, three, four, six or twelve
   * @param isEndOfMonthConvention  whether to use end of month rules
   * @param exDividendDays the number of ex-dividend days
   * @param index The index of the previous coupon in the nominalDates array
   * @param calendar The working day calendar to be used in calculating ex-dividend dates, not null
   * @return the accrued interest
   */
  public static double getAccruedInterest(final DayCount dayCount, final ZonedDateTime settlementDate, final ZonedDateTime[] nominalDates, final double coupon, final double paymentsPerYear,
      final boolean isEndOfMonthConvention, final int exDividendDays, final int index, final Calendar calendar) {
    Validate.notNull(dayCount, "day-count");
    Validate.notNull(settlementDate, "date");
    Validate.noNullElements(nominalDates, "nominalDates");
    Validate.notNull(calendar, "calendar");
    Validate.isTrue(paymentsPerYear > 0);
    Validate.isTrue(exDividendDays >= 0);
    final int length = nominalDates.length;
    Validate.isTrue(index >= 0 && index < length);
    final double accruedInterest = getAccruedInterest(dayCount, index, length, nominalDates[index], settlementDate, nominalDates[index + 1], coupon, paymentsPerYear, isEndOfMonthConvention);
    ZonedDateTime exDividendDate = nominalDates[index + 1];
    for (int i = 0; i < exDividendDays; i++) {
      while (!calendar.isWorkingDay(exDividendDate.toLocalDate())) {
        exDividendDate = exDividendDate.minusDays(1);
      }
      exDividendDate = exDividendDate.minusDays(1);
    }
    if (exDividendDays != 0 && exDividendDate.isBefore(settlementDate)) {
      return accruedInterest - coupon;
    }
    return accruedInterest;
  }

  /**
   * Calculates the accrued interest for a {@code LocalDate}.
   *
   * @param dayCount  the day count convention, not null
   * @param settlementDate  the settlement date, not null
   * @param nominalDates  the nominalDates, not null, no null elements
   * @param coupon  the coupon value
   * @param paymentsPerYear  the number of payments per year, one, two, three, four, six or twelve
   * @param isEndOfMonthConvention  whether to use end of month rules
   * @param exDividendDays the number of ex-dividend days
   * @param calendar The working day calendar to be used in calculating ex-dividend dates, not null
   * @return the accrued interest
   */
  //TODO one where you can pass in array of coupons
  public static double getAccruedInterest(final DayCount dayCount, final LocalDate settlementDate, final LocalDate[] nominalDates, final double coupon, final double paymentsPerYear,
      final boolean isEndOfMonthConvention, final int exDividendDays, final Calendar calendar) {
    Validate.notNull(dayCount, "day-count");
    Validate.notNull(settlementDate, "date");
    Validate.noNullElements(nominalDates, "nominalDates");
    Validate.notNull(calendar, "calendar");
    Validate.isTrue(paymentsPerYear > 0);
    Validate.isTrue(exDividendDays >= 0);
    final int i = Arrays.binarySearch(nominalDates, settlementDate);
    if (i > 0) {
      return 0;
    }
    final int index = -i - 2;
    final int length = nominalDates.length;
    if (index < 0) {
      throw new IllegalArgumentException("Settlement date is before first accrual date");
    }
    if (index == length) {
      throw new IllegalArgumentException("Settlement date is after maturity date");
    }
    final ZonedDateTime previousCouponDate = nominalDates[index].atStartOfDay(ZoneOffset.UTC);
    final ZonedDateTime date = settlementDate.atStartOfDay(ZoneOffset.UTC);
    final ZonedDateTime nextCouponDate = nominalDates[index + 1].atStartOfDay(ZoneOffset.UTC);
    final double accruedInterest = getAccruedInterest(dayCount, index, length, previousCouponDate, date, nextCouponDate, coupon, paymentsPerYear, isEndOfMonthConvention);
    LocalDate exDividendDate = nominalDates[index + 1];
    for (int j = 0; j < exDividendDays; j++) {
      while (!calendar.isWorkingDay(exDividendDate)) {
        exDividendDate = exDividendDate.minusDays(1);
      }
      exDividendDate = exDividendDate.minusDays(1);
    }
    if (exDividendDays != 0 && exDividendDate.isBefore(settlementDate)) {
      return accruedInterest - coupon;
    }
    return accruedInterest;
  }

  /**
   * Calculates the accrued interest for a {@code LocalDate}.
   *
   * @param dayCount  the day count convention, not null
   * @param settlementDate  the settlement date, not null
   * @param nominalDates  the nominalDates, not null, no null elements
   * @param coupon  the coupon value
   * @param paymentsPerYear  the number of payments per year, one, two, three, four, six or twelve
   * @param isEndOfMonthConvention  whether to use end of month rules
   * @param exDividendDays the number of ex-dividend days
   * @param index The index of the previous coupon in the nominalDates
   * @param calendar The working day calendar to be used in calculating ex-dividend dates, not null
   * @return the accrued interest
   */
  public static double getAccruedInterest(final DayCount dayCount, final LocalDate settlementDate, final LocalDate[] nominalDates, final double coupon, final double paymentsPerYear,
      final boolean isEndOfMonthConvention, final int exDividendDays, final int index, final Calendar calendar) {
    Validate.notNull(dayCount, "day-count");
    Validate.notNull(settlementDate, "date");
    Validate.noNullElements(nominalDates, "nominalDates");
    Validate.notNull(calendar, "calendar");
    Validate.isTrue(paymentsPerYear > 0);
    Validate.isTrue(exDividendDays >= 0);
    final int length = nominalDates.length;
    Validate.isTrue(index >= 0 && index < length);
    final ZonedDateTime previousCouponDate = nominalDates[index].atStartOfDay(ZoneOffset.UTC);
    final ZonedDateTime date = settlementDate.atStartOfDay(ZoneOffset.UTC);
    final ZonedDateTime nextCouponDate = nominalDates[index + 1].atStartOfDay(ZoneOffset.UTC);
    double accruedInterest;
    if (date.isAfter(nextCouponDate)) {
      accruedInterest = 0;
    } else {
      accruedInterest = getAccruedInterest(dayCount, index, length, previousCouponDate, date, nextCouponDate, coupon, paymentsPerYear, isEndOfMonthConvention);
    }
    LocalDate exDividendDate = nominalDates[index + 1];
    for (int i = 0; i < exDividendDays; i++) {
      while (!calendar.isWorkingDay(exDividendDate)) {
        exDividendDate = exDividendDate.minusDays(1);
      }
      exDividendDate = exDividendDate.minusDays(1);
    }
    if (exDividendDays != 0 && exDividendDate.isBefore(settlementDate)) {
      return accruedInterest - coupon;
    }
    return accruedInterest;
  }

  /**
   * Calculates the accrued interest for a {@code LocalDate}.
   *
   * @param dayCount  the day count convention, not null
   * @param settlementDate  the settlement date, not null
   * @param nominalDates  the nominalDates, not null, no null elements
   * @param settlementDates  the settlement dates, not null, no null elements
   * @param coupon  the coupon value
   * @param paymentsPerYear  the number of payments per year, one, two, three, four, six or twelve
   * @param isEndOfMonthConvention  whether to use end of month rules
   * @param exDividendDays the number of ex-dividend days
   * @param index The index of the previous coupon in the nominalDates
   * @param calendar The working day calendar used to calculate the ex-dividend date, not null
   * @return the accrued interest
   */
  public static double getAccruedInterest(final DayCount dayCount, final LocalDate settlementDate, final LocalDate[] nominalDates, final LocalDate[] settlementDates, final double coupon,
      final double paymentsPerYear, final boolean isEndOfMonthConvention, final int exDividendDays, final int index, final Calendar calendar) {
    Validate.notNull(dayCount, "day-count");
    Validate.notNull(settlementDate, "date");
    Validate.notNull(calendar, "calendar");
    Validate.noNullElements(nominalDates, "nominalDates");
    Validate.noNullElements(settlementDates, "settlementDates");
    Validate.isTrue(paymentsPerYear > 0);
    Validate.isTrue(exDividendDays >= 0);
    final int length = nominalDates.length;
    Validate.isTrue(index >= 0 && index < length);
    final LocalDate previousCouponDate = nominalDates[index];
    final LocalDate nextCouponDate = nominalDates[index + 1];
    double accruedInterest;
    if (settlementDate.isAfter(nextCouponDate)) {
      if (settlementDate.isBefore(settlementDates[index + 1])) {
        accruedInterest = coupon;
      } else {
        accruedInterest = 0;
      }
    } else {
      accruedInterest = getAccruedInterest(dayCount, index, length, previousCouponDate, settlementDate, nextCouponDate, coupon, paymentsPerYear, isEndOfMonthConvention);
    }
    LocalDate exDividendDate = nominalDates[index + 1];
    for (int i = 0; i < exDividendDays; i++) {
      while (!calendar.isWorkingDay(exDividendDate)) {
        exDividendDate = exDividendDate.minusDays(1);
      }
      exDividendDate = exDividendDate.minusDays(1);
    }
    if (exDividendDays != 0 && exDividendDate.isBefore(settlementDate)) {
      return accruedInterest - coupon;
    }
    return accruedInterest;
  }

  public static double getAccruedInterest(final DayCount dayCount, final int index, final int length, final ZonedDateTime previousCouponDate, final ZonedDateTime date,
      final ZonedDateTime nextCouponDate, final double coupon, final double paymentsPerYear, final boolean isEndOfMonthConvention) {
    if (dayCount instanceof ActualActualICMANormal) {
      if (isEndOfMonthConvention) {
        throw new IllegalArgumentException("Inconsistent definition; asked for accrual with EOM convention but are not using Actual/Actual ICMA");
      }
      final StubType stubType = getStubType(index, length, previousCouponDate, nextCouponDate, paymentsPerYear, isEndOfMonthConvention);
      return ((ActualActualICMANormal) dayCount).getAccruedInterest(previousCouponDate, date, nextCouponDate, coupon, paymentsPerYear, stubType);

    } else if (dayCount instanceof ActualActualICMA) {
      final StubType stubType = getStubType(index, length, previousCouponDate, nextCouponDate, paymentsPerYear, isEndOfMonthConvention);
      return ((ActualActualICMA) dayCount).getAccruedInterest(previousCouponDate, date, nextCouponDate, coupon, paymentsPerYear, stubType);

    } else if (dayCount instanceof ThirtyUThreeSixty) {
      return ((ThirtyUThreeSixty) dayCount).getAccruedInterest(previousCouponDate, date, coupon, isEndOfMonthConvention);
    }
    return dayCount.getAccruedInterest(previousCouponDate, date, nextCouponDate, coupon, paymentsPerYear);
  }

  public static double getAccruedInterest(final DayCount dayCount, final int index, final int length, final LocalDate previousCouponDate, final LocalDate date,
      final LocalDate nextCouponDate, final double coupon, final double paymentsPerYear, final boolean isEndOfMonthConvention) {
    if (dayCount instanceof ActualActualICMANormal) {
      if (isEndOfMonthConvention) {
        throw new IllegalArgumentException("Inconsistent definition; asked for accrual with EOM convention but are not using Actual/Actual ICMA");
      }
      final StubType stubType = getStubType(index, length, previousCouponDate, nextCouponDate, paymentsPerYear, isEndOfMonthConvention);
      return ((ActualActualICMANormal) dayCount).getAccruedInterest(previousCouponDate, date, nextCouponDate, coupon, paymentsPerYear, stubType);

    } else if (dayCount instanceof ActualActualICMA) {
      final StubType stubType = getStubType(index, length, previousCouponDate, nextCouponDate, paymentsPerYear, isEndOfMonthConvention);
      return ((ActualActualICMA) dayCount).getAccruedInterest(previousCouponDate, date, nextCouponDate, coupon, paymentsPerYear, stubType);

    } else if (dayCount instanceof ThirtyUThreeSixty) {
      return ((ThirtyUThreeSixty) dayCount).getAccruedInterest(previousCouponDate, date, coupon, isEndOfMonthConvention);
    }
    return dayCount.getAccruedInterest(previousCouponDate, date, nextCouponDate, coupon, paymentsPerYear);
  }

  private static StubType getStubType(final int index, final int length, final ZonedDateTime previousCouponDate, final ZonedDateTime nextCouponDate, final double paymentsPerYear,
      final boolean isEndOfMonthConvention) {
    StubType stubType;
    if (index == 0) {
      LocalDate[] schedule = new LocalDate[] {previousCouponDate.toLocalDate(), nextCouponDate.toLocalDate()};
      stubType = StubCalculator.getStartStubType(schedule, paymentsPerYear, isEndOfMonthConvention);

    } else if (index == length - 2) {
      LocalDate[] schedule = new LocalDate[] {previousCouponDate.toLocalDate(), nextCouponDate.toLocalDate()};
      stubType = StubCalculator.getEndStubType(schedule, paymentsPerYear, isEndOfMonthConvention);

    } else {
      stubType = StubType.NONE;
    }
    return stubType;
  }

  private static StubType getStubType(final int index, final int length, final LocalDate previousCouponDate, final LocalDate nextCouponDate, final double paymentsPerYear,
      final boolean isEndOfMonthConvention) {
    StubType stubType;
    if (index == 0) {
      LocalDate[] schedule = new LocalDate[] {previousCouponDate, nextCouponDate};
      stubType = StubCalculator.getStartStubType(schedule, paymentsPerYear, isEndOfMonthConvention);

    } else if (index == length - 2) {
      LocalDate[] schedule = new LocalDate[] {previousCouponDate, nextCouponDate};
      stubType = StubCalculator.getEndStubType(schedule, paymentsPerYear, isEndOfMonthConvention);

    } else {
      stubType = StubType.NONE;
    }
    return stubType;
  }
}
TOP

Related Classes of com.opengamma.financial.convention.daycount.AccruedInterestCalculator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.