Package org.jquantlib.cashflow

Source Code of org.jquantlib.cashflow.CashFlows

/*
Copyright (C) 2009 Ueli Hofstetter
Copyright (C) 2009 Richard Gomes

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.cashflow;

import org.jquantlib.QL;
import org.jquantlib.Settings;
import org.jquantlib.daycounters.DayCounter;
import org.jquantlib.lang.exceptions.LibraryException;
import org.jquantlib.math.Constants;
import org.jquantlib.math.Ops;
import org.jquantlib.math.solvers1D.Brent;
import org.jquantlib.quotes.Handle;
import org.jquantlib.termstructures.Compounding;
import org.jquantlib.termstructures.InterestRate;
import org.jquantlib.termstructures.YieldTermStructure;
import org.jquantlib.termstructures.yieldcurves.FlatForward;
import org.jquantlib.time.Date;
import org.jquantlib.time.Frequency;
import org.jquantlib.util.TypedVisitor;
import org.jquantlib.util.Visitor;

/**
* Cashflow-analysis functions
*
* @author Ueli Hofstetter
* @author Richard Gomes
*/

//
// =================== W A R N I N G ================
//
// This class requires a total rewrite. See: http://bugs.jquantlib.org/view.php?id=357

// TODO: code review :: please verify against QL/C++ code

public class CashFlows {

    private final String not_enough_information_available = "not enough information available";
    private final String no_cashflows = "no cashflows";
    private final String unsupported_compounding_type = "unsupported compounding type";
    private final String compounded_rate_required = "compounded rate required";
    private final String unsupported_frequency = "unsupported frequency";
    private final String unknown_duration_type = "unsupported duration type";
    private final String infeasible_cashflow = "the given cash flows cannot result in the given market price due to their sign";

    private static double basisPoint_ = 1.0e-4;

    /**
     * Singleton instance for the whole application.
     * <p>
     * In an application server environment, it could be by class loader
     * depending on scope of the JQuantLib library to the module.
     *
     * @see <a
     *      href="http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html">The
     *      "Double-Checked Locking is Broken" Declaration </a>
     */
    private static volatile CashFlows instance = null;


    //
    // private constructors
    //

    private CashFlows() {
        // cannot be directly instantiated
    }

    //
    // public static methods
    //

    public static CashFlows getInstance() {
        if (instance == null) {
            synchronized (CashFlows.class) {
                if (instance == null) {
                    instance = new CashFlows();
                }
            }
        }
        return instance;
    }

    //
    // public methods
    //

    public Date startDate(final Leg cashflows) {
        Date d = Date.maxDate();
        for (int i = 0; i < cashflows.size(); ++i) {
            final Coupon c = (Coupon) cashflows.get(i);
            if (c != null) {
                d = Date.min(c.accrualStartDate(), d);
            }
        }
        // TODO: code review :: please verify against QL/C++ code
        QL.ensure(d.lt(Date.maxDate()) , not_enough_information_available); // QA:[RG]::verified
        return d;
    }

    public Date maturityDate(final Leg cashflows) {
        Date d = Date.minDate();
        for (int i = 0; i < cashflows.size(); i++) {
            d = Date.max(d, cashflows.get(i).date());
        }
        // TODO: code review :: please verify against QL/C++ code
        QL.ensure (d.gt(Date.minDate()), no_cashflows);
        return d;
    }


    public double npv(
            final Leg cashflows,
            final Handle<YieldTermStructure> discountCurve,
            final Date settlementDate,
            final Date npvDate) {
        return npv(cashflows, discountCurve, settlementDate, npvDate, 0);
    }

    /**
     * NPV of the cash flows.
     * <p>
     * The NPV is the sum of the cash flows, each discounted according to the
     * given term structure.
     *
     * @param cashflows
     * @param discountCurve
     * @param settlementDate
     * @param npvDate
     * @param exDividendDays
     * @return
     */
    public double npv(
            final Leg cashflows,
            final Handle<YieldTermStructure> discountCurve,
            final Date settlementDate,
            final Date npvDate,
            final int exDividendDays) {

        Date date = settlementDate;
        if (date.isNull()) {
            date = discountCurve.currentLink().referenceDate();
        }

        double totalNPV = 0.0;
        for (int i = 0; i < cashflows.size(); ++i) {
            if (!cashflows.get(i).hasOccurred(date.add(exDividendDays))) {
                totalNPV += cashflows.get(i).amount() * discountCurve.currentLink().discount(cashflows.get(i).date());
            }
        }

        if (npvDate.isNull())
            return totalNPV;
        else
            return totalNPV / discountCurve.currentLink().discount(npvDate);
    }

