Пример #1
0
        public override void calculate()
        {
            if (arguments_.exercise.type() != Exercise.Type.European)
            {
                throw new ApplicationException("not an European option");
            }

            StrikedTypePayoff payoff = arguments_.payoff as StrikedTypePayoff;

            if (payoff == null)
            {
                throw new ApplicationException("non-striked payoff given");
            }

            double variance         = process_.blackVolatility().link.blackVariance(arguments_.exercise.lastDate(), payoff.strike());
            double dividendDiscount = process_.dividendYield().link.discount(arguments_.exercise.lastDate());
            double riskFreeDiscount = process_.riskFreeRate().link.discount(arguments_.exercise.lastDate());
            double spot             = process_.stateVariable().link.value();

            if (!(spot > 0.0))
            {
                throw new ApplicationException("negative or null underlying given");
            }
            double forwardPrice = spot * dividendDiscount / riskFreeDiscount;

            BlackCalculator black = new BlackCalculator(payoff, forwardPrice, Math.Sqrt(variance), riskFreeDiscount);

            results_.value        = black.value();
            results_.delta        = black.delta(spot);
            results_.deltaForward = black.deltaForward();
            results_.elasticity   = black.elasticity(spot);
            results_.gamma        = black.gamma(spot);

            DayCounter rfdc  = process_.riskFreeRate().link.dayCounter();
            DayCounter divdc = process_.dividendYield().link.dayCounter();
            DayCounter voldc = process_.blackVolatility().link.dayCounter();
            double     t     = rfdc.yearFraction(process_.riskFreeRate().link.referenceDate(), arguments_.exercise.lastDate());

            results_.rho = black.rho(t);

            t = divdc.yearFraction(process_.dividendYield().link.referenceDate(), arguments_.exercise.lastDate());
            results_.dividendRho = black.dividendRho(t);

            t             = voldc.yearFraction(process_.blackVolatility().link.referenceDate(), arguments_.exercise.lastDate());
            results_.vega = black.vega(t);
            try {
                results_.theta       = black.theta(spot, t);
                results_.thetaPerDay = black.thetaPerDay(spot, t);
            } catch {
                results_.theta       = null;
                results_.thetaPerDay = null;
            }

            results_.strikeSensitivity  = black.strikeSensitivity();
            results_.itmCashProbability = black.itmCashProbability();
        }
Пример #2
0
        private double vanillaEquivalent()
        {
            // Call KI equates to vanilla - callKO
            StrikedTypePayoff payoff       = arguments_.payoff as StrikedTypePayoff;
            double            forwardPrice = underlying() * dividendDiscount() / riskFreeDiscount();
            BlackCalculator   black        = new BlackCalculator(payoff, forwardPrice, stdDeviation(), riskFreeDiscount());
            double            vanilla      = black.value();

            if (vanilla < 0.0)
            {
                vanilla = 0.0;
            }
            return(vanilla);
        }
Пример #3
0
        public override void calculate() {

            if(arguments_.exercise.type() != Exercise.Type.European)
                throw new ApplicationException("not an European option");

            StrikedTypePayoff payoff = arguments_.payoff as StrikedTypePayoff;
            if (payoff == null)
                throw new ApplicationException("non-striked payoff given");

            double variance = process_.blackVolatility().link.blackVariance(arguments_.exercise.lastDate(), payoff.strike());
            double dividendDiscount = process_.dividendYield().link.discount(arguments_.exercise.lastDate());
            double riskFreeDiscount = process_.riskFreeRate().link.discount(arguments_.exercise.lastDate());
            double spot = process_.stateVariable().link.value();
            if (!(spot > 0.0))
                throw new ApplicationException("negative or null underlying given");
            double forwardPrice = spot * dividendDiscount / riskFreeDiscount;

            BlackCalculator black = new BlackCalculator(payoff, forwardPrice, Math.Sqrt(variance), riskFreeDiscount);

            results_.value = black.value();
            results_.delta = black.delta(spot);
            results_.deltaForward = black.deltaForward();
            results_.elasticity = black.elasticity(spot);
            results_.gamma = black.gamma(spot);

            DayCounter rfdc  = process_.riskFreeRate().link.dayCounter();
            DayCounter divdc = process_.dividendYield().link.dayCounter();
            DayCounter voldc = process_.blackVolatility().link.dayCounter();
            double t = rfdc.yearFraction(process_.riskFreeRate().link.referenceDate(), arguments_.exercise.lastDate());
            results_.rho = black.rho(t);

            t = divdc.yearFraction(process_.dividendYield().link.referenceDate(), arguments_.exercise.lastDate());
            results_.dividendRho = black.dividendRho(t);

            t = voldc.yearFraction(process_.blackVolatility().link.referenceDate(), arguments_.exercise.lastDate());
            results_.vega = black.vega(t);
            try {
                results_.theta = black.theta(spot, t);
                results_.thetaPerDay = black.thetaPerDay(spot, t);
            } catch {
                results_.theta = null;
                results_.thetaPerDay = null;
            }

            results_.strikeSensitivity  = black.strikeSensitivity();
            results_.itmCashProbability = black.itmCashProbability();
        }
Пример #4
0
        public override void calculate()
        {
            Utils.QL_REQUIRE(arguments_.exercise.type() == Exercise.Type.European, () => "not an European Option");

            EuropeanExercise exercise = arguments_.exercise as EuropeanExercise;

            Utils.QL_REQUIRE(exercise != null, () => "not an European Option");

            SpreadBasketPayoff spreadPayoff = arguments_.payoff as SpreadBasketPayoff;

            Utils.QL_REQUIRE(spreadPayoff != null, () => " spread payoff expected");

            PlainVanillaPayoff payoff = spreadPayoff.basePayoff() as PlainVanillaPayoff;

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

            double f1 = process1_.stateVariable().link.value();
            double f2 = process2_.stateVariable().link.value();

            // use atm vols
            double variance1 = process1_.blackVolatility().link.blackVariance(exercise.lastDate(), f1);
            double variance2 = process2_.blackVolatility().link.blackVariance(exercise.lastDate(), f2);

            double riskFreeDiscount = process1_.riskFreeRate().link.discount(exercise.lastDate());

            Func <double, double> Square = x => x * x;
            double f = f1 / (f2 + strike);
            double v = Math.Sqrt(variance1
                                 + variance2 * Square(f2 / (f2 + strike))
                                 - 2 * rho_ * Math.Sqrt(variance1 * variance2)
                                 * (f2 / (f2 + strike)));

            BlackCalculator black = new BlackCalculator(new PlainVanillaPayoff(payoff.optionType(), 1.0), f, v, riskFreeDiscount);

            results_.value = (f2 + strike) * black.value();
        }
Пример #5
0
 public Calculator(BlackCalculator black) {
     black_ = black;
 }
