public virtual void test_trinomialTree() { int nSteps = 135; LatticeSpecification[] lattices = new LatticeSpecification[] { new CoxRossRubinsteinLatticeSpecification(), new TrigeorgisLatticeSpecification() }; double tol = 5.0e-3; foreach (bool isCall in new bool[] { true, false }) { foreach (double strike in STRIKES) { foreach (double interest in INTERESTS) { foreach (double vol in VOLS) { foreach (double dividend in DIVIDENDS) { OptionFunction function = EuropeanVanillaOptionFunction.of(strike, TIME, PutCall.ofPut(!isCall), nSteps); double exact = BlackScholesFormulaRepository.price(SPOT, strike, TIME, vol, interest, interest - dividend, isCall); foreach (LatticeSpecification lattice in lattices) { double computed = TRINOMIAL_TREE.optionPrice(function, lattice, SPOT, vol, interest, dividend); assertEquals(computed, exact, Math.Max(exact, 1d) * tol); } } } } } } }
/// <summary> /// Price an option under the specified trinomial lattice. /// <para> /// It is assumed that the volatility, interest rate and continuous dividend rate are constant /// over the lifetime of the option. /// /// </para> /// </summary> /// <param name="function"> the option </param> /// <param name="lattice"> the lattice specification </param> /// <param name="spot"> the spot </param> /// <param name="volatility"> the volatility </param> /// <param name="interestRate"> the interest rate </param> /// <param name="dividendRate"> the dividend rate </param> /// <returns> the option price </returns> public virtual double optionPrice(OptionFunction function, LatticeSpecification lattice, double spot, double volatility, double interestRate, double dividendRate) { int nSteps = function.NumberOfSteps; double timeToExpiry = function.TimeToExpiry; double dt = timeToExpiry / (double)nSteps; double discount = Math.Exp(-interestRate * dt); DoubleArray @params = lattice.getParametersTrinomial(volatility, interestRate - dividendRate, dt); double middleFactor = @params.get(1); double downFactor = @params.get(2); double upProbability = @params.get(3); double midProbability = @params.get(4); double downProbability = @params.get(5); ArgChecker.isTrue(upProbability > 0d, "upProbability should be greater than 0"); ArgChecker.isTrue(upProbability < 1d, "upProbability should be smaller than 1"); ArgChecker.isTrue(midProbability > 0d, "midProbability should be greater than 0"); ArgChecker.isTrue(midProbability < 1d, "midProbability should be smaller than 1"); ArgChecker.isTrue(downProbability > 0d, "downProbability should be greater than 0"); DoubleArray values = function.getPayoffAtExpiryTrinomial(spot, downFactor, middleFactor); for (int i = nSteps - 1; i > -1; --i) { values = function.getNextOptionValues(discount, upProbability, midProbability, downProbability, values, spot, downFactor, middleFactor, i); } return(values.get(0)); }