/**
* Copyright (C) 2013 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.analytics.financial.credit.isdastandardmodel;
import org.threeten.bp.LocalDate;
import org.threeten.bp.Period;
import com.opengamma.util.ArgumentChecker;
/**
* Utility for producing sets of IMM dates.
*/
public abstract class IMMDateLogic {
private static final int IMM_DAY = 20;
private static final int[] IMM_MONTHS = new int[] {3, 6, 9, 12 };
private static final int[] INDEX_ROLL_MONTHS = new int[] {3, 9 };
/**
* IMM dates are 20th March, June, September and December
* @param date the date
* @return true is date is an IMM date
*/
public static boolean isIMMDate(final LocalDate date) {
if (date.getDayOfMonth() != IMM_DAY) {
return false;
}
if ((date.getMonthValue() % 3) != 0) {
return false;
}
return true;
}
/**
* Index roll dates are 20th March and September
* @param date the date
* @return true is date is an IMM date
*/
public static boolean isIndexRollDate(final LocalDate date) {
if (date.getDayOfMonth() != IMM_DAY) {
return false;
}
final int month = date.getMonthValue();
return month == INDEX_ROLL_MONTHS[0] || month == INDEX_ROLL_MONTHS[1];
}
/**
* Get a set of IMM dates fixed periods from an initial IMM date.
* @param baseIMMDate The base IMM date (all dates are some interval on from this)
* @param tenors The periods (typically this would look like 6M, 1Y, 2Y, 3Y, 5Y, 10Y)
* @return Set of IMM dates
*/
public static LocalDate[] getIMMDateSet(final LocalDate baseIMMDate, final Period[] tenors) {
ArgumentChecker.notNull(baseIMMDate, "startIMMDate");
ArgumentChecker.noNulls(tenors, "tenors");
final int n = tenors.length;
ArgumentChecker.isTrue(isIMMDate(baseIMMDate), "start is not an IMM date");
final LocalDate nextIMM = baseIMMDate;
final LocalDate[] res = new LocalDate[n];
for (int i = 0; i < n; i++) {
res[i] = nextIMM.plus(tenors[i]);
}
return res;
}
/**
* Get a complete set of IMM dates from some starting IMM date
* @param startIMMDate The starting IMM date (this will be the first entry)
* @param size number of dates
* @return set of IMM dates
*/
public static LocalDate[] getIMMDateSet(final LocalDate startIMMDate, final int size) {
ArgumentChecker.isTrue(isIMMDate(startIMMDate), "start is not an IMM date");
final LocalDate[] res = new LocalDate[size];
res[0] = startIMMDate;
for (int i = 1; i < size; i++) {
final int tMonth = res[i - 1].getMonthValue();
final int tYear = res[i - 1].getYear();
if (tMonth != 12) {
res[i] = LocalDate.of(tYear, tMonth + 3, IMM_DAY);
} else {
res[i] = LocalDate.of(tYear + 1, 3, IMM_DAY);
}
}
return res;
}
/**
* IMM dates are 20th March, June, September and December. This returns the next IMM date from the given date - if the date
* is an IMM date the next IMM date (i.e. 3 months on) is returned.
* @param date a given date
* @return the next IMM date
*/
public static LocalDate getNextIMMDate(final LocalDate date) {
final int day = date.getDayOfMonth();
final int month = date.getMonthValue();
final int year = date.getYear();
if (month % 3 == 0) { //in an IMM month
if (day < IMM_DAY) {
return LocalDate.of(year, month, IMM_DAY);
} else {
if (month != 12) {
return LocalDate.of(year, month + 3, IMM_DAY);
} else {
return LocalDate.of(year + 1, IMM_MONTHS[0], IMM_DAY);
}
}
} else {
return LocalDate.of(year, IMM_MONTHS[month / 3], IMM_DAY);
}
}
/**
* IMM dates are 20th March, June, September and December. This returns the previous IMM date from the given date - if the date
* is an IMM date the previous IMM date (i.e. 3 months before) is returned.
* @param date a given date
* @return the next IMM date
*/
public static LocalDate getPrevIMMDate(final LocalDate date) {
final int day = date.getDayOfMonth();
final int month = date.getMonthValue();
final int year = date.getYear();
if (month % 3 == 0) { //in an IMM month
if (day > IMM_DAY) {
return LocalDate.of(year, month, IMM_DAY);
} else {
if (month != 3) {
return LocalDate.of(year, month - 3, IMM_DAY);
} else {
return LocalDate.of(year - 1, IMM_MONTHS[3], IMM_DAY);
}
}
} else {
final int i = month / 3;
if (i == 0) {
return LocalDate.of(year - 1, IMM_MONTHS[3], IMM_DAY);
} else {
return LocalDate.of(year, IMM_MONTHS[i - 1], IMM_DAY);
}
}
}
/**
* Index roll dates are 20th March and September. This returns the next roll date from the given date - if the date
* is a roll date the next roll date (i.e. 6 months on) is returned.
* @param date a given date
* @return the next Index roll date
*/
public static LocalDate getNextIndexRollDate(final LocalDate date) {
final int day = date.getDayOfMonth();
final int month = date.getMonthValue();
final int year = date.getYear();
if (isIndexRollDate(date)) { //on an index roll
if (month == INDEX_ROLL_MONTHS[0]) {
return LocalDate.of(year, INDEX_ROLL_MONTHS[1], IMM_DAY);
} else {
return LocalDate.of(year + 1, INDEX_ROLL_MONTHS[0], IMM_DAY);
}
} else {
if (month < INDEX_ROLL_MONTHS[0]) {
return LocalDate.of(year, INDEX_ROLL_MONTHS[0], IMM_DAY);
} else if (month == INDEX_ROLL_MONTHS[0]) {
if (day < IMM_DAY) {
return LocalDate.of(year, month, IMM_DAY);
} else {
return LocalDate.of(year, INDEX_ROLL_MONTHS[1], IMM_DAY);
}
} else if (month < INDEX_ROLL_MONTHS[1]) {
return LocalDate.of(year, INDEX_ROLL_MONTHS[1], IMM_DAY);
} else if (month == INDEX_ROLL_MONTHS[1]) {
if (day < IMM_DAY) {
return LocalDate.of(year, month, IMM_DAY);
} else {
return LocalDate.of(year + 1, INDEX_ROLL_MONTHS[0], IMM_DAY);
}
} else {
return LocalDate.of(year + 1, INDEX_ROLL_MONTHS[0], IMM_DAY);
}
}
}
}