    public double npv(
            final Leg leg,
            final Handle<YieldTermStructure> discountCurve) {
        return npv(leg, discountCurve, new Date(), new Date(), 0);
    }

    /**
     * NPV of the cash flows.
     * <p>
     * The NPV is the sum of the cash flows, each discounted according to the
     * given constant interest rate. The result is affected by the choice of the
     * interest-rate compounding and the relative frequency and day counter.
     */
    public double npv(final Leg cashflows, final InterestRate irr, final Date settlementDate) {

        Date date = settlementDate;
        if (date.isNull()) {
            date = new Settings().evaluationDate();
        }

        final YieldTermStructure flatRate = new FlatForward(date, irr.rate(), irr.dayCounter(), irr.compounding(), irr.frequency());
        return npv(cashflows, new Handle<YieldTermStructure>(flatRate), date, date, 0);
    }

    public double npv(final Leg leg, final InterestRate interestRate) {
        return npv(leg, interestRate, new Date());
    }


    /*
     * BPS Functions implied from quantlib default variables
     * since we cannot assign variables to defaults in the parameter lists of functions,
     * we use function chaining to effectively assign a single default at each level.
     */

    public double bps (final Leg cashflows, final Handle <YieldTermStructure> discountCurve)
    {
        // default variable of settlement date
        return bps (cashflows, discountCurve, new Settings().evaluationDate());
    }

    public double bps (final Leg cashflows, final Handle <YieldTermStructure> discountCurve,
                       final Date settlementDate)
    {
        // default variable of npv date
        return bps (cashflows, discountCurve, settlementDate, settlementDate);
    }

    public double bps (final Leg cashflows, final Handle <YieldTermStructure> discountCurve,
                       final Date settlementDate, final Date npvDate)
    {
        // default variable of ex-dividend days
        return bps (cashflows, discountCurve, settlementDate, npvDate, 0);
    }


    /*
     * Acutal BPS Functions ported from quantlib
     */

    /**
     * Basis-point sensitivity of the cash flows.
     * <p>
     * The result is the change in NPV due to a uniform 1-basis-point change in
     * the rate paid by the cash flows. The change for each coupon is discounted
     * according to the given term structure.
     */
    public double bps(final Leg cashflows, final Handle<YieldTermStructure> discountCurve,
                      final Date settlementDate, final Date npvDate, final int exDividendDays) {

        Date date = settlementDate;
        if (date.isNull()) {
            date = discountCurve.currentLink().referenceDate();
        }

        final BPSCalculator calc = new BPSCalculator(discountCurve, npvDate);
        for (int i = 0; i < cashflows.size(); ++i) {
            if (!cashflows.get(i).hasOccurred(date.add(exDividendDays))) {
                cashflows.get(i).accept(calc);
            }
        }
        return basisPoint_ * calc.result();
    }

    /**
     * Basis-point sensitivity of the cash flows.
     * <p>
     * The result is the change in NPV due to a uniform 1-basis-point change in
     * the rate paid by the cash flows. The change for each coupon is discounted
     * according to the given term structure.
     */
    public double bps(final Leg cashflows, final InterestRate irr, Date settlementDate){
        if (settlementDate.isNull())
        {
            settlementDate = new Settings().evaluationDate();
        }
        final YieldTermStructure flatRate = new FlatForward(settlementDate, irr.rate(),
                    irr.dayCounter(), irr.compounding(), irr.frequency());
        return bps(cashflows, new Handle<YieldTermStructure>(flatRate), settlementDate, settlementDate);
     }

    /**
     * At-the-money rate of the cash flows.
     * <p>
     * The result is the fixed rate for which a fixed rate cash flow vector,
     * equivalent to the input vector, has the required NPV according to the
     * given term structure. If the required NPV is not given, the input cash
     * flow vector's NPV is used instead.
     */
    public double atmRate(final Leg leg, final Handle<YieldTermStructure> discountCurve, final Date settlementDate,
            final Date npvDate, final int exDividendDays, double npv) {
        final double bps = bps(leg, discountCurve, settlementDate, npvDate, exDividendDays);
        if (npv == 0) {
            npv = npv(leg, discountCurve, settlementDate, npvDate, exDividendDays);
        }
        return basisPoint_ * npv / bps;
    }