Пример #6
0
        public override void calculate()
        {
            Utils.QL_REQUIRE(arguments_.exercise.type() == Exercise.Type.American, () => "not an American Option");

            AmericanExercise ex = arguments_.exercise as AmericanExercise;

            Utils.QL_REQUIRE(ex != null, () => "non-American exercise given");

            Utils.QL_REQUIRE(!ex.payoffAtExpiry(), () => "payoff at expiry not handled");

            StrikedTypePayoff payoff = arguments_.payoff as StrikedTypePayoff;

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

            double variance         = process_.blackVolatility().link.blackVariance(ex.lastDate(), payoff.strike());
            double dividendDiscount = process_.dividendYield().link.discount(ex.lastDate());
            double riskFreeDiscount = process_.riskFreeRate().link.discount(ex.lastDate());
            double spot             = process_.stateVariable().link.value();

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

            double          forwardPrice = spot * dividendDiscount / riskFreeDiscount;
            BlackCalculator black        = new BlackCalculator(payoff, forwardPrice, Math.Sqrt(variance), riskFreeDiscount);

            if (dividendDiscount >= 1.0 && payoff.optionType() == Option.Type.Call)
            {
                // early exercise never optimal
                results_.value        = black.value();
                results_.delta        = black.delta(spot);
                results_.deltaForward = black.deltaForward();
                results_.elasticity   = black.elasticity(spot);
                results_.gamma        = black.gamma(spot);

                DayCounter rfdc  = process_.riskFreeRate().link.dayCounter();
                DayCounter divdc = process_.dividendYield().link.dayCounter();
                DayCounter voldc = process_.blackVolatility().link.dayCounter();
                double     t     = rfdc.yearFraction(process_.riskFreeRate().link.referenceDate(), arguments_.exercise.lastDate());
                results_.rho = black.rho(t);

                t = divdc.yearFraction(process_.dividendYield().link.referenceDate(), arguments_.exercise.lastDate());
                results_.dividendRho = black.dividendRho(t);

                t                    = voldc.yearFraction(process_.blackVolatility().link.referenceDate(), arguments_.exercise.lastDate());
                results_.vega        = black.vega(t);
                results_.theta       = black.theta(spot, t);
                results_.thetaPerDay = black.thetaPerDay(spot, t);

                results_.strikeSensitivity  = black.strikeSensitivity();
                results_.itmCashProbability = black.itmCashProbability();
            }
            else
            {
                // early exercise can be optimal
                CumulativeNormalDistribution cumNormalDist = new CumulativeNormalDistribution();
                NormalDistribution           normalDist    = new NormalDistribution();

                double tolerance = 1e-6;
                double Sk        = BaroneAdesiWhaleyApproximationEngine.criticalPrice(payoff, riskFreeDiscount, dividendDiscount,
                                                                                      variance, tolerance);

                double forwardSk = Sk * dividendDiscount / riskFreeDiscount;

                double alpha = -2.0 * Math.Log(riskFreeDiscount) / (variance);
                double beta  = 2.0 * Math.Log(dividendDiscount / riskFreeDiscount) / (variance);
                double h     = 1 - riskFreeDiscount;
                double phi   = 0;
                switch (payoff.optionType())
                {
                case Option.Type.Call:
                    phi = 1;
                    break;

                case Option.Type.Put:
                    phi = -1;
                    break;

                default:
                    Utils.QL_FAIL("invalid option type");
                    break;
                }
                //it can throw: to be fixed
                // FLOATING_POINT_EXCEPTION
                double temp_root    = Math.Sqrt((beta - 1) * (beta - 1) + (4 * alpha) / h);
                double lambda       = (-(beta - 1) + phi * temp_root) / 2;
                double lambda_prime = -phi * alpha / (h * h * temp_root);

                double black_Sk = Utils.blackFormula(payoff.optionType(), payoff.strike(), forwardSk, Math.Sqrt(variance)) *
                                  riskFreeDiscount;
                double hA = phi * (Sk - payoff.strike()) - black_Sk;

                double d1_Sk = (Math.Log(forwardSk / payoff.strike()) + 0.5 * variance) / Math.Sqrt(variance);
                double d2_Sk = d1_Sk - Math.Sqrt(variance);
                double part1 = forwardSk * normalDist.value(d1_Sk) / (alpha * Math.Sqrt(variance));
                double part2 = -phi *forwardSk *cumNormalDist.value(phi *d1_Sk) * Math.Log(dividendDiscount) /
                               Math.Log(riskFreeDiscount);

                double part3 = +phi *payoff.strike() * cumNormalDist.value(phi * d2_Sk);

                double V_E_h = part1 + part2 + part3;

                double b = (1 - h) * alpha * lambda_prime / (2 * (2 * lambda + beta - 1));
                double c = -((1 - h) * alpha / (2 * lambda + beta - 1)) *
                           (V_E_h / (hA) + 1 / h + lambda_prime / (2 * lambda + beta - 1));
                double temp_spot_ratio = Math.Log(spot / Sk);
                double chi             = temp_spot_ratio * (b * temp_spot_ratio + c);

                if (phi * (Sk - spot) > 0)
                {
                    results_.value = black.value() + hA * Math.Pow((spot / Sk), lambda) / (1 - chi);
                }
                else
                {
                    results_.value = phi * (spot - payoff.strike());
                }

                double temp_chi_prime   = (2 * b / spot) * Math.Log(spot / Sk);
                double chi_prime        = temp_chi_prime + c / spot;
                double chi_double_prime = 2 * b / (spot * spot) - temp_chi_prime / spot - c / (spot * spot);
                results_.delta = phi * dividendDiscount * cumNormalDist.value(phi * d1_Sk) +
                                 (lambda / (spot * (1 - chi)) + chi_prime / ((1 - chi) * (1 - chi))) *
                                 (phi * (Sk - payoff.strike()) - black_Sk) * Math.Pow((spot / Sk), lambda);

                results_.gamma = phi * dividendDiscount * normalDist.value(phi * d1_Sk) / (spot * Math.Sqrt(variance)) +
                                 (2 * lambda * chi_prime / (spot * (1 - chi) * (1 - chi)) +
                                  2 * chi_prime * chi_prime / ((1 - chi) * (1 - chi) * (1 - chi)) +
                                  chi_double_prime / ((1 - chi) * (1 - chi)) +
                                  lambda * (1 - lambda) / (spot * spot * (1 - chi))) *
                                 (phi * (Sk - payoff.strike()) - black_Sk) * Math.Pow((spot / Sk), lambda);
            } // end of "early exercise can be optimal"
        }
