BinomialTreeOptionPricingModel extends TreeOptionPricingModel { @Override public GreekResultCollection getGreeks(final LatticeSpecification lattice, final OptionFunctionProvider1D function, final double spot, final double volatility, final double interestRate, final double dividend) { ArgumentChecker.notNull(lattice, "lattice"); ArgumentChecker.notNull(function, "function"); ArgumentChecker.isTrue(spot > 0., "Spot should be positive"); ArgumentChecker.isTrue(Doubles.isFinite(spot), "Spot should be finite"); ArgumentChecker.isTrue(volatility > 0., "volatility should be positive"); ArgumentChecker.isTrue(Doubles.isFinite(volatility), "volatility should be finite"); ArgumentChecker.isTrue(Doubles.isFinite(interestRate), "interestRate should be finite"); ArgumentChecker.isTrue(Doubles.isFinite(dividend), "dividend should be finite"); final GreekResultCollection collection = new GreekResultCollection(); final LatticeSpecification modLattice = (lattice instanceof TimeVaryingLatticeSpecification) ? new TrigeorgisLatticeSpecification() : lattice; final int nSteps = function.getNumberOfSteps(); final double strike = function.getStrike(); final double timeToExpiry = function.getTimeToExpiry(); final double dt = timeToExpiry / nSteps; final double discount = Math.exp(-interestRate * dt); final double[] params = modLattice.getParameters(spot, strike, timeToExpiry, volatility, interestRate - dividend, nSteps, dt); final double upFactor = params[0]; final double downFactor = params[1]; final double upProbability = params[2]; final double downProbability = params[3]; final double upOverDown = upFactor / downFactor; ArgumentChecker.isTrue(upProbability > 0., "upProbability should be greater than 0."); ArgumentChecker.isTrue(upProbability < 1., "upProbability should be smaller than 1."); double[] values = function.getPayoffAtExpiry(spot, downFactor, upOverDown); final double[] res = new double[4]; final double[] pForDelta = new double[] {spot * downFactor, spot * upFactor }; final double[] pForGamma = new double[] {pForDelta[0] * downFactor, pForDelta[0] * upFactor, pForDelta[1] * upFactor }; for (int i = nSteps - 1; i > -1; --i) { values = function.getNextOptionValues(discount, upProbability, downProbability, values, spot, 0., downFactor, upOverDown, i); if (i == 2) { res[2] = 2. * ((values[2] - values[1]) / (pForGamma[2] - pForGamma[1]) - (values[1] - values[0]) / (pForGamma[1] - pForGamma[0])) / (pForGamma[2] - pForGamma[0]); res[3] = values[1]; } if (i == 1) { res[1] = (values[1] - values[0]) / (pForDelta[1] - pForDelta[0]); } } res[0] = values[0]; res[3] = modLattice.getTheta(spot, volatility, interestRate, dividend, dt, res); collection.put(Greek.FAIR_PRICE, res[0]); collection.put(Greek.DELTA, res[1]); collection.put(Greek.GAMMA, res[2]); collection.put(Greek.THETA, res[3]); return collection; }  @Override double getPrice(final LatticeSpecification lattice, final OptionFunctionProvider1D function, final double spot, final double volatility, final double interestRate, final double dividend); @Override double getPrice(final OptionFunctionProvider1D function, final double spot, final double[] volatility, final double[] interestRate, final double[] dividend); @Override double getPrice(final LatticeSpecification lattice, final OptionFunctionProvider1D function, final double spot, final double volatility, final double interestRate,
      final DividendFunctionProvider dividend); @Override double getPrice(final OptionFunctionProvider2D function, final double spot1, final double spot2, final double volatility1, final double volatility2, final double correlation,
      final double interestRate, final double dividend1, final double dividend2); @Override GreekResultCollection getGreeks(final LatticeSpecification lattice, final OptionFunctionProvider1D function, final double spot, final double volatility, final double interestRate,
      final double dividend); @Override GreekResultCollection getGreeks(final OptionFunctionProvider1D function, final double spot, final double[] volatility, final double[] interestRate, final double[] dividend); @Override GreekResultCollection getGreeks(final LatticeSpecification lattice, final OptionFunctionProvider1D function, final double spot, final double volatility, final double interestRate,
      final DividendFunctionProvider dividend); @Override double[] getGreeks(final OptionFunctionProvider2D function, final double spot1, final double spot2, final double volatility1, final double volatility2, final double correlation,
      final double interestRate, final double dividend1, final double dividend2); @Override double getPrice(final OptionFunctionProvider1D function, final StandardOptionDataBundle data);  }
