public override void calculate()
        {
            Utils.QL_REQUIRE(process_.x0() > 0.0, () => "negative or null underlying given");

            StrikedTypePayoff payoff = arguments_.payoff as StrikedTypePayoff;

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

            Exercise exercise = arguments_.exercise;

            double t = process_.riskFreeRate().link.dayCounter().yearFraction(process_.riskFreeRate().link.referenceDate(),
                                                                              exercise.lastDate());

            double a     = model_.link.parameters()[0];
            double sigma = model_.link.parameters()[1];
            double eta   = process_.blackVolatility().link.blackVol(exercise.lastDate(), payoff.strike());

            double varianceOffset;

            if (a * t > Math.Pow(Const.QL_EPSILON, 0.25))
            {
                double v  = sigma * sigma / (a * a) * (t + 2 / a * Math.Exp(-a * t) - 1 / (2 * a) * Math.Exp(-2 * a * t) - 3 / (2 * a));
                double mu = 2 * rho_ * sigma * eta / a * (t - 1 / a * (1 - Math.Exp(-a * t)));

                varianceOffset = v + mu;
            }
            else
            {
                // low-a algebraic limit
                double v  = sigma * sigma * t * t * t * (1 / 3.0 - 0.25 * a * t + 7 / 60.0 * a * a * t * t);
                double mu = rho_ * sigma * eta * t * t * (1 - a * t / 3.0 + a * a * t * t / 12.0);

                varianceOffset = v + mu;
            }

            Handle <BlackVolTermStructure> volTS = new Handle <BlackVolTermStructure>(
                new ShiftedBlackVolTermStructure(varianceOffset, process_.blackVolatility()));

            GeneralizedBlackScholesProcess adjProcess =
                new GeneralizedBlackScholesProcess(process_.stateVariable(),
                                                   process_.dividendYield(),
                                                   process_.riskFreeRate(),
                                                   volTS);

            AnalyticEuropeanEngine bsmEngine = new AnalyticEuropeanEngine(adjProcess);

            VanillaOption option = new VanillaOption(payoff, exercise);

            option.setupArguments(bsmEngine.getArguments());

            bsmEngine.calculate();

            results_ = bsmEngine.getResults() as OneAssetOption.Results;
        }
Пример #2
0
        protected override void performCalculations()
        {
            exerciseDate_ = calendar_.advance(termStructure_.link.referenceDate(), maturity_);
            tau_          = termStructure_.link.timeFromReference(exerciseDate_);
            type_         = strikePrice_ * termStructure_.link.discount(tau_) >=
                            s0_.link.value() * dividendYield_.link.discount(tau_)
                 ? Option.Type.Call
                 : Option.Type.Put;
            StrikedTypePayoff payoff   = new PlainVanillaPayoff(type_, strikePrice_);
            Exercise          exercise = new EuropeanExercise(exerciseDate_);

            option_ = new VanillaOption(payoff, exercise);
            base.performCalculations();
        }
        public override void calculate()
        {
            AmericanExercise ex = arguments_.exercise as AmericanExercise;

            Utils.QL_REQUIRE(ex != null, () => "non-American exercise given");
            Utils.QL_REQUIRE(ex.payoffAtExpiry(), () => "payoff must be at expiry");
            Utils.QL_REQUIRE(ex.dates()[0] <= process_.blackVolatility().link.referenceDate(), () =>
                             "American option with window exercise not handled yet");

            StrikedTypePayoff payoff = arguments_.payoff as StrikedTypePayoff;

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

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

            Utils.QL_REQUIRE(spot > 0.0, () => "negative or null underlying given");

            double variance = process_.blackVolatility().link.blackVariance(ex.lastDate(), payoff.strike());
            double?barrier  = arguments_.barrier;

            Utils.QL_REQUIRE(barrier > 0.0, () => "positive barrier value required");
            Barrier.Type barrierType = arguments_.barrierType;

            // KO degenerate cases
            if ((barrierType == Barrier.Type.DownOut && spot <= barrier) ||
                (barrierType == Barrier.Type.UpOut && spot >= barrier))
            {
                // knocked out, no value
                results_.value       = 0;
                results_.delta       = 0;
                results_.gamma       = 0;
                results_.vega        = 0;
                results_.theta       = 0;
                results_.rho         = 0;
                results_.dividendRho = 0;
                return;
            }

            // KI degenerate cases
            if ((barrierType == Barrier.Type.DownIn && spot <= barrier) ||
                (barrierType == Barrier.Type.UpIn && spot >= barrier))
            {
                // knocked in - is a digital european
                Exercise exercise = new EuropeanExercise(arguments_.exercise.lastDate());

                IPricingEngine engine = new AnalyticEuropeanEngine(process_);

                VanillaOption opt = new VanillaOption(payoff, exercise);
                opt.setPricingEngine(engine);
                results_.value       = opt.NPV();
                results_.delta       = opt.delta();
                results_.gamma       = opt.gamma();
                results_.vega        = opt.vega();
                results_.theta       = opt.theta();
                results_.rho         = opt.rho();
                results_.dividendRho = opt.dividendRho();
                return;
            }

            double riskFreeDiscount = process_.riskFreeRate().link.discount(ex.lastDate());

            AnalyticBinaryBarrierEngine_helper helper = new AnalyticBinaryBarrierEngine_helper(
                process_, payoff, ex, arguments_);

            results_.value = helper.payoffAtExpiry(spot, variance, riskFreeDiscount);
        }