Пример #7
0
        public override void calculate(IPricingEngineResults r)
        {
            OneAssetOption.Results results = r as OneAssetOption.Results;
            setGridLimits();
            initializeInitialCondition();
            initializeOperator();
            initializeBoundaryConditions();
            initializeStepCondition();

            List <IOperator>          operatorSet  = new List <IOperator>();
            List <Vector>             arraySet     = new List <Vector>();
            BoundaryConditionSet      bcSet        = new BoundaryConditionSet();
            StepConditionSet <Vector> conditionSet = new StepConditionSet <Vector>();

            prices_ = (SampledCurve)intrinsicValues_.Clone();

            controlPrices_   = (SampledCurve)intrinsicValues_.Clone();
            controlOperator_ = (TridiagonalOperator)finiteDifferenceOperator_.Clone();
            controlBCs_[0]   = BCs_[0];
            controlBCs_[1]   = BCs_[1];

            operatorSet.Add(finiteDifferenceOperator_);
            operatorSet.Add(controlOperator_);

            arraySet.Add(prices_.values());
            arraySet.Add(controlPrices_.values());

            bcSet.Add(BCs_);
            bcSet.Add(controlBCs_);

            conditionSet.Add(stepCondition_);
            conditionSet.Add(new NullCondition <Vector>());

            var model = new FiniteDifferenceModel <ParallelEvolver <CrankNicolson <TridiagonalOperator> > >(operatorSet, bcSet);

            object temp = arraySet;

            model.rollback(ref temp, getResidualTime(), 0.0, timeSteps_, conditionSet);
            arraySet = (List <Vector>)temp;

            prices_.setValues(arraySet[0]);
            controlPrices_.setValues(arraySet[1]);

            StrikedTypePayoff striked_payoff = payoff_ as StrikedTypePayoff;

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

            double variance         = process_.blackVolatility().link.blackVariance(exerciseDate_, striked_payoff.strike());
            double dividendDiscount = process_.dividendYield().link.discount(exerciseDate_);
            double riskFreeDiscount = process_.riskFreeRate().link.discount(exerciseDate_);
            double spot             = process_.stateVariable().link.value();
            double forwardPrice     = spot * dividendDiscount / riskFreeDiscount;

            BlackCalculator black = new BlackCalculator(striked_payoff, forwardPrice, Math.Sqrt(variance), riskFreeDiscount);

            results.value = prices_.valueAtCenter()
                            - controlPrices_.valueAtCenter()
                            + black.value();
            results.delta = prices_.firstDerivativeAtCenter()
                            - controlPrices_.firstDerivativeAtCenter()
                            + black.delta(spot);
            results.gamma = prices_.secondDerivativeAtCenter()
                            - controlPrices_.secondDerivativeAtCenter()
                            + black.gamma(spot);
            results.additionalResults["priceCurve"] = prices_;
        }
        public override void calculate()
        {
            if (!(arguments_.exercise.type() == Exercise.Type.American))
            {
                throw new ApplicationException("not an American Option");
            }

            AmericanExercise ex = arguments_.exercise as AmericanExercise;

            if (ex == null)
            {
                throw new ApplicationException("non-American exercise given");
            }

            if (ex.payoffAtExpiry())
            {
                throw new ApplicationException("payoff at expiry not handled");
            }

            StrikedTypePayoff payoff = arguments_.payoff as StrikedTypePayoff;

            if (payoff == null)
            {
                throw new ApplicationException("non-striked payoff given");
            }

            double variance         = process_.blackVolatility().link.blackVariance(ex.lastDate(), payoff.strike());
            double dividendDiscount = process_.dividendYield().link.discount(ex.lastDate());
            double riskFreeDiscount = process_.riskFreeRate().link.discount(ex.lastDate());
            double spot             = process_.stateVariable().link.value();

            if (!(spot > 0.0))
            {
                throw new ApplicationException("negative or null underlying given");
            }
            double          forwardPrice = spot * dividendDiscount / riskFreeDiscount;
            BlackCalculator black        = new BlackCalculator(payoff, forwardPrice, Math.Sqrt(variance), riskFreeDiscount);

            if (dividendDiscount >= 1.0 && payoff.optionType() == Option.Type.Call)
            {
                // early exercise never optimal
                results_.value        = black.value();
                results_.delta        = black.delta(spot);
                results_.deltaForward = black.deltaForward();
                results_.elasticity   = black.elasticity(spot);
                results_.gamma        = black.gamma(spot);

                DayCounter rfdc  = process_.riskFreeRate().link.dayCounter();
                DayCounter divdc = process_.dividendYield().link.dayCounter();
                DayCounter voldc = process_.blackVolatility().link.dayCounter();
                double     t     = rfdc.yearFraction(process_.riskFreeRate().link.referenceDate(), arguments_.exercise.lastDate());
                results_.rho = black.rho(t);

                t = divdc.yearFraction(process_.dividendYield().link.referenceDate(), arguments_.exercise.lastDate());
                results_.dividendRho = black.dividendRho(t);

                t                    = voldc.yearFraction(process_.blackVolatility().link.referenceDate(), arguments_.exercise.lastDate());
                results_.vega        = black.vega(t);
                results_.theta       = black.theta(spot, t);
                results_.thetaPerDay = black.thetaPerDay(spot, t);

                results_.strikeSensitivity  = black.strikeSensitivity();
                results_.itmCashProbability = black.itmCashProbability();
            }
            else
            {
                // early exercise can be optimal
                CumulativeNormalDistribution cumNormalDist = new CumulativeNormalDistribution();
                double tolerance = 1e-6;
                double Sk        = criticalPrice(payoff, riskFreeDiscount,
                                                 dividendDiscount, variance, tolerance);
                double forwardSk = Sk * dividendDiscount / riskFreeDiscount;
                double d1        = (Math.Log(forwardSk / payoff.strike()) + 0.5 * variance)
                                   / Math.Sqrt(variance);
                double n = 2.0 * Math.Log(dividendDiscount / riskFreeDiscount) / variance;
                double K = -2.0 * Math.Log(riskFreeDiscount) /
                           (variance * (1.0 - riskFreeDiscount));
                double Q, a;
                switch (payoff.optionType())
                {
                case Option.Type.Call:
                    Q = (-(n - 1.0) + Math.Sqrt(((n - 1.0) * (n - 1.0)) + 4.0 * K)) / 2.0;
                    a = (Sk / Q) * (1.0 - dividendDiscount * cumNormalDist.value(d1));
                    if (spot < Sk)
                    {
                        results_.value = black.value() +
                                         a * Math.Pow((spot / Sk), Q);
                    }
                    else
                    {
                        results_.value = spot - payoff.strike();
                    }
                    break;

                case Option.Type.Put:
                    Q = (-(n - 1.0) - Math.Sqrt(((n - 1.0) * (n - 1.0)) + 4.0 * K)) / 2.0;
                    a = -(Sk / Q) *
                        (1.0 - dividendDiscount * cumNormalDist.value(-d1));
                    if (spot > Sk)
                    {
                        results_.value = black.value() +
                                         a * Math.Pow((spot / Sk), Q);
                    }
                    else
                    {
                        results_.value = payoff.strike() - spot;
                    }
                    break;

                default:
                    throw new ApplicationException("unknown option type");
                }
            } // end of "early exercise can be optimal"
        }
Пример #9
0
        public override void calculate(IPricingEngineResults r)
        {
            OneAssetOption.Results results = r as OneAssetOption.Results;
            setGridLimits();
            initializeInitialCondition();
            initializeOperator();
            initializeBoundaryConditions();
            initializeStepCondition();

            // typedef StandardSystemFiniteDifferenceModel model_type;

            List<IOperator> operatorSet = new List<IOperator>();
            List<Vector> arraySet = new List<Vector>();
            BoundaryConditionSet bcSet = new BoundaryConditionSet();
            StepConditionSet<Vector> conditionSet = new StepConditionSet<Vector>();

            prices_ = (SampledCurve)intrinsicValues_.Clone();

            controlPrices_ = (SampledCurve)intrinsicValues_.Clone();
            controlOperator_ = (TridiagonalOperator)finiteDifferenceOperator_.Clone();
            controlBCs_[0] = BCs_[0];
            controlBCs_[1] = BCs_[1];

            operatorSet.Add(finiteDifferenceOperator_);
            operatorSet.Add(controlOperator_);

            arraySet.Add(prices_.values());
            arraySet.Add(controlPrices_.values());

            bcSet.Add(BCs_);
            bcSet.Add(controlBCs_);

            conditionSet.Add(stepCondition_);
            conditionSet.Add(new NullCondition<Vector>());

            var model = new FiniteDifferenceModel<ParallelEvolver<CrankNicolson<TridiagonalOperator>>>(operatorSet, bcSet);

            object temp = arraySet;
            model.rollback(ref temp, getResidualTime(), 0.0, timeSteps_, conditionSet);
            arraySet = (List<Vector>)temp;

            prices_.setValues(arraySet[0]);
            controlPrices_.setValues(arraySet[1]);

            StrikedTypePayoff striked_payoff = payoff_ as StrikedTypePayoff;
            if (striked_payoff == null)
                throw new ApplicationException("non-striked payoff given");

            double variance = process_.blackVolatility().link.blackVariance(exerciseDate_, striked_payoff.strike());
            double dividendDiscount = process_.dividendYield().link.discount(exerciseDate_);
            double riskFreeDiscount = process_.riskFreeRate().link.discount(exerciseDate_);
            double spot = process_.stateVariable().link.value();
            double forwardPrice = spot * dividendDiscount / riskFreeDiscount;

            BlackCalculator black = new BlackCalculator(striked_payoff, forwardPrice, Math.Sqrt(variance), riskFreeDiscount);

            results.value = prices_.valueAtCenter()
                - controlPrices_.valueAtCenter()
                + black.value();
            results.delta = prices_.firstDerivativeAtCenter()
                - controlPrices_.firstDerivativeAtCenter()
                + black.delta(spot);
            results.gamma = prices_.secondDerivativeAtCenter()
                - controlPrices_.secondDerivativeAtCenter()
                + black.gamma(spot);
            results.additionalResults.Add("priceCurve", prices_);
        }
