BlackScholesMertonPDEPricer { public double price(final double s0, final double k, final double r, final double b, final double t, final double sigma, final boolean isCall, final int spaceNodes, final int timeNodes) { return price(s0, k, r, b, t, sigma, isCall, false, spaceNodes, timeNodes); } BlackScholesMertonPDEPricer();  BlackScholesMertonPDEPricer(final boolean useBurnin);  BlackScholesMertonPDEPricer(final boolean useBurnin, final double burninFrac);  BlackScholesMertonPDEPricer(final boolean useBurnin, final double burninFrac, final double burninTheta, final double mainTheta); double price(final double s0, final double k, final double r, final double b, final double t, final double sigma, final boolean isCall, final int spaceNodes,
      final int timeNodes); double price(final double s0, final double k, final double r, final double b, final double t, final double sigma, final boolean isCall,
      final boolean isAmerican, final int spaceNodes, final int timeNodes); double price(final double s0, final double k, final double r, final double b, final double t, final double sigma, final boolean isCall,
      final boolean isAmerican, final int spaceNodes, final int timeNodes, final double beta, final double lambda, final double sd); double price(final double s0, final double k, final double r, final double b, final double t, final double sigma, final boolean isCall,
      final boolean isAmerican, final PDEGrid1D[] grid, final double[] theta);  }
