Package org.jquantlib.instruments

Source Code of org.jquantlib.instruments.VanillaSwap$Arguments

/*
Copyright (C) 2009 John Martin

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.
*/

/*
Copyright (C) 2006, 2008 Ferdinando Ametrano
Copyright (C) 2000, 2001, 2002, 2003 RiskMap srl
Copyright (C) 2003, 2004, 2005, 2006, 2007 StatPro Italia srl

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

QuantLib is free software: you can redistribute it and/or modify it
under the terms of the QuantLib license.  You should have received a
copy of the license along with this program; if not, please email
<quantlib-dev@lists.sf.net>. The license is also available online at
<http://quantlib.org/license.shtml>.

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.
*/
package org.jquantlib.instruments;

import java.util.ArrayList;
import java.util.List;

import org.jquantlib.QL;
import org.jquantlib.cashflow.CashFlow;
import org.jquantlib.cashflow.FixedRateCoupon;
import org.jquantlib.cashflow.FixedRateLeg;
import org.jquantlib.cashflow.IborCoupon;
import org.jquantlib.cashflow.IborLeg;
import org.jquantlib.cashflow.Leg;
import org.jquantlib.daycounters.DayCounter;
import org.jquantlib.indexes.IborIndex;
import org.jquantlib.lang.exceptions.LibraryException;
import org.jquantlib.math.Constants;
import org.jquantlib.pricingengines.PricingEngine;
import org.jquantlib.time.BusinessDayConvention;
import org.jquantlib.time.Date;
import org.jquantlib.time.Schedule;

/**
* Plain-vanilla swap
*
* @note if you define TodaysPayments like this
* <pre>
* new Settings().setTodaysPayments(true);
* </pre>
* payments occurring at the settlement date of
* the swap are included in the NPV, and therefore
* affect the fair-rate and fair-spread
* calculation. This might not be what you want.
*
* @category instruments
*
* @author Richard Gomes
*/
// TODO: code review :: license, class comments, comments for access modifiers, comments for @Override
public class VanillaSwap extends Swap {

    static final /*@Spread*/ double  basisPoint = 1.0e-4;

    private final Type type;
    private final /*@Real*/ double nominal;
    private final Schedule fixedSchedule;
    private final /*@Rate*/ double  fixedRate;
    private final DayCounter fixedDayCount;
    private final Schedule floatingSchedule;
    private final IborIndex iborIndex;
    private final /*@Spread*/ double spread;
    private final DayCounter floatingDayCount;
    private final BusinessDayConvention paymentConvention;
    // private final Array fixingDays;

    // results
    private /*@Rate*/ double fairRate;
    private /*@Spread*/ double fairSpread;


    public VanillaSwap(
            final Type type,
            final /*@Real*/ double nominal,
            final Schedule fixedSchedule,
            final /*@Rate*/ double fixedRate,
            final DayCounter fixedDayCount,
            final Schedule floatSchedule,
            final IborIndex iborIndex,
            final /*@Spread*/ double spread,
            final DayCounter floatingDayCount) {
        this(type, nominal, fixedSchedule, fixedRate, fixedDayCount, floatSchedule,
                iborIndex, spread, floatingDayCount, BusinessDayConvention.Following);
    }

    //FIXME: remove parameter "fixingDays"
    public VanillaSwap(
            final Type type,
            final /*@Real*/ double nominal,
            final Schedule fixedSchedule,
            final /*@Rate*/ double fixedRate,
            final DayCounter fixedDayCount,
            final Schedule floatSchedule,
            final IborIndex iborIndex,
            final /*@Spread*/ double spread,
            final DayCounter floatingDayCount,
            final BusinessDayConvention paymentConvention
    /*, final Array fixingDays*/) {
        super(2);
        this.type = type;
        this.nominal = nominal;
        this.fixedSchedule = fixedSchedule;
        this.fixedRate = fixedRate;
        this.fixedDayCount = fixedDayCount;
        this.floatingSchedule = floatSchedule;
        this.iborIndex = iborIndex;
        this.spread = spread;
        this.floatingDayCount = floatingDayCount;
        this.paymentConvention = paymentConvention;
        //FIXME this.fixingDays = fixingDays;

        final Leg fixedLeg = new FixedRateLeg(fixedSchedule, fixedDayCount)
        .withNotionals(nominal)
        .withCouponRates(fixedRate)
        .withPaymentAdjustment(paymentConvention)
        .Leg();

        // JM where are gearings set they cannot be null for the floating leg.
        final Leg floatingLeg = new IborLeg(floatingSchedule, iborIndex)
        .withNotionals(nominal)
        .withPaymentDayCounter(floatingDayCount)
        .withPaymentAdjustment(paymentConvention)

        //FIXME:: .withFixingDays (fixingDays) // FIXME: slight deviation from quantlib, need to expose fixing days up the stack

        .withSpreads(spread)

        // FIXME: JM quantlib does not assign this, it is currently required for construction
        // .withGearings(1.0)

        .Leg();

        for (final CashFlow item : floatingLeg) {
            item.addObserver(this);
        }

        super.legs.add(fixedLeg);
        super.legs.add(floatingLeg);
        if (type==Type.Payer) {
            super.payer[0] = -1.0;
            super.payer[1] = +1.0;
        } else {
            super.payer[0] = +1.0;
            super.payer[1] = -1.0;
        }
    }

