Exemple #1
0
        public double value(IPath path)
        {
            Utils.QL_REQUIRE(!(path as Path).empty(), () => "the path cannot be empty");

            TimeGrid doubleGrid = (path as Path).timeGrid();
            int      startIndex = doubleGrid.closestIndex(lookbackStart_);
            double   underlying;

            switch (payoff_.optionType())
            {
            case Option.Type.Put:
                underlying = (path as Path).values().GetRange(startIndex, (path as Path).values().Count - startIndex).Min();
                break;

            case Option.Type.Call:
                underlying = (path as Path).values().GetRange(startIndex, (path as Path).values().Count - startIndex).Max();
                break;

            default:
                underlying = 0.0;
                Utils.QL_FAIL("unknown option type");
                break;
            }

            return(payoff_.value(underlying) * discount_);
        }
Exemple #2
0
        protected override PathPricer <IPath> pathPricer()
        {
            TimeGrid grid     = this.timeGrid();
            double   discount = (this.process_ as GeneralizedBlackScholesProcess)
                                .riskFreeRate().currentLink().discount(grid.Last());

            ContinuousFixedLookbackOption.Arguments           arg1 = this.arguments_ as ContinuousFixedLookbackOption.Arguments;
            ContinuousPartialFixedLookbackOption.Arguments    arg2 = this.arguments_ as ContinuousPartialFixedLookbackOption.Arguments;
            ContinuousFloatingLookbackOption.Arguments        arg3 = this.arguments_ as ContinuousFloatingLookbackOption.Arguments;
            ContinuousPartialFloatingLookbackOption.Arguments arg4 = this.arguments_ as ContinuousPartialFloatingLookbackOption.Arguments;

            if (arg2 != null)
            {
                return(mc_looback_path_pricer(arg2, this.process_ as GeneralizedBlackScholesProcess, discount));
            }
            else if (arg1 != null)
            {
                return(mc_looback_path_pricer(arg1, this.process_ as GeneralizedBlackScholesProcess, discount));
            }
            else if (arg4 != null)
            {
                return(mc_looback_path_pricer(arg4, this.process_ as GeneralizedBlackScholesProcess, discount));
            }
            else if (arg3 != null)
            {
                return(mc_looback_path_pricer(arg3, this.process_ as GeneralizedBlackScholesProcess, discount));
            }
            else
            {
                return(null);
            }
        }
        public PiecewiseTimeDependentHestonModel(Handle <YieldTermStructure> riskFreeRate,
                                                 Handle <YieldTermStructure> dividendYield,
                                                 Handle <Quote> s0,
                                                 double v0,
                                                 Parameter theta,
                                                 Parameter kappa,
                                                 Parameter sigma,
                                                 Parameter rho,
                                                 TimeGrid timeGrid)
            : base(5)
        {
            s0_            = s0;
            riskFreeRate_  = riskFreeRate;
            dividendYield_ = dividendYield;
            timeGrid_      = timeGrid;

            arguments_[0] = theta;
            arguments_[1] = kappa;
            arguments_[2] = sigma;
            arguments_[3] = rho;
            arguments_[4] = new ConstantParameter(v0, new PositiveConstraint());

            s0.registerWith(update);
            riskFreeRate.registerWith(update);
            dividendYield.registerWith(update);
        }
Exemple #4
0
        public override Lattice tree(TimeGrid grid)
        {
            TermStructureFittingParameter phi             = new TermStructureFittingParameter(termStructure());
            ShortRateDynamics             numericDynamics = new Dynamics(phi, a(), sigma());
            TrinomialTree trinomial   = new TrinomialTree(numericDynamics.process(), grid);
            ShortRateTree numericTree = new ShortRateTree(trinomial, numericDynamics, grid);

            TermStructureFittingParameter.NumericalImpl impl =
                (TermStructureFittingParameter.NumericalImpl)phi.implementation();
            impl.reset();
            for (int i = 0; i < (grid.size() - 1); i++)
            {
                double discountBond = termStructure().link.discount(grid[i + 1]);
                Vector statePrices  = numericTree.statePrices(i);
                int    size         = numericTree.size(i);
                double dt           = numericTree.timeGrid().dt(i);
                double dx           = trinomial.dx(i);
                double x            = trinomial.underlying(i, 0);
                double value        = 0.0;
                for (int j = 0; j < size; j++)
                {
                    value += statePrices[j] * Math.Exp(-x * dt);
                    x     += dx;
                }
                value = Math.Log(value / discountBond) / dt;
                impl.setvalue(grid[i], value);
            }
            return(numericTree);
        }
