/*
 Copyright (C) 2008 Srinivas Hasti
 Copyright (C) 2010 NeelSheyal
 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
 . The license is also available online at
 .

 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.termstructures.yieldcurves;



import org.jquantlib.QL;
import org.jquantlib.Settings;
import org.jquantlib.cashflow.FloatingRateCoupon;
import org.jquantlib.daycounters.DayCounter;
import org.jquantlib.indexes.IborIndex;
import org.jquantlib.indexes.SwapIndex;
import org.jquantlib.instruments.MakeVanillaSwap;
import org.jquantlib.instruments.VanillaSwap;
import org.jquantlib.quotes.Handle;
import org.jquantlib.quotes.Quote;
import org.jquantlib.quotes.RelinkableHandle;
import org.jquantlib.termstructures.BootstrapHelper;
import org.jquantlib.termstructures.YieldTermStructure;
import org.jquantlib.time.BusinessDayConvention;
import org.jquantlib.time.Calendar;
import org.jquantlib.time.Date;
import org.jquantlib.time.Frequency;
import org.jquantlib.time.Period;
import org.jquantlib.time.TimeUnit;
import org.jquantlib.util.PolymorphicVisitor;
import org.jquantlib.util.Visitor;

/**
 * Rate helper for bootstrapping over swap rates
 *
 * @author Richard Gomes
 * @author Neel Sheyal
 */
//
public class SwapRateHelper extends RelativeDateRateHelper {

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

    protected final Period tenor;
    protected final Calendar calendar;
    protected final BusinessDayConvention fixedConvention;
    protected final Frequency fixedFrequency;
    protected final DayCounter fixedDayCount;
    protected final IborIndex iborIndex;
    protected VanillaSwap swap;
    protected RelinkableHandle termStructureHandle = new RelinkableHandle  (null);
    protected final Handle spread;
    protected final Period fwdStart;


    //
    // public constructors
    //

    
    public SwapRateHelper(
            final Handle rate,
            final SwapIndex swapIndex) {
    	this(rate, swapIndex, new Handle(), new Period(0, TimeUnit.Days));
    }
    public SwapRateHelper(
            final Handle rate,
            final SwapIndex swapIndex,
            final Handle spread) {
    	this(rate, swapIndex, spread, new Period(0, TimeUnit.Days));
    }
    public SwapRateHelper(
            final Handle rate,
            final SwapIndex swapIndex,
            final Handle spread,
            final Period fwdStart) {
        super(rate);
        QL.validateExperimentalMode();

        this.tenor = swapIndex.tenor();
        this.calendar = swapIndex.fixingCalendar();
        this.fixedConvention = swapIndex.fixedLegConvention();
        this.fixedFrequency = swapIndex.fixedLegTenor().frequency();
        this.fixedDayCount = swapIndex.dayCounter();
        this.iborIndex = swapIndex.iborIndex();
        this.spread = spread;
        this.fwdStart = fwdStart;

        this.iborIndex.addObserver(this);
        this.spread.addObserver(this);

        initializeDates();
    }


    public SwapRateHelper(
            final Handle rate,
            final Period tenor,
            final Calendar calendar,
            final Frequency fixedFrequency,
            final BusinessDayConvention fixedConvention,
            final DayCounter fixedDayCount,
            final IborIndex iborIndex) {
    	this(rate, tenor, calendar, fixedFrequency, fixedConvention, fixedDayCount, iborIndex, new Handle(), new Period(0, TimeUnit.Days));
    }
    public SwapRateHelper(
            final Handle rate,
            final Period tenor,
            final Calendar calendar,
            final Frequency fixedFrequency,
            final BusinessDayConvention fixedConvention,
            final DayCounter fixedDayCount,
            final IborIndex iborIndex,
            final Handle spread) {
    	this(rate, tenor, calendar, fixedFrequency, fixedConvention, fixedDayCount, iborIndex, spread, new Period(0, TimeUnit.Days));
    }
    public SwapRateHelper(
            final Handle rate,
            final Period tenor,
            final Calendar calendar,
            final Frequency fixedFrequency,
            final BusinessDayConvention fixedConvention,
            final DayCounter fixedDayCount,
            final IborIndex iborIndex,
            final Handle spread,
            final Period fwdStart) {
        super(rate);
        QL.validateExperimentalMode();

        this.tenor = tenor;
        this.calendar = calendar;
        this.fixedConvention = fixedConvention;
        this.fixedFrequency = fixedFrequency;
        this.fixedDayCount = fixedDayCount;
        this.iborIndex = iborIndex;
        this.spread =spread;
        this.fwdStart =fwdStart;

        this.iborIndex.addObserver(this);
        this.spread.addObserver(this);

        initializeDates();
    }