@Test(expectedExceptions = IllegalArgumentException.class) public void negativeSpotGetGreeksTest() { _model.getGreeks(_lattice, _function1D, -SPOT, VOL, INTEREST, DIVIDEND); }
@Test(expectedExceptions = IllegalArgumentException.class) public void negativeVolGetGreeksTest() { _model.getGreeks(_lattice, _function1D, SPOT, -VOL, INTEREST, DIVIDEND); }
@Test(expectedExceptions = IllegalArgumentException.class) public void negativeProbabilityGetGreeksTest() { _model.getGreeks(_lattice, _function1D, SPOT, 0.01, -10. * INTEREST, DIVIDEND); }
@Test(expectedExceptions = IllegalArgumentException.class) public void largeProbabilityGetGreeksTest() { _model.getGreeks(_lattice, _function1D, SPOT, 0.001, INTEREST, DIVIDEND); }
@Test(expectedExceptions = IllegalArgumentException.class) public void negativeSpotGetGreeksDivTest() { _model.getGreeks(_lattice, _function1D, -SPOT, VOL, INTEREST, _cashDividend); }
@Test(expectedExceptions = IllegalArgumentException.class) public void negativeVolGetGreeksDivTest() { _model.getGreeks(_lattice, _function1D, SPOT, -VOL, INTEREST, _cashDividend); }
@Test(expectedExceptions = IllegalArgumentException.class) public void negativeProbabilityGetGreeksDivTest() { _model.getGreeks(_lattice, _function1D, SPOT, 0.01, -10. * INTEREST, _cashDividend); }
@Test(expectedExceptions = IllegalArgumentException.class) public void largeProbabilityGetGreeksDivTest() { _model.getGreeks(_lattice, _function1D, SPOT, 0.001, INTEREST, _cashDividend); }
@Test(expectedExceptions = IllegalArgumentException.class) public void negativeSpotGetGreeksVaryingTest() { _model.getGreeks(_function1D, -SPOT, VOLS, INTERESTS, DIVIDENDS); }
@Test(expectedExceptions = IllegalArgumentException.class) public void negativeVolGetGreeksVaryingTest() { VOLS[2] = -VOLS[2]; _model.getGreeks(_function1D, SPOT, VOLS, INTERESTS, DIVIDENDS); }
@Test(expectedExceptions = IllegalArgumentException.class) public void largeProbabilityGetGreeksVaryingTest() { final OptionFunctionProvider1D function = new EuropeanVanillaOptionFunctionProvider(105.1, 4.2e18, STEPS, false); VOLS[2] = 1.e-9; _model.getGreeks(function, SPOT, VOLS, INTERESTS, DIVIDENDS); }
@Test(expectedExceptions = IllegalArgumentException.class) public void wrongRateLengthGreeksVaryingTest() { _model.getGreeks(_function1D, SPOT, VOLS, new double[] {INTEREST }, DIVIDENDS); }
@Test(expectedExceptions = IllegalArgumentException.class) public void wrongDividendLengthGreeksVaryingTest() { _model.getGreeks(_function1D, SPOT, VOLS, INTERESTS, new double[] {DIVIDEND }); }
@Test(expectedExceptions = IllegalArgumentException.class) public void wrongVolsLengthGreeksVaryingTest() { _model.getGreeks(_function1D, SPOT, new double[] {VOL }, INTERESTS, DIVIDENDS); }
@Test(expectedExceptions = IllegalArgumentException.class) public void negativeSpot1GetGreeksTwoAssetTest() { _model.getGreeks(_function2D, -SPOT, SPOT, VOL, VOL, 0.5, INTEREST, DIVIDEND, DIVIDEND); }
@Test(expectedExceptions = IllegalArgumentException.class) public void negativeSpot2GetGreeksTwoAssetTest() { _model.getGreeks(_function2D, SPOT, -SPOT, VOL, VOL, 0.5, INTEREST, DIVIDEND, DIVIDEND); }
@Test(expectedExceptions = IllegalArgumentException.class) public void negativeVol1GetGreeksTwoAssetTest() { _model.getGreeks(_function2D, SPOT, SPOT, -VOL, VOL, 0.5, INTEREST, DIVIDEND, DIVIDEND); }
@Test(expectedExceptions = IllegalArgumentException.class) public void negativeVol2GetGreeksTwoAssetTest() { _model.getGreeks(_function2D, SPOT, SPOT, VOL, -VOL, 0.5, INTEREST, DIVIDEND, DIVIDEND); }
@Test(expectedExceptions = IllegalArgumentException.class) public void largeUUProbability2GetGreeksTwoAssetTest() { _model.getGreeks(_function2D, SPOT, SPOT, VOL, VOL, 0.5, 100. * INTEREST, DIVIDEND, DIVIDEND); }
@Test(expectedExceptions = IllegalArgumentException.class) public void negativeUDProbabilityGetGreeksTwoAssetTest() { _model.getGreeks(_function2D, SPOT, SPOT, VOL, VOL, 0.5, INTEREST, 100. * DIVIDEND, -100. * DIVIDEND); }
@Test(expectedExceptions = IllegalArgumentException.class) public void largeUDProbability2GetGreeksTwoAssetTest() { _model.getGreeks(_function2D, SPOT, SPOT, VOL, VOL, 0.5, INTEREST, -100. * DIVIDEND, 200. * DIVIDEND); }
@Test(expectedExceptions = IllegalArgumentException.class) public void negativeDUProbabilityGetGreeksTwoAssetTest() { final double vol = 10000.; final double vol2 = 10000.; final OptionFunctionProvider2D function2D = new EuropeanSpreadOptionFunctionProvider(105.1, 10., 10, false); _model.getGreeks(function2D, SPOT, SPOT, vol - 1.1, vol2 - 1, 0., -vol - 0.1, -0.5 * vol * vol, -vol2 - 0.5 * vol2 * vol2); }
@Test(expectedExceptions = IllegalArgumentException.class) public void negativeDDProbabilityGetGreeksTwoAssetTest() { final double vol = 10000000.; final double vol2 = 10000000.; final OptionFunctionProvider2D function2D = new EuropeanSpreadOptionFunctionProvider(105.1, 10., 10, false); _model.getGreeks(function2D, SPOT, SPOT, vol - 1.01, vol2 - 1., 0., -vol + 2.1, -0.5 * vol * vol, -vol2 - 0.5 * vol2 * vol2); }
@Test(expectedExceptions = IllegalArgumentException.class) public void smallCorrelationGetGreeksTwoAssetTest() { _model.getGreeks(_function2D, SPOT, SPOT, VOL, VOL, -21.5, INTEREST, DIVIDEND, DIVIDEND); }
@Test(expectedExceptions = IllegalArgumentException.class) public void largeCorrelationGetGreeksTwoAssetTest() { _model.getGreeks(_function2D, SPOT, SPOT, VOL, VOL, 11.5, INTEREST, DIVIDEND, DIVIDEND); }