Пример #10
0
        public override void calculate()
        {
            if (!(arguments_.exercise.type() == Exercise.Type.American))
                throw new ApplicationException("not an American Option");

            AmericanExercise ex = arguments_.exercise as AmericanExercise;
            if (ex == null) throw new ApplicationException("non-American exercise given");

            if(ex.payoffAtExpiry()) throw new ApplicationException("payoff at expiry not handled");

            StrikedTypePayoff payoff = arguments_.payoff as StrikedTypePayoff;
            if (payoff == null) throw new ApplicationException("non-striked payoff given");

            double variance = process_.blackVolatility().link.blackVariance(ex.lastDate(), payoff.strike());
            double dividendDiscount = process_.dividendYield().link.discount(ex.lastDate());
            double riskFreeDiscount = process_.riskFreeRate().link.discount(ex.lastDate());
            double spot = process_.stateVariable().link.value();
            if (!(spot > 0.0)) throw new ApplicationException("negative or null underlying given");
            double forwardPrice = spot * dividendDiscount / riskFreeDiscount;
            BlackCalculator black = new BlackCalculator(payoff, forwardPrice, Math.Sqrt(variance), riskFreeDiscount);

            if (dividendDiscount>=1.0 && payoff.optionType()==Option.Type.Call) {
                // early exercise never optimal
                results_.value        = black.value();
                results_.delta        = black.delta(spot);
                results_.deltaForward = black.deltaForward();
                results_.elasticity   = black.elasticity(spot);
                results_.gamma        = black.gamma(spot);

                DayCounter rfdc  = process_.riskFreeRate().link.dayCounter();
                DayCounter divdc = process_.dividendYield().link.dayCounter();
                DayCounter voldc = process_.blackVolatility().link.dayCounter();
                double t = rfdc.yearFraction(process_.riskFreeRate().link.referenceDate(), arguments_.exercise.lastDate());
                results_.rho = black.rho(t);

                t = divdc.yearFraction(process_.dividendYield().link.referenceDate(), arguments_.exercise.lastDate());
                results_.dividendRho = black.dividendRho(t);

                t = voldc.yearFraction(process_.blackVolatility().link.referenceDate(), arguments_.exercise.lastDate());
                results_.vega        = black.vega(t);
                results_.theta       = black.theta(spot, t);
                results_.thetaPerDay = black.thetaPerDay(spot, t);

                results_.strikeSensitivity  = black.strikeSensitivity();
                results_.itmCashProbability = black.itmCashProbability();
            } else {
                // early exercise can be optimal
                CumulativeNormalDistribution cumNormalDist = new CumulativeNormalDistribution();
                double tolerance = 1e-6;
                double Sk = criticalPrice(payoff, riskFreeDiscount,
                    dividendDiscount, variance, tolerance);
                double forwardSk = Sk * dividendDiscount / riskFreeDiscount;
                double d1 = (Math.Log(forwardSk/payoff.strike()) + 0.5*variance)
                    /Math.Sqrt(variance);
                double n = 2.0*Math.Log(dividendDiscount/riskFreeDiscount)/variance;
                double K = -2.0*Math.Log(riskFreeDiscount)/
                    (variance*(1.0-riskFreeDiscount));
                double Q, a;
                switch (payoff.optionType()) {
                    case Option.Type.Call:
                        Q = (-(n-1.0) + Math.Sqrt(((n-1.0)*(n-1.0))+4.0*K))/2.0;
                        a =  (Sk/Q) * (1.0 - dividendDiscount * cumNormalDist.value(d1));
                        if (spot<Sk) {
                            results_.value = black.value() +
                                a * Math.Pow((spot/Sk), Q);
                        } else {
                            results_.value = spot - payoff.strike();
                        }
                        break;
                    case Option.Type.Put:
                        Q = (-(n-1.0) - Math.Sqrt(((n-1.0)*(n-1.0))+4.0*K))/2.0;
                        a = -(Sk/Q) *
                            (1.0 - dividendDiscount * cumNormalDist.value(-d1));
                        if (spot>Sk) {
                            results_.value = black.value() +
                                a * Math.Pow((spot / Sk), Q);
                        } else {
                            results_.value = payoff.strike() - spot;
                        }
                        break;
                    default:
                      throw new ApplicationException("unknown option type");
                }
            } // end of "early exercise can be optimal"
        }
Пример #11
0
        public override void calculate()
        {
            if (!(arguments_.exercise.type() == Exercise.Type.American))
            {
                throw new ApplicationException("not an American Option");
            }

            AmericanExercise ex = arguments_.exercise as AmericanExercise;

            if (ex == null)
            {
                throw new ApplicationException("non-American exercise given");
            }

            if (ex.payoffAtExpiry())
            {
                throw new ApplicationException("payoff at expiry not handled");
            }

            PlainVanillaPayoff payoff = arguments_.payoff as PlainVanillaPayoff;

            if (payoff == null)
            {
                throw new ApplicationException("non-plain payoff given");
            }

            double variance         = process_.blackVolatility().link.blackVariance(ex.lastDate(), payoff.strike());
            double dividendDiscount = process_.dividendYield().link.discount(ex.lastDate());
            double riskFreeDiscount = process_.riskFreeRate().link.discount(ex.lastDate());

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

            if (!(spot > 0.0))
            {
                throw new ApplicationException("negative or null underlying given");
            }

            double strike = payoff.strike();

            if (payoff.optionType() == Option.Type.Put)
            {
                // use put-call simmetry
                Utils.swap <double>(ref spot, ref strike);
                Utils.swap <double>(ref riskFreeDiscount, ref dividendDiscount);
                payoff = new PlainVanillaPayoff(Option.Type.Call, strike);
            }

            if (dividendDiscount >= 1.0)
            {
                // early exercise is never optimal - use Black formula
                double          forwardPrice = spot * dividendDiscount / riskFreeDiscount;
                BlackCalculator black        = new BlackCalculator(payoff, forwardPrice, Math.Sqrt(variance), riskFreeDiscount);

                results_.value        = black.value();
                results_.delta        = black.delta(spot);
                results_.deltaForward = black.deltaForward();
                results_.elasticity   = black.elasticity(spot);
                results_.gamma        = black.gamma(spot);

                DayCounter rfdc  = process_.riskFreeRate().link.dayCounter();
                DayCounter divdc = process_.dividendYield().link.dayCounter();
                DayCounter voldc = process_.blackVolatility().link.dayCounter();
                double     t     = rfdc.yearFraction(process_.riskFreeRate().link.referenceDate(), arguments_.exercise.lastDate());
                results_.rho = black.rho(t);

                t = divdc.yearFraction(process_.dividendYield().link.referenceDate(), arguments_.exercise.lastDate());
                results_.dividendRho = black.dividendRho(t);

                t                    = voldc.yearFraction(process_.blackVolatility().link.referenceDate(), arguments_.exercise.lastDate());
                results_.vega        = black.vega(t);
                results_.theta       = black.theta(spot, t);
                results_.thetaPerDay = black.thetaPerDay(spot, t);

                results_.strikeSensitivity  = black.strikeSensitivity();
                results_.itmCashProbability = black.itmCashProbability();
            }
            else
            {
                // early exercise can be optimal - use approximation
                results_.value = americanCallApproximation(spot, strike, riskFreeDiscount, dividendDiscount, variance);
            }
        }
Пример #12
0
        public override void calculate()
        {
            Utils.QL_REQUIRE(arguments_.exercise.type() == Exercise.Type.European, () => "not an European option");

            StrikedTypePayoff payoff = arguments_.payoff as StrikedTypePayoff;

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

            Date   settlementDate = process_.riskFreeRate().link.referenceDate();
            double riskless       = 0.0;
            int    i;

            for (i = 0; i < arguments_.cashFlow.Count; i++)
            {
                if (arguments_.cashFlow[i].date() >= settlementDate)
                {
                    riskless += arguments_.cashFlow[i].amount() *
                                process_.riskFreeRate().link.discount(arguments_.cashFlow[i].date());
                }
            }

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

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

            double dividendDiscount = process_.dividendYield().link.discount(arguments_.exercise.lastDate());
            double riskFreeDiscount = process_.riskFreeRate().link.discount(arguments_.exercise.lastDate());
            double forwardPrice     = spot * dividendDiscount / riskFreeDiscount;

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

            BlackCalculator black = new BlackCalculator(payoff, forwardPrice, Math.Sqrt(variance), riskFreeDiscount);

            results_.value = black.value();
            results_.delta = black.delta(spot);
            results_.gamma = black.gamma(spot);

            DayCounter rfdc  = process_.riskFreeRate().link.dayCounter();
            DayCounter voldc = process_.blackVolatility().link.dayCounter();
            double     t     = voldc.yearFraction(process_.blackVolatility().link.referenceDate(), arguments_.exercise.lastDate());

            results_.vega = black.vega(t);

            double delta_theta = 0.0, delta_rho = 0.0;

            for (i = 0; i < arguments_.cashFlow.Count; i++)
            {
                Date d = arguments_.cashFlow[i].date();
                if (d >= settlementDate)
                {
                    delta_theta -= arguments_.cashFlow[i].amount() *
                                   process_.riskFreeRate().link.zeroRate(d, rfdc, Compounding.Continuous, Frequency.Annual).value() *
                                   process_.riskFreeRate().link.discount(d);
                    double t1 = process_.time(d);
                    delta_rho += arguments_.cashFlow[i].amount() * t1 *
                                 process_.riskFreeRate().link.discount(t1);
                }
            }
            t = process_.time(arguments_.exercise.lastDate());
            try
            {
                results_.theta = black.theta(spot, t) +
                                 delta_theta * black.delta(spot);
            }
            catch (Exception)
            {
                results_.theta = null;
            }

            results_.rho = black.rho(t) + delta_rho * black.delta(spot);
        }
