finmath/finmath-lib

CDS Schedules

AlessandroGnoatto opened this issue · 1 comments

Hi,

I am trying to hack the Schedule generator in order to replicate the coupon of a Credit Default Swap according to the ISDA model. This is what I got so far. Any help in finding bugs/wrong reasonings etc is appreciated.

My source is the following document by ISDA: https://www.isda.org/a/vGiDE/amend-single-name-on-the-run-frequency-faq-revised-as-of-12-10.pdf

Here is my code:

package schedule;

import java.time.LocalDate;
import java.time.Month;
import java.util.StringTokenizer;

import net.finmath.time.Schedule;
import net.finmath.time.ScheduleGenerator;
import net.finmath.time.businessdaycalendar.BusinessdayCalendarExcludingTARGETHolidays;
import net.finmath.time.businessdaycalendar.BusinessdayCalendar.DateOffsetUnit;

public class ScheduleTest {

public static void main(String[] args) {

/*
 * Today is   
 */
LocalDate referenceDate = LocalDate.of(2015, 12, 20);

ScheduleTest test = new ScheduleTest();

String tenor = "5Y";

System.out.println(test.getPreviousRollDate(referenceDate).getDayOfWeek());
System.out.println(test.getFirstImmDateAfterRoll(referenceDate).getDayOfWeek());

System.out.println("Maturity Date of the CDS: this is an unadjusted IMM Date");
LocalDate unadjustedMaturityDate = test.getMaturityDate(referenceDate, tenor);
System.out.println(unadjustedMaturityDate);
System.out.println(unadjustedMaturityDate.getDayOfWeek());

BusinessdayCalendarExcludingTARGETHolidays cal = new BusinessdayCalendarExcludingTARGETHolidays();
if(cal.isBusinessday(unadjustedMaturityDate)==false) {
  System.out.println(unadjustedMaturityDate + " is not a good business day.");
}

Schedule schedule = ScheduleGenerator.createScheduleFromConventions(
    test.getPreviousRollDate(referenceDate)/* referenceDate */,
    test.getFirstImmDateAfterRoll(referenceDate)/* startDate */,
    test.getMaturityDate(referenceDate, tenor) /* maturity */,
    "quarterly" /* frequency */,
    "act/360" /* daycountConvention */,
    "first" /* shortPeriodConvention */,
    "following",
    new BusinessdayCalendarExcludingTARGETHolidays(),
    0,
    0);

System.out.println(schedule);

}

/**

  • CDS maturities are rolled twice a year, on March 20 and September 20
  • For a given trade date, return the previous roll date, this is either
  • March 20 or September 20.
  • @param tradeDate representing the date at which the trade is entered.
  • @return the previous roll date.
    */
    public LocalDate getPreviousRollDate(LocalDate tradeDate) {
    //Date is before march
    if(tradeDate.isBefore(LocalDate.of(tradeDate.getYear(), 3, 19))) {
    return LocalDate.of(tradeDate.getYear() -1, 9, 20);
    }else if(tradeDate.isAfter(LocalDate.of(tradeDate.getYear(), 3, 19)) && tradeDate.isBefore(LocalDate.of(tradeDate.getYear(), 9, 19)) ) {
    return LocalDate.of(tradeDate.getYear(), 3, 20);
    }else {
    return LocalDate.of(tradeDate.getYear(), 9, 20);
    }
    }

/**

  • Find the first IMM date after the previous roll date.
  • From this date we compute the maturity of the contract.
  • @param tradeDate representing the date at which the trade is entered.
  • @return the next IMM date after the previous roll date.
    */
    public LocalDate getFirstImmDateAfterRoll(LocalDate tradeDate) {
LocalDate rollDate = getPreviousRollDate(tradeDate);

//Roll month is march
if(rollDate.getMonth().equals(Month.MARCH)) {
  //The first Imm Date is 20 June of the same year
  return LocalDate.of(rollDate.getYear(), Month.JUNE, 20);
}else {
  //The roll month is September, hence the first IMM date is 20 December.
  return LocalDate.of(rollDate.getYear(), Month.DECEMBER, 20);
}

}

public LocalDate getMaturityDate(LocalDate tradeDate, String dateOffsetCode) {
dateOffsetCode = dateOffsetCode.trim();

StringTokenizer tokenizer = new StringTokenizer(dateOffsetCode);

LocalDate maturityDate = getFirstImmDateAfterRoll(tradeDate);

while(tokenizer.hasMoreTokens()) {
  String maturityCodeSingle = tokenizer.nextToken();
  String[] maturityCodeSingleParts = maturityCodeSingle.split("(?<=[0-9|\\.])(?=[A-Z|a-z])");
  
  if(maturityCodeSingleParts.length == 2) {
    int maturityValue = Integer.valueOf(maturityCodeSingleParts[0]);
    DateOffsetUnit dateOffsetUnit = DateOffsetUnit.getEnum(maturityCodeSingleParts[1]);

    switch(dateOffsetUnit) {
    case DAYS:
    {
      maturityDate = maturityDate.plusDays(maturityValue);
      break;
    }
    case WEEKS:
    {
      maturityDate = maturityDate.plusWeeks(maturityValue);
      break;
    }
    case MONTHS:
    {
      maturityDate = maturityDate.plusMonths(maturityValue);
      break;
    }
    case YEARS:
    {
      maturityDate = maturityDate.plusYears(maturityValue);
      break;
    }
    default:
      throw new IllegalArgumentException("Cannot handle dateOffsetCode '" + dateOffsetCode + "'.");
    }
  }
  else {
    throw new IllegalArgumentException("Cannot handle dateOffsetCode '" + dateOffsetCode + "'.");
  }
}
return maturityDate;

}

}

Hi @AlessandroGnoatto, are you still looking for help on this? I am interested to contribute to the repo.