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);
                                }
                            }
                        }
                    }
                }
            }
        }
Exemple #2
0
        //-----------------------------------------------------------------------
        private Pair <ImmutableList <double[]>, RecombiningTrinomialTreeData> calibrate(System.Func <DoublesPair, double> impliedVolatilitySurface, double spot, System.Func <double, double> interestRate, System.Func <double, double> dividendRate)
        {
            double[][]           stateValue  = new double[nSteps + 1][];
            double[]             df          = new double[nSteps];
            double[]             timePrim    = new double[nSteps + 1];
            IList <DoubleMatrix> probability = new List <DoubleMatrix>(nSteps);
            int nTotal = (nSteps - 1) * (nSteps - 1) + 1;

            double[] timeRes = new double[nTotal];
            double[] spotRes = new double[nTotal];
            double[] volRes  = new double[nTotal];
            // uniform grid based on TrigeorgisLatticeSpecification
            double volatility = impliedVolatilitySurface(DoublesPair.of(maxTime, spot));
            double dt         = maxTime / nSteps;
            double dx         = volatility * Math.Sqrt(3d * dt);
            double upFactor   = Math.Exp(dx);
            double downFactor = Math.Exp(-dx);

            double[] adSec      = new double[2 * nSteps + 1];
            double[] assetPrice = new double[2 * nSteps + 1];
            for (int i = nSteps; i > -1; --i)
            {
                timePrim[i] = dt * i;
                if (i == 0)
                {
                    resolveFirstLayer(interestRate, dividendRate, nTotal, dt, spot, adSec, assetPrice, timeRes, spotRes, volRes, df, stateValue, probability);
                }
                else
                {
                    double   zeroRate         = interestRate(timePrim[i]);
                    double   zeroDividendRate = dividendRate(timePrim[i]);
                    double   zeroCostRate     = zeroRate - zeroDividendRate;
                    int      nNodes           = 2 * i + 1;
                    double[] assetPriceLocal  = new double[nNodes];
                    double[] callOptionPrice  = new double[nNodes];
                    double[] putOptionPrice   = new double[nNodes];
                    int      position         = i - 1;
                    double   assetTmp         = spot * Math.Pow(upFactor, i);
                    // call options for upper half nodes
                    for (int j = nNodes - 1; j > position - 1; --j)
                    {
                        assetPriceLocal[j] = assetTmp;
                        double impliedVol = impliedVolatilitySurface(DoublesPair.of(timePrim[i], assetPriceLocal[j]));
                        callOptionPrice[j] = BlackScholesFormulaRepository.price(spot, assetPriceLocal[j], timePrim[i], impliedVol, zeroRate, zeroCostRate, true);
                        assetTmp          *= downFactor;
                    }
                    // put options for lower half nodes
                    assetTmp = spot * Math.Pow(downFactor, i);
                    for (int j = 0; j < position + 2; ++j)
                    {
                        assetPriceLocal[j] = assetTmp;
                        double impliedVol = impliedVolatilitySurface(DoublesPair.of(timePrim[i], assetPriceLocal[j]));
                        putOptionPrice[j] = BlackScholesFormulaRepository.price(spot, assetPriceLocal[j], timePrim[i], impliedVol, zeroRate, zeroCostRate, false);
                        assetTmp         *= upFactor;
                    }
                    resolveLayer(interestRate, dividendRate, i, nTotal, position, dt, zeroRate, zeroDividendRate, callOptionPrice, putOptionPrice, adSec, assetPrice, assetPriceLocal, timeRes, spotRes, volRes, df, stateValue, probability);
                }
            }
            ImmutableList <double[]>     localVolData = ImmutableList.of(timeRes, spotRes, volRes);
            RecombiningTrinomialTreeData treeData     = RecombiningTrinomialTreeData.of(DoubleMatrix.ofUnsafe(stateValue), probability, DoubleArray.ofUnsafe(df), DoubleArray.ofUnsafe(timePrim));

            return(Pair.of(localVolData, treeData));
        }