Exemple #5
0
        public override Lattice tree(TimeGrid grid)
        {
            TermStructureFittingParameter phi = new TermStructureFittingParameter(termStructure());

            ShortRateDynamics numericDynamics =
                new Dynamics(phi, a(), sigma());

            TrinomialTree trinomial =
                new TrinomialTree(numericDynamics.process(), grid);
            ShortRateTree numericTree =
                new ShortRateTree(trinomial, numericDynamics, grid);

            TermStructureFittingParameter.NumericalImpl impl =
                (TermStructureFittingParameter.NumericalImpl)phi.implementation();
            impl.reset();
            double value = 1.0;
            double vMin  = -50.0;
            double vMax  = 50.0;

            for (int i = 0; i < (grid.size() - 1); i++)
            {
                double discountBond = termStructure().link.discount(grid[i + 1]);
                double xMin         = trinomial.underlying(i, 0);
                double dx           = trinomial.dx(i);
                Helper finder       = new Helper(i, xMin, dx, discountBond, numericTree);
                Brent  s1d          = new Brent();
                s1d.setMaxEvaluations(1000);
                value = s1d.solve(finder, 1e-7, value, vMin, vMax);
                impl.setvalue(grid[i], value);
            }
            return(numericTree);
        }
Exemple #6
0
        protected override IPathGenerator <IRNG> pathGenerator()
        {
            TimeGrid grid = timeGrid();
            IRNG     gen  = new RNG().make_sequence_generator(grid.size() - 1, seed_);

            return(new PathGenerator <IRNG>(process_, grid, gen, brownianBridge_));
        }
Exemple #7
0
        public double value(IPath path)
        {
            Utils.QL_REQUIRE(!(path as Path).empty(), () => "the path cannot be empty");

            TimeGrid doubleGrid    = (path as Path).timeGrid();
            int      endIndex      = doubleGrid.closestIndex(lookbackEnd_);
            double   terminalPrice = (path as Path).back();
            double   strike;

            switch (payoff_.optionType())
            {
            case Option.Type.Call:
                strike = (path as Path).values().GetRange(0, endIndex).Min();
                break;

            case Option.Type.Put:
                strike = (path as Path).values().GetRange(0, endIndex).Max();
                break;

            default:
                strike = 0.0;
                Utils.QL_FAIL("unknown option type");
                break;
            }

            return(payoff_.value(terminalPrice, strike) * discount_);
        }
Exemple #8
0
 public TreeLattice(TimeGrid timeGrid, int n) : base(timeGrid)
 {
     n_ = n;
     Utils.QL_REQUIRE(n > 0, () => "there is no zeronomial lattice!");
     statePrices_      = new InitializedList <Vector>(1, new Vector(1, 1.0));
     statePricesLimit_ = 0;
 }
 public TreeCallableFixedRateBondEngine(ShortRateModel model, TimeGrid timeGrid,
                                        Handle <YieldTermStructure> termStructure)
     : base(model, timeGrid)
 {
     termStructure_ = termStructure;
     termStructure_.registerWith(update);
 }
Exemple #10
0
        public override Lattice tree(TimeGrid grid)
        {
            ShortRateDynamics dyn   = dynamics();
            TrinomialTree     tree1 = new TrinomialTree(dyn.xProcess(), grid);
            TrinomialTree     tree2 = new TrinomialTree(dyn.yProcess(), grid);

            return((Lattice)(new ShortRateTree(tree1, tree2, dyn)));
        }
