/*
* 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.daycount.defaultimpl;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.logging.Logger;
import org.jfin.date.Period;
import org.jfin.date.ScheduleGenerator;
import org.jfin.date.daycount.DaycountCalculator;
import org.jfin.date.daycount.DaycountException;
import org.jfin.date.util.ISDADateFormat;
/**
* If startCalendar and endCalendar are equal dates, returns zero.
*/
public class ISMAActualActual extends DaycountCalculator
{
private static Logger logger = Logger
.getLogger("org.jfin.date.daycount.defaultimpl.ISMAActualActual");
public double calculateDaycountFraction(Calendar startCalendar,
Calendar endCalendar) throws DaycountException
{
return calculateDaycountFraction(startCalendar, endCalendar, null, null);
}
public double calculateDaycountFraction(Calendar startCalendar,
Calendar endCalendar, Calendar periodStartCalendar,
Calendar periodEndCalendar) throws DaycountException
{
logger.finer("Calculating daycount fraction for "
+ ISDADateFormat.format(startCalendar) + " - "
+ ISDADateFormat.format(endCalendar));
if (periodStartCalendar != null && periodEndCalendar != null)
{
logger.finer("Provided with reference period "
+ ISDADateFormat.format(periodStartCalendar) + " - "
+ ISDADateFormat.format(periodEndCalendar));
}
if (startCalendar.after(endCalendar))
{
logger.fine("Dates are wrong way round so swap over");
Calendar holdCalendar = startCalendar;
startCalendar = endCalendar;
endCalendar = holdCalendar;
}
if (startCalendar.equals(endCalendar))
{
logger.fine("Dates are the same so return zero");
return 0.0;
}
// when the reference period is not specified, try taking
// it equal to (d1,d2)
Calendar refPeriodStart = ( periodStartCalendar != null ? periodStartCalendar
: startCalendar );
Calendar refPeriodEnd = ( periodEndCalendar != null ? periodEndCalendar
: endCalendar );
logger.finer("Using reference period "
+ ISDADateFormat.format(refPeriodStart) + " - "
+ ISDADateFormat.format(refPeriodEnd));
if (!( refPeriodEnd.after(refPeriodStart) && refPeriodEnd
.after(startCalendar) ))
{
throw new DaycountException("invalid reference period: "
+ "date 1: " + ISDADateFormat.format(startCalendar)
+ ", date 2: " + ISDADateFormat.format(endCalendar)
+ ", reference period start: "
+ ISDADateFormat.format(refPeriodStart)
+ ", reference period end: "
+ ISDADateFormat.format(refPeriodEnd));
}
// estimate roughly the length in months of a period
// Integer months =
// Integer(0.5+12*Real(refPeriodEnd-refPeriodStart)/365);
double monthsEstimate = daysBetween(refPeriodStart, refPeriodEnd)
* ( 12.0d / 365.0d );
int months = (int) Math.round(monthsEstimate);
logger.finer("Estimated months as " + months + " (" + monthsEstimate
+ ")");
if (months == 0)
{
logger
.fine("Short period (Estimated months is 0), taking reference period as 1 year from d1.");
refPeriodStart = startCalendar;
refPeriodEnd = (Calendar) startCalendar.clone();
refPeriodEnd.add(Calendar.YEAR, 1);
months = 12;
}
double period = (double) months / 12.0;
logger.finer("Period calculated as " + period);
if (endCalendar.before(refPeriodEnd)
|| endCalendar.equals(refPeriodEnd))
{
logger
.finer("refPeriodEnd is a future (maybe notional) payment date");
if (startCalendar.after(refPeriodStart)
|| startCalendar.equals(refPeriodStart))
{
logger.finer("refPeriodStart is the last (maybe notional) "
+ "payment date. "
+ "refPeriodStart <= d1 <= d2 <= refPeriodEnd "
+ "[maybe the equality should be enforced, since "
+ "refPeriodStart < d1 <= d2 < refPeriodEnd "
+ "could give wrong results] ???");
long numerator = daysBetween(startCalendar, endCalendar);
long denominator = daysBetween(refPeriodStart, refPeriodEnd);
logger.fine("Calculating portion between " + "date 1: "
+ ISDADateFormat.format(startCalendar) + ", date 2: "
+ ISDADateFormat.format(endCalendar) + " as " + period
+ " * " + numerator + "/" + denominator);
return period * (double) numerator / (double) denominator;
} else
{
logger.finer("refPeriodStart is the next (maybe notional) "
+ "payment date and refPeriodEnd is the second next "
+ "(maybe notional) payment date. "
+ "d1 < refPeriodStart < refPeriodEnd "
+ "AND d2 <= refPeriodEnd "
+ "this case is long first coupon ");
Calendar previousRef = (Calendar) startCalendar.clone();
logger.finer("The last notional payment date is "
+ ISDADateFormat.format(previousRef));
//previousRef.add(Calendar.MONTH, months * -1);
if (endCalendar.after(refPeriodStart))
return calculateDaycountFraction(startCalendar,
refPeriodStart, previousRef, refPeriodStart)
+ calculateDaycountFraction(refPeriodStart,
endCalendar, refPeriodStart, refPeriodEnd);
else
return calculateDaycountFraction(startCalendar,
endCalendar, previousRef, refPeriodStart);
}
} else
{
logger
.finer("refPeriodEnd is the last (notional?) payment date "
+ "d1 < refPeriodEnd < d2 AND refPeriodStart < refPeriodEnd");
if (!( refPeriodStart.before(startCalendar) || refPeriodStart
.equals(startCalendar) ))
{
throw new DaycountException(
"invalid dates: d1 < refPeriodStart < refPeriodEnd < d2");
}
logger.finer("refPeriodStart <= d1 < refPeriodEnd < d2");
// the part from d1 to refPeriodEnd
double sum = calculateDaycountFraction(startCalendar, refPeriodEnd,
refPeriodStart, refPeriodEnd);
logger.finer("The part from d1 to refPeriodEnd is " + sum);
// the part from refPeriodEnd to d2
// count how many regular periods are in [refPeriodEnd, d2],
// then add the remaining time
int i = 0;
Calendar newRefStart, newRefEnd;
do
{
newRefStart = (Calendar) refPeriodEnd.clone();
newRefStart.add(Calendar.MONTH, months * i);
newRefEnd = (Calendar) refPeriodEnd.clone();
newRefEnd.add(Calendar.MONTH, ( months * ( i + 1 ) ));
if (endCalendar.before(newRefEnd))
{
break;
} else
{
sum += period;
i++;
}
} while (true);
double secondSum = calculateDaycountFraction(newRefStart,
endCalendar, newRefStart, newRefEnd);
logger.finer("The part from refPeriodEnd to d2 is " + sum);
sum += secondSum;
return sum;
}
}
}
Ads help maintain this website.