    public double atmRate(final Leg leg, final Handle<YieldTermStructure> discountCurve) {
        return atmRate(leg, discountCurve, new Date(), new Date(), 0, 0);
    }

    /**
     * Internal rate of return.
     * <p>
     * The IRR is the interest rate at which the NPV of the cash flows equals
     * the given market price. The function verifies the theoretical existance
     * of an IRR and numerically establishes the IRR to the desired precision.
     */
    public double irr(final Leg cashflows, final double marketPrice, final DayCounter dayCounter, final Compounding compounding,
            final Frequency frequency, final Date settlementDate, final double tolerance, final int maxIterations,
            final double guess) {

        Date date = settlementDate;
        if (date.isNull()) {
            date = new Settings().evaluationDate();
        }

        // depending on the sign of the market price, check that cash
        // flows of the opposite sign have been specified (otherwise
        // IRR is nonsensical.)

        int lastSign = sign(-marketPrice), signChanges = 0;
        for (int i = 0; i < cashflows.size(); ++i) {
            if (!cashflows.get(i).hasOccurred(date)) {
                final int thisSign = sign(cashflows.get(i).amount());
                if (lastSign * thisSign < 0) {
                    signChanges++;
                }
                if (thisSign != 0) {
                    lastSign = thisSign;
                }
            }
        }

        QL.ensure(signChanges > 0 , infeasible_cashflow); // QA:[RG]::verified

        /*
         * THIS COMMENT COMES UNMODIFIED FROM QL/C++ SOURCES
         *
         * The following is commented out due to the lack of a QL_WARN macro
         *
         * if (signChanges > 1) { // Danger of non-unique solution // Check the
         * aggregate cash flows (Norstrom) Real aggregateCashFlow = marketPrice;
         * signChanges = 0; for (Size i = 0; i < cashflows.size(); ++i) { Real
         * nextAggregateCashFlow = aggregateCashFlow + cashflows[i]->amount();
         * if (aggregateCashFlow * nextAggregateCashFlow < 0.0) signChanges++;
         * aggregateCashFlow = nextAggregateCashFlow; } if (signChanges > 1)
         * QL_WARN( "danger of non-unique solution"); }
         */

        final Brent solver = new Brent();
        solver.setMaxEvaluations(maxIterations);
        return solver.solve(new IRRFinder(cashflows, marketPrice, dayCounter, compounding, frequency, date), tolerance, guess,
                guess / 10.0);
    }

    public double irr(final Leg leg, final double marketPrice, final DayCounter dayCounter, final Compounding compounding) {
        return irr(
                leg, marketPrice, dayCounter, compounding,
                Frequency.NoFrequency, new Date(),
                1.0e-10, 10000, 0.05);
    }

    /**
     * Cash-flow duration.
     * <p>
     * The simple duration of a string of cash flows is defined as
     * {@latex[ D_ \mathrm{simple} = \frac{\sum t_i c_i B(t_i)}{\sum c_i B(t_i)} } where {@latex$ c_i } is the amount of
     * the {@latex$ i }-th cash flow, {@latex$ t_i } is its payment time, and {@latex$ B(t_i) } is the corresponding
     * discount according to the passed yield.
     * <p>
     * The modified duration is defined as {@latex[ D_ \mathrm{modified} = -\frac{1}{P} \frac{\partial P}{\partial y} } where
     * {@latex$ P }is the present value of the cash flows according to the given IRR {@latex$ y }.
     * <p>
     * The Macaulay duration is defined for a compounded IRR as
     * {@latex[ D_ \mathrm{Macaulay} = \left( 1 + \frac{y}{N} \right) D_{\mathrm{modified}} } where
     * {@latex$ y } is the IRR and {@latex$ N } is the number of cash flows per year.
     */
    public double duration(final Leg leg, final InterestRate y, final Duration duration, final Date settlementDate) {

        Date date = settlementDate;
        if (date.isNull()) {
            date = new Settings().evaluationDate();
        }

        switch (duration) {
        case Simple:
            return simpleDuration(leg, y, date);
        case Modified:
            return modifiedDuration(leg, y, date);
        case Macaulay:
            return macaulayDuration(leg, y, date);
        default:
            throw new LibraryException(unknown_duration_type); // QA:[RG]::verified
        }
    }

