private double logContactPriceFromPureSpot(final LocalVolatilitySurfaceMoneyness lv) { final double fT = DIV_CURVES.getF(EXPIRY); final double dT = DIV_CURVES.getD(EXPIRY); final double dStar = dT / (fT - dT); final ConvectionDiffusionPDE1DCoefficients pde = PDE_PROVIDER.getLogBackwardsLocalVol(EXPIRY, lv); final double theta = 0.5; final double yL = -0.5; final double yH = 0.5; final ConvectionDiffusionPDESolver solver = new ThetaMethodFiniteDifference(theta, false); final BoundaryCondition lower = new NeumannBoundaryCondition(1 / (1 + dStar * Math.exp(-yL)), yL, true); final BoundaryCondition upper = new NeumannBoundaryCondition(1.0, yH, false); final MeshingFunction timeMesh = new ExponentialMeshing(0.0, EXPIRY, 100, 0.0); final MeshingFunction spaceMesh = new ExponentialMeshing(yL, yH, 101, 0.0); final PDEGrid1D grid = new PDEGrid1D(timeMesh, spaceMesh); final PDE1DDataBundle<ConvectionDiffusionPDE1DCoefficients> db = new PDE1DDataBundle<>(pde, PURE_LOG_PAY_OFF, lower, upper, grid); final PDEResults1D res = solver.solve(db); final int n = res.getNumberSpaceNodes(); final double val = res.getFunctionValue(n / 2); return val; }
/** * Check the the log-contract is correctly prices using a backwards PDE expressed in terms of (the * log of) the real stock price - this requires having jumps conditions in the PDE. The local * volatility surface is derived from the flat pure local volatility surface. */ @Test public void backwardsLogSpotPDEtest() { final double fT = DIV_CURVES.getF(EXPIRY); final double lnFT = Math.log(fT); final double val = logContractPriceFromSpotPDE(LOCAL_VOL); assertEquals(PURE_VOL, Math.sqrt(-2 * (val - lnFT) / EXPIRY), 1e-4); // System.out.println(val + "\t" + Math.sqrt(-2 * (val - lnFT) / EXPIRY)); }
/** * Price the log-contact using the PDE in spot (with the jump conditions) with a flat local * volatility surface, and the PDE in pure spot using the pure local volatility surface derived * from the flat surface. They MUST give the same answer */ @Test public void backwardsPDETest() { final double fT = DIV_CURVES.getF(EXPIRY); final double lnFT = Math.log(fT); final double val1 = logContractPriceFromSpotPDE(LOCAL_VOL_FLAT); final double val2 = logContactPriceFromPureSpot(PURE_LOCAL_VOL); // convert to realised vol final double vol1 = Math.sqrt(-2 * (val1 - lnFT) / EXPIRY); final double vol2 = Math.sqrt(-2 * (val2 - lnFT) / EXPIRY); assertEquals(vol1, vol2, 1e-3); // System.out.println(vol1 + "\t" + vol2); }
/** * 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)); }