BjerksundStenslandModel { protected double[] bivariateNormDiv(double a, double b, boolean posRho) { double rho = posRho ? RHO : -RHO; double na = NORMAL.getPDF(a); double nb = NORMAL.getPDF(b); double x1 = (b - rho * a) / RHO_STAR; double x2 = (a - rho * b) / RHO_STAR; double nx1 = NORMAL.getPDF(x1); double nx2 = NORMAL.getPDF(x2); double cnx1 = NORMAL.getCDF(x1); double cnx2 = NORMAL.getCDF(x2); double[] res = new double[5]; res[0] = na * cnx1; res[1] = nb * cnx2; res[2] = -na * (a * cnx1 + rho / RHO_STAR * nx1); res[3] = -nb * (b * cnx2 + rho / RHO_STAR * nx2); res[4] = na * nx1 / RHO_STAR; return res; }  Function1D<StandardOptionDataBundle, Double> getPricingFunction(final AmericanVanillaOptionDefinition definition); double price(double s0, double k, double r, double b, double t, double sigma, boolean isCall); double[] getPriceAdjoint(double s0, double k, double r, double b, double t, double sigma, boolean isCall); double[] getPriceDeltaGamma(double s0, double k, double r, double b, double t, double sigma, boolean isCall); double[] getPriceAndVega(double s0, double k, double r, double b, double t, double sigma, boolean isCall); Function1D<Double, double[]> getPriceAndVegaFunction(final double s0, final double k, final double r, final double b, final double t, final boolean isCall); double impliedVolatility(double price, double s0, double k, double r, double b, double t, boolean isCall); double impliedVolatility(double price, double s0, double k, double r, double b, double t, boolean isCall, double guess);  }
@Test public void biVarNormTest() { final double rho = Math.sqrt(0.5 * (Math.sqrt(5) - 1)); final double a = 1.2; final double b = -0.6; final double eps = 1e-5; final BjerksundStenslandModel bs = new BjerksundStenslandModel(); final double cent = BIVARIATE_NORMAL.getCDF(new double[] {a, b, rho }); final double[] sense = bs.bivariateNormDiv(a, b, true); final double aUp = BIVARIATE_NORMAL.getCDF(new double[] {a + eps, b, rho }); final double aDown = BIVARIATE_NORMAL.getCDF(new double[] {a - eps, b, rho }); final double bUp = BIVARIATE_NORMAL.getCDF(new double[] {a, b + eps, rho }); final double bDown = BIVARIATE_NORMAL.getCDF(new double[] {a, b - eps, rho }); final double aUpbUp = BIVARIATE_NORMAL.getCDF(new double[] {a + eps, b + eps, rho }); final double aDownbDown = BIVARIATE_NORMAL.getCDF(new double[] {a - eps, b - eps, rho }); final double aUpbDown = BIVARIATE_NORMAL.getCDF(new double[] {a + eps, b - eps, rho }); final double aDownbUp = BIVARIATE_NORMAL.getCDF(new double[] {a - eps, b + eps, rho }); double fd = (aUp - aDown) / 2 / eps; assertEquals("dB/da", fd, sense[0], Math.abs(fd) * 1e-5); fd = (bUp - bDown) / 2 / eps; assertEquals("dB/db", fd, sense[1], Math.abs(fd) * 1e-5); fd = (aUp + aDown - 2 * cent) / eps / eps; assertEquals("d^2B/da^2", fd, sense[2], Math.abs(fd) * 1e-4); fd = (bUp + bDown - 2 * cent) / eps / eps; assertEquals("d^2B/db^2", fd, sense[3], Math.abs(fd) * 1e-5); fd = (aUpbUp + aDownbDown - aUpbDown - aDownbUp) / 4 / eps / eps; assertEquals("d^2B/dadb", fd, sense[4], Math.abs(fd) * 2e-4); }