Package com.opengamma.analytics.financial.model.finitedifference.applications

Source Code of com.opengamma.analytics.financial.model.finitedifference.applications.TermStructureRatesTest

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

import static org.testng.AssertJUnit.assertEquals;

import java.util.Arrays;

import org.testng.annotations.Test;

import com.opengamma.analytics.financial.model.finitedifference.BoundaryCondition;
import com.opengamma.analytics.financial.model.finitedifference.ConvectionDiffusionPDE1DCoefficients;
import com.opengamma.analytics.financial.model.finitedifference.ConvectionDiffusionPDE1DStandardCoefficients;
import com.opengamma.analytics.financial.model.finitedifference.ExponentialMeshing;
import com.opengamma.analytics.financial.model.finitedifference.MeshingFunction;
import com.opengamma.analytics.financial.model.finitedifference.NeumannBoundaryCondition;
import com.opengamma.analytics.financial.model.finitedifference.PDE1DDataBundle;
import com.opengamma.analytics.financial.model.finitedifference.PDEGrid1D;
import com.opengamma.analytics.financial.model.finitedifference.PDEResults1D;
import com.opengamma.analytics.financial.model.finitedifference.ThetaMethodFiniteDifference;
import com.opengamma.analytics.financial.model.interestrate.curve.ForwardCurve;
import com.opengamma.analytics.financial.model.option.pricing.analytic.formula.EuropeanVanillaOption;
import com.opengamma.analytics.financial.model.volatility.BlackFormulaRepository;
import com.opengamma.analytics.financial.model.volatility.local.LocalVolatilitySurfaceStrike;
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.Integrator1D;
import com.opengamma.analytics.math.integration.RungeKuttaIntegrator1D;
import com.opengamma.analytics.math.surface.ConstantDoublesSurface;

/**
* Check that the pde solver correctly prices the forward
*/
public class TermStructureRatesTest {
  private static final PDE1DCoefficientsProvider PDE = new PDE1DCoefficientsProvider();

  private static final LocalVolatilityBackwardsPDEPricer PRICER = new LocalVolatilityBackwardsPDEPricer();
  private static final ForwardCurve FWD_CURVE;
  // private static final YieldAndDiscountCurve DIS_CURVE;
  private static final Curve<Double, Double> RISK_FREE_CURVE;
  private static final LocalVolatilitySurfaceStrike LOCAL_VOL_SUR;
  private static final double S0 = 10.0;
  private static final double T = 5.0;
  private static final double SIGMA = 0.3;
  private static final double DF;

  static {

    final Function1D<Double, Double> r = new Function1D<Double, Double>() {
      @Override
      public Double evaluate(final Double t) {
        return (-0.04 + 0.1 * t) * Math.exp(-0.5 * t) + 0.08;
      }
    };

    final Function1D<Double, Double> b = new Function1D<Double, Double>() {
      @Override
      public Double evaluate(final Double t) {
        return (-0.04 + 0.1 * t) * Math.exp(-0.5 * t) - 0.08 * Math.exp(-0.3 * t) - 0.05;
      }
    };

    RISK_FREE_CURVE = FunctionalDoublesCurve.from(r);
    FWD_CURVE = new ForwardCurve(S0, FunctionalDoublesCurve.from(b));
    LOCAL_VOL_SUR = new LocalVolatilitySurfaceStrike(ConstantDoublesSurface.from(SIGMA));

    final Integrator1D<Double, Double> integrator = new RungeKuttaIntegrator1D();
    DF = Math.exp(-integrator.integrate(r, 0.0, T));
  }

  /**
   * Check a forward is priced correctly by the PDE solver
   */
  @Test
  public void forwardTest() {
    //forward (how much would you pay now to receive the asset at time T) is just a zero strike call
    final EuropeanVanillaOption option = new EuropeanVanillaOption(0.0, T, true);

    final int tNodes = 100;
    final int nu = 10;
    final int xNodes = nu * tNodes;

    final double pvFwd = DF * FWD_CURVE.getForward(T);

    final double pdePrice = PRICER.price(FWD_CURVE, RISK_FREE_CURVE, option, LOCAL_VOL_SUR, false, xNodes, tNodes);
    //System.out.println(pdePrice);

    //can recover accurate forward price with moderate grid
    assertEquals(pvFwd, pdePrice, pvFwd * 5e-6);
  }

