com.opengamma.analytics.financial.model.interestrate.curve.ForwardCurve.java Source code

Java tutorial

Introduction

Here is the source code for com.opengamma.analytics.financial.model.interestrate.curve.ForwardCurve.java

Source

/**
 * Copyright (C) 2011 - present by OpenGamma Inc. and the OpenGamma group of companies
 * 
 * Please see distribution for license.
 */
package com.opengamma.analytics.financial.model.interestrate.curve;

import org.apache.commons.lang.ObjectUtils;

import com.opengamma.analytics.math.curve.ConstantDoublesCurve;
import com.opengamma.analytics.math.curve.Curve;
import com.opengamma.analytics.math.curve.FunctionalDoublesCurve;
import com.opengamma.analytics.math.function.Function1D;
import com.opengamma.analytics.math.integration.RungeKuttaIntegrator1D;
import com.opengamma.analytics.util.serialization.InvokedSerializedForm;
import com.opengamma.util.ArgumentChecker;

/**
 * 
 */
public class ForwardCurve {
    private static final RungeKuttaIntegrator1D INTEGRATOR = new RungeKuttaIntegrator1D();
    private final Curve<Double, Double> _fwdCurve;
    private final Curve<Double, Double> _drift;
    private final double _spot;

    public ForwardCurve(final Curve<Double, Double> fwdCurve, final Curve<Double, Double> driftCurve) {
        ArgumentChecker.notNull(fwdCurve, "null fwdCurve");
        ArgumentChecker.notNull(driftCurve, "null driftCurve");
        _fwdCurve = fwdCurve;
        _drift = driftCurve;
        _spot = _fwdCurve.getYValue(0.0);
    }

    public ForwardCurve(final Curve<Double, Double> fwdCurve) {
        ArgumentChecker.notNull(fwdCurve, "curve");
        _fwdCurve = fwdCurve;
        _drift = getDriftCurve(fwdCurve); //TODO YieldAndDiscountCurve should have a getForwardRate method, which should be used here
        _spot = _fwdCurve.getYValue(0.0);
    }

    /**
     * Forward curve with zero drift (i.e. curve is constant)
     * @param spot The spot rate
     */
    public ForwardCurve(final double spot) {
        _fwdCurve = ConstantDoublesCurve.from(spot);
        _drift = ConstantDoublesCurve.from(0.0);
        _spot = spot;
    }

    /**
     * Forward curve with constant drift
     * @param spot  The spot
     * @param drift The drift
     */
    public ForwardCurve(final double spot, final double drift) {
        _drift = ConstantDoublesCurve.from(drift);
        _fwdCurve = getForwardCurve(spot, drift);
        _spot = spot;
    }

    /**
     * Forward curve with functional drift.
     * <b>Warning</b> This will be slow if you want access to the forward at many times
     * @param spot The spot rate
     * @param driftCurve The drift curve
     */
    public ForwardCurve(final double spot, final Curve<Double, Double> driftCurve) {
        ArgumentChecker.notNull(driftCurve, "null driftCurve");
        _drift = driftCurve;
        _fwdCurve = getForwardCurve(spot, driftCurve);
        _spot = spot;
    }

    public ForwardCurve(final Function1D<Double, Double> func) {
        this(FunctionalDoublesCurve.from(func));
    }

    public Curve<Double, Double> getForwardCurve() {
        return _fwdCurve;
    }

    public double getForward(final double t) {
        return _fwdCurve.getYValue(t);
    }

    /**
     * Gets the drift.
     * @return the drift
     */
    public Curve<Double, Double> getDriftCurve() {
        return _drift;
    }

    public double getDrift(final double t) {
        return _drift.getYValue(t);
    }

    public double getSpot() {
        return _spot;
    }