    public /*@Rate*/ double  fairRate() /* @ReadOnly */ {
        calculate();
        QL.require(!Double.isNaN(fairRate) , "result not available"); // QA:[RG]::verified // TODO: message
        return fairRate;
    }

    public /*@Spread*/ double fairSpread() /* @ReadOnly */ {
        calculate();
        QL.require(!Double.isNaN(fairSpread) , "result not available"); // QA:[RG]::verified // TODO: message
        return fairSpread;
    }


    public final Leg fixedLeg() /* @ReadOnly */ {
        return legs.get(0);
    }

    public final Leg floatingLeg() /* @ReadOnly */ {
        return legs.get(1);
    }


    public /*@Real*/ double fixedLegBPS() /* @ReadOnly */ {
        calculate();
        QL.require(!Double.isNaN(legBPS[0]) , "result not available"); // QA:[RG]::verified // TODO: message
        return legBPS[0];
    }

    public /*@Real*/ double floatingLegBPS() /* @ReadOnly */ {
        calculate();
        QL.require(!Double.isNaN(legBPS[1]) , "result not available");
        return legBPS[1];
    }

    public /*@Real*/ double fixedLegNPV() /* @ReadOnly */ {
        calculate();
        QL.require(!Double.isNaN(legNPV[0]) , "result not available"); // QA:[RG]::verified // TODO: message
        return legNPV[0];
    }

    public /*@Real*/ double floatingLegNPV() /* @ReadOnly */ {
        calculate();
        QL.require(!Double.isNaN(legNPV[1]) , "result not available"); // QA:[RG]::verified // TODO: message
        return legNPV[1];
    }

    @Override
    public void setupExpired() /* @ReadOnly */ {
        super.setupExpired();
        legBPS[0] = 0.0;
        legBPS[1] = 0.0;
        fairRate   = Constants.NULL_REAL;
        fairSpread = Constants.NULL_REAL;
    }

    @Override
    public void setupArguments(final PricingEngine.Arguments arguments) /* @ReadOnly */ {
        super.setupArguments(arguments);
        if (arguments.getClass().isAssignableFrom(VanillaSwap.Arguments.class)) {
            final VanillaSwap.ArgumentsImpl a = (VanillaSwap.ArgumentsImpl) arguments;

            a.type = type;
            a.nominal = nominal;

            final Leg fixedCoupons = fixedLeg();

            a.fixedResetDates = new ArrayList<Date>(fixedCoupons.size());
            a.fixedPayDates = new ArrayList<Date>(fixedCoupons.size());
            a.fixedCoupons = new ArrayList</*@Real*/ Double>(fixedCoupons.size());

            for (int i=0; i<fixedCoupons.size(); i++) {
                final FixedRateCoupon coupon = (FixedRateCoupon) fixedCoupons.get(i);
                a.fixedPayDates.set(i, coupon.date());
                a.fixedResetDates.set(i, coupon.accrualStartDate());
                a.fixedCoupons.set(i, coupon.amount());
            }

            final Leg floatingCoupons = floatingLeg();

            a.floatingResetDates = new ArrayList<Date>(floatingCoupons.size());
            a.floatingPayDates = new ArrayList<Date>(floatingCoupons.size());
            a.floatingFixingDates = new ArrayList<Date>(floatingCoupons.size());

            a.floatingAccrualTimes = new ArrayList</*@Time*/ Double>(floatingCoupons.size());
            a.floatingSpreads = new ArrayList</*@Spread*/ Double>(floatingCoupons.size());
            a.floatingCoupons = new ArrayList</*@Real*/ Double>(floatingCoupons.size());
            for (int i=0; i<floatingCoupons.size(); ++i) {
                final IborCoupon coupon = (IborCoupon) floatingCoupons.get(i);

                a.floatingResetDates.set(i, coupon.accrualStartDate());
                a.floatingPayDates.set(i, coupon.date());

                a.floatingFixingDates.set(i, coupon.fixingDate());
                a.floatingAccrualTimes.set(i, coupon.accrualPeriod());
                a.floatingSpreads.set(i, coupon.spread());
                try {
                    a.floatingCoupons.set(i, coupon.amount());
                } catch (final Exception e) {
                    a.floatingCoupons.set(i, Constants.NULL_REAL);
                }
            }
        }
    }