Exemple #11
0
        protected override IPathGenerator <IRNG> pathGenerator()
        {
            int      dimensions = process_.factors();
            TimeGrid grid       = timeGrid();
            IRNG     generator  = (IRNG)FastActivator <RNG> .Create().make_sequence_generator(dimensions * (grid.size() - 1), seed_);

            return(new PathGenerator <IRNG>(process_, grid, generator, brownianBridge_));
        }
 //! Plain tree build-up from short-rate dynamics
 public ShortRateTree(TrinomialTree tree,
                      ShortRateDynamics dynamics,
                      TimeGrid timeGrid)
     : base(timeGrid, tree.size(1))
 {
     tree_     = tree;
     dynamics_ = dynamics;
 }
 public TreeVanillaSwapEngine(ShortRateModel model,
                              TimeGrid timeGrid,
                              Handle <YieldTermStructure> termStructure)
     : base(model, timeGrid)
 {
     termStructure_ = termStructure;
     termStructure_.registerWith(update);
 }
Exemple #14
0
 public MultiPath(int nAsset, TimeGrid timeGrid)
 {
     multiPath_ = new List <Path>(nAsset);
     for (int i = 0; i < nAsset; i++)
     {
         multiPath_.Add(new Path(timeGrid));
     }
     Utils.QL_REQUIRE(nAsset > 0, () => "number of asset must be positive");
 }
 public LatticeShortRateModelEngine(ShortRateModel model,
                                    TimeGrid timeGrid)
     : base(model)
 {
     timeGrid_  = new TimeGrid(timeGrid.Last(), timeGrid.size() - 1 /*timeGrid.dt(1) - timeGrid.dt(0)*/);
     timeGrid_  = timeGrid;
     timeSteps_ = 0;
     lattice_   = this.model_.link.tree(timeGrid);
 }
        public TrinomialTree(StochasticProcess1D process,
                             TimeGrid timeGrid,
                             bool isPositive /*= false*/)
            : base(timeGrid.size())
        {
            branchings_ = new List <Branching>();
            dx_         = new InitializedList <double>(1);
            timeGrid_   = timeGrid;
            x0_         = process.x0();

            int nTimeSteps = timeGrid.size() - 1;
            int jMin       = 0;
            int jMax       = 0;

            for (int i = 0; i < nTimeSteps; i++)
            {
                double t  = timeGrid[i];
                double dt = timeGrid.dt(i);

                //Variance must be independent of x
                double v2 = process.variance(t, 0.0, dt);
                double v  = Math.Sqrt(v2);
                dx_.Add(v * Math.Sqrt(3.0));

                Branching branching = new Branching();
                for (int j = jMin; j <= jMax; j++)
                {
                    double x    = x0_ + j * dx_[i];
                    double m    = process.expectation(t, x, dt);
                    int    temp = (int)(Math.Floor((m - x0_) / dx_[i + 1] + 0.5));

                    if (isPositive)
                    {
                        while (x0_ + (temp - 1) * dx_[i + 1] <= 0)
                        {
                            temp++;
                        }
                    }

                    double e  = m - (x0_ + temp * dx_[i + 1]);
                    double e2 = e * e;
                    double e3 = e * Math.Sqrt(3.0);

                    double p1 = (1.0 + e2 / v2 - e3 / v) / 6.0;
                    double p2 = (2.0 - e2 / v2) / 3.0;
                    double p3 = (1.0 + e2 / v2 + e3 / v) / 6.0;

                    branching.add(temp, p1, p2, p3);
                }
                branchings_.Add(branching);

                jMin = branching.jMin();
                jMax = branching.jMax();
            }
        }