    public double duration(final Leg leg, final InterestRate y) {
        return duration(leg, y, Duration.Modified, new Date());
    }

    /**
     * Cash-flow convexity
     * <p>
     * The convexity of a string of cash flows is defined as {@latex[ C = \frac{1}{P} \frac{\partial^2 P}{\partial y^2} } where
     * {@latex$ P } is the present value of the cash flows according to the given IRR {@latex$ y }.
     */
    public double convexity(final Leg cashFlows, final InterestRate rate, final Date settlementDate) {

        Date date = settlementDate;
        if (date.isNull()) {
            date = new Settings().evaluationDate();
        }

        final DayCounter dayCounter = rate.dayCounter();

        double P = 0.0;
        double d2Pdy2 = 0.0;
        final double y = rate.rate();
        final int N = rate.frequency().toInteger();

        for (int i = 0; i < cashFlows.size(); ++i) {
            if (!cashFlows.get(i).hasOccurred(date)) {
                final double t = dayCounter.yearFraction(date, cashFlows.get(i).date());
                final double c = cashFlows.get(i).amount();
                final double B = rate.discountFactor(t);

                P += c * B;
                switch (rate.compounding()) {
                case Simple:
                    d2Pdy2 += c * 2.0 * B * B * B * t * t;
                    break;
                case Compounded:
                    d2Pdy2 += c * B * t * (N * t + 1) / (N * (1 + y / N) * (1 + y / N));
                    break;
                case Continuous:
                    d2Pdy2 += c * B * t * t;
                    break;
                case SimpleThenCompounded:
                default:
                    throw new LibraryException(unsupported_compounding_type); // QA:[RG]::verified
                }
            }
        }

        if (P == 0.0)
            return 0.0; // no cashflows
        return d2Pdy2 / P;
    }

    public double convexity(final Leg leg, final InterestRate y) {
        return convexity(leg, y, new Date());
    }








    private double simpleDuration(final Leg cashflows, final InterestRate rate, final Date settlementDate) {

        double P = 0.0;
        double tP = 0.0;

        for (int i = 0; i < cashflows.size(); ++i) {
            if (!cashflows.get(i).hasOccurred(settlementDate)) {
                final double t = rate.dayCounter().yearFraction(settlementDate, cashflows.get(i).date());
                final double c = cashflows.get(i).amount();
                final double B = rate.discountFactor(t);

                P += c * B;
                tP += t * c * B;
            }
        }

        if (P == 0.0)
            // no cashflows
            return 0.0;

        return tP / P;
    }

    private double modifiedDuration(final Leg cashflows, final InterestRate rate, final Date settlementDate) {

        double P = 0.0;
        double dPdy = 0.0;
        final double y = rate.rate();
        final int N = rate.frequency().toInteger();

        for (int i = 0; i < cashflows.size(); ++i) {
            if (!cashflows.get(i).hasOccurred(settlementDate)) {
                final double t = rate.dayCounter().yearFraction(settlementDate, cashflows.get(i).date());
                final double c = cashflows.get(i).amount();
                final double B = rate.discountFactor(t);

                P += c * B;
                switch (rate.compounding()) {
                case Simple:
                    dPdy -= c * B * B * t;
                    break;
                case Compounded:
                    dPdy -= c * B * t / (1 + y / N);
                    break;
                case Continuous:
                    dPdy -= c * B * t;
                    break;
                case SimpleThenCompounded:
                default:
                    throw new LibraryException(unsupported_compounding_type); // QA:[RG]::verified
                }
            }
        }

        if (P == 0.0)
            // no cashflows
            return 0.0;
        return -dPdy / P;
    }

    private double macaulayDuration(final Leg cashflows, final InterestRate rate, final Date settlementDate) {

        final double y = rate.rate();
        final int N = rate.frequency().toInteger();
        QL.require(rate.compounding().equals(Compounding.Compounded), compounded_rate_required);
        QL.require(N>=1, unsupported_frequency);
        return (1 + y / N) * modifiedDuration(cashflows, rate, settlementDate);
    }

    private int sign(final double x) {
        if (x == 0)
            return 0;
        else if (x > 0)
            return 1;
        else
            return -1;
    }

