TrinomialOptionModel extends TreeOptionModel<OptionDefinition, T> { @Override public Function1D<T, RecombiningTrinomialTree<DoublesPair>> getTreeGeneratingFunction(final OptionDefinition definition) { return new Function1D<T, RecombiningTrinomialTree<DoublesPair>>() { @SuppressWarnings({"synthetic-access" }) @Override public RecombiningTrinomialTree<DoublesPair> evaluate(final T data) { 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 m = _model.getMidFactor(definition, data, _n, _j); final double d = _model.getDownFactor(definition, data, _n, _j); final double spot = data.getSpot(); final double t = definition.getTimeToExpiry(data.getDate()); final double r = data.getInterestRate(t); final double edx = Math.exp(_model.getDX(definition, data, _n, _j)); final double df = Math.exp(-r * t / _n); double newSpot = spot * Math.pow(edx, -_n); final DoublesPair[] tempResults = new DoublesPair[_j]; 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 *= edx; } double optionValue, spotValue; T newData; for (int i = _n - 1; i >= 0; i--) { for (int j = 1; j <= RecombiningTrinomialTree.NODES.evaluate(i); j++) { optionValue = df * (u * tempResults[j + 1].second + m * tempResults[j].second + d * tempResults[j - 1].second); spotValue = df * tempResults[j].first; newData = (T) data.withSpot(spotValue); tempResults[j - 1] = DoublesPair.of(spotValue, exerciseFunction.shouldExercise(newData, optionValue) ? payoffFunction.getPayoff(newData, optionValue) : optionValue); if (i <= _maxDepthToSave) { spotAndOptionPrices[i][j - 1] = tempResults[j - 1]; } } } return new RecombiningTrinomialTree<>(spotAndOptionPrices); } }; } TrinomialOptionModel(final TrinomialOptionModelDefinition<OptionDefinition, T> model);  TrinomialOptionModel(final TrinomialOptionModelDefinition<OptionDefinition, T> model, final int n);  TrinomialOptionModel(final TrinomialOptionModelDefinition<OptionDefinition, T> model, final int n, final int maxDepthToSave); @Override GreekResultCollection getGreeks(final OptionDefinition definition, final T data, final Set<Greek> requiredGreeks); @Override Function1D<T, RecombiningTrinomialTree<DoublesPair>> getTreeGeneratingFunction(final OptionDefinition definition);  }
@Test public void test() { final TrinomialOptionModel<StandardOptionDataBundle> model = new TrinomialOptionModel<>(TRINOMIAL, 3); final Function1D<StandardOptionDataBundle, RecombiningTrinomialTree<DoublesPair>> f = model.getTreeGeneratingFunction(CALL); final DoublesPair[][] tree = f.evaluate(DATA).getNodes(); final DoublesPair[][] expected = new DoublesPair[4][7]; final double df1 = Math.exp(-0.02); final double df2 = Math.exp(-0.04); final double df3 = Math.exp(-0.06); expected[0][0] = DoublesPair.of(df3 * 100., 8.4253); expected[1][0] = DoublesPair.of(df2 * 81.87, 0.6525); expected[1][1] = DoublesPair.of(df2 * 100., 6.4148); expected[1][2] = DoublesPair.of(df2 * 122.14, 24.0802); expected[2][0] = DoublesPair.of(df1 * 67.03, 0.); expected[2][1] = DoublesPair.of(df1 * 81.87, 0.); expected[2][2] = DoublesPair.of(df1 * 100., 3.8008); expected[2][3] = DoublesPair.of(df1 * 122.14, 22.9051); expected[2][4] = DoublesPair.of(df1 * 149.18, 49.6782); expected[3][0] = DoublesPair.of(54.88, 0.); expected[3][1] = DoublesPair.of(67.03, 0.); expected[3][2] = DoublesPair.of(81.87, 0.); expected[3][3] = DoublesPair.of(100., 0.); expected[3][4] = DoublesPair.of(122.14, 22.1403); expected[3][5] = DoublesPair.of(149.18, 49.1825); expected[3][6] = DoublesPair.of(182.21, 82.2119); for (int i = 0; i < 4; i++) { for (int j = 0; j < RecombiningTrinomialTree.NODES.evaluate(i); j++) { assertEquals(tree[i][j].first, expected[i][j].first, 1e-2); assertEquals(tree[i][j].second, expected[i][j].second, 1e-4); } } }