Package org.jquantlib.daycounters

Source Code of org.jquantlib.daycounters.ActualActual$ImplISMA

/*
Copyright (C) 2008 Srinivas Hasti

This source code is release under the BSD License.

This file is part of JQuantLib, a free-software/open-source library
for financial quantitative analysts and developers - http://jquantlib.org/

JQuantLib is free software: you can redistribute it and/or modify it
under the terms of the JQuantLib license.  You should have received a
copy of the license along with this program; if not, please email
<jquant-devel@lists.sourceforge.net>. The license is also available online at
<http://www.jquantlib.org/index.php/LICENSE.TXT>.

This program 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 license for more details.

JQuantLib is based on QuantLib. http://quantlib.org/
When applicable, the original copyright notice follows this notice.
*/

package org.jquantlib.daycounters;

import org.jquantlib.QL;
import org.jquantlib.lang.annotation.QualityAssurance;
import org.jquantlib.lang.annotation.QualityAssurance.Quality;
import org.jquantlib.lang.annotation.QualityAssurance.Version;
import org.jquantlib.lang.exceptions.LibraryException;
import org.jquantlib.time.Date;
import org.jquantlib.time.Month;
import org.jquantlib.time.Period;
import org.jquantlib.time.TimeUnit;

/**
* Implementation of ActualActual day counters.
*
* @see <a href="http://en.wikipedia.org/wiki/Day_count_convention">Day count convention</a>
*
* @author Srinivas Hasti
* @author Richard Gomes
*
*/
@QualityAssurance(quality=Quality.Q4_UNIT, version=Version.V097, reviewers="Richard Gomes")
public class ActualActual extends DayCounter {

    //
    // public enums
    //

    /**
     * Actual/Actual Calendar Conventions
     */
    public static enum Convention {
        ISMA, Bond,
        ISDA, Historical, Actual365,
        AFB, Euro
    }


    //
    // public constructors
    //

    public ActualActual() {
        this(Convention.ISDA);
    }

    public ActualActual(final ActualActual.Convention c) {
        switch (c) {
            case ISMA:
            case Bond:
                super.impl = new ImplISMA();
                break;
            case ISDA:
            case Historical:
            case Actual365:
                super.impl = new ImplISDA();
                break;
            case AFB:
            case Euro:
                super.impl = new ImplAFB();
                break;
            default:
                throw new LibraryException("unknown act/act convention"); // TODO: message
        }
    }


    //
    // inner classes
    //

    final private class ImplISMA extends DayCounter.Impl {

        @Override
        public final String name() /* @ReadOnly */{
            return "Actual/Actual (ISMA)";
        }

        @Override
        public final double yearFraction(
                final Date d1, final Date d2,
                final Date d3, final Date d4) /* @ReadOnly */{

            if (d1.equals(d2))
                return 0.0;

            if (d1.gt(d2))
                return -yearFraction(d2, d1, d3, d4);

            // when the reference period is not specified, try taking
            // it equal to (d1,d2)
            Date refPeriodStart = (!d3.isNull() ? d3 : d1);
            Date refPeriodEnd   = (!d4.isNull() ? d4 : d2);

            QL.ensure(refPeriodEnd.gt(refPeriodStart) && refPeriodEnd.gt(d1) , "invalid reference period")// QA:[RG]::verified // TODO: message

            // estimate roughly the length in months of a period
            int months = (int) (0.5 + 12 * (refPeriodEnd.sub(refPeriodStart)) / 365.0);

            // for short periods...
            if (months == 0) {
                // ...take the reference period as 1 year from d1
                refPeriodStart = d1;
                refPeriodEnd = d1.add(Period.ONE_YEAR_FORWARD);
                months = 12;
            }

            final double period = months / 12.0;

            if (d2.le(refPeriodEnd)) {
                // here refPeriodEnd is a future (notional?) payment date
                if (d1.ge(refPeriodStart))
                    // here 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] ???
                    return period * dayCount(d1, d2)
                    / dayCount(refPeriodStart, refPeriodEnd);
                else {
                    // here 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

                    // the last notional payment date
                    final Date previousRef = refPeriodStart.add(new Period(
                            -months, TimeUnit.Months));
                    if (d2.gt(refPeriodStart))
                        return yearFraction(d1, refPeriodStart, previousRef,
                                refPeriodStart)
                                + yearFraction(refPeriodStart, d2,
                                        refPeriodStart, refPeriodEnd);
                    else
                        return yearFraction(d1, d2, previousRef,
                                refPeriodStart);
                }
            } else {
                // TODO: code review :: please verify against QL/C++ code

                // here refPeriodEnd is the last notional payment date
                // d1 < refPeriodEnd < d2 AND refPeriodStart < refPeriodEnd
                QL.require(refPeriodStart.le(d1) , "invalid dates"); // TODO: message

                // now it is: refPeriodStart <= d1 < refPeriodEnd < d2

                // the part from d1 to refPeriodEnd
                double sum = yearFraction(d1, refPeriodEnd, refPeriodStart, refPeriodEnd);

                // the part from refPeriodEnd to d2
                // count how many regular periods are in [refPeriodEnd, d2],
                // then add the remaining time
                int i = 0;
                Date newRefStart, newRefEnd;
                do {
                    newRefStart = refPeriodEnd.add(new Period(months * i, TimeUnit.Months));
                    newRefEnd = refPeriodEnd.add(new Period(months * (i + 1), TimeUnit.Months));
                    if (d2.lt(newRefEnd))
                        break;
                    else {
                        sum += period;
                        i++;
                    }
                } while (true);
                sum += yearFraction(newRefStart, d2, newRefStart, newRefEnd);
                return sum;
            }
        }
    }