    final public int previousCashFlow(final Leg leg) {
        return previousCashFlow(leg, new Date());
    }

    final public int previousCashFlow(final Leg leg, Date refDate) {
        if (refDate.isNull()) {
            refDate = new Settings().evaluationDate();
        }

        if (!(leg.get(0).hasOccurred(refDate)))
            return leg.size();

        final int i = nextCashFlowIndex(leg, refDate);
        final Date beforeLastPaymentDate = leg.get(i - 1).date();// (*--i)->date()-1;
        return nextCashFlowIndex(leg, beforeLastPaymentDate);
    }

    final public double previousCouponRate(final Leg cashFlows) {
        return previousCouponRate(cashFlows, new Date());
    }

    final public double previousCouponRate(final Leg cashFlows, final Date settlement) {
        final int cf = previousCashFlow(cashFlows, settlement);
        return couponRate(cashFlows, cashFlows, cf);
    }

    final public double nextCouponRate(final Leg leg) {
        return nextCouponRate(leg, new Date());
    }

    final public double nextCouponRate(final Leg cashFlows, final Date settlement) {
        final int cf = nextCashFlowIndex(cashFlows, settlement);
        return couponRate(cashFlows, cashFlows, cf);
    }

    /**
     * NOTE: should return null when no cashflow could be found!
     *
     * @param cashFlows
     * @param settlement
     * @return
     */
    final public CashFlow nextCashFlow(final Leg cashFlows, Date settlement) {
        if (settlement.isNull()) {
            settlement = new Settings().evaluationDate();
        }
        for (int i = 0; i < cashFlows.size(); ++i) {
            // the first coupon paying after d is the one we're after
            if (!cashFlows.get(i).hasOccurred(settlement))
                return cashFlows.get(i);
        }
        return null;// cashFlows.get(cashFlows.size());
    }

    /**
     * NOTE: returns the index! for cashflow.end() the returned index would
     * throw a index out of bounds exception
     *
     * @param cashFlows
     * @param settlement
     * @return
     */
    final public int nextCashFlowIndex(final Leg cashFlows, Date settlement) {
        if (settlement.isNull()) {
            settlement = new Settings().evaluationDate();
        }
        for (int i = 0; i < cashFlows.size(); ++i) {
            // the first coupon paying after d is the one we're after
            if (!cashFlows.get(i).hasOccurred(settlement))
                return i;
        }
        return cashFlows.size();
    }

    final public CashFlow nextCashFlow(final Leg cashFlows) {
        return nextCashFlow(cashFlows, new Date());
    }

    /**
     * Yield value of a basis point The yield value of a one basis point change
     * in price is the derivative of the yield with respect to the price
     * multiplied by 0.01
     *
     * @param leg
     * @param y
     * @param settlmentDate
     * @return
     */
    final public double yieldValueBasisPoint(final Leg leg, final InterestRate y, final Date settlementDate) {
        final double shift = 0.01;

        final double dirtyPrice = npv(leg, y, settlementDate);
        final double modifiedDuration = duration(leg, y, Duration.Modified, settlementDate);

        return (1.0 / (-dirtyPrice * modifiedDuration)) * shift;
    }

    final public double yieldValueBasisPoint(final Leg leg, final InterestRate y) {
        return yieldValueBasisPoint(leg, y, new Date());

    }

    // utility functions
    final public double couponRate(final Leg leg, final Leg iteratorLeg, final int iteratorIndex) {
        if (iteratorLeg.size() <= iteratorIndex)
            return 0.0;

        final Date paymentDate = iteratorLeg.get(iteratorIndex).date();
        boolean firstCouponFound = false;
        /* @Real */double nominal = Constants.NULL_REAL;
        /* @Time */double accrualPeriod = Constants.NULL_TIME;
        DayCounter dc = null;
        /* @Rate */double result = 0.0;

        for (int i = iteratorIndex; i < leg.size(); i++) {
            final CashFlow cf = iteratorLeg.get(i);
            if (cf.date().eq(paymentDate)) {
                if (cf instanceof Coupon) {
                    final Coupon cp = (Coupon) cf;
                    if (firstCouponFound) {
                        QL.require(nominal == cp.nominal() && accrualPeriod == cp.accrualPeriod() && dc == cp.dayCounter() , "cannot aggregate two different coupons")// QA:[RG]::verified // TODO: message
                    } else {
                        firstCouponFound = true;
                        nominal = cp.nominal();
                        accrualPeriod = cp.accrualPeriod();
                        dc = cp.dayCounter();
                    }
                    result += cp.rate();
                }
            }
        }
        QL.ensure((firstCouponFound) , "next cashflow (" + paymentDate + ") is not a coupon"); // QA:[RG]::verified // TODO: message
        return result;
    }


