public virtual void test_optionPrice() { double tol = 1.0e-12; EuropeanVanillaOptionFunction test = EuropeanVanillaOptionFunction.of(STRIKE, TIME_TO_EXPIRY, PutCall.PUT, NUM); double spot = 100d; double u = 1.05; double d = 0.98; double m = Math.Sqrt(u * d); double up = 0.29; double dp = 0.25; double mp = 1d - up - dp; // test getPayoffAtExpiryTrinomial DoubleArray computedPayoff = test.getPayoffAtExpiryTrinomial(spot, d, m); int expectedSize = 2 * NUM + 1; assertEquals(computedPayoff.size(), expectedSize); for (int i = 0; i < expectedSize; ++i) { double price = spot * Math.Pow(u, 0.5 * i) * Math.Pow(d, NUM - 0.5 * i); double expectedPayoff = Math.Max(STRIKE - price, 0d); assertEquals(computedPayoff.get(i), expectedPayoff, tol); } // test getNextOptionValues double df = 0.92; int n = 2; DoubleArray values = DoubleArray.of(1.4, 0.9, 0.1, 0.05, 0.0, 0.0, 0.0); DoubleArray computedNextValues = test.getNextOptionValues(df, up, mp, dp, values, spot, d, m, n); DoubleArray expectedNextValues = DoubleArray.of(df * (1.4 * dp + 0.9 * mp + 0.1 * up), df * (0.9 * dp + 0.1 * mp + 0.05 * up), df * (0.1 * dp + 0.05 * mp), df * 0.05 * dp, 0.0); assertTrue(DoubleArrayMath.fuzzyEquals(computedNextValues.toArray(), expectedNextValues.toArray(), tol)); }
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); } } } } } } }
public virtual void test_of() { EuropeanVanillaOptionFunction test = EuropeanVanillaOptionFunction.of(STRIKE, TIME_TO_EXPIRY, PutCall.PUT, NUM); assertEquals(test.Sign, -1d); assertEquals(test.Strike, STRIKE); assertEquals(test.TimeToExpiry, TIME_TO_EXPIRY); assertEquals(test.NumberOfSteps, NUM); }
//----------------------------------------------------------------------- public override bool Equals(object obj) { if (obj == this) { return(true); } if (obj != null && obj.GetType() == this.GetType()) { EuropeanVanillaOptionFunction other = (EuropeanVanillaOptionFunction)obj; return(JodaBeanUtils.equal(strike, other.strike) && JodaBeanUtils.equal(timeToExpiry, other.timeToExpiry) && JodaBeanUtils.equal(sign, other.sign) && (numberOfSteps == other.numberOfSteps)); } return(false); }
/// <summary> /// Test consistency between price methods, and Greek via finite difference. /// </summary> public virtual void test_trinomialTree() { int nSteps = 135; double dt = TIME / nSteps; LatticeSpecification lattice = new CoxRossRubinsteinLatticeSpecification(); double fdEps = 1.0e-4; 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[] @params = lattice.getParametersTrinomial(vol, interest - dividend, dt).toArray(); DoubleArray time = DoubleArray.of(nSteps + 1, i => dt * i); DoubleArray df = DoubleArray.of(nSteps, i => Math.Exp(-interest * dt)); double[][] stateValue = new double[nSteps + 1][]; stateValue[0] = new double[] { SPOT }; IList <DoubleMatrix> prob = new List <DoubleMatrix>(); double[] probs = new double[] { @params[5], @params[4], @params[3] }; for (int i = 0; i < nSteps; ++i) { int index = i; stateValue[i + 1] = DoubleArray.of(2 * i + 3, j => SPOT * Math.Pow(@params[2], index + 1 - j) * Math.Pow(@params[1], j)).toArray(); double[][] probMatrix = new double[2 * i + 1][]; Arrays.fill(probMatrix, probs); prob.Add(DoubleMatrix.ofUnsafe(probMatrix)); } RecombiningTrinomialTreeData treeData = RecombiningTrinomialTreeData.of(DoubleMatrix.ofUnsafe(stateValue), prob, df, time); double priceData = TRINOMIAL_TREE.optionPrice(function, treeData); double priceParams = TRINOMIAL_TREE.optionPrice(function, lattice, SPOT, vol, interest, dividend); assertEquals(priceData, priceParams); ValueDerivatives priceDeriv = TRINOMIAL_TREE.optionPriceAdjoint(function, treeData); assertEquals(priceDeriv.Value, priceData); double priceUp = TRINOMIAL_TREE.optionPrice(function, lattice, SPOT + fdEps, vol, interest, dividend); double priceDw = TRINOMIAL_TREE.optionPrice(function, lattice, SPOT - fdEps, vol, interest, dividend); double fdDelta = 0.5 * (priceUp - priceDw) / fdEps; assertEquals(priceDeriv.getDerivative(0), fdDelta, 3.0e-2); } } } } } }