public override void calculate()
        {
            // cache lookup for precalculated results
            for (int i = 0; i < cachedArgs2results_.Count; ++i)
            {
                if (cachedArgs2results_[i].first.exercise.type()
                    == arguments_.exercise.type() &&
                    cachedArgs2results_[i].first.exercise.dates()
                    == arguments_.exercise.dates())
                {
                    PlainVanillaPayoff p1 = arguments_.payoff as PlainVanillaPayoff;
                    PlainVanillaPayoff p2 = cachedArgs2results_[i].first.payoff as PlainVanillaPayoff;

                    if (p1 != null && p1.strike() == p2.strike() &&
                        p1.optionType() == p2.optionType())
                    {
                        Utils.QL_REQUIRE(arguments_.cashFlow.empty(),
                                         () => "multiple strikes engine does "
                                         + "not work with discrete dividends");
                        results_ = cachedArgs2results_[i].second;
                        return;
                    }
                }
            }

            HestonProcess process = model_.currentLink().process();

            FdmHestonSolver solver = new FdmHestonSolver(
                new Handle <HestonProcess>(process),
                getSolverDesc(1.5), schemeDesc_,
                new Handle <FdmQuantoHelper>(), leverageFct_);

            double v0   = process.v0();
            double spot = process.s0().currentLink().value();

            results_.value = solver.valueAt(spot, v0);
            results_.delta = solver.deltaAt(spot, v0);
            results_.gamma = solver.gammaAt(spot, v0);
            results_.theta = solver.thetaAt(spot, v0);

            cachedArgs2results_ = new InitializedList <Pair <DividendVanillaOption.Arguments, DividendVanillaOption.Results> >(strikes_.Count);
            StrikedTypePayoff payoff = arguments_.payoff as StrikedTypePayoff;

            for (int i = 0; i < strikes_.Count; ++i)
            {
                cachedArgs2results_[i] = new Pair <DividendVanillaOption.Arguments, OneAssetOption.Results>(new DividendVanillaOption.Arguments(), new OneAssetOption.Results());
                cachedArgs2results_[i].first.exercise = arguments_.exercise;
                cachedArgs2results_[i].first.payoff   = new PlainVanillaPayoff(payoff.optionType(), strikes_[i]);
                double d = payoff.strike() / strikes_[i];

                cachedArgs2results_[i].second.value = solver.valueAt(spot * d, v0) / d;
                cachedArgs2results_[i].second.delta = solver.deltaAt(spot * d, v0);
                cachedArgs2results_[i].second.gamma = solver.gammaAt(spot * d, v0) * d;
                cachedArgs2results_[i].second.theta = solver.thetaAt(spot * d, v0) / d;
            }
        }