    //
    // private methods
    //


    /**
     * Basis-point value Obtained by setting dy = 0.0001 in the 2nd-order Taylor
     * series expansion.
     *
     * @param leg
     * @param y
     * @param settlementDate
     * @return
     */
    final private double basisPointValue(final Leg leg, final InterestRate y, final Date settlementDate) {
        /* @Real */final double shift = 0.0001;
        /* @Real */final double dirtyPrice = npv(leg, y, settlementDate);
        /* @Real */final double modifiedDuration = duration(leg, y, Duration.Modified, settlementDate);
        /* @Real */final double convexity = convexity(leg, y, settlementDate);

        /* @Real */double delta = -modifiedDuration * dirtyPrice;

        /* @Real */double gamma = (convexity / 100.0) * dirtyPrice;

        delta *= shift;
        gamma *= shift * shift;

        return delta + 0.5 * gamma;
    }

    final private double basisPointValue(final Leg leg, final InterestRate y) {
        return basisPointValue(leg, y, new Date());
    }



    //
    // public Enums
    //

    /**
     * Duration type
     */
    public enum Duration {
        Simple, Macaulay, Modified
    }


    //
    // private inner classes
    //

    private class IRRFinder implements Ops.DoubleOp {

        private final Leg cashflows_;
        private final double marketPrice_;
        private final DayCounter dayCounter_;
        private final Compounding compounding_;
        private final Frequency frequency_;
        private final Date settlementDate_;

        public IRRFinder(final Leg cashflows, final double marketPrice, final DayCounter dayCounter, final Compounding compounding,
                final Frequency frequency, final Date settlementDate) {
            this.cashflows_ = cashflows;
            this.marketPrice_ = marketPrice;
            this.dayCounter_ = dayCounter;
            this.compounding_ = compounding;
            this.frequency_ = frequency;
            this.settlementDate_ = settlementDate;
        }

        @Override
        public double op(final double guess) {
            final InterestRate rate = new InterestRate(guess, dayCounter_, compounding_, frequency_);
            final double NPV = npv(cashflows_, rate, settlementDate_);
            return marketPrice_ - NPV;
        }
    }

    private class BPSCalculator implements TypedVisitor<Object> {

        private static final String UNKNOWN_VISITABLE = "unknow visitable object";

        private final Handle<YieldTermStructure> termStructure;
        private final Date npvDate;

        private double result;

        public BPSCalculator(final Handle<YieldTermStructure> termStructure, final Date npvDate) {
            this.termStructure = termStructure;
            this.npvDate = npvDate;
            this.result = 0.0;
        }

        public double result() {
            if (npvDate.isNull())
                return result;
            else
                return result / termStructure.currentLink().discount(npvDate);
        }

        //
        // private inner classes
        //

        private class CashFlowVisitor implements Visitor<Object> {
            @Override
            public void visit(final Object o) {
                // nothing
            }
        }

        private class CouponVisitor implements Visitor<Object> {
            @Override
            public void visit(final Object o) {
                final Coupon c = (Coupon) o;
                result += c.accrualPeriod() * c.nominal() * termStructure.currentLink().discount(c.date());
            }
        }

        //
        // implements TypedVisitor
        //

        @Override
        public Visitor<Object> getVisitor(final Class<? extends Object> klass) {

            //FIXME
            //Coupon is a Cashflow, therfore any Coupon types will never get to the CashflowVisitor.
            //This may be fine for now, but could become problematic if other types are introduced.

            if (Coupon.class.isAssignableFrom (klass))
                return new CouponVisitor();
            if (CashFlow.class.isAssignableFrom (klass))
                return new CashFlowVisitor();
            throw new LibraryException(UNKNOWN_VISITABLE); // QA:[RG]::verified
        }
    }
}
TOP

Related Classes of org.jquantlib.cashflow.CashFlows

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.