    @Override
    public void fetchResults(final PricingEngine.Results results) /* @ReadOnly */ {
        super.fetchResults(results);

        if (results.getClass().isAssignableFrom(VanillaSwap.Results.class)) {
            final VanillaSwap.ResultsImpl r = (VanillaSwap.ResultsImpl)results;
            fairRate = r.fairRate;
            fairSpread = r.fairSpread;
        } else {
            fairRate   = Constants.NULL_REAL;
            fairSpread = Constants.NULL_REAL;
        }

        if (Double.isNaN(fairRate)) {
            // calculate it from other results
            if (!Double.isNaN(legBPS[0])) {
                fairRate = fixedRate- NPV/(legBPS[0]/basisPoint);
            }
        }
        if (Double.isNaN(fairSpread)) {
            // ditto
            if (!Double.isNaN(legBPS[1])) {
                fairSpread = spread - NPV/(legBPS[1]/basisPoint);
            }
        }
    }


    @Override
    public String toString() {
        return type.toString();
    }


    //
    // inner public enums
    //

    public enum Type {
        Receiver (-1),
        Payer (1);

        private final int enumValue;

        private Type(final int frequency) {
            this.enumValue = frequency;
        }

        static public Type valueOf(final int value) {
            switch (value) {
            case -1:
                return Type.Receiver;
            case 1:
                return Type.Payer;
            default:
                throw new LibraryException("value must be one of -1, 1"); // QA:[RG]::verified // TODO: message
            }
        }

        public int toInteger() {
            return this.enumValue;
        }
    }






    //
    // inner interfaces
    //

    public interface Arguments extends Swap.Arguments { }


    public interface Results extends Swap.Results { }


    //
    // ???? inner classes
    //


    /**
     * Arguments for simple swap calculation
     *
     * @author Richard Gomes
     */
    // TODO: code review :: object model needs to be validated and eventually refactored
    public class ArgumentsImpl extends Swap.ArgumentsImpl implements VanillaSwap.Arguments {

        public Type type;
        public /*@Real*/ double nominal;

        public List<Date> fixedResetDates;
        public List<Date> fixedPayDates;
        public List</*@Time*/ Double> floatingAccrualTimes;
        public List<Date> floatingResetDates;
        public List<Date> floatingFixingDates;
        public List<Date> floatingPayDates;

        public List</*@Real*/ Double> fixedCoupons;
        public List</*@Spread*/ Double> floatingSpreads;
        public List</*@Real*/ Double> floatingCoupons;


        @Override
        public void validate() /* @ReadOnly */ {
            super.validate();
            QL.require(!Double.isNaN(nominal) , "nominal null or not set"); // QA:[RG]::verified // TODO: message
            QL.require(fixedResetDates.size() == fixedPayDates.size() , "number of fixed start dates different from number of fixed payment dates");
            QL.require(fixedPayDates.size() == fixedCoupons.size() , "number of fixed payment dates different from number of fixed coupon amounts");
            QL.require(floatingResetDates.size() == floatingPayDates.size() , "number of floating start dates different from number of floating payment dates");
            QL.require(floatingFixingDates.size() == floatingPayDates.size() , "number of floating fixing dates different from number of floating payment dates");
            QL.require(floatingAccrualTimes.size() == floatingPayDates.size() , "number of floating accrual Times different from number of floating payment dates");
            QL.require(floatingSpreads.size() == floatingPayDates.size() , "number of floating spreads different from number of floating payment dates");
            QL.require(floatingPayDates.size() == floatingCoupons.size() , "number of floating payment dates different from number of floating coupon amounts");
        }

    }




    /**
     * Results from simple swap calculation
     *
     * @author Richard Gomes
     */
    // TODO: code review :: object model needs to be validated and eventually refactored
    public class ResultsImpl extends Swap.ResultsImpl implements VanillaSwap.Results {

        public /*@Rate*/ double  fairRate;
        public /*@Spread*/ double  fairSpread;

        @Override
        public void reset() {
            super.reset();
            fairRate   = Constants.NULL_REAL;
            fairSpread = Constants.NULL_REAL;
        }


    }




}
TOP

Related Classes of org.jquantlib.instruments.VanillaSwap$Arguments

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.