Package org.jquantlib.model.shortrate.onefactormodels

Source Code of org.jquantlib.model.shortrate.onefactormodels.HullWhite$Dynamics

/*
Copyright (C) 2008 Praneet Tiwari
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.model.shortrate.onefactormodels;

import static org.jquantlib.pricingengines.BlackFormula.blackFormula;

import org.jquantlib.QL;
import org.jquantlib.instruments.Option;
import org.jquantlib.math.Constants;
import org.jquantlib.math.matrixutilities.Array;
import org.jquantlib.methods.lattices.Lattice;
import org.jquantlib.methods.lattices.TrinomialTree;
import org.jquantlib.model.NullParameter;
import org.jquantlib.model.Parameter;
import org.jquantlib.model.TermStructureFittingParameter;
import org.jquantlib.processes.OrnsteinUhlenbeckProcess;
import org.jquantlib.quotes.Handle;
import org.jquantlib.termstructures.Compounding;
import org.jquantlib.termstructures.YieldTermStructure;
import org.jquantlib.time.Frequency;
import org.jquantlib.time.TimeGrid;

/**
* Single-factor Hull-White (extended Vasicek) model class.
* <p>
* This class implements the standard single-factor Hull-White model defined by
* <p>
* {@latex[ dr_t = (\theta(t) - \alpha r_t)dt + \sigma dW_t }
* <p>
* where {@latex$ \alpha } and {@latex$ \sigma } are constants.
*
* @note When the term structure is relinked, the r0 parameter of the underlying Vasicek model is not updated.
*
* @category shortrate
*
* @author Praneet Tiwari
*/
// TODO: code review :: license, class comments, comments for access modifiers, comments for @Override
public class HullWhite extends Vasicek implements TermStructureConsistentModel {

    private final TermStructureConsistentModelClass termStructureConsistentModelClass;

    private Parameter phi_;

    //
    // public constructors
    //

    public HullWhite(final Handle<YieldTermStructure> termStructure) {
        this(termStructure, 0.1, 0.01);
    }

    public HullWhite(
            final Handle<YieldTermStructure> termStructure,
            final double a) {
        this(termStructure, a, 0.01);
    }

    public HullWhite(
            final Handle<YieldTermStructure> termStructure,
            final double a,
            final double sigma) {

        super(termStructure.currentLink().forwardRate(0.0, 0.0, Compounding.Continuous, Frequency.NoFrequency).rate(),
                a, 0.0, sigma, 0.0);

        if (System.getProperty("EXPERIMENTAL") == null)
            throw new UnsupportedOperationException("Work in progress");

        termStructureConsistentModelClass = new TermStructureConsistentModelClass(termStructure);
        b_ = new NullParameter();
        lambda_ = new NullParameter();
        generateArguments();

        termStructureConsistentModelClass.termStructure().addObserver(this);
    }

    //
    // protected methods
    //

    @Override
    protected void generateArguments() {
        phi_ = new FittingParameter(termStructureConsistentModelClass.termStructure(), a(), sigma());
    }

    //
    // public methods
    //

    @Override
    public double discountBondOption(
            final Option.Type type,
            final double strike,
            final double /* @Time */ maturity,
            final double /* @Time */ bondMaturity) /* @ReadOnly */ {

        final double /* @Real */_a = a();
        double /* @Real */v;
        if (_a < Math.sqrt(Constants.QL_EPSILON))
            v = sigma() * B(maturity, bondMaturity) * Math.sqrt(maturity);
        else
            v = sigma() * B(maturity, bondMaturity) * Math.sqrt(0.5 * (1.0 - Math.exp(-2.0 * _a * maturity)) / _a);
        final double /* @Real */f = termStructureConsistentModelClass.termStructure().currentLink().discount(bondMaturity);
        final double /* @Real */k = termStructureConsistentModelClass.termStructure().currentLink().discount(maturity) * strike;

        return blackFormula(type, k, f, v);
    }

    /**
     *  Futures convexity bias (i.e., the difference between
     *  futures implied rate and forward rate) calculated as in
     *  <p>
     *  G. Kirikos, D. Novak, "Convexity Conundrums", Risk Magazine, March 1997.
     *
     *  @note t and T should be expressed in yearfraction using deposit day counter, F_quoted is futures' market price.
     */
    public /* @Rate */ double convexityBias(
            final double futurePrice,
            final /* @Time */ double t,
            final /* @Time */ double T,
            final double sigma,
            final double a) {

        QL.require(futurePrice >= 0.0 , "negative futures price not allowed"); // QA:[RG]::verified // TODO: message
        QL.require(t >= 0.0 , "negative t not allowed"); // QA:[RG]::verified // TODO: message
        QL.require(T >= t , "T must not be less than t"); // QA:[RG]::verified // TODO: message
        QL.require(a >= 0.0 , "negative a not allowed"); // QA:[RG]::verified // TODO: message

        final double /* @Time */deltaT = (T - t);
        final double /* @Real */tempDeltaT = (1. - Math.exp(-a * deltaT)) / a;
        final double /* @Real */halfSigmaSquare = sigma * sigma / 2.0;

        // lambda adjusts for the fact that the underlying is an interest rate
        final double /* @Real */lambda = halfSigmaSquare * (1. - Math.exp(-2.0 * a * t)) / a * tempDeltaT * tempDeltaT;

        final double /* @Real */tempT = (1.0 - Math.exp(-a * t)) / a;

        // phi is the MtM adjustment
        final double /* @Real */phi = halfSigmaSquare * tempDeltaT * tempT * tempT;

        // the adjustment
        final double /* @Real */z = lambda + phi;

        final double /* @Rate */futureRate = (100.0 - futurePrice) / 100.0;
        return (1.0 - Math.exp(-z)) * (futureRate + 1.0 / (T - t));
    }


