/** * Copyright (C) 2013 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.strata.pricer.impl.credit.isda; import java.time.LocalDate; import java.time.Period; import com.opengamma.strata.collect.ArgChecker; /** * 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(LocalDate date) { return date.getDayOfMonth() == IMM_DAY && (date.getMonthValue() % 3) == 0; } /** * Index roll dates are 20th March and September. * * @param date the date * @return true is date is an IMM date */ public static boolean isIndexRollDate(LocalDate date) { if (date.getDayOfMonth() != IMM_DAY) { return false; } 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(LocalDate baseIMMDate, Period[] tenors) { ArgChecker.notNull(baseIMMDate, "startIMMDate"); ArgChecker.noNulls(tenors, "tenors"); int n = tenors.length; ArgChecker.isTrue(isIMMDate(baseIMMDate), "start is not an IMM date"); LocalDate[] res = new LocalDate[n]; for (int i = 0; i < n; i++) { res[i] = baseIMMDate.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(LocalDate startIMMDate, int size) { ArgChecker.isTrue(isIMMDate(startIMMDate), "start is not an IMM date"); LocalDate[] res = new LocalDate[size]; res[0] = startIMMDate; for (int i = 1; i < size; i++) { int tMonth = res[i - 1].getMonthValue(); 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(LocalDate date) { int day = date.getDayOfMonth(); int month = date.getMonthValue(); 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(LocalDate date) { int day = date.getDayOfMonth(); int month = date.getMonthValue(); 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 { 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(LocalDate date) { int day = date.getDayOfMonth(); int month = date.getMonthValue(); 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); } } } }