Пример #13
0
        public override void calculate()
        {
            /* this engine cannot really check for the averageType==Geometric
               since it can be used as control variate for the Arithmetic version
                QL_REQUIRE(arguments_.averageType == Average::Geometric,
                           "not a geometric average option");
            */

            if(!(arguments_.exercise.type() == Exercise.Type.European))
                throw new ApplicationException("not an European Option");

            double runningLog;
            int pastFixings;
            if (arguments_.averageType == Average.Type.Geometric) {
                if(!(arguments_.runningAccumulator>0.0))
                    throw new ApplicationException("positive running product required: "
                           + arguments_.runningAccumulator + " not allowed");
                runningLog =
                    Math.Log(arguments_.runningAccumulator.GetValueOrDefault());
                pastFixings = arguments_.pastFixings.GetValueOrDefault();
            } else {  // it is being used as control variate
                runningLog = 1.0;
                pastFixings = 0;
            }

            PlainVanillaPayoff payoff = (PlainVanillaPayoff)(arguments_.payoff);
            if (payoff == null)
                throw new ApplicationException("non-plain payoff given");

            Date referenceDate = process_.riskFreeRate().link.referenceDate();
            DayCounter rfdc  = process_.riskFreeRate().link.dayCounter();
            DayCounter divdc = process_.dividendYield().link.dayCounter();
            DayCounter voldc = process_.blackVolatility().link.dayCounter();
            List<double> fixingTimes = new InitializedList<double>(arguments_.fixingDates.Count());
            int i;
            for (i=0; i<arguments_.fixingDates.Count(); i++) {
                if (arguments_.fixingDates[i]>=referenceDate) {
                    double t = voldc.yearFraction(referenceDate,
                        arguments_.fixingDates[i]);
                    fixingTimes.Add(t);
                }
            }

            int remainingFixings = fixingTimes.Count();
            int numberOfFixings = pastFixings + remainingFixings;
            double N = numberOfFixings;

            double pastWeight   = pastFixings/N;
            double futureWeight = 1.0-pastWeight;

            /*double timeSum = std::accumulate(fixingTimes.begin(),
                                           fixingTimes.end(), 0.0);*/
            double timeSum = 0;
            fixingTimes.ForEach((ii, vv) => timeSum += fixingTimes[ii]);

            double vola = process_.blackVolatility().link.blackVol(
                                                  arguments_.exercise.lastDate(),
                                                  payoff.strike());
            double temp = 0.0;
            for (i=pastFixings+1; i<numberOfFixings; i++)
                temp += fixingTimes[i-pastFixings-1]*(N-i);
            double variance = vola*vola /N/N * (timeSum+ 2.0*temp);
            double dsigG_dsig = Math.Sqrt((timeSum + 2.0*temp))/N;
            double sigG = vola * dsigG_dsig;
            double dmuG_dsig = -(vola * timeSum)/N;

            Date exDate = arguments_.exercise.lastDate();
            double dividendRate = process_.dividendYield().link.
                zeroRate(exDate, divdc,  Compounding.Continuous, Frequency.NoFrequency).rate();
            double riskFreeRate = process_.riskFreeRate().link.
                zeroRate(exDate, rfdc,  Compounding.Continuous, Frequency.NoFrequency).rate();
            double nu = riskFreeRate - dividendRate - 0.5*vola*vola;

            double s = process_.stateVariable().link.value();
            if(!(s > 0.0))
                throw new ApplicationException("positive underlying value required");

            int M = (pastFixings == 0 ? 1 : pastFixings);
            double muG = pastWeight * runningLog/M +
                futureWeight * Math.Log(s) + nu*timeSum/N;
            double forwardPrice = Math.Exp(muG + variance / 2.0);

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

            BlackCalculator black = new BlackCalculator(payoff, forwardPrice, Math.Sqrt(variance),
                                  riskFreeDiscount);

            results_.value = black.value();
            results_.delta = futureWeight*black.delta(forwardPrice)*forwardPrice/s;
            results_.gamma = forwardPrice*futureWeight/(s*s)
                    *(  black.gamma(forwardPrice)*futureWeight*forwardPrice
                      - pastWeight*black.delta(forwardPrice) );

            double Nx_1, nx_1;
            CumulativeNormalDistribution CND = new CumulativeNormalDistribution();
            NormalDistribution ND = new NormalDistribution();
            if (sigG > Const.QL_Epsilon) {
                double x_1  = (muG-Math.Log(payoff.strike())+variance)/sigG;
                Nx_1 = CND.value(x_1);
                nx_1 = ND.value( x_1);
            } else {
                Nx_1 = (muG > Math.Log(payoff.strike()) ? 1.0 : 0.0);
                nx_1 = 0.0;
            }
            results_.vega = forwardPrice * riskFreeDiscount *
                       ( (dmuG_dsig + sigG * dsigG_dsig)*Nx_1 + nx_1*dsigG_dsig );

            if (payoff.optionType() == Option.Type.Put)
                results_.vega -= riskFreeDiscount * forwardPrice *
                                                  (dmuG_dsig + sigG * dsigG_dsig);

            double tRho = rfdc.yearFraction(process_.riskFreeRate().link.referenceDate(),
                                          arguments_.exercise.lastDate());
            results_.rho = black.rho(tRho)*timeSum/(N*tRho)
                          - (tRho-timeSum/N)*results_.value;

            double tDiv = divdc.yearFraction(
                               process_.dividendYield().link.referenceDate(),
                               arguments_.exercise.lastDate());

            results_.dividendRho = black.dividendRho(tDiv)*timeSum /(N*tDiv);

            results_.strikeSensitivity = black.strikeSensitivity();

            results_.theta =  Utils.blackScholesTheta(process_,
                                               results_.value.GetValueOrDefault(),
                                               results_.delta.GetValueOrDefault(),
                                               results_.gamma.GetValueOrDefault());
        }