    //
    // overrides OneFactorModel
    //

    @Override
    public Lattice tree(final TimeGrid grid) {
        final TermStructureFittingParameter phi = new TermStructureFittingParameter(termStructureConsistentModelClass.termStructure());
        // needed to activate the above constructor
        final ShortRateDynamics numericDynamics = (new Dynamics(phi, a(), sigma()));
        final TrinomialTree trinomial = new TrinomialTree(numericDynamics.process(), grid, true);
        final ShortRateTree numericTree = new OneFactorModel.ShortRateTree(trinomial, numericDynamics, grid);

        // typedef TermStructureFittingParameter::NumericalImpl NumericalImpl;
        final TermStructureFittingParameter.NumericalImpl impl = (TermStructureFittingParameter.NumericalImpl) phi.implementation();
        impl.reset();
        for (int /* @Size */i = 0; i < (grid.size() - 1); i++) {
            final double /* @Real */discountBond = termStructureConsistentModelClass.termStructure().currentLink().discount(grid.at(i + 1));
            final Array statePrices = numericTree.statePrices(i);
            final int /* @Size */size = numericTree.size(i);
            final double /* @Time */dt = numericTree.timeGrid().dt(i);
            final double /* @Real */dx = trinomial.dx(i);
            double /* @Real */x = trinomial.underlying(i, 0);
            double /* @Real */value = 0.0;
            for (int /* @Size */j = 0; j < size; j++) {
                value += statePrices.get(j) * Math.exp(-x * dt);
                x += dx;
            }
            value = Math.log(value / discountBond) / dt;
            // impl->set(grid[i], value);
            impl.set(grid.index(i), value); // ???????????????
        }
        return numericTree;
    }


    //
    // overrides Vasicek
    //

    @Override
    protected double A(/* @Time */ final double t, /* @Time */ final double T) /* @ReadOnly */ {
        final double /* @DiscountFactor */discount1 = termStructureConsistentModelClass.termStructure().currentLink().discount(t);
        final double /* @DiscountFactor */discount2 = termStructureConsistentModelClass.termStructure().currentLink().discount(T);
        final double /* @Rate */forward = termStructureConsistentModelClass.termStructure().currentLink().forwardRate(t, t,
                Compounding.Continuous, Frequency.NoFrequency).rate();
        final double /* @Real */temp = sigma() * B(t, T);
        final double /* @Real */value = B(t, T) * forward - 0.25 * temp * temp * B(0.0, 2.0 * t);
        return Math.exp(value) * discount2 / discount1;
    }


    @Override
    public ShortRateDynamics dynamics() {
        return (new Dynamics(phi_, a(), sigma()));
    }

    //
    // implements TermStructureConsistentModel
    //

    @Override
    public Handle<YieldTermStructure> termStructure() {
        return termStructureConsistentModelClass.termStructure();
    }


    //
    // static inner classes
    //

    /**
     * Analytical term-structure fitting parameter \f$ \varphi(t) \f$.
     *
     * {@latex$ \varphi(t) } is analytically defined by
     * <p>
     * {@latex[ \varphi(t) = f(t) + \frac{1}{2}[\frac{\sigma(1-e^{-at})}{a}]^2 }
     * <p>
     * where {@latex$ f(t) } is the instantaneous forward rate at {@latex$ t }.
     */
    static private class FittingParameter extends TermStructureFittingParameter {

        public FittingParameter(final Handle<YieldTermStructure> termStructure, final double a, final double sigma) {
            super(new Impl(termStructure, a, sigma));
        }


        //
        // private inner classes
        //

        static private class Impl implements Parameter.Impl {

            private final Handle<YieldTermStructure> termStructure;
            private final double a;
            private final double sigma;

            public Impl(
                    final Handle<YieldTermStructure> termStructure,
                    final double a,
                    final double sigma) {
                this.termStructure = termStructure;
                this.a = a;
                this.sigma = sigma;
            }

            @Override
            public double value(final Array params, final double t) {
                final double forwardRate = termStructure.currentLink().forwardRate(
                        t, t, Compounding.Continuous, Frequency.NoFrequency).rate();
                final double temp = sigma*(1.0 - Math.exp(-a*t))/a;
                return (forwardRate + 0.5*temp*temp);
            }
        }

    }


    /**
     * Short-rate dynamics in the Hull-White model
     * <p>
     * The short-rate is here
     * <p>
     * {@latex[ r_t = \varphi(t) + x_t }
     * <p>
     * where {@latex$ \varphi(t) } is the deterministic time-dependent parameter used for
     * term-structure fitting and {@latex$ x_t } is the state variable following an Ornstein-Uhlenbeck process.
     */
    public class Dynamics extends ShortRateDynamics {

        private final Parameter fitting_;

        public Dynamics(final Parameter  fitting, final double a, final double sigma) {
            super(new OrnsteinUhlenbeckProcess(a, sigma, /* default */0.0, /* default */0.0));
            fitting_ = (fitting);
        }

        @Override
        public double variable(/* @Time */ final double t, /* @Rate */ final double r) /* @ReadOnly */ {
            return r - fitting_.get(t);
        }

        @Override
        public double shortRate(/* @Time */ final double t, final double x) /* @ReadOnly */ {
            return x + fitting_.get(t);
        }

    }

}
TOP

Related Classes of org.jquantlib.model.shortrate.onefactormodels.HullWhite$Dynamics

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.