Exemple #17
0
        private Sample <IPath> next(bool antithetic)
        {
            if (brownianBridge_)
            {
                Utils.QL_FAIL("Brownian bridge not supported");
                return(null);
            }

            Sample <List <double> > sequence_ =
                antithetic
            ? generator_.lastSequence()
            : generator_.nextSequence();

            int m = process_.size();
            int n = process_.factors();

            MultiPath path = (MultiPath)next_.value;

            Vector asset = process_.initialValues();

            for (int j = 0; j < m; j++)
            {
                path[j].setFront(asset[j]);
            }

            Vector temp;

            next_.weight = sequence_.weight;

            TimeGrid timeGrid = path[0].timeGrid();
            double   t, dt;

            for (int i = 1; i < path.pathSize(); i++)
            {
                int offset = (i - 1) * n;
                t  = timeGrid[i - 1];
                dt = timeGrid.dt(i - 1);
                if (antithetic)
                {
                    temp = -1 * new Vector(sequence_.value.GetRange(offset, n));
                }
                else
                {
                    temp = new Vector(sequence_.value.GetRange(offset, n));
                }

                asset = process_.evolve(t, asset, dt, temp);
                for (int j = 0; j < m; j++)
                {
                    path[j][i] = asset[j];
                }
            }
            return(next_);
        }
Exemple #18
0
        public Path(TimeGrid timeGrid, Vector values)
        {
            timeGrid_ = timeGrid;
            values_   = values.Clone();
            if (values_.empty())
            {
                values_ = new Vector(timeGrid_.size());
            }

            Utils.QL_REQUIRE(values_.size() == timeGrid_.size(), () => "different number of times and asset values");
        }
Exemple #19
0
 // constructors
 public PathGenerator(StochasticProcess process, double length, int timeSteps, GSG generator, bool brownianBridge)
 {
     brownianBridge_ = brownianBridge;
     generator_      = generator;
     dimension_      = generator_.dimension();
     timeGrid_       = new TimeGrid(length, timeSteps);
     process_        = process as StochasticProcess1D;
     next_           = new Sample <IPath>(new Path(timeGrid_), 1.0);
     temp_           = new InitializedList <double>(dimension_);
     bb_             = new BrownianBridge(timeGrid_);
     Utils.QL_REQUIRE(dimension_ == timeSteps, () =>
                      "sequence generator dimensionality (" + dimension_ + ") != timeSteps (" + timeSteps + ")");
 }
Exemple #20
0
        protected override IPathGenerator <IRNG> controlPathGenerator()
        {
            int      dimensions = process_.factors();
            TimeGrid grid       = this.timeGrid();
            IRNG     generator  = (IRNG) new  RNG().make_sequence_generator(dimensions * (grid.size() - 1), this.seed_);
            HybridHestonHullWhiteProcess process = process_ as HybridHestonHullWhiteProcess;

            Utils.QL_REQUIRE(process != null, () => "invalid process");
            HybridHestonHullWhiteProcess cvProcess = new HybridHestonHullWhiteProcess(process.hestonProcess(),
                                                                                      process.hullWhiteProcess(), 0.0, process.discretization());

            return(new MultiPathGenerator <IRNG>(cvProcess, grid, generator, false));
        }
        public override void calculate()
        {
            if (base.model_ == null)
            {
                throw new ArgumentException("no model specified");
            }

            Date       referenceDate;
            DayCounter dayCounter;

            ITermStructureConsistentModel tsmodel =
                (ITermStructureConsistentModel)base.model_.link;

            try
            {
                if (tsmodel != null)
                {
                    referenceDate = tsmodel.termStructure().link.referenceDate();
                    dayCounter    = tsmodel.termStructure().link.dayCounter();
                }
                else
                {
                    referenceDate = termStructure_.link.referenceDate();
                    dayCounter    = termStructure_.link.dayCounter();
                }
            }
            catch
            {
                referenceDate = termStructure_.link.referenceDate();
                dayCounter    = termStructure_.link.dayCounter();
            }

            DiscretizedSwap swap  = new DiscretizedSwap(arguments_, referenceDate, dayCounter);
            List <double>   times = swap.mandatoryTimes();
            Lattice         lattice;

            if (lattice_ != null)
            {
                lattice = lattice_;
            }
            else
            {
                TimeGrid timeGrid = new TimeGrid(times, times.Count, timeSteps_);
                lattice = model_.link.tree(timeGrid);
            }

            swap.initialize(lattice, times.Last());
            swap.rollback(0.0);

            results_.value = swap.presentValue();
        }