Пример #14
0
        public override void calculate()
        {
            Utils.QL_REQUIRE(arguments_.accruedCoupon == null &&
                             arguments_.lastFixing == null, () =>
                             "this engine cannot price options already started");
            Utils.QL_REQUIRE(arguments_.localCap == null &&
                             arguments_.localFloor == null &&
                             arguments_.globalCap == null &&
                             arguments_.globalFloor == null, () =>
                             "this engine cannot price capped/floored options");

            Utils.QL_REQUIRE(arguments_.exercise.type() == Exercise.Type.European, () => "not an European option");

            PercentageStrikePayoff moneyness = arguments_.payoff as PercentageStrikePayoff;

            Utils.QL_REQUIRE(moneyness != null, () => "wrong payoff given");

            List <Date> resetDates = arguments_.resetDates;

            resetDates.Add(arguments_.exercise.lastDate());

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

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

            StrikedTypePayoff payoff = new PlainVanillaPayoff(moneyness.optionType(), 1.0);

            results_.value = 0.0;
            results_.delta = results_.gamma = 0.0;
            results_.theta = 0.0;
            results_.rho   = results_.dividendRho = 0.0;
            results_.vega  = 0.0;

            for (int i = 1; i < resetDates.Count; i++)
            {
                double discount  = process_.riskFreeRate().link.discount(resetDates[i - 1]);
                double rDiscount = process_.riskFreeRate().link.discount(resetDates[i]) /
                                   process_.riskFreeRate().link.discount(resetDates[i - 1]);
                double qDiscount = process_.dividendYield().link.discount(resetDates[i]) /
                                   process_.dividendYield().link.discount(resetDates[i - 1]);
                double forward  = (1.0 / moneyness.strike()) * qDiscount / rDiscount;
                double variance = process_.blackVolatility().link.blackForwardVariance(
                    resetDates[i - 1], resetDates[i],
                    underlying * moneyness.strike());

                BlackCalculator black = new BlackCalculator(payoff, forward, Math.Sqrt(variance), rDiscount);

                DayCounter rfdc  = process_.riskFreeRate().link.dayCounter();
                DayCounter divdc = process_.dividendYield().link.dayCounter();
                DayCounter voldc = process_.blackVolatility().link.dayCounter();

                results_.value += discount * moneyness.strike() * black.value();
                results_.delta += 0.0;
                results_.gamma += 0.0;
                results_.theta += process_.riskFreeRate().link.forwardRate(
                    resetDates[i - 1], resetDates[i], rfdc, Compounding.Continuous, Frequency.NoFrequency).value() *
                                  discount * moneyness.strike() * black.value();

                double dt = rfdc.yearFraction(resetDates[i - 1], resetDates[i]);
                double t  = rfdc.yearFraction(process_.riskFreeRate().link.referenceDate(), resetDates[i - 1]);
                results_.rho += discount * moneyness.strike() * (black.rho(dt) - t * black.value());

                dt = divdc.yearFraction(resetDates[i - 1], resetDates[i]);
                results_.dividendRho += discount * moneyness.strike() * black.dividendRho(dt);

                dt             = voldc.yearFraction(resetDates[i - 1], resetDates[i]);
                results_.vega += discount * moneyness.strike() * black.vega(dt);
            }
        }
        public override void calculate()
        {
            Utils.QL_REQUIRE( arguments_.exercise.type() == Exercise.Type.European, () => "not an European option" );

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

            Date settlementDate = process_.riskFreeRate().link.referenceDate();
            double riskless = 0.0;
            int i;
            for (i=0; i<arguments_.cashFlow.Count; i++)
                if (arguments_.cashFlow[i].date() >= settlementDate)
                        riskless += arguments_.cashFlow[i].amount() *
                            process_.riskFreeRate().link.discount(arguments_.cashFlow[i].date());

            double spot = process_.stateVariable().link.value() - riskless;
             Utils.QL_REQUIRE( spot > 0.0, () => "negative or null underlying after subtracting dividends" );

            double dividendDiscount = process_.dividendYield().link.discount(arguments_.exercise.lastDate());
            double riskFreeDiscount = process_.riskFreeRate().link.discount(arguments_.exercise.lastDate());
            double forwardPrice = spot * dividendDiscount / riskFreeDiscount;

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

            BlackCalculator black = new BlackCalculator(payoff, forwardPrice, Math.Sqrt(variance),	riskFreeDiscount);

            results_.value = black.value();
            results_.delta = black.delta(spot);
            results_.gamma = black.gamma(spot);

            DayCounter rfdc  = process_.riskFreeRate().link.dayCounter();
            DayCounter voldc = process_.blackVolatility().link.dayCounter();
            double t = voldc.yearFraction( process_.blackVolatility().link.referenceDate(),arguments_.exercise.lastDate());
            results_.vega = black.vega(t);

            double delta_theta = 0.0, delta_rho = 0.0;
            for (i = 0; i < arguments_.cashFlow.Count; i++)
            {
                Date d = arguments_.cashFlow[i].date();
                if (d >= settlementDate)
                {
                        delta_theta -= arguments_.cashFlow[i].amount() *
                        process_.riskFreeRate().link.zeroRate(d,rfdc,Compounding.Continuous,Frequency.Annual).value() *
                        process_.riskFreeRate().link.discount(d);
                        double t1 = process_.time(d);
                        delta_rho += arguments_.cashFlow[i].amount() * t1 *
                                        process_.riskFreeRate().link.discount(t1);
                }
            }
            t = process_.time(arguments_.exercise.lastDate());
            try
            {
                results_.theta = black.theta(spot, t) +
                                        delta_theta * black.delta(spot);
            }
            catch (Exception)
            {
                results_.theta = null;
            }

            results_.rho = black.rho(t) +	delta_rho * black.delta(spot);
        }
Пример #16
0
        public override void calculate()
        {
            if (arguments_.averageType != Average.Type.Geometric)
            {
                throw new ApplicationException("not a geometric average option");
            }

            if (arguments_.exercise.type() != Exercise.Type.European)
            {
                throw new ApplicationException("not an European Option");
            }

            Date exercise = arguments_.exercise.lastDate();

            PlainVanillaPayoff payoff = (PlainVanillaPayoff)(arguments_.payoff);

            if (payoff == null)
            {
                throw new ApplicationException("non-plain payoff given");
            }

            double volatility =
                process_.blackVolatility().link.blackVol(exercise, payoff.strike());
            double variance =
                process_.blackVolatility().link.blackVariance(exercise,
                                                              payoff.strike());
            double riskFreeDiscount =
                process_.riskFreeRate().link.discount(exercise);

            DayCounter rfdc  = process_.riskFreeRate().link.dayCounter();
            DayCounter divdc = process_.dividendYield().link.dayCounter();
            DayCounter voldc = process_.blackVolatility().link.dayCounter();

            double dividendYield = 0.5 * (
                process_.riskFreeRate().link.zeroRate(exercise, rfdc,
                                                      Compounding.Continuous,
                                                      Frequency.NoFrequency).rate() +
                process_.dividendYield().link.zeroRate(exercise, divdc,
                                                       Compounding.Continuous,
                                                       Frequency.NoFrequency).rate() +
                volatility * volatility / 6.0);

            double t_q = divdc.yearFraction(
                process_.dividendYield().link.referenceDate(), exercise);
            double dividendDiscount = Math.Exp(-dividendYield * t_q);

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

            if (!(spot > 0.0))
            {
                throw new ApplicationException("negative or null underlying");
            }

            double forward = spot * dividendDiscount / riskFreeDiscount;

            BlackCalculator black = new BlackCalculator(payoff,
                                                        forward,
                                                        Math.Sqrt(variance / 3.0),
                                                        riskFreeDiscount);

            results_.value = black.value();
            results_.delta = black.delta(spot);
            results_.gamma = black.gamma(spot);

            results_.dividendRho = black.dividendRho(t_q) / 2.0;

            double t_r = rfdc.yearFraction(process_.riskFreeRate().link.referenceDate(),
                                           arguments_.exercise.lastDate());

            results_.rho = black.rho(t_r) + 0.5 * black.dividendRho(t_q);

            double t_v = voldc.yearFraction(
                process_.blackVolatility().link.referenceDate(),
                arguments_.exercise.lastDate());

            results_.vega = black.vega(t_v) / Math.Sqrt(3.0) +
                            black.dividendRho(t_q) * volatility / 6.0;
            try{
                results_.theta = black.theta(spot, t_v);
            }
            catch (System.Exception /*Error*/) {
                results_.theta = double.NaN; //Null<Real>();
            }
        }