@Test public void speedAccuracyTest() { final double s0 = 10.0; final double k = 13.0; final double r = 0.06; final double b = 0.04; final double t = 1.75; final double sigma = 0.5; final boolean isCall = true; double nu = 125; int tSteps = 100; int sSteps = (int) (nu * tSteps); double pdePDE = PRICER.price(s0, k, r, b, t, sigma, isCall, false, sSteps, tSteps); nu = 125; for (int i = 0; i < 5; i++) { tSteps = (int) (100 + Math.pow(10.0, (i + 6.0) / 4.0)); sSteps = (int) (nu * tSteps); final double size = tSteps * sSteps; final double bsPrice = Math.exp(-r * t) * BlackFormulaRepository.price(s0 * Math.exp(b * t), k, t, sigma, isCall); pdePDE = PRICER.price(s0, k, r, b, t, sigma, isCall, false, sSteps, tSteps); final double relErr = Math.abs(1 - pdePDE / bsPrice); final double logErrorCeil = Math.log10(1.25 / size); final double logRelError = Math.log10(relErr); assertTrue("error exceeds ceiling " + logRelError + "\t" + logErrorCeil, logRelError < logErrorCeil); assertEquals("error smaller than expected", logErrorCeil, logRelError, 1e-1); } }
@Test public void europeanTest() { final double s0 = 10.0; final double[] kSet = {7.0, 9.0, 10.0, 13.0, 17.0 }; final double[] rSet = {0.0, 0.04, 0.2 }; final double[] qSet = {-0.05, 0.0, 0.1 }; final double[] tSet = {0.1, 2.0 }; final double sigma = 0.3; final boolean[] isCallSet = {true, false }; final int tSteps = 100; final int nu = 80; final int sSteps = nu * tSteps; for (final double k : kSet) { for (final double r : rSet) { for (final double q : qSet) { final double b = r - q; for (final double t : tSet) { for (final boolean isCall : isCallSet) { final double bsPrice = Math.exp(-r * t) * BlackFormulaRepository.price(s0 * Math.exp(b * t), k, t, sigma, isCall); final double pdePDE = PRICER.price(s0, k, r, b, t, sigma, isCall, false, sSteps, tSteps); final double absErr = Math.abs(pdePDE - bsPrice); final double relErr = Math.abs(1 - pdePDE / bsPrice); if (k < 17.0) { assertTrue(k + "\t" + r + "\t" + q + "\t" + t + "\t" + isCall + "\t" + bsPrice + "\t" + pdePDE + "\t" + absErr + "\t" + relErr, absErr < 3e-5); } else { assertTrue(k + "\t" + r + "\t" + q + "\t" + t + "\t" + isCall + "\t" + bsPrice + "\t" + pdePDE + "\t" + absErr + "\t" + relErr, absErr < 1e-4); } } } } } } }
@Test(enabled = false, description = "Disabled 02/10/14 as it is not passing") public void americanTest() { final double s0 = 10.0; final double[] kSet = {7.0, 9.0, 10.0, 13.0, 17.0 }; final double[] rSet = {0.0, 0.04, 0.2 }; final double[] qSet = {-0.05, 0.0, 0.1 }; final double[] tSet = {0.05, 0.25 }; final double sigma = 0.3; final boolean[] isCallSet = {true, false }; final int tSteps = 80; final int nu = 20; final int sSteps = nu * tSteps; for (final double k : kSet) { for (final double r : rSet) { for (final double q : qSet) { final double b = r - q; for (final double t : tSet) { for (final boolean isCall : isCallSet) { final double bsPrice = Math.exp(-r * t) * BlackFormulaRepository.price(s0 * Math.exp(b * t), k, t, sigma, isCall); final double amAprox = AMERICAN_APPOX_PRCIER.price(s0, k, r, b, t, sigma, isCall); final double pdePrice = PRICER.price(s0, k, r, b, t, sigma, isCall, true, sSteps, tSteps); assertTrue(k + "\t" + r + "\t" + q + "\t" + t + "\t" + isCall + "\t" + bsPrice + "\t" + amAprox + "\t" + pdePrice, (pdePrice - amAprox) > -5e-6); final double absErr = Math.abs(pdePrice - amAprox); final double relErr = Math.abs(1 - pdePrice / amAprox); assertTrue(k + "\t" + r + "\t" + q + "\t" + t + "\t" + isCall + "\t" + amAprox + "\t" + pdePrice + "\t" + absErr + "\t" + relErr, absErr < 1e-2); } } } } } }
@Test public void nonuniformGridTest() { final double s0 = 10.0; final double k = 13.0; final double r = 0.06; final double b = 0.04; final double t = 1.75; final double sigma = 0.5; final boolean isCall = false; final double beta = 0.01; final double lambda = 0.0; final double sd = 6.0; final int tSteps = 100; final double nu = 10; final int sSteps = (int) (nu * tSteps); final double bsPrice = Math.exp(-r * t) * BlackFormulaRepository.price(s0 * Math.exp(b * t), k, t, sigma, isCall); final double pdePrice1 = PRICER.price(s0, k, r, b, t, sigma, isCall, false, sSteps, tSteps); final double pdePrice2 = PRICER.price(s0, k, r, b, t, sigma, isCall, false, sSteps, tSteps, beta, lambda, sd); final double relErr1 = Math.abs(pdePrice1 / bsPrice - 1.0); final double relErr2 = Math.abs(pdePrice2 / bsPrice - 1.0); assertEquals(0, relErr1, 5e-4); assertEquals(0, relErr2, 2e-6); }
@Test(enabled = false) public void optNuTest() { final double s0 = 10.0; final double k = 13.0; final double r = 0.06; final double b = 0.04; final double t = 1.75; final double sigma = 0.5; final boolean isCall = true; final double nu = 80; int tSteps = 100; int sSteps = (int) (nu * tSteps); double pdePDE = PRICER.price(s0, k, r, b, t, sigma, isCall, false, sSteps, tSteps); final double[] nuSet = new double[] {1, 2, 5, 10, 20, 40, 60, 80, 100, 125, 150, 200, 500 }; final int n = (int) 1e9; for (final double nu1 : nuSet) { tSteps = (int) Math.sqrt(n / nu1); sSteps = n / tSteps; final double bsPrice = Math.exp(-r * t) * BlackFormulaRepository.price(s0 * Math.exp(b * t), k, t, sigma, isCall); final double startTime = System.nanoTime() / 1e6; pdePDE = PRICER.price(s0, k, r, b, t, sigma, isCall, false, sSteps, tSteps); final double endTime = System.nanoTime() / 1e6; final double duration = endTime - startTime; final double relErr = Math.abs(1 - pdePDE / bsPrice); System.out.println(tSteps + "\t" + sSteps + "\t" + duration + "\t" + nu1 + "\t" + relErr); } }
@Test(enabled = false) public void unifromGridAmericanCallTest() { final double s0 = 90; final double k = 100; final double r = -1e-5; final double b = 0.04; final double sigma = 0.35; final double t = 0.5; final boolean isCall = false; System.out.println(r + "\t" + b + "\t" + -0.5 * sigma * sigma * (b / sigma / sigma - 0.5) * (b / sigma / sigma - 0.5)); final int tSteps = 100; final int nu = 80; final int sSteps = nu * tSteps; final double bsPrice = Math.exp(-r * t) * BlackFormulaRepository.price(s0 * Math.exp(b * t), k, t, sigma, isCall); final double bsPrice2 = Math.exp(-(r - b) * t) * BlackFormulaRepository.price(k * Math.exp(-b * t), s0, t, sigma, !isCall); final double amAprox = AMERICAN_APPOX_PRCIER.price(s0, k, r, b, t, sigma, isCall); final double pdePrice = PRICER.price(s0, k, r, b, t, sigma, isCall, true, sSteps, tSteps); final double pdePricePC = 0.0; System.out.println(b + "\t" + bsPrice + "\t" + bsPrice2 + "\t" + amAprox + "\t" + pdePrice + "\t" + pdePricePC + "\t" + (1 - pdePrice / bsPrice)); }
@Test(enabled = false) public void debugTest() { System.out.println("BlackScholesMertonPDEPricerTest.debugTest"); final BjerksundStenslandModel amPricer = new BjerksundStenslandModel(); final BlackScholesMertonPDEPricer pricer = new BlackScholesMertonPDEPricer(false); final double s0 = 10.0; final double k = 7.0; final double r = 0.2; final double b = 0.1; final double t = 2.0; final double sigma = 0.3; final boolean isCall = false; final boolean isAmerican = true; final double nu = 80; final int tSteps = 500; final int sSteps = (int) (nu * tSteps); pricer.price(s0, k, r, b, t, sigma, isCall, false, sSteps, tSteps); final double df = Math.exp(-r * t); final double fwd = s0 * Math.exp(b * t); final double bsPrice = df * BlackFormulaRepository.price(fwd, k, t, sigma, isCall); final double startTime = System.nanoTime() / 1e6; final double pdePrice = pricer.price(s0, k, r, b, t, sigma, isCall, isAmerican, sSteps, tSteps); final double endTime = System.nanoTime() / 1e6; final double duration = endTime - startTime; final double amPrice = amPricer.price(s0, k, r, b, t, sigma, isCall); final double relErr = Math.abs(1 - pdePrice / amPrice); System.out.println(tSteps + "\t" + sSteps + "\t" + duration + df * fwd + "\t" + amPrice + "\t" + pdePrice + "\t" + relErr); }