  /**
   * Check a zero coupon bond is priced correctly by the PDE solver. Note, as this is not something one normally prices this way, there
   * is no helper class for the set up
   */
  @Test
  public void zeroCouponBondTest() {
    final ConvectionDiffusionPDE1DStandardCoefficients coef = PDE.getBackwardsLocalVol(RISK_FREE_CURVE, FWD_CURVE.getDriftCurve(), T, LOCAL_VOL_SUR);
    final Function1D<Double, Double> payoff = new Function1D<Double, Double>() {
      @Override
      public Double evaluate(final Double x) {
        return 1.0;
      }
    };

    final int tNodes = 100;
    final int nu = 5;
    final int xNodes = nu * tNodes;
    final double sMin = S0 / 5.0;
    final double sMax = 5 * S0;
    final MeshingFunction xMesh = new ExponentialMeshing(sMin, sMax, xNodes, 0.0, new double[] {S0 });
    final MeshingFunction tMesh = new ExponentialMeshing(0, T, tNodes, 0.0);
    final PDEGrid1D grid = new PDEGrid1D(tMesh, xMesh);

    final BoundaryCondition lower = new NeumannBoundaryCondition(0.0, sMin, true);
    final BoundaryCondition upper = new NeumannBoundaryCondition(0.0, sMax, true);
    final PDE1DDataBundle<ConvectionDiffusionPDE1DCoefficients> data = new PDE1DDataBundle<ConvectionDiffusionPDE1DCoefficients>(coef, payoff, lower, upper, grid);
    final ThetaMethodFiniteDifference solver = new ThetaMethodFiniteDifference();
    final PDEResults1D res = solver.solve(data);
    final int index = Arrays.binarySearch(grid.getSpaceNodes(), S0);
    final double pdePrice = res.getFunctionValue(index);

    //System.out.println(DF+"\t"+pdePrice);
    assertEquals(DF, pdePrice, DF * 5e-5);
  }

  @Test
  public void optionTest() {
    final double k = 6.0;
    final boolean isCall = false;

    final EuropeanVanillaOption option = new EuropeanVanillaOption(k, T, isCall);

    final int tNodes = 120;
    final int nu = 10;
    final int xNodes = nu * tNodes;

    final double bsPrice = DF * BlackFormulaRepository.price(FWD_CURVE.getForward(T), k, T, SIGMA, isCall);

    double pdePrice = PRICER.price(FWD_CURVE, RISK_FREE_CURVE, option, LOCAL_VOL_SUR, false, xNodes, tNodes, 0.1, 0.0, 5.0);
    //   double resErr = Math.abs((pdePrice-bsPrice)/bsPrice);
    //  System.out.println(bsPrice +"\t"+pdePrice+"\t"+resErr);

    assertEquals(bsPrice, pdePrice, bsPrice * 1e-4);

    //now price in terms of the forward - gives around 3 times improvement in accuracy
    final ForwardCurve fc = new ForwardCurve(FWD_CURVE.getForward(T));
    final ConstantDoublesCurve r = ConstantDoublesCurve.from(0.0);
    pdePrice = DF * PRICER.price(fc, r, option, LOCAL_VOL_SUR, false, xNodes, tNodes, 0.1, 0.0, 5.0);

    // resErr = Math.abs((pdePrice-bsPrice)/bsPrice);
    // System.out.println(bsPrice +"\t"+pdePrice+"\t"+resErr);
    assertEquals(bsPrice, pdePrice, bsPrice * 3e-5);
  }

}
TOP

Related Classes of com.opengamma.analytics.financial.model.finitedifference.applications.TermStructureRatesTest

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.