Пример #17
0
        public override void calculate()
        {
            if (!(arguments_.exercise.type() == Exercise.Type.American))
                throw new ApplicationException("not an American Option");

            AmericanExercise ex = arguments_.exercise as AmericanExercise;

            if (ex == null)
                throw new ApplicationException("non-American exercise given");

            if (ex.payoffAtExpiry())
                throw new ApplicationException("payoff at expiry not handled");

            StrikedTypePayoff payoff = arguments_.payoff as StrikedTypePayoff;
            if (payoff == null)
                throw new ApplicationException("non-striked payoff given");

            double variance = process_.blackVolatility().link.blackVariance(ex.lastDate(), payoff.strike());
            double dividendDiscount = process_.dividendYield().link.discount(ex.lastDate());
            double riskFreeDiscount = process_.riskFreeRate().link.discount(ex.lastDate());
            double spot = process_.stateVariable().link.value();

            if (!(spot > 0.0))
                throw new ApplicationException("negative or null underlying given");

            double forwardPrice = spot * dividendDiscount / riskFreeDiscount;
            BlackCalculator black = new BlackCalculator(payoff, forwardPrice, Math.Sqrt(variance), riskFreeDiscount);

            if (dividendDiscount>=1.0 && payoff.optionType()==Option.Type.Call)
            {
                // early exercise never optimal
                results_.value = black.value();
                results_.delta = black.delta(spot);
                results_.deltaForward = black.deltaForward();
                results_.elasticity = black.elasticity(spot);
                results_.gamma = black.gamma(spot);

                DayCounter rfdc = process_.riskFreeRate().link.dayCounter();
                DayCounter divdc = process_.dividendYield().link.dayCounter();
                DayCounter voldc = process_.blackVolatility().link.dayCounter();
                double t = rfdc.yearFraction(process_.riskFreeRate().link.referenceDate(), arguments_.exercise.lastDate());
                results_.rho = black.rho(t);

                t = divdc.yearFraction(process_.dividendYield().link.referenceDate(), arguments_.exercise.lastDate());
                results_.dividendRho = black.dividendRho(t);

                t = voldc.yearFraction(process_.blackVolatility().link.referenceDate(), arguments_.exercise.lastDate());
                results_.vega = black.vega(t);
                results_.theta = black.theta(spot, t);
                results_.thetaPerDay = black.thetaPerDay(spot, t);

                results_.strikeSensitivity = black.strikeSensitivity();
                results_.itmCashProbability = black.itmCashProbability();
            }
            else
            {
                // early exercise can be optimal
                CumulativeNormalDistribution cumNormalDist = new CumulativeNormalDistribution();
                NormalDistribution normalDist = new NormalDistribution();

                double tolerance = 1e-6;
                double Sk = BaroneAdesiWhaleyApproximationEngine.criticalPrice(payoff, riskFreeDiscount, dividendDiscount, variance, tolerance);

                double forwardSk = Sk * dividendDiscount / riskFreeDiscount;

                double alpha = -2.0 *Math.Log(riskFreeDiscount)/(variance);
                double beta = 2.0 *Math.Log(dividendDiscount/riskFreeDiscount)/ (variance);
                double h = 1 - riskFreeDiscount;
                double phi;
                switch (payoff.optionType())
                {
                    case Option.Type.Call:
                        phi = 1;
                        break;
                    case Option.Type.Put:
                        phi = -1;
                        break;
                    default:
                        throw new ArgumentException("invalid option type");
                }
                //it can throw: to be fixed
                // FLOATING_POINT_EXCEPTION
                double temp_root = Math.Sqrt ((beta-1)*(beta-1) + (4 *alpha)/h);
                double lambda = (-(beta-1) + phi * temp_root) / 2;
                double lambda_prime = - phi * alpha / (h *h * temp_root);

                double black_Sk = Utils.blackFormula(payoff.optionType(), payoff.strike(), forwardSk, Math.Sqrt(variance)) * riskFreeDiscount;
                double hA = phi * (Sk - payoff.strike()) - black_Sk;

                double d1_Sk = (Math.Log(forwardSk/payoff.strike()) + 0.5 *variance) /Math.Sqrt(variance);
                double d2_Sk = d1_Sk - Math.Sqrt(variance);
                double part1 = forwardSk * normalDist.value(d1_Sk) / (alpha * Math.Sqrt(variance));
                double part2 = - phi * forwardSk * cumNormalDist.value(phi * d1_Sk) * Math.Log(dividendDiscount) / Math.Log(riskFreeDiscount);
                double part3 = + phi * payoff.strike() * cumNormalDist.value(phi * d2_Sk);
                double V_E_h = part1 + part2 + part3;

                double b = (1-h) * alpha * lambda_prime / (2*(2 *lambda + beta - 1));
                double c = - ((1 - h) * alpha / (2 * lambda + beta - 1)) * (V_E_h / (hA) + 1 / h + lambda_prime / (2 *lambda + beta - 1));
                double temp_spot_ratio = Math.Log(spot / Sk);
                double chi = temp_spot_ratio * (b * temp_spot_ratio + c);

                if (phi*(Sk-spot) > 0)
                {
                    results_.value = black.value() + hA * Math.Pow((spot/Sk), lambda) / (1 - chi);
                }
                else
                {
                    results_.value = phi * (spot - payoff.strike());
                }

                double temp_chi_prime = (2 * b / spot) * Math.Log(spot/Sk);
                double chi_prime = temp_chi_prime + c / spot;
                double chi_double_prime = 2 *b/(spot *spot) - temp_chi_prime / spot - c / (spot *spot);
                results_.delta = phi * dividendDiscount * cumNormalDist.value (phi * d1_Sk) + (lambda / (spot * (1 - chi)) + chi_prime / ((1 - chi)*(1 - chi))) * (phi * (Sk - payoff.strike()) - black_Sk) * Math.Pow((spot/Sk), lambda);

                results_.gamma = phi * dividendDiscount * normalDist.value (phi *d1_Sk) / (spot * Math.Sqrt(variance)) + (2 * lambda * chi_prime / (spot * (1 - chi) * (1 - chi)) + 2 * chi_prime * chi_prime / ((1 - chi) * (1 - chi) * (1 - chi)) + chi_double_prime / ((1 - chi) * (1 - chi)) + lambda * (1 - lambda) / (spot * spot * (1 - chi))) * (phi * (Sk - payoff.strike()) - black_Sk) * Math.Pow((spot/Sk), lambda);

            } // end of "early exercise can be optimal"
        }
        public override void calculate()
        {
            /* this engine cannot really check for the averageType==Geometric
             * since it can be used as control variate for the Arithmetic version
             * QL_REQUIRE(arguments_.averageType == Average::Geometric,"not a geometric average option")
             */
            Utils.QL_REQUIRE(arguments_.exercise.type() == Exercise.Type.European, () => "not an European Option");

            double runningLog;
            int    pastFixings;

            if (arguments_.averageType == Average.Type.Geometric)
            {
                Utils.QL_REQUIRE(arguments_.runningAccumulator > 0.0, () =>
                                 "positive running product required: " + arguments_.runningAccumulator + " not allowed");

                runningLog  = Math.Log(arguments_.runningAccumulator.GetValueOrDefault());
                pastFixings = arguments_.pastFixings.GetValueOrDefault();
            }
            else
            { // it is being used as control variate
                runningLog  = 1.0;
                pastFixings = 0;
            }

            PlainVanillaPayoff payoff = arguments_.payoff as PlainVanillaPayoff;

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

            Date          referenceDate = process_.riskFreeRate().link.referenceDate();
            DayCounter    rfdc          = process_.riskFreeRate().link.dayCounter();
            DayCounter    divdc         = process_.dividendYield().link.dayCounter();
            DayCounter    voldc         = process_.blackVolatility().link.dayCounter();
            List <double> fixingTimes   = new List <double>();
            int           i;

            for (i = 0; i < arguments_.fixingDates.Count; i++)
            {
                if (arguments_.fixingDates[i] >= referenceDate)
                {
                    double t = voldc.yearFraction(referenceDate, arguments_.fixingDates[i]);
                    fixingTimes.Add(t);
                }
            }

            int    remainingFixings = fixingTimes.Count;
            int    numberOfFixings  = pastFixings + remainingFixings;
            double N = numberOfFixings;

            double pastWeight   = pastFixings / N;
            double futureWeight = 1.0 - pastWeight;

            double timeSum = 0;

            fixingTimes.ForEach((ii, vv) => timeSum += fixingTimes[ii]);

            double vola = process_.blackVolatility().link.blackVol(arguments_.exercise.lastDate(), payoff.strike());
            double temp = 0.0;

            for (i = pastFixings + 1; i < numberOfFixings; i++)
            {
                temp += fixingTimes[i - pastFixings - 1] * (N - i);
            }
            double variance   = vola * vola / N / N * (timeSum + 2.0 * temp);
            double dsigG_dsig = Math.Sqrt((timeSum + 2.0 * temp)) / N;
            double sigG       = vola * dsigG_dsig;
            double dmuG_dsig  = -(vola * timeSum) / N;

            Date   exDate       = arguments_.exercise.lastDate();
            double dividendRate = process_.dividendYield().link.
                                  zeroRate(exDate, divdc, Compounding.Continuous, Frequency.NoFrequency).rate();
            double riskFreeRate = process_.riskFreeRate().link.
                                  zeroRate(exDate, rfdc, Compounding.Continuous, Frequency.NoFrequency).rate();
            double nu = riskFreeRate - dividendRate - 0.5 * vola * vola;

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

            Utils.QL_REQUIRE(s > 0.0, () => "positive underlying value required");

            int    M            = (pastFixings == 0 ? 1 : pastFixings);
            double muG          = pastWeight * runningLog / M + futureWeight * Math.Log(s) + nu * timeSum / N;
            double forwardPrice = Math.Exp(muG + variance / 2.0);

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

            BlackCalculator black = new BlackCalculator(payoff, forwardPrice, Math.Sqrt(variance), riskFreeDiscount);

            results_.value = black.value();
            results_.delta = futureWeight * black.delta(forwardPrice) * forwardPrice / s;
            results_.gamma = forwardPrice * futureWeight / (s * s)
                             * (black.gamma(forwardPrice) * futureWeight * forwardPrice
                                - pastWeight * black.delta(forwardPrice));

            double Nx_1, nx_1;
            CumulativeNormalDistribution CND = new CumulativeNormalDistribution();
            NormalDistribution           ND  = new NormalDistribution();

            if (sigG > Const.QL_EPSILON)
            {
                double x_1 = (muG - Math.Log(payoff.strike()) + variance) / sigG;
                Nx_1 = CND.value(x_1);
                nx_1 = ND.value(x_1);
            }
            else
            {
                Nx_1 = (muG > Math.Log(payoff.strike()) ? 1.0 : 0.0);
                nx_1 = 0.0;
            }
            results_.vega = forwardPrice * riskFreeDiscount *
                            ((dmuG_dsig + sigG * dsigG_dsig) * Nx_1 + nx_1 * dsigG_dsig);

            if (payoff.optionType() == Option.Type.Put)
            {
                results_.vega -= riskFreeDiscount * forwardPrice *
                                 (dmuG_dsig + sigG * dsigG_dsig);
            }

            double tRho = rfdc.yearFraction(process_.riskFreeRate().link.referenceDate(),
                                            arguments_.exercise.lastDate());

            results_.rho = black.rho(tRho) * timeSum / (N * tRho)
                           - (tRho - timeSum / N) * results_.value;

            double tDiv = divdc.yearFraction(
                process_.dividendYield().link.referenceDate(),
                arguments_.exercise.lastDate());

            results_.dividendRho = black.dividendRho(tDiv) * timeSum / (N * tDiv);

            results_.strikeSensitivity = black.strikeSensitivity();

            results_.theta = Utils.blackScholesTheta(process_,
                                                     results_.value.GetValueOrDefault(),
                                                     results_.delta.GetValueOrDefault(),
                                                     results_.gamma.GetValueOrDefault());
        }