    protected static Curve<Double, Double> getForwardCurve(final double spot,
            final YieldAndDiscountCurve riskFreeCurve, final YieldAndDiscountCurve costOfCarryCurve) {
        ArgumentChecker.notNull(riskFreeCurve, "risk-free curve");
        ArgumentChecker.notNull(costOfCarryCurve, "cost-of-carry curve");
        final Function1D<Double, Double> f = new Function1D<Double, Double>() {

            @Override
            public Double evaluate(final Double t) {
                return spot * costOfCarryCurve.getDiscountFactor(t) / riskFreeCurve.getDiscountFactor(t);
            }

        };
        return new FunctionalDoublesCurve(f) {
            public Object writeReplace() {
                return new InvokedSerializedForm(ForwardCurve.class, "getForwardCurve", spot, riskFreeCurve,
                        costOfCarryCurve);
            }
        };
    }

    protected static Curve<Double, Double> getForwardCurve(final Double spot, final Double drift) {
        final Function1D<Double, Double> fwd = new Function1D<Double, Double>() {

            @Override
            public Double evaluate(final Double t) {
                return spot * Math.exp(drift * t);
            }

        };

        return new FunctionalDoublesCurve(fwd) {

            public Object writeReplace() {
                return new InvokedSerializedForm(ForwardCurve.class, "getForwardCurve", spot, drift);
            }
        };
    }

    protected static Curve<Double, Double> getForwardCurve(final Double spot,
            final Curve<Double, Double> driftCurve) {
        final Function1D<Double, Double> fwd = new Function1D<Double, Double>() {

            @Override
            public Double evaluate(final Double t) {
                final Function1D<Double, Double> driftFunc = new Function1D<Double, Double>() {

                    @Override
                    public Double evaluate(final Double y) {
                        return driftCurve.getYValue(y);
                    }

                };
                @SuppressWarnings("synthetic-access")
                final double temp = INTEGRATOR.integrate(driftFunc, 0.0, t);
                return spot * Math.exp(temp);
            }

        };
        return new FunctionalDoublesCurve(fwd) {

            public Object writeReplace() {
                return new InvokedSerializedForm(ForwardCurve.class, "getForwardCurve", spot, driftCurve);
            }
        };
    }

    protected static Curve<Double, Double> getDriftCurve(final Curve<Double, Double> fwdCurve) {
        final Function1D<Double, Double> drift = new Function1D<Double, Double>() {
            private final double _eps = 1e-3;

            @Override
            public Double evaluate(final Double t) {

                final double up = Math.log(fwdCurve.getYValue(t + _eps));

                if (t < _eps) {
                    final double mid = Math.log(fwdCurve.getYValue(t));
                    return (up - mid) / _eps;
                }
                final double down = Math.log(fwdCurve.getYValue(t - _eps));
                return (up - down) / 2 / _eps;
            }

        };

        return new FunctionalDoublesCurve(drift) {
            public Object writeReplace() {
                return new InvokedSerializedForm(ForwardCurve.class, "getDriftCurve", fwdCurve);
            }
        };
    }

    /**
     * Shift the forward curve by a fractional amount, shift, such that the new curve F'(T) = (1 + shift) * F(T), has
     * an unchanged drift.
     * @param shift The fractional shift amount, i.e. 0.1 will produce a curve 10% larger than the original
     * @return The shifted curve
     */
    public ForwardCurve withFractionalShift(final double shift) {
        ArgumentChecker.isTrue(shift > -1, "shift must be > -1");

        final Function1D<Double, Double> func = new Function1D<Double, Double>() {
            @SuppressWarnings("synthetic-access")
            @Override
            public Double evaluate(final Double t) {
                return (1 + shift) * _fwdCurve.getYValue(t);
            }
        };
        return new ForwardCurve(FunctionalDoublesCurve.from(func), _drift);
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + _drift.hashCode();
        result = prime * result + _fwdCurve.hashCode();
        long temp;
        temp = Double.doubleToLongBits(_spot);
        result = prime * result + (int) (temp ^ (temp >>> 32));
        return result;
    }

    @Override
    public boolean equals(final Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final ForwardCurve other = (ForwardCurve) obj;
        if (!ObjectUtils.equals(_drift, other._drift)) {
            return false;
        }
        if (!ObjectUtils.equals(_fwdCurve, other._fwdCurve)) {
            return false;
        }
        if (Double.doubleToLongBits(_spot) != Double.doubleToLongBits(other._spot)) {
            return false;
        }
        return true;
    }

}