Ejemplo n.º 1
0
 static {
   final TreeMap<Double, Double> data = new TreeMap<Double, Double>();
   final TreeMap<Double, Double> transformedData = new TreeMap<Double, Double>();
   double x;
   for (int i = 0; i < 10; i++) {
     x = Double.valueOf(i);
     data.put(x, FUNCTION.evaluate(x));
     transformedData.put(x, Math.log(FUNCTION.evaluate(x)));
   }
   MODEL = LINEAR.getDataBundle(data);
   TRANSFORMED_MODEL = INTERPOLATOR.getDataBundle(transformedData);
 }
  /**
   * Prices a log-contract for a given local volatility surface by backwards solving the PDE
   * expressed in terms of (the log of) the real stock price - this requires having jumps conditions
   * in the PDE
   *
   * @param lv Local volatility
   * @return Forward (non-discounted) price of log-contact
   */
  private double logContractPriceFromSpotPDE(final LocalVolatilitySurfaceStrike lv) {

    // Set up the PDE to give the forward (non-discounted) option price
    final ConvectionDiffusionPDE1DCoefficients pde =
        PDE_PROVIDER.getLogBackwardsLocalVol(0.0, -DRIFT, EXPIRY, lv);
    final Function1D<Double, Double> initialCon =
        INITIAL_COND_PROVIDER.getLogContractPayoffInLogCoordinate();

    final double theta = 0.5;
    final double yL = Math.log(SPOT / 6);
    final double yH = Math.log(6 * SPOT);
    final ConvectionDiffusionPDESolver solver = new ThetaMethodFiniteDifference(theta, false);

    final BoundaryCondition lower1 = new NeumannBoundaryCondition(1.0, yL, true);
    final BoundaryCondition upper1 = new NeumannBoundaryCondition(1.0, yH, false);

    final MeshingFunction timeMesh1 =
        new ExponentialMeshing(0, EXPIRY - DIVIDEND_DATE - 1e-6, 50, 0.0);
    final MeshingFunction timeMesh2 =
        new ExponentialMeshing(EXPIRY - DIVIDEND_DATE + 1e-6, EXPIRY, 50, 0.0);
    final MeshingFunction spaceMesh = new ExponentialMeshing(yL, yH, 101, 0.0);

    final PDEGrid1D grid1 = new PDEGrid1D(timeMesh1, spaceMesh);
    final double[] sNodes1 = grid1.getSpaceNodes();

    // run the PDE solver backward to the dividend date
    final PDE1DDataBundle<ConvectionDiffusionPDE1DCoefficients> db1 =
        new PDE1DDataBundle<>(pde, initialCon, lower1, upper1, grid1);
    final PDETerminalResults1D res1 = (PDETerminalResults1D) solver.solve(db1);

    // Map the spot nodes after (in calendar time) the dividend payment to nodes before
    final int nSNodes = sNodes1.length;
    final double[] sNodes2 = new double[nSNodes];
    final double lnBeta = Math.log(1 - BETA);
    for (int i = 0; i < nSNodes; i++) {
      final double temp = sNodes1[i];
      if (temp < 0) {
        sNodes2[i] = Math.log(Math.exp(temp) + ALPHA) - lnBeta;
      } else {
        sNodes2[i] = temp + Math.log(1 + ALPHA * Math.exp(-temp)) - lnBeta;
      }
    }

    final PDEGrid1D grid2 = new PDEGrid1D(timeMesh2.getPoints(), sNodes2);
    final BoundaryCondition lower2 = new NeumannBoundaryCondition(1.0, sNodes2[0], true);
    final BoundaryCondition upper2 = new NeumannBoundaryCondition(1.0, sNodes2[nSNodes - 1], false);

    // run the PDE solver backward from the dividend date to zero
    final PDE1DDataBundle<ConvectionDiffusionPDE1DCoefficients> db2 =
        new PDE1DDataBundle<>(pde, res1.getTerminalResults(), lower2, upper2, grid2);
    final PDETerminalResults1D res2 = (PDETerminalResults1D) solver.solve(db2);

    final Interpolator1DDataBundle interpolDB2 =
        INTEPOLATOR1D.getDataBundle(sNodes2, res2.getTerminalResults());
    final double val2 = INTEPOLATOR1D.interpolate(interpolDB2, Math.log(SPOT));
    return val2;
  }
