BinomialOptionModel extends TreeOptionModel<OptionDefinition, T> { @Override public Function1D<T, RecombiningBinomialTree<DoublesPair>> getTreeGeneratingFunction(final OptionDefinition definition) { return new Function1D<T, RecombiningBinomialTree<DoublesPair>>() { @SuppressWarnings({"synthetic-access" }) @Override public RecombiningBinomialTree<DoublesPair> evaluate(final T data) { final DoublesPair[] tempResults = new DoublesPair[_j]; final DoublesPair[][] spotAndOptionPrices = new DoublesPair[_maxDepthToSave + 1][_maxWidthToSave]; final OptionPayoffFunction<T> payoffFunction = definition.getPayoffFunction(); final OptionExerciseFunction<T> exerciseFunction = definition.getExerciseFunction(); final double u = _model.getUpFactor(definition, data, _n, _j); final double d = _model.getDownFactor(definition, data, _n, _j); final RecombiningBinomialTree<Double> pTree = _model.getUpProbabilityTree(definition, data, _n, _j); final double spot = data.getSpot(); final double t = definition.getTimeToExpiry(data.getDate()); final double r = data.getInterestRate(t); double newSpot = spot * Math.pow(d, _n); for (int i = 0; i < _j; i++) { tempResults[i] = DoublesPair.of(newSpot, payoffFunction.getPayoff((T) data.withSpot(newSpot), 0.)); if (_n == _maxDepthToSave) { spotAndOptionPrices[_n][i] = tempResults[i]; } newSpot *= u / d; } final double df = Math.exp(-r * t / _n); double optionValue, spotValue; T newData; double p; for (int i = _n - 1; i >= 0; i--) { for (int j = 0; j < RecombiningBinomialTree.NODES.evaluate(i); j++) { p = pTree.getNode(i, j); optionValue = df * ((1 - p) * tempResults[j].second + p * tempResults[j + 1].second); spotValue = tempResults[j].first / d; newData = (T) data.withSpot(spotValue); tempResults[j] = DoublesPair.of(spotValue, exerciseFunction.shouldExercise(newData, optionValue) ? payoffFunction.getPayoff(newData, optionValue) : optionValue); if (i <= _maxDepthToSave) { spotAndOptionPrices[i][j] = tempResults[j]; } } } return new RecombiningBinomialTree<>(spotAndOptionPrices); } }; } BinomialOptionModel(final BinomialOptionModelDefinition<OptionDefinition, T> model);  BinomialOptionModel(final BinomialOptionModelDefinition<OptionDefinition, T> model, final int n);  BinomialOptionModel(final BinomialOptionModelDefinition<OptionDefinition, T> model, final int n, final int maxDepthToSave); @Override GreekResultCollection getGreeks(final OptionDefinition definition, final T data, final Set<Greek> requiredGreeks); GreekVisitor<Double> getGreekVisitor(final Function1D<T, RecombiningBinomialTree<DoublesPair>> treeFunction, final T data, final OptionDefinition definition); @Override Function1D<T, RecombiningBinomialTree<DoublesPair>> getTreeGeneratingFunction(final OptionDefinition definition);  }
@Test public void testEuropeanCallTree() { final ZonedDateTime date = DateUtils.getUTCDate(2009, 1, 1); final StandardOptionDataBundle data = new StandardOptionDataBundle(YieldCurve.from(ConstantDoublesCurve.from(0.06)), 0., new VolatilitySurface(ConstantDoublesSurface.from(0.)), 100., date); final OptionDefinition option = new EuropeanVanillaOptionDefinition(100, new Expiry(DateUtils.getDateOffsetWithYearFraction(date, 1)), true); final Function1D<StandardOptionDataBundle, RecombiningBinomialTree<DoublesPair>> f = BINOMIAL_THREE_STEPS.getTreeGeneratingFunction(option); final DoublesPair[][] result = f.evaluate(data).getNodes(); final DoublesPair[][] expected = new DoublesPair[4][4]; expected[0][0] = DoublesPair.of(100., 10.1457); expected[1][0] = DoublesPair.of(90.91, 3.2545); expected[1][1] = DoublesPair.of(110., 15.4471); expected[2][0] = DoublesPair.of(82.64, 0.); expected[2][1] = DoublesPair.of(100., 5.7048); expected[2][2] = DoublesPair.of(121., 22.9801); expected[3][0] = DoublesPair.of(75.13, 0.); expected[3][1] = DoublesPair.of(90.91, 0.); expected[3][2] = DoublesPair.of(110., 10.); expected[3][3] = DoublesPair.of(133.1, 33.1); assertTrees(expected, result, 4); }
@Test public void testAmericanPutTree() { final ZonedDateTime date = DateUtils.getUTCDate(2009, 1, 1); final StandardOptionDataBundle data = new StandardOptionDataBundle(YieldCurve.from(ConstantDoublesCurve.from(0.06)), 0., new VolatilitySurface(ConstantDoublesSurface.from(0.)), 100., date); final OptionDefinition option = new AmericanVanillaOptionDefinition(100, new Expiry(DateUtils.getDateOffsetWithYearFraction(date, 1)), false); final Function1D<StandardOptionDataBundle, RecombiningBinomialTree<DoublesPair>> f = BINOMIAL_THREE_STEPS.getTreeGeneratingFunction(option); final DoublesPair[][] result = f.evaluate(data).getNodes(); final DoublesPair[][] expected = new DoublesPair[4][4]; expected[0][0] = DoublesPair.of(100., 4.6546); expected[1][0] = DoublesPair.of(90.91, 9.2356); expected[1][1] = DoublesPair.of(110., 1.5261); expected[2][0] = DoublesPair.of(82.64, 17.3554); expected[2][1] = DoublesPair.of(100., 3.7247); expected[2][2] = DoublesPair.of(121., 0.); expected[3][0] = DoublesPair.of(75.13, 24.8685); expected[3][1] = DoublesPair.of(90.91, 9.0909); expected[3][2] = DoublesPair.of(110., 0.); expected[3][3] = DoublesPair.of(133.1, 0.); assertTrees(expected, result, 4); }