    public SwapRateHelper(
            final /*@Rate*/ double rate,
            final Period tenor,
            final Calendar calendar,
            final Frequency fixedFrequency,
            final BusinessDayConvention fixedConvention,
            final DayCounter fixedDayCount,
            final IborIndex iborIndex) {
    	this(rate, tenor, calendar, fixedFrequency, fixedConvention, fixedDayCount, iborIndex, new Handle(), new Period(0, TimeUnit.Days));
    }
    public SwapRateHelper(
            final /*@Rate*/ double rate,
            final Period tenor,
            final Calendar calendar,
            final Frequency fixedFrequency,
            final BusinessDayConvention fixedConvention,
            final DayCounter fixedDayCount,
            final IborIndex iborIndex,
            final Handle spread) {
    	this(rate, tenor, calendar, fixedFrequency, fixedConvention, fixedDayCount, iborIndex, spread, new Period(0, TimeUnit.Days));
    }
    public SwapRateHelper(
            final /*@Rate*/ double rate,
            final Period tenor,
            final Calendar calendar,
            final Frequency fixedFrequency,
            final BusinessDayConvention fixedConvention,
            final DayCounter fixedDayCount,
            final IborIndex iborIndex,
            final Handle spread,
            final Period fwdStart) {
        super(rate);
        QL.validateExperimentalMode();

        this.tenor = tenor;
        this.calendar = calendar;
        this.fixedConvention = fixedConvention;
        this.fixedFrequency = fixedFrequency;
        this.fixedDayCount = fixedDayCount;
        this.iborIndex = iborIndex;
        this.spread = spread;
        this.fwdStart = fwdStart;

        this.iborIndex.addObserver(this);
        this.spread.addObserver(this);

        initializeDates();
    }


    public SwapRateHelper(
            final /*@Rate*/ double rate,
            final SwapIndex swapIndex) {
    	this(rate, swapIndex, new Handle(), new Period(0, TimeUnit.Days));
    }
    public SwapRateHelper(
            final /*@Rate*/ double rate,
            final SwapIndex swapIndex,
            final Handle spread) {
    	this(rate, swapIndex, spread, new Period(0, TimeUnit.Days));
    }
    public SwapRateHelper(
            final /*@Rate*/ double rate,
            final SwapIndex swapIndex,
            final Handle spread,
            final Period fwdStart) {
        super(rate);
        QL.validateExperimentalMode();

        this.tenor = swapIndex.tenor();
        this.calendar = swapIndex.fixingCalendar();
        this.fixedConvention = swapIndex.fixedLegConvention();
        this.fixedFrequency = swapIndex.fixedLegTenor().frequency();
        this.fixedDayCount = swapIndex.dayCounter();
        this.iborIndex = swapIndex.iborIndex();
        this.spread = spread;
        this.fwdStart = fwdStart;

        this.iborIndex.addObserver(this);
        this.spread.addObserver(this);

        initializeDates();
    }


    //
    // protected methods
    //

	/** 
     * 
     * @see org.jquantlib.termstructures.yield.RelativeDateRateHelper#initializeDates()
     */
    @Override
    protected void initializeDates() {
        // dummy ibor index with curve/swap arguments
        final IborIndex clonedIborIndex = iborIndex.clone(this.termStructureHandle).currentLink();

        // do not pass the spread here, as it might be a Quote i.e. it can dynamically change
        this.swap = new MakeVanillaSwap(tenor, clonedIborIndex, 0.0, fwdStart)
        .withFixedLegDayCount(fixedDayCount)
        .withFixedLegTenor(new Period(fixedFrequency))
        .withFixedLegConvention(fixedConvention)
        .withFixedLegTerminationDateConvention(fixedConvention)
        .withFixedLegCalendar(calendar)
        .withFloatingLegCalendar(calendar).value();

        this.earliestDate = swap.startDate();

        // Usually...
        this.latestDate = swap.maturityDate();

        // ...but due to adjustments, the last floating coupon might need a later date for fixing
        if (new Settings().isUseIndexedCoupon()) {
            final FloatingRateCoupon lastFloating = (FloatingRateCoupon) this.swap.floatingLeg().last();
            final Date fixingValueDate = this.iborIndex.valueDate(lastFloating.fixingDate());
            final Date endValueDate = this.iborIndex.maturityDate(fixingValueDate);
            this.latestDate = Date.max(latestDate, endValueDate);
        }
    }


    /**
     * Do not set the relinkable handle as an observer.
     * Force recalculation when needed
     * 
     * @see org.jquantlib.termstructures.BootstrapHelper#setTermStructure
     *
     * @param t
     */
    @Override
    public void setTermStructure(final YieldTermStructure t) {
        this.termStructureHandle.linkTo(t, false);
        super.setTermStructure(t);
    }


    /** 
     * @see org.jquantlib.termstructures.BootstrapHelper#getImpliedQuote()
     */
    @Override
    public /*@Real*/ double impliedQuote() /* @ReadOnly */ {
        QL.require(termStructure != null , "term structure not set");

        // we didn't register as observers - force calculation
        swap.recalculate();

        // weak implementation... to be improved
        /*@Real*/ final double floatingLegNPV = swap.floatingLegNPV();
        /*@Spread*/ final double spread = this.spread.empty() ? 0.0 : this.spread.currentLink().value();
        /*@Real*/ final double spreadNPV = swap.floatingLegBPS()/basisPoint*spread;
        /*@Real*/ final double totNPV = - (floatingLegNPV+spreadNPV);
        /*@Real*/ final double result = totNPV/(swap.fixedLegBPS()/basisPoint);
        return result;
    }

    public /*@Spread*/ double spread() /* @ReadOnly */ {
        return this.spread.empty() ? 0.0 : spread.currentLink().value();
    }

    public VanillaSwap swap() /* @ReadOnly */ {
        return this.swap;
    }

    public final Period forwardStart() /* @ReadOnly */ {
        return this.fwdStart;
    }


    //
    // implements PolymorphicVisitable
    //

    @Override
    public void accept(final PolymorphicVisitor pv) {
        final Visitor v = (pv!=null) ? pv.visitor(this.getClass()) : null;
        if (v != null) {
            v.visit(this);
        } else {
            super.accept(pv);
        }
    }

}

 

Ads help maintain this website.