Ejemplo n.º 3
0
  public void testMixedLogNormalVolSurface() {

    final double[] weights = new double[] {0.9, 0.1};
    final double[] sigmas = new double[] {0.2, 0.8};
    final MultiHorizonMixedLogNormalModelData data =
        new MultiHorizonMixedLogNormalModelData(weights, sigmas);
    final LocalVolatilitySurfaceStrike lv =
        MixedLogNormalVolatilitySurface.getLocalVolatilitySurface(FORWARD_CURVE, data);
    final LocalVolatilitySurfaceMoneyness lvm =
        LocalVolatilitySurfaceConverter.toMoneynessSurface(lv, FORWARD_CURVE);
    final double expected =
        Math.sqrt(weights[0] * sigmas[0] * sigmas[0] + weights[1] * sigmas[1] * sigmas[1]);

    final double ft = FORWARD_CURVE.getForward(EXPIRY);
    final double theta = 0.5;
    // Review the accuracy is very dependent on these numbers
    final double fL = Math.log(ft / 30);
    final double fH = Math.log(30 * ft);

    final ConvectionDiffusionPDESolver solver = new ThetaMethodFiniteDifference(theta, false);

    final BoundaryCondition lower = new NeumannBoundaryCondition(1.0, fL, true);
    final BoundaryCondition upper = new NeumannBoundaryCondition(1.0, fH, false);

    final MeshingFunction timeMesh = new ExponentialMeshing(0, EXPIRY, 50, 0.0);
    final MeshingFunction spaceMesh = new HyperbolicMeshing(fL, fH, (fL + fH) / 2, 101, 0.4);

    final ConvectionDiffusionPDE1DStandardCoefficients pde =
        PDE_DATA_PROVIDER.getLogBackwardsLocalVol(EXPIRY, lvm);

    final PDEGrid1D grid = new PDEGrid1D(timeMesh, spaceMesh);
    final PDE1DDataBundle<ConvectionDiffusionPDE1DCoefficients> db =
        new PDE1DDataBundle<ConvectionDiffusionPDE1DCoefficients>(
            pde, INITIAL_COND, lower, upper, grid);
    final PDEResults1D res = solver.solve(db);

    final int n = res.getNumberSpaceNodes();
    final double[] values = new double[n];
    for (int i = 0; i < n; i++) {

      values[i] = res.getFunctionValue(i);
    }

    final Interpolator1DDataBundle idb = INTERPOLATOR.getDataBundle(grid.getSpaceNodes(), values);
    final double elogS = INTERPOLATOR.interpolate(idb, Math.log(ft));
    final double kVol = Math.sqrt(-2 * (elogS - Math.log(ft)) / EXPIRY);

    assertEquals(
        expected, kVol,
        1e-3); // TODO Improve on 10bps error - local surface is (by construction) very smooth.
               // NOTE: this has got worse since we improved the T -> 0
    // behaviour of the mixed log-normal local volatility surface
  }
  /**
   * Check the the log-contract is correctly prices using a backwards PDE expressed in terms of (the
   * log of) the forward F(t,T) - this requires NO jumps conditions in the PDE
   */
  @Test
  public void backwardsDebugPDEtest() {
    final double fT = DIV_CURVES.getF(EXPIRY);
    final double lnFT = Math.log(fT);

    final Function1D<Double, Double> payoff =
        new Function1D<Double, Double>() {

          @Override
          public Double evaluate(final Double y) {
            return y - lnFT;
          }
        };

    // ZZConvectionDiffusionPDEDataBundle pdeBundle1 = getBackwardsPDEDataBundle(EXPIRY, LOCAL_VOL,
    // payoff);
    // ConvectionDiffusionPDE1DCoefficients pde =
    // PDE_PROVIDER.getLogBackwardsLocalVol(FORWARD_CURVE, EXPIRY, LOCAL_VOL);
    final ConvectionDiffusionPDE1DCoefficients pde =
        PDE_PROVIDER.getLogBackwardsLocalVol(0.0, 0.0, EXPIRY, LOCAL_VOL_SPECIAL);

    final double theta = 0.5;
    final double range = Math.log(5);
    final double yL = lnFT - range;
    final double yH = lnFT + range;
    final ConvectionDiffusionPDESolver solver = new ThetaMethodFiniteDifference(theta, false);

    final BoundaryCondition lower = new NeumannBoundaryCondition(1.0, yL, true);
    final BoundaryCondition upper = new NeumannBoundaryCondition(1.0, yH, false);

    final MeshingFunction timeMesh = new ExponentialMeshing(0, EXPIRY, 100, 0.0);
    final MeshingFunction spaceMesh = new ExponentialMeshing(yL, yH, 101, 0.0);

    final PDEGrid1D grid = new PDEGrid1D(timeMesh, spaceMesh);
    final double[] sNodes = grid.getSpaceNodes();

    // run the PDE solver backward to the dividend date
    // PDE1DDataBundle<ConvectionDiffusionPDE1DCoefficients> db1 = new
    // PDE1DDataBundle<ConvectionDiffusionPDE1DCoefficients>(pde, initialCon, lower1, upper1,
    // grid1);
    final PDE1DDataBundle<ConvectionDiffusionPDE1DCoefficients> db1 =
        new PDE1DDataBundle<>(pde, payoff, lower, upper, grid);
    final PDETerminalResults1D res = (PDETerminalResults1D) solver.solve(db1);

    final Interpolator1DDataBundle interpolDB =
        INTEPOLATOR1D.getDataBundle(sNodes, res.getTerminalResults());

    final double val = INTEPOLATOR1D.interpolate(interpolDB, lnFT);
    assertEquals(0.41491529, Math.sqrt(-2 * (val) / EXPIRY), 5e-4); // Number from backwardsPDETest
    //   System.out.println(val + "\t" + Math.sqrt(-2 * val / EXPIRY));
  }
Ejemplo n.º 5
0
 @Test
 public void testDataBundleType1() {
   assertEquals(
       INTERPOLATOR.getDataBundle(new double[] {1, 2, 3}, new double[] {1, 2, 3}).getClass(),
       ArrayInterpolator1DDataBundle.class);
 }