RollGeskeWhaleyModel { public double price(final double spot, final double strike, final double interestRate, final double timeToExpiry, final double volatility, final double[] dividends, final double[] dividendTimes) { ArgumentChecker.isTrue(spot > 0., "spot is not positive"); ArgumentChecker.isTrue(strike > 0., "strike is not positive"); ArgumentChecker.isFalse(Double.isNaN(interestRate), "interestRate is NaN"); ArgumentChecker.isTrue(timeToExpiry > 0., "timeToExpiry is not positive"); ArgumentChecker.isTrue(volatility >= -0., "volatility is negative"); ArgumentChecker.notNull(dividends, "dividends"); ArgumentChecker.notNull(dividendTimes, "dividendTimes"); final int nDivs = dividends.length; ArgumentChecker.isTrue(nDivs == dividendTimes.length, "dividends and dividendTimes should be the same length"); for (int i = 0; i < nDivs; ++i) { ArgumentChecker.isTrue(Doubles.isFinite(dividends[i]), "dividends contains infinity or NaN"); ArgumentChecker.isTrue(Doubles.isFinite(dividendTimes[i]), "dividendTimes contains infinity or NaN"); } if (dividendTimes[0] > timeToExpiry) { return BlackScholesFormulaRepository.price(spot, strike, timeToExpiry, volatility, interestRate, interestRate, true); } final int position = FunctionUtils.getLowerBoundIndex(dividendTimes, timeToExpiry); double modSpot = spot; for (int i = 0; i < position; ++i) { modSpot -= (dividends[i] * Math.exp(-interestRate * dividendTimes[i])); } return price(modSpot, strike, interestRate, timeToExpiry, volatility, dividends[position], dividendTimes[position]); } RollGeskeWhaleyModel(); double price(final double spot, final double strike, final double interestRate, final double timeToExpiry, final double volatility, final double[] dividends, final double[] dividendTimes); double[] getPriceAdjoint(final double spot, final double strike, final double interestRate, final double timeToExpiry, final double volatility, final double[] dividends,
      final double[] dividendTimes); double impliedVolatility(final double price, final double spot, final double strike, final double interestRate, final double timeToExpiry, final double[] dividends,
      final double[] dividendTimes); double price(final double spot, final double strike, final double interestRate, final double timeToExpiry, final double volatility, final double dividendAmount, final double dividendTime); double[] getPriceAdjoint(final double spot, final double strike, final double interestRate, final double timeToExpiry, final double volatility, final double dividendAmount,
      final double dividendTime); double impliedVolatility(final double price, final double spot, final double strike, final double interestRate, final double timeToExpiry, final double dividendAmount,
      final double dividendTime);  }
@Test public void priceLimtedTest() { final int nStrikes = STRIKES_INPUT.length; final int nVols = VOLS.length; final int nInt = INTEREST_RATES.length; final double eps = 1.e-5; for (int i = 0; i < nStrikes; ++i) { for (int j = 0; j < nVols; ++j) { for (int k = 0; k < nInt; ++k) { final double dividendTimes = TIME_TO_EXPIRY - eps; final double dividend = eps; final double price = MODEL.price(SPOT, STRIKES_INPUT[i], INTEREST_RATES[k], TIME_TO_EXPIRY, VOLS[j], dividend, dividendTimes); final double priceZeroDiv = MODEL.price(SPOT, STRIKES_INPUT[i], INTEREST_RATES[k], TIME_TO_EXPIRY, VOLS[j], 0., dividendTimes); final double priceZeroTime = MODEL.price(SPOT, STRIKES_INPUT[i], INTEREST_RATES[k], TIME_TO_EXPIRY, VOLS[j], DIVIDENDS[0], 0.); final double priceSmallTime = MODEL.price(SPOT, STRIKES_INPUT[i], INTEREST_RATES[k], TIME_TO_EXPIRY, VOLS[j], DIVIDENDS[0], eps); final double bs = BlackScholesFormulaRepository.price(SPOT, STRIKES_INPUT[i], TIME_TO_EXPIRY, VOLS[j], INTEREST_RATES[k], INTEREST_RATES[k], true); final double bsMod = BlackScholesFormulaRepository.price(SPOT - dividend, STRIKES_INPUT[i], TIME_TO_EXPIRY, VOLS[j], INTEREST_RATES[k], INTEREST_RATES[k], true); assertEquals(bsMod, price, Math.max(eps, Math.abs(bs) * eps)); assertEquals(bs, priceZeroDiv, 1.e-14); assertEquals(priceSmallTime, priceZeroTime, Math.max(eps, Math.abs(priceZeroTime) * eps)); } } } }
@Test public void priceBjsTest() { final int nStrikes = STRIKES_INPUT.length; final int nVols = VOLS.length; final int nInt = INTEREST_RATES.length; for (int i = 0; i < nStrikes; ++i) { for (int j = 0; j < nVols; ++j) { for (int k = 0; k < nInt; ++k) { final double dividend = SPOT * 1.e-3; final double dividendTime = TIME_TO_EXPIRY * 1.e-3; final double price = MODEL.price(SPOT, STRIKES_INPUT[i], INTEREST_RATES[k], TIME_TO_EXPIRY, VOLS[j], dividend, dividendTime); final double modSpot = SPOT - dividend * Math.exp(-INTEREST_RATES[k] * dividendTime); final BjerksundStenslandModel bjs = new BjerksundStenslandModel(); final double bjsPrice = bjs.price(modSpot, STRIKES_INPUT[i], INTEREST_RATES[k], INTEREST_RATES[k], TIME_TO_EXPIRY, VOLS[j], true); assertEquals(bjsPrice, price, Math.max(1.e-2, Math.abs(bjsPrice) * 1.e-2)); } } } }
@Test public void treeComparisonTest() { final int nStrikes = STRIKES_INPUT.length; final int nVols = VOLS.length; final int nInt = INTEREST_RATES.length; final int nDiv = MULTI_DIVIDENDS.length; final int nDivT = MULTI_DIVIDEND_TIMES.length; final LatticeSpecification lattice = new LeisenReimerLatticeSpecification(); final int steps = 101; for (int i = 0; i < nStrikes; ++i) { for (int j = 0; j < nVols; ++j) { for (int k = 0; k < nInt; ++k) { for (int l = 0; l < nDiv; ++l) { for (int m = 0; m < nDivT - 1; ++m) { if (MULTI_DIVIDENDS[l][2] != 0.) { final double price = MODEL.price(SPOT, STRIKES_INPUT[i], INTEREST_RATES[k], TIME_TO_EXPIRY, VOLS[j], MULTI_DIVIDENDS[l][2], MULTI_DIVIDEND_TIMES[m][2]); final OptionFunctionProvider1D function = new AmericanVanillaOptionFunctionProvider(STRIKES_INPUT[i], TIME_TO_EXPIRY, steps, true); final DividendFunctionProvider cashDividend = new CashDividendFunctionProvider(new double[] {MULTI_DIVIDEND_TIMES[m][2] }, new double[] {MULTI_DIVIDENDS[l][2] }); final BinomialTreeOptionPricingModel model = new BinomialTreeOptionPricingModel(); final double priceTree = model.getPrice(lattice, function, SPOT, VOLS[j], INTEREST_RATES[k], cashDividend); assertEquals(priceTree, price, Math.max(2.e-2, priceTree * 5.e-2)); } } } } } } }