/*
 * 

jFin, open source derivatives trade processing

* *

Copyright (C) 2005, 2006, 2007 Morgan Brown Consultancy Ltd.

* *

This file is part of jFin.

* *

jFin is free software; you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version.

* *

jFin is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public * License for more details.

* *

You should have received a copy of the GNU General Public License along * with jFin; if not, write to the Free Software Foundation, Inc., 51 Franklin * St, Fifth Floor, Boston, MA 02110-1301 USA.

*/ package org.jfin.date; import java.text.ParseException; import java.util.ArrayList; import java.util.Calendar; import java.util.List; import java.util.logging.Logger; import org.jfin.date.util.ISDADateFormat; /** * Utility class for creating an UNADJUSTED schedule between two dates using a * given stub type and frequency. */ public class ScheduleGenerator { private static Logger logger = Logger .getLogger("org.jfin.date.ScheduleGenerator"); /** * Used to generate a List containing an schedule ordered by period dates. * The periods will be adjacent to each other, e.g: d1,d2 d2,d3 d3,d4 * * @param startDate * @param maturityString * Parsed by Tenor, e.g. "10Y", "6M", etc * @param frequency * @param stubType * @return A List containing the schedule * @throws ScheduleException * @throws ParseException */ public static List generateSchedule(Calendar startDate, String maturityString, Frequency frequency, StubType stubType) throws ScheduleException, ParseException { return generateSchedule(startDate,maturityString, frequency, stubType,-1); } /** * Used to generate a List containing an schedule ordered by period dates. * The periods will be adjacent to each other, e.g: d1,d2 d2,d3 d3,d4 * * @param startDate * @param maturityString * Parsed by Tenor, e.g. "10Y", "6M", etc * @param frequency * @param stubType * @param maxPeriods * @return A List containing the schedule * @throws ScheduleException * @throws ParseException */ public static List generateSchedule(Calendar startDate, String maturityString, Frequency frequency, StubType stubType, int maxPeriods) throws ScheduleException, ParseException { Tenor tenor = new Tenor(maturityString); return generateSchedule(startDate, tenor, frequency, stubType, maxPeriods); } /** * Used to generate a List containing an schedule ordered by period dates. * The periods will be adjacent to each other, e.g: d1,d2 d2,d3 d3,d4 * * @param startDate * @param maturityString * Parsed by Tenor, e.g. "10Y", "6M", etc * @param frequency * @param stubType * @param prototype * @return A List containing the schedule * @throws ScheduleException * @throws ParseException */ public static List generateSchedule(Calendar startDate, String maturityString, Frequency frequency, StubType stubType, Period prototype) throws ScheduleException, ParseException { return generateSchedule(startDate, maturityString, frequency, stubType, prototype, -1); } /** * Used to generate a List containing an schedule ordered by period dates. * The periods will be adjacent to each other, e.g: d1,d2 d2,d3 d3,d4 * * @param startDate * @param maturityString * Parsed by Tenor, e.g. "10Y", "6M", etc * @param frequency * @param stubType * @param prototype * @return A List containing the schedule * @throws ScheduleException * @throws ParseException */ public static List generateSchedule(Calendar startDate, String maturityString, Frequency frequency, StubType stubType, Period prototype, int maxPeriods) throws ScheduleException, ParseException { Tenor tenor = new Tenor(maturityString); return generateSchedule(startDate, tenor, frequency, stubType, prototype, maxPeriods); } /** * Used to generate a List containing an schedule ordered by period dates. * The periods will be adjacent to each other, e.g: d1,d2 d2,d3 d3,d4 * * @param startDate * @param maturity * @param frequency * @param stubType * @return A List containing the schedule * @throws ScheduleException */ public static List generateSchedule(Calendar startDate, Tenor maturity, Frequency frequency, StubType stubType) throws ScheduleException { return generateSchedule(startDate, maturity, frequency, stubType, -1); } /** * Used to generate a List containing an schedule ordered by period dates. * The periods will be adjacent to each other, e.g: d1,d2 d2,d3 d3,d4 * * @param startDate * @param maturity * @param frequency * @param stubType * @param maxPeriods * @return A List containing the schedule * @throws ScheduleException */ public static List generateSchedule(Calendar startDate, Tenor maturity, Frequency frequency, StubType stubType, int maxPeriods) throws ScheduleException { Calendar endDate = (Calendar) startDate.clone(); endDate.add(maturity.getCalendarUnit(), maturity.getAmount()); return generateSchedule(startDate, endDate, frequency, stubType, maxPeriods); } /** * Used to generate a List containing an schedule ordered by period dates. * The periods will be adjacent to each other, e.g: d1,d2 d2,d3 d3,d4 * * @param startDate * @param maturity * @param frequency * @param stubType * @param prototype * @return A List containing the schedule * @throws ScheduleException */ public static List generateSchedule(Calendar startDate, Tenor maturity, Frequency frequency, StubType stubType, Period prototype) throws ScheduleException { return generateSchedule( startDate, maturity, frequency, stubType, prototype, -1); } /** * Used to generate a List containing an schedule ordered by period dates. * The periods will be adjacent to each other, e.g: d1,d2 d2,d3 d3,d4 * * @param startDate * @param maturity * @param frequency * @param stubType * @param prototype * @return A List containing the schedule * @throws ScheduleException */ public static List generateSchedule(Calendar startDate, Tenor maturity, Frequency frequency, StubType stubType, Period prototype, int maxPeriods) throws ScheduleException { Calendar endDate = (Calendar) startDate.clone(); endDate.add(maturity.getCalendarUnit(), maturity.getAmount()); return generateSchedule(startDate, endDate, frequency, stubType, prototype, maxPeriods); } /** * Used to generate a List containing an schedule ordered by period dates. * The periods will be adjacent to each other, e.g: d1,d2 d2,d3 d3,d4 * * @param startDate * @param endDate * @param frequency * @param stubType * @return A List containing the schedule * @throws ScheduleException */ public static List generateSchedule(Calendar startDate, Calendar endDate, Frequency frequency, StubType stubType) throws ScheduleException { return generateSchedule( startDate, endDate, frequency, stubType, -1); } /** * Used to generate a List containing an schedule ordered by period dates. * The periods will be adjacent to each other, e.g: d1,d2 d2,d3 d3,d4 * * @param startDate * @param endDate * @param frequency * @param stubType * @param maxPeriods * @return A List containing the schedule * @throws ScheduleException */ public static List generateSchedule(Calendar startDate, Calendar endDate, Frequency frequency, StubType stubType, int maxPeriods) throws ScheduleException { return generateSchedule(startDate, endDate, frequency.getPeriodAmount(), frequency.getPeriodUnit(), stubType, maxPeriods); } /** * Used to generate a List containing an schedule ordered by period dates. * The periods will be adjacent to each other, e.g: d1,d2 d2,d3 d3,d4 * * @param startDate * @param endDate * @param frequency * @param stubType * @return A List containing the schedule * @throws ScheduleException */ public static List generateSchedule(Calendar startDate, Calendar endDate, Frequency frequency, StubType stubType, Period prototype) throws ScheduleException { return generateSchedule( startDate, endDate, frequency, stubType, prototype, -1); } /** * Used to generate a List containing an schedule ordered by period dates. * The periods will be adjacent to each other, e.g: d1,d2 d2,d3 d3,d4 * * @param startDate * @param endDate * @param frequency * @param stubType * @return A List containing the schedule * @throws ScheduleException */ public static List generateSchedule(Calendar startDate, Calendar endDate, Frequency frequency, StubType stubType, Period prototype, int maxPeriods) throws ScheduleException { return generateSchedule(startDate, endDate, frequency.getPeriodAmount(), frequency.getPeriodUnit(), stubType, prototype, maxPeriods); } /** * Used to generate a List containing an schedule ordered by period dates. * The periods will be adjacent to each other, e.g: d1,d2 d2,d3 d3,d4 * * @param startDate * @param endDate * @param frequencyAmount * @param frequencyUnit * @param stubType * @return A List containing the schedule * @throws ScheduleException */ public static List generateSchedule(Calendar startDate, Calendar endDate, int frequencyAmount, int frequencyUnit, StubType stubType) throws ScheduleException { return generateSchedule( startDate, endDate, frequencyAmount, frequencyUnit, stubType, -1); } /** * Used to generate a List containing an schedule ordered by period dates. * The periods will be adjacent to each other, e.g: d1,d2 d2,d3 d3,d4 * * @param startDate * @param endDate * @param frequencyAmount * @param frequencyUnit * @param stubType * @return A List containing the schedule * @throws ScheduleException */ public static List generateSchedule(Calendar startDate, Calendar endDate, int frequencyAmount, int frequencyUnit, StubType stubType, int maxPeriods) throws ScheduleException { Period prototype = new Period(); return generateSchedule(startDate, endDate, frequencyAmount, frequencyUnit, stubType, prototype, maxPeriods); } /** * Used to generate a List containing an schedule ordered by period dates. * The periods will be adjacent to each other, e.g: d1,d2 d2,d3 d3,d4 * * @param startDate * @param endDate * @param frequencyAmount * @param frequencyUnit * @param stubType * @param prototype * @return A List containing the schedule * @throws ScheduleException */ public static List generateSchedule(Calendar startDate, Calendar endDate, int frequencyAmount, int frequencyUnit, StubType stubType, Period prototype) throws ScheduleException { return generateSchedule(startDate, endDate, frequencyAmount, frequencyUnit, stubType, prototype,-1); } /** * Used to generate a List containing an schedule ordered by period dates. * The periods will be adjacent to each other, e.g: d1,d2 d2,d3 d3,d4 * * @param startDate * @param endDate * @param frequencyAmount * @param frequencyUnit * @param stubType * @param prototype * @param maxPeriods * @return A List containing the schedule * @throws ScheduleException */ public static List generateSchedule(Calendar startDate, Calendar endDate, int frequencyAmount, int frequencyUnit, StubType stubType, Period prototype, int maxPeriods) throws ScheduleException { Calendar cleanEndDate = copyAndReset(endDate); Calendar cleanStartDate = copyAndReset(startDate); int periodCount = 0; logger.fine("Generating " +stubType.name()+ " " +frequencyAmount+":"+ getCalendarUnitDescriptor(frequencyUnit) +" schedule between "+ISDADateFormat.format(startDate)+" and "+ISDADateFormat.format(endDate)); if (stubType == StubType.SHORT_LAST || stubType == StubType.NONE) { ArrayList schedule = new ArrayList(); Calendar holdDate = copyAndReset(startDate); int count = 1; while (holdDate.before(cleanEndDate)) { Calendar nextDate = copyAndReset(startDate); nextDate.add(frequencyUnit, frequencyAmount*count); count++; Calendar notionalStartDate = null; Calendar notionalEndDate = null; if (nextDate.after(cleanEndDate)) { if (stubType == StubType.SHORT_LAST) { notionalStartDate = holdDate; notionalEndDate = nextDate; nextDate = cleanEndDate; } else { throw new ScheduleException( "StubType.NONE used when periods do not fit start and end date"); } } Period toAdd = (Period)prototype.clone(); toAdd.setStartCalendar(holdDate); toAdd.setEndCalendar(nextDate); toAdd.setReferenceStartCalendar(notionalStartDate); toAdd.setReferenceEndCalendar(notionalEndDate); schedule.add(toAdd); holdDate = nextDate; periodCount++; if(maxPeriods>0 && periodCount>maxPeriods) { throw new ScheduleException("Maximum number of periods ("+maxPeriods+") exceeded."); } } return schedule; } else if (stubType == StubType.SHORT_FIRST) { ArrayList schedule = new ArrayList(); Calendar holdDate = copyAndReset(endDate); int count = 1; while (holdDate.after(cleanStartDate)) { Calendar nextDate = copyAndReset(endDate); nextDate.add(frequencyUnit, -1 * frequencyAmount*count); count++; Calendar notionalStartDate = null; Calendar notionalEndDate = null; if (nextDate.before(cleanStartDate)) { notionalStartDate = nextDate; notionalEndDate = holdDate; nextDate = cleanStartDate; } Period toAdd = (Period)prototype.clone(); toAdd.setStartCalendar(nextDate); toAdd.setEndCalendar(holdDate); toAdd.setReferenceStartCalendar(notionalStartDate); toAdd.setReferenceEndCalendar(notionalEndDate); schedule.add(0, toAdd); holdDate = nextDate; periodCount++; if(maxPeriods>0 && periodCount>maxPeriods) { throw new ScheduleException("Maximum number of periods ("+maxPeriods+") exceeded."); } } return schedule; } else if (stubType == StubType.LONG_LAST) { ArrayList schedule = new ArrayList(); Calendar holdDate = copyAndReset(startDate); int count = 1; while (holdDate.before(cleanEndDate)) { Calendar nextDate = copyAndReset(startDate); nextDate.add(frequencyUnit, frequencyAmount*count); Calendar nextDate2 = copyAndReset(startDate); nextDate2.add(frequencyUnit, frequencyAmount*(count+1)); count++; Calendar notionalStartDate = null; Calendar notionalEndDate = null; if (nextDate2.after(cleanEndDate)) { notionalStartDate = nextDate; notionalEndDate = nextDate2; nextDate = cleanEndDate; } Period toAdd = (Period)prototype.clone(); toAdd.setStartCalendar(holdDate); toAdd.setEndCalendar(nextDate); toAdd.setReferenceStartCalendar(notionalStartDate); toAdd.setReferenceEndCalendar(notionalEndDate); schedule.add(toAdd); holdDate = nextDate; periodCount++; if(maxPeriods>0 && periodCount>maxPeriods) { throw new ScheduleException("Maximum number of periods ("+maxPeriods+") exceeded."); } } return schedule; } else if (stubType == StubType.LONG_FIRST) { ArrayList schedule = new ArrayList(); Calendar holdDate = copyAndReset(endDate); int count=1; while (holdDate.after(cleanStartDate)) { Calendar nextDate = copyAndReset(endDate); nextDate.add(frequencyUnit, -1 * frequencyAmount*count); Calendar nextDate2 = copyAndReset(endDate); nextDate2.add(frequencyUnit, -1 * frequencyAmount*(count+1)); count++; Calendar notionalStartDate = null; Calendar notionalEndDate = null; if (nextDate2.before(cleanStartDate)) { notionalStartDate = nextDate2; notionalEndDate = nextDate; nextDate = cleanStartDate; } Period toAdd = (Period)prototype.clone(); toAdd.setStartCalendar(nextDate); toAdd.setEndCalendar(holdDate); toAdd.setReferenceStartCalendar(notionalStartDate); toAdd.setReferenceEndCalendar(notionalEndDate); schedule.add(0, toAdd); holdDate = nextDate; periodCount++; if(maxPeriods>0 && periodCount>maxPeriods) { throw new ScheduleException("Maximum number of periods ("+maxPeriods+") exceeded."); } } return schedule; } else { throw new ScheduleException("Unsupported stub type " + stubType); } } /** * Copy a calendar and reset it's time to midnight to avoid * problems relating to generating schedules around midnight. * @param calendar The calendar to copy and reset * @return Calendar the calendar which has been copied and reset */ public static Calendar copyAndReset(Calendar calendar) { Calendar copy = (Calendar)calendar.clone(); copy.set(Calendar.HOUR_OF_DAY,0); copy.set(Calendar.MINUTE,0); copy.set(Calendar.SECOND,0); copy.set(Calendar.MILLISECOND,0); return copy; } public static String getCalendarUnitDescriptor(int calendarUnit) { switch(calendarUnit) { case Calendar.DAY_OF_MONTH: return "DAY"; case Calendar.DAY_OF_WEEK: return "DAY"; case Calendar.DAY_OF_YEAR: return "DAY"; case Calendar.MONTH: return "MONTH"; case Calendar.YEAR: return "YEAR"; default: return "UNKNOWN"; } } }

Ads help maintain this website.