Esempio n. 2
0
        public override void calculate()
        {
            // 1. Mesher
            HestonProcess process  = model_.currentLink().process();
            double        maturity = process.time(arguments_.exercise.lastDate());

            // 1.1 The variance mesher
            int tGridMin      = 5;
            int tGridAvgSteps = Math.Max(tGridMin, tGrid_ / 50);
            FdmHestonLocalVolatilityVarianceMesher varianceMesher
                = new FdmHestonLocalVolatilityVarianceMesher(vGrid_, process, leverageFct_, maturity, tGridAvgSteps);

            // 1.2 the equity mesher
            StrikedTypePayoff payoff = arguments_.payoff as StrikedTypePayoff;

            double?xMin = null;
            double?xMax = null;

            if (arguments_.barrierType == Barrier.Type.DownIn ||
                arguments_.barrierType == Barrier.Type.DownOut)
            {
                xMin = Math.Log(arguments_.barrier.Value);
            }
            if (arguments_.barrierType == Barrier.Type.UpIn ||
                arguments_.barrierType == Barrier.Type.UpOut)
            {
                xMax = Math.Log(arguments_.barrier.Value);
            }

            Fdm1dMesher equityMesher =
                new FdmBlackScholesMesher(xGrid_,
                                          FdmBlackScholesMesher.processHelper(process.s0(),
                                                                              process.dividendYield(),
                                                                              process.riskFreeRate(),
                                                                              varianceMesher.volaEstimate()),
                                          maturity,
                                          payoff.strike(),
                                          xMin,
                                          xMax,
                                          0.0001,
                                          1.5,
                                          new Pair <double?, double?>(),
                                          arguments_.cashFlow);

            FdmMesher mesher =
                new FdmMesherComposite(equityMesher, varianceMesher);

            // 2. Calculator
            StrikedTypePayoff rebatePayoff =
                new CashOrNothingPayoff(Option.Type.Call, 0.0, arguments_.rebate.Value);
            FdmInnerValueCalculator calculator =
                new FdmLogInnerValue(rebatePayoff, mesher, 0);

            // 3. Step conditions
            Utils.QL_REQUIRE(arguments_.exercise.type() == Exercise.Type.European,
                             () => "only european style option are supported");

            FdmStepConditionComposite conditions =
                FdmStepConditionComposite.vanillaComposite(
                    arguments_.cashFlow, arguments_.exercise,
                    mesher, calculator,
                    process.riskFreeRate().currentLink().referenceDate(),
                    process.riskFreeRate().currentLink().dayCounter());

            // 4. Boundary conditions
            FdmBoundaryConditionSet boundaries = new FdmBoundaryConditionSet();

            if (arguments_.barrierType == Barrier.Type.DownIn ||
                arguments_.barrierType == Barrier.Type.DownOut)
            {
                boundaries.Add(new FdmDirichletBoundary(mesher, arguments_.rebate.Value, 0,
                                                        FdmDirichletBoundary.Side.Lower));
            }
            if (arguments_.barrierType == Barrier.Type.UpIn ||
                arguments_.barrierType == Barrier.Type.UpOut)
            {
                boundaries.Add(new FdmDirichletBoundary(mesher, arguments_.rebate.Value, 0,
                                                        FdmDirichletBoundary.Side.Upper));
            }

            // 5. Solver
            FdmSolverDesc solverDesc = new FdmSolverDesc();

            solverDesc.mesher       = mesher;
            solverDesc.bcSet        = boundaries;
            solverDesc.condition    = conditions;
            solverDesc.calculator   = calculator;
            solverDesc.maturity     = maturity;
            solverDesc.dampingSteps = dampingSteps_;
            solverDesc.timeSteps    = tGrid_;

            FdmHestonSolver solver =
                new FdmHestonSolver(
                    new Handle <HestonProcess>(process),
                    solverDesc, schemeDesc_,
                    new Handle <FdmQuantoHelper>(),
                    leverageFct_);

            double spot = process.s0().currentLink().value();

            results_.value = solver.valueAt(spot, process.v0());
            results_.delta = solver.deltaAt(spot, process.v0());
            results_.gamma = solver.gammaAt(spot, process.v0());
            results_.theta = solver.thetaAt(spot, process.v0());
        }
        public override void calculate()
        {
            // 1. Mesher
            HestonProcess process  = model_.currentLink().process();
            double        maturity = process.time(arguments_.exercise.lastDate());

            // 1.1 Variance Mesher
            int tGridMin      = 5;
            int tGridAvgSteps = Math.Max(tGridMin, tGrid_ / 50);
            FdmHestonLocalVolatilityVarianceMesher varianceMesher = new FdmHestonLocalVolatilityVarianceMesher(vGrid_,
                                                                                                               process,
                                                                                                               leverageFct_,
                                                                                                               maturity,
                                                                                                               tGridAvgSteps);

            // 1.2 Equity Mesher
            StrikedTypePayoff payoff = arguments_.payoff as StrikedTypePayoff;

            double?xMin = null;
            double?xMax = null;

            if (arguments_.barrierType == Barrier.Type.DownIn ||
                arguments_.barrierType == Barrier.Type.DownOut)
            {
                xMin = Math.Log(arguments_.barrier.Value);
            }
            if (arguments_.barrierType == Barrier.Type.UpIn ||
                arguments_.barrierType == Barrier.Type.UpOut)
            {
                xMax = Math.Log(arguments_.barrier.Value);
            }

            Fdm1dMesher equityMesher =
                new FdmBlackScholesMesher(xGrid_,
                                          FdmBlackScholesMesher.processHelper(process.s0(),
                                                                              process.dividendYield(),
                                                                              process.riskFreeRate(),
                                                                              varianceMesher.volaEstimate()),
                                          maturity,
                                          payoff.strike(),
                                          xMin,
                                          xMax,
                                          0.0001,
                                          1.5,
                                          new Pair <double?, double?>(),
                                          arguments_.cashFlow);

            FdmMesher mesher =
                new FdmMesherComposite(equityMesher, varianceMesher);

            // 2. Calculator
            FdmInnerValueCalculator calculator =
                new FdmLogInnerValue(payoff, mesher, 0);

            // 3. Step conditions
            List <IStepCondition <Vector> > stepConditions = new List <IStepCondition <Vector> >();
            List <List <double> >           stoppingTimes  = new List <List <double> >();

            // 3.1 Step condition if discrete dividends
            FdmDividendHandler dividendCondition =
                new FdmDividendHandler(arguments_.cashFlow, mesher,
                                       process.riskFreeRate().currentLink().referenceDate(),
                                       process.riskFreeRate().currentLink().dayCounter(), 0);

            if (!arguments_.cashFlow.empty())
            {
                stepConditions.Add(dividendCondition);
                stoppingTimes.Add(dividendCondition.dividendTimes());
            }

            Utils.QL_REQUIRE(arguments_.exercise.type() == Exercise.Type.European,
                             () => "only european style option are supported");

            FdmStepConditionComposite conditions =
                new FdmStepConditionComposite(stoppingTimes, stepConditions);

            // 4. Boundary conditions
            FdmBoundaryConditionSet boundaries = new FdmBoundaryConditionSet();

            if (arguments_.barrierType == Barrier.Type.DownIn ||
                arguments_.barrierType == Barrier.Type.DownOut)
            {
                boundaries.Add(
                    new FdmDirichletBoundary(mesher, arguments_.rebate.Value, 0,
                                             FdmDirichletBoundary.Side.Lower));
            }

            if (arguments_.barrierType == Barrier.Type.UpIn ||
                arguments_.barrierType == Barrier.Type.UpOut)
            {
                boundaries.Add(
                    new FdmDirichletBoundary(mesher, arguments_.rebate.Value, 0,
                                             FdmDirichletBoundary.Side.Upper));
            }

            // 5. Solver
            FdmSolverDesc solverDesc = new FdmSolverDesc();

            solverDesc.mesher       = mesher;
            solverDesc.bcSet        = boundaries;
            solverDesc.condition    = conditions;
            solverDesc.calculator   = calculator;
            solverDesc.maturity     = maturity;
            solverDesc.dampingSteps = dampingSteps_;
            solverDesc.timeSteps    = tGrid_;

            FdmHestonSolver solver =
                new FdmHestonSolver(
                    new Handle <HestonProcess>(process),
                    solverDesc, schemeDesc_,
                    new Handle <FdmQuantoHelper>(), leverageFct_);

            double spot = process.s0().currentLink().value();

            results_.value = solver.valueAt(spot, process.v0());
            results_.delta = solver.deltaAt(spot, process.v0());
            results_.gamma = solver.gammaAt(spot, process.v0());
            results_.theta = solver.thetaAt(spot, process.v0());

            // 6. Calculate vanilla option and rebate for in-barriers
            if (arguments_.barrierType == Barrier.Type.DownIn ||
                arguments_.barrierType == Barrier.Type.UpIn)
            {
                // Cast the payoff
                StrikedTypePayoff castedPayoff = arguments_.payoff as StrikedTypePayoff;

                // Calculate the vanilla option
                DividendVanillaOption vanillaOption =
                    new DividendVanillaOption(castedPayoff, arguments_.exercise,
                                              dividendCondition.dividendDates(),
                                              dividendCondition.dividends());

                vanillaOption.setPricingEngine(
                    new FdHestonVanillaEngine(
                        model_, tGrid_, xGrid_,
                        vGrid_, dampingSteps_,
                        schemeDesc_));

                // Calculate the rebate value
                DividendBarrierOption rebateOption =
                    new DividendBarrierOption(arguments_.barrierType,
                                              arguments_.barrier.Value,
                                              arguments_.rebate.Value,
                                              castedPayoff, arguments_.exercise,
                                              dividendCondition.dividendDates(),
                                              dividendCondition.dividends());

                int xGridMin = 20;
                int vGridMin = 10;
                int rebateDampingSteps
                    = (dampingSteps_ > 0) ? Math.Min(1, dampingSteps_ / 2) : 0;

                rebateOption.setPricingEngine(new FdHestonRebateEngine(
                                                  model_, tGrid_, Math.Max(xGridMin, xGrid_ / 4),
                                                  Math.Max(vGridMin, vGrid_ / 4),
                                                  rebateDampingSteps, schemeDesc_));

                results_.value = vanillaOption.NPV() + rebateOption.NPV()
                                 - results_.value;
                results_.delta = vanillaOption.delta() + rebateOption.delta()
                                 - results_.delta;
                results_.gamma = vanillaOption.gamma() + rebateOption.gamma()
                                 - results_.gamma;
                results_.theta = vanillaOption.theta() + rebateOption.theta()
                                 - results_.theta;
            }
        }