/**
* 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 java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.List;
import org.threeten.bp.LocalDate;
import com.opengamma.financial.convention.daycount.DayCount;
import com.opengamma.financial.convention.daycount.DayCounts;
import com.opengamma.util.ArgumentChecker;
/**
*
*/
public class ISDACompliantScheduleGenerator {
private static final DayCount ACT365 = DayCounts.ACT_365;
/**
* This mimics JpmcdsRiskyTimeLine from the ISDA model in c
* @param startDate start date
* @param endDate end date
* @param disCurveDates all the points in the discount curve
* @param spreadCurveDates all the points in the risky curve
* @return An ascending array of dates that is the unique combination of all the input dates (including startDate and endDate) that are not strictly
* before startDate or after EndDate (hence startDate will be the first entry and enddate the last).
*/
public static LocalDate[] getIntegrationNodesAsDates(final LocalDate startDate, final LocalDate endDate, final LocalDate[] disCurveDates, final LocalDate[] spreadCurveDates) {
ArgumentChecker.notNull(startDate, "null startDate");
ArgumentChecker.notNull(endDate, "null endDate");
ArgumentChecker.noNulls(disCurveDates, "nulls in disCurveDates");
ArgumentChecker.noNulls(spreadCurveDates, "nulls in spreadCurveDates");
ArgumentChecker.isTrue(endDate.isAfter(startDate), "endDate of {} is not after startDate of {}", endDate.toString(), startDate.toString());
final int nDisCurvePoints = disCurveDates.length;
final int nSpreadCurvePoints = spreadCurveDates.length;
final LinkedHashSet<LocalDate> set = new LinkedHashSet<>(2 + nDisCurvePoints + nSpreadCurvePoints);
set.add(startDate);
for (final LocalDate date : disCurveDates) {
set.add(date);
}
for (final LocalDate date : spreadCurveDates) {
set.add(date);
}
set.add(endDate);
final int n = set.size();
final LocalDate[] res = new LocalDate[n];
set.toArray(res);
Arrays.sort(res);
// remove dates strictly before startDate and strictly after endDate
int a = 0;
int b = n - 1;
while (res[a].isBefore(startDate)) {
a++;
}
while (res[b].isAfter(endDate)) {
b--;
}
final int newLength = b - a + 1;
if (newLength == n) {
return res; // nothing got chopped off
}
final LocalDate[] res2 = new LocalDate[newLength];
System.arraycopy(res, a, res2, 0, newLength);
return res2;
}
/**
* This calls getIntegrationNodesAsDates to get an array of dates then calculates the year fraction from today to those points using
* ACT/365
* @param today the date to measure year-fractions from. Must NOT have today after startDate
* @param startDate start date
* @param endDate end date
* @param disCurveDates all the points in the discount curve
* @param spreadCurveDates all the points in the risky curve
* @return An ascending array of times from today @see getIntegrationNodesAsDates
*/
public static double[] getIntegrationNodesAsTimes(final LocalDate today, final LocalDate startDate, final LocalDate endDate, final LocalDate[] disCurveDates, final LocalDate[] spreadCurveDates) {
ArgumentChecker.notNull(today, "null today");
ArgumentChecker.notNull(startDate, "null startDate");
ArgumentChecker.isFalse(today.isAfter(startDate), "today is after startDate");
final LocalDate[] dates = getIntegrationNodesAsDates(startDate, endDate, disCurveDates, spreadCurveDates);
return getYearFractionFromToday(today, dates);
}
/**
* Truncate an sort (ascending) array of dates so the the interior values are strictly after startDate and strictly before endEnd,
* and startDate and endDate becomes to first and last entries
* @param startDate This will be the first value in the list
* @param endDate This will be the last value in the list
* @param dateList Must be sorted
* @return dates between startDate and endDate
*/
public static LocalDate[] truncateList(final LocalDate startDate, final LocalDate endDate, final LocalDate[] dateList) {
ArgumentChecker.notNull(startDate, "null startDate");
ArgumentChecker.notNull(endDate, "null endDate");
ArgumentChecker.noNulls(dateList, "nulls in dateList");
ArgumentChecker.isTrue(endDate.isAfter(startDate), "require enddate after startDate");
final int n = dateList.length;
if (n == 0) {
return new LocalDate[] {startDate, endDate };
}
final List<LocalDate> temp = new ArrayList<>(n + 2);
for (final LocalDate d : dateList) {
if (d.isAfter(startDate) && d.isBefore(endDate)) {
temp.add(d);
}
}
final int m = temp.size();
final LocalDate[] tArray = new LocalDate[m];
temp.toArray(tArray);
final LocalDate[] res = new LocalDate[m + 2];
res[0] = startDate;
System.arraycopy(tArray, 0, res, 1, m);
res[m + 1] = endDate;
return res;
}
/**
* Year fractions from a fixed date to a set of dates using ACT/365
* @param today the date to measure from
* @param dates set of dates to measure to
* @return set of yearfractions (array of double)
*/
public static double[] getYearFractionFromToday(final LocalDate today, final LocalDate[] dates) {
return getYearFractionFromToday(today, dates, ACT365);
}
/**
* Year fractions from a fixed date to a set of dates using the specified day-count
* @param today the date to measure from
* @param dates set of dates to measure to
* @param dayCount The day-count
* @return set of yearfractions (array of double)
*/
public static double[] getYearFractionFromToday(final LocalDate today, final LocalDate[] dates, final DayCount dayCount) {
ArgumentChecker.notNull(today, "null today");
ArgumentChecker.noNulls(dates, "nulls in dates");
ArgumentChecker.notNull(dayCount, "null dayCount");
final int n = dates.length;
final double[] res = new double[n];
for (int i = 0; i < n; i++) {
res[i] = dayCount.getDayCountFraction(today, dates[i]);
}
return res;
}
}