Пример #19
0
        public override void calculate()
        {
            if (arguments_.averageType != Average.Type.Geometric)
                throw new ApplicationException("not a geometric average option");

            if (arguments_.exercise.type() != Exercise.Type.European)
                throw new ApplicationException("not an European Option");

            Date exercise = arguments_.exercise.lastDate();

            PlainVanillaPayoff payoff = (PlainVanillaPayoff)(arguments_.payoff);
            if (payoff == null)
                throw new ApplicationException("non-plain payoff given");

            double volatility =
                process_.blackVolatility().link.blackVol(exercise, payoff.strike());
            double variance =
                process_.blackVolatility().link.blackVariance(exercise,
                                                           payoff.strike());
            double riskFreeDiscount =
                process_.riskFreeRate().link.discount(exercise);

            DayCounter rfdc = process_.riskFreeRate().link.dayCounter();
            DayCounter divdc = process_.dividendYield().link.dayCounter();
            DayCounter voldc = process_.blackVolatility().link.dayCounter();

            double dividendYield = 0.5 * (
                process_.riskFreeRate().link.zeroRate(exercise, rfdc,
                                                   Compounding.Continuous,
                                                   Frequency.NoFrequency).rate() +
                process_.dividendYield().link.zeroRate(exercise, divdc,
                                                   Compounding.Continuous,
                                                   Frequency.NoFrequency).rate() +
                volatility * volatility / 6.0);

            double t_q = divdc.yearFraction(
                process_.dividendYield().link.referenceDate(), exercise);
            double dividendDiscount = Math.Exp(-dividendYield * t_q);

            double spot = process_.stateVariable().link.value();
            if (!(spot > 0.0))
                throw new ApplicationException("negative or null underlying");

            double forward = spot * dividendDiscount / riskFreeDiscount;

            BlackCalculator black = new BlackCalculator(payoff,
                                                        forward,
                                                        Math.Sqrt(variance / 3.0),
                                                        riskFreeDiscount);

            results_.value = black.value();
            results_.delta = black.delta(spot);
            results_.gamma = black.gamma(spot);

            results_.dividendRho = black.dividendRho(t_q) / 2.0;

            double t_r = rfdc.yearFraction(process_.riskFreeRate().link.referenceDate(),
                                         arguments_.exercise.lastDate());
            results_.rho = black.rho(t_r) + 0.5 * black.dividendRho(t_q);

            double t_v = voldc.yearFraction(
                process_.blackVolatility().link.referenceDate(),
                arguments_.exercise.lastDate());
            results_.vega = black.vega(t_v) / Math.Sqrt(3.0) +
                            black.dividendRho(t_q) * volatility / 6.0;
            try{
                results_.theta = black.theta(spot, t_v);
            }
            catch (System.Exception /*Error*/){
                results_.theta = double.NaN; //Null<Real>();
            }
        }
Пример #20
0
 public Calculator(BlackCalculator black)
 {
     black_ = black;
 }
Пример #21
0
        public override void calculate() {

            if (!(arguments_.exercise.type() == Exercise.Type.American))
                throw new ApplicationException("not an American Option");

            AmericanExercise ex = arguments_.exercise as AmericanExercise;
            if(ex == null) throw new ApplicationException("non-American exercise given");
            
            if(ex.payoffAtExpiry()) throw new ApplicationException("payoff at expiry not handled");

            PlainVanillaPayoff payoff = arguments_.payoff as PlainVanillaPayoff;
            if(payoff == null) throw new ApplicationException("non-plain payoff given");

            double variance = process_.blackVolatility().link.blackVariance(ex.lastDate(), payoff.strike());
            double dividendDiscount = process_.dividendYield().link.discount(ex.lastDate());
            double riskFreeDiscount = process_.riskFreeRate().link.discount(ex.lastDate());
            
            double spot = process_.stateVariable().link.value();
            if (!(spot > 0.0)) throw new ApplicationException("negative or null underlying given");
            
            double strike = payoff.strike();

            if (payoff.optionType()==Option.Type.Put) {
                // use put-call simmetry
                Utils.swap<double>(ref spot, ref strike);
                Utils.swap<double>(ref riskFreeDiscount, ref dividendDiscount);
                payoff = new PlainVanillaPayoff(Option.Type.Call, strike);
            }

            if (dividendDiscount>=1.0) {
                // early exercise is never optimal - use Black formula
                double forwardPrice = spot * dividendDiscount / riskFreeDiscount;
                BlackCalculator black = new BlackCalculator(payoff, forwardPrice, Math.Sqrt(variance), riskFreeDiscount);

                results_.value        = black.value();
                results_.delta        = black.delta(spot);
                results_.deltaForward = black.deltaForward();
                results_.elasticity   = black.elasticity(spot);
                results_.gamma        = black.gamma(spot);

                DayCounter rfdc  = process_.riskFreeRate().link.dayCounter();
                DayCounter divdc = process_.dividendYield().link.dayCounter();
                DayCounter voldc = process_.blackVolatility().link.dayCounter();
                double t = rfdc.yearFraction(process_.riskFreeRate().link.referenceDate(), arguments_.exercise.lastDate());
                results_.rho = black.rho(t);

                t = divdc.yearFraction(process_.dividendYield().link.referenceDate(), arguments_.exercise.lastDate());
                results_.dividendRho = black.dividendRho(t);

                t = voldc.yearFraction(process_.blackVolatility().link.referenceDate(), arguments_.exercise.lastDate());
                results_.vega        = black.vega(t);
                results_.theta       = black.theta(spot, t);
                results_.thetaPerDay = black.thetaPerDay(spot, t);

                results_.strikeSensitivity  = black.strikeSensitivity();
                results_.itmCashProbability = black.itmCashProbability();
            } else {
                // early exercise can be optimal - use approximation
                results_.value = americanCallApproximation(spot, strike, riskFreeDiscount, dividendDiscount, variance);
            }
        }