Exemple #22
0
        public MultiPathGenerator(StochasticProcess process, TimeGrid times, GSG generator, bool brownianBridge)
        {
            brownianBridge_ = brownianBridge;
            process_        = process;
            generator_      = generator;
            next_           = new Sample <IPath>(new MultiPath(process.size(), times), 1.0);

            Utils.QL_REQUIRE(generator_.dimension() == process.factors() * (times.size() - 1), () =>
                             "dimension (" + generator_.dimension()
                             + ") is not equal to ("
                             + process.factors() + " * " + (times.size() - 1)
                             + ") the number of factors "
                             + "times the number of time steps");
            Utils.QL_REQUIRE(times.size() > 1, () => "no times given");
        }
        public LongstaffSchwartzPathPricer(TimeGrid times, IEarlyExercisePathPricer <PathType, double> pathPricer,
                                           YieldTermStructure termStructure)
        {
            calibrationPhase_ = true;
            pathPricer_       = pathPricer;
            coeff_            = new InitializedList <Vector>(times.size() - 1);
            dF_ = new InitializedList <double>(times.size() - 1);
            v_  = pathPricer_.basisSystem();

            for (int i = 0; i < times.size() - 1; ++i)
            {
                dF_[i] = termStructure.discount(times[i + 1])
                         / termStructure.discount(times[i]);
            }
        }
 //! generic times
 public BrownianBridge(TimeGrid timeGrid)
 {
     size_        = timeGrid.size() - 1;
     t_           = new InitializedList <double>(size_);
     sqrtdt_      = new InitializedList <double>(size_);
     sqrtdt_      = new InitializedList <double>(size_);
     bridgeIndex_ = new InitializedList <int>(size_);
     leftIndex_   = new InitializedList <int>(size_);
     rightIndex_  = new InitializedList <int>(size_);
     leftWeight_  = new InitializedList <double>(size_);
     rightWeight_ = new InitializedList <double>(size_);
     stdDev_      = new InitializedList <double>(size_);
     for (int i = 0; i < size_; ++i)
     {
         t_[i] = timeGrid[i + 1];
     }
     initialize();
 }
            //! Tree build-up + numerical fitting to term-structure
            public ShortRateTree(TrinomialTree tree, ShortRateDynamics dynamics, TermStructureFittingParameter.NumericalImpl theta,
                                 TimeGrid timeGrid)
                : base(timeGrid, tree.size(1))
            {
                tree_     = tree;
                dynamics_ = dynamics;
                theta.reset();
                double value = 1.0;
                double vMin  = -100.0;
                double vMax  = 100.0;

                for (int i = 0; i < (timeGrid.size() - 1); i++)
                {
                    double discountBond = theta.termStructure().link.discount(t_[i + 1]);
                    Helper finder       = new Helper(i, discountBond, theta, this);
                    Brent  s1d          = new Brent();
                    s1d.setMaxEvaluations(1000);
                    value = s1d.solve(finder, 1e-7, value, vMin, vMax);
                    theta.change(value);
                }
            }
        public override void calculate()
        {
            Utils.QL_REQUIRE(model_ != null, () => "no model specified");

            Date       referenceDate;
            DayCounter dayCounter;

            ITermStructureConsistentModel tsmodel = (ITermStructureConsistentModel)base.model_.link;

            if (tsmodel != null)
            {
                referenceDate = tsmodel.termStructure().link.referenceDate();
                dayCounter    = tsmodel.termStructure().link.dayCounter();
            }
            else
            {
                referenceDate = termStructure_.link.referenceDate();
                dayCounter    = termStructure_.link.dayCounter();
            }

            DiscretizedCallableFixedRateBond callableBond = new DiscretizedCallableFixedRateBond(arguments_, referenceDate, dayCounter);
            Lattice lattice;

            if (lattice_ != null)
            {
                lattice = lattice_;
            }
            else
            {
                List <double> times    = callableBond.mandatoryTimes();
                TimeGrid      timeGrid = new TimeGrid(times, times.Count, timeSteps_);
                lattice = model_.link.tree(timeGrid);
            }

            double redemptionTime = dayCounter.yearFraction(referenceDate, arguments_.redemptionDate);

            callableBond.initialize(lattice, redemptionTime);
            callableBond.rollback(0.0);
            results_.value = results_.settlementValue = callableBond.presentValue();
        }