    final private class ImplISDA extends DayCounter.Impl {

        @Override
        public final String name() /* @ReadOnly */{
            return "Actual/Actual (ISDA)";
        }

        @Override
        public final double yearFraction(
                final Date dateStart, final Date dateEnd,
                final Date refPeriodStart, final Date refPeriodEnd) /* @ReadOnly */{
            if (dateStart.equals(dateEnd))
                return 0.0;
            if (dateStart.gt(dateEnd))
                return -yearFraction(dateEnd, dateStart, new Date(), new Date());

            final int y1 = dateStart.year();
            final int y2 = dateEnd.year();
            final double dib1 = Date.isLeap(dateStart.year()) ? 366.0 : 365.0;
            final double dib2 = Date.isLeap(dateEnd.year())   ? 366.0 : 365.0;

            double sum = y2 - y1 - 1;

            // Days from start to starting of following year
            sum += (dib1 - dateStart.dayOfYear() + 1) / dib1;
            // Days from beginning of year to the endDate
            sum += (dateEnd.dayOfYear() - 1) / dib2;
            return sum;
        }

    }


    final private class ImplAFB extends DayCounter.Impl {

        @Override
        public final String name() /* @ReadOnly */ {
            return "Actual/Actual (AFB)";
        }

        @Override
        public final double yearFraction(
                final Date dateStart, final Date dateEnd,
                final Date refPeriodStart, final Date refPeriodEnd) /* @ReadOnly */{
            if (dateStart.equals(dateEnd))
                return 0.0;
            if (dateStart.gt(dateEnd))
                return -1.0 * yearFraction(dateEnd, dateStart, new Date(), new Date());

            Date newD2 = dateEnd;
            Date temp = dateEnd;
            double sum = 0.0;
            while (temp.gt(dateStart)) {
                temp = newD2.add(Period.ONE_YEAR_BACKWARD);
                if (temp.dayOfMonth() == 28 && temp.month().value() == 2 && Date.isLeap(temp.year()))
                    temp.inc();
                if (temp.ge(dateStart)) {
                    sum += 1.0;
                    newD2 = temp;
                }
            }

            double den = 365.0;

            if (Date.isLeap(newD2.year())) {
                if (newD2.gt(new Date(29, Month.February, newD2.year())) &&
                        dateStart.le(new Date(29, Month.February, newD2.year())))
                    den += 1.0;
            } else if (Date.isLeap(dateStart.year()))
                if (newD2.gt(new Date(29, Month.February, dateStart.year())) &&
                        dateStart.le(new Date(29, Month.February, dateStart.year())))
                    den += 1.0;
            return sum + dayCount(dateStart, newD2) / den;
        }

    }

}
TOP

Related Classes of org.jquantlib.daycounters.ActualActual$ImplISMA

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.