Exemple #27
0
        protected override PathPricer <IPath> pathPricer()
        {
            PlainVanillaPayoff payoff = arguments_.payoff as PlainVanillaPayoff;

            Utils.QL_REQUIRE(payoff != null, () => "non-plain payoff given");

            TimeGrid      grid      = timeGrid();
            List <double> discounts = new InitializedList <double>(grid.size());

            for (int i = 0; i < grid.size(); i++)
            {
                discounts[i] = process_.riskFreeRate().currentLink().discount(grid[i]);
            }

            // do this with template parameters?
            if (isBiased_)
            {
                return(new BiasedBarrierPathPricer(arguments_.barrierType,
                                                   arguments_.barrier,
                                                   arguments_.rebate,
                                                   payoff.optionType(),
                                                   payoff.strike(),
                                                   discounts));
            }
            else
            {
                IRNG sequenceGen = new RandomSequenceGenerator <MersenneTwisterUniformRng>(grid.size() - 1, 5);
                return(new BarrierPathPricer(arguments_.barrierType,
                                             arguments_.barrier,
                                             arguments_.rebate,
                                             payoff.optionType(),
                                             payoff.strike(),
                                             discounts,
                                             process_,
                                             sequenceGen));
            }
        }
        public override void calculate()
        {
            DayCounter rfdc   = process_.riskFreeRate().link.dayCounter();
            DayCounter divdc  = process_.dividendYield().link.dayCounter();
            DayCounter voldc  = process_.blackVolatility().link.dayCounter();
            Calendar   volcal = process_.blackVolatility().link.calendar();

            double s0 = process_.stateVariable().link.value();

            Utils.QL_REQUIRE(s0 > 0.0, () => "negative or null underlying given");
            double v             = process_.blackVolatility().link.blackVol(arguments_.exercise.lastDate(), s0);
            Date   maturityDate  = arguments_.exercise.lastDate();
            double r             = process_.riskFreeRate().link.zeroRate(maturityDate, rfdc, Compounding.Continuous, Frequency.NoFrequency).value();
            double q             = process_.dividendYield().link.zeroRate(maturityDate, divdc, Compounding.Continuous, Frequency.NoFrequency).value();
            Date   referenceDate = process_.riskFreeRate().link.referenceDate();

            // binomial trees with constant coefficient
            Handle <YieldTermStructure>    flatRiskFree  = new Handle <YieldTermStructure>(new FlatForward(referenceDate, r, rfdc));
            Handle <YieldTermStructure>    flatDividends = new Handle <YieldTermStructure>(new FlatForward(referenceDate, q, divdc));
            Handle <BlackVolTermStructure> flatVol       = new Handle <BlackVolTermStructure>(new BlackConstantVol(referenceDate, volcal, v, voldc));

            StrikedTypePayoff payoff = arguments_.payoff as StrikedTypePayoff;

            Utils.QL_REQUIRE(payoff != null, () => "non-striked payoff given");

            double maturity = rfdc.yearFraction(referenceDate, maturityDate);

            StochasticProcess1D bs = new GeneralizedBlackScholesProcess(process_.stateVariable(),
                                                                        flatDividends, flatRiskFree, flatVol);

            // correct timesteps to ensure a (local) minimum, using Boyle and Lau
            // approach. See Journal of Derivatives, 1/1994,
            // "Bumping up against the barrier with the binomial method"
            // Note: this approach works only for CoxRossRubinstein lattices, so
            // is disabled if T is not a CoxRossRubinstein or derived from it.
            int optimum_steps = timeSteps_;

            if (maxTimeSteps_ > timeSteps_ && s0 > 0 && arguments_.barrier > 0) // boost::is_base_of<CoxRossRubinstein, T>::value &&
            {
                double divisor;
                if (s0 > arguments_.barrier)
                {
                    divisor = Math.Pow(Math.Log(s0 / arguments_.barrier.Value), 2);
                }
                else
                {
                    divisor = Math.Pow(Math.Log(arguments_.barrier.Value / s0), 2);
                }
                if (!Utils.close(divisor, 0))
                {
                    for (int i = 1; i < timeSteps_; ++i)
                    {
                        int optimum = (int)((i * i * v * v * maturity) / divisor);
                        if (timeSteps_ < optimum)
                        {
                            optimum_steps = optimum;
                            break; // found first minimum with iterations>=timesteps
                        }
                    }
                }

                if (optimum_steps > maxTimeSteps_)
                {
                    optimum_steps = maxTimeSteps_; // too high, limit
                }
            }

            TimeGrid grid = new TimeGrid(maturity, optimum_steps);

            ITree tree = getTree_(bs, maturity, optimum_steps, payoff.strike());

            BlackScholesLattice <ITree> lattice = new BlackScholesLattice <ITree>(tree, r, maturity, optimum_steps);

            DiscretizedAsset option = getAsset_(arguments_, process_, grid);

            option.initialize(lattice, maturity);

            // Partial derivatives calculated from various points in the
            // binomial tree
            // (see J.C.Hull, "Options, Futures and other derivatives", 6th edition, pp 397/398)

            // Rollback to third-last step, and get underlying prices (s2) &
            // option values (p2) at this point
            option.rollback(grid[2]);
            Vector va2 = new Vector(option.values());

            Utils.QL_REQUIRE(va2.size() == 3, () => "Expect 3 nodes in grid at second step");
            double p2u = va2[2];                   // up
            double p2m = va2[1];                   // mid
            double p2d = va2[0];                   // down (low)
            double s2u = lattice.underlying(2, 2); // up price
            double s2m = lattice.underlying(2, 1); // middle price
            double s2d = lattice.underlying(2, 0); // down (low) price

            // calculate gamma by taking the first derivate of the two deltas
            double delta2u = (p2u - p2m) / (s2u - s2m);
            double delta2d = (p2m - p2d) / (s2m - s2d);
            double gamma   = (delta2u - delta2d) / ((s2u - s2d) / 2);

            // Rollback to second-last step, and get option values (p1) at
            // this point
            option.rollback(grid[1]);
            Vector va = new Vector(option.values());

            Utils.QL_REQUIRE(va.size() == 2, () => "Expect 2 nodes in grid at first step");
            double p1u = va[1];
            double p1d = va[0];
            double s1u = lattice.underlying(1, 1); // up (high) price
            double s1d = lattice.underlying(1, 0); // down (low) price

            double delta = (p1u - p1d) / (s1u - s1d);

            // Finally, rollback to t=0
            option.rollback(0.0);
            double p0 = option.presentValue();

            // Store results
            results_.value = p0;
            results_.delta = delta;
            results_.gamma = gamma;
            // theta can be approximated by calculating the numerical derivative
            // between mid value at third-last step and at t0. The underlying price
            // is the same, only time varies.
            results_.theta = (p2m - p0) / grid[2];
        }
        public override Lattice tree(TimeGrid grid)
        {
            TrinomialTree trinomial = new TrinomialTree(dynamics().process(), grid, true);

            return(new ShortRateTree(trinomial, dynamics(), grid));
        }
Exemple #30
0
 public abstract Lattice tree(TimeGrid t);