Exemplo n.º 1
0
        public override void calculate()
        {
            PlainVanillaPayoff payoff = arguments_.payoff as PlainVanillaPayoff;

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

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

            switch (payoff.optionType())
            {
            case Option.Type.Call:
                Utils.QL_REQUIRE(payoff.strike() >= 0.0, () => "Strike must be positive or null");
                results_.value = A(1);
                break;

            case Option.Type.Put:
                Utils.QL_REQUIRE(payoff.strike() > 0.0, () => "Strike must be positive");
                results_.value = A(-1);
                break;

            default:
                Utils.QL_FAIL("Unknown type");
                break;
            }
        }
Exemplo n.º 2
0
        // calculate the value of euro max basket call
        private double euroTwoAssetMaxBasketCall(double forward1, double forward2, double strike, double riskFreeDiscount,
                                                 double variance1, double variance2, double rho)
        {
            StrikedTypePayoff payoff = new PlainVanillaPayoff(Option.Type.Call, strike);

            double black1 = Utils.blackFormula(payoff.optionType(), payoff.strike(), forward1,
                                               Math.Sqrt(variance1)) * riskFreeDiscount;

            double black2 = Utils.blackFormula(payoff.optionType(), payoff.strike(), forward2,
                                               Math.Sqrt(variance2)) * riskFreeDiscount;

            return(black1 + black2 -
                   euroTwoAssetMinBasketCall(forward1, forward2, strike,
                                             riskFreeDiscount,
                                             variance1, variance2, rho));
        }
Exemplo n.º 3
0
 public static double bachelierBlackFormula(PlainVanillaPayoff payoff,
                                            double forward,
                                            double stdDev,
                                            double discount = 1.0)
 {
     return(bachelierBlackFormula(payoff.optionType(), payoff.strike(), forward, stdDev, discount));
 }
Exemplo n.º 4
0
 public static double bachelierBlackFormulaStdDevDerivative(PlainVanillaPayoff payoff,
                                                            double forward,
                                                            double stdDev,
                                                            double discount = 1.0)
 {
     return(bachelierBlackFormulaStdDevDerivative(payoff.strike(), forward, stdDev, discount));
 }
Exemplo n.º 5
0
        private double strike()
        {
            PlainVanillaPayoff payoff = arguments_.payoff as PlainVanillaPayoff;

            Utils.QL_REQUIRE(payoff != null, () => "Non-plain payoff given");
            return(payoff.strike());
        }
Exemplo n.º 6
0
 public static double blackFormulaCashItmProbability(PlainVanillaPayoff payoff,
                                                     double forward,
                                                     double stdDev,
                                                     double displacement = 0.0)
 {
     return(blackFormulaCashItmProbability(payoff.optionType(),
                                           payoff.strike(), forward, stdDev, displacement));
 }
Exemplo n.º 7
0
 public static double blackFormulaStdDevSecondDerivative(PlainVanillaPayoff payoff,
                                                         double forward,
                                                         double stdDev,
                                                         double discount     = 1.0,
                                                         double displacement = 0.0)
 {
     return(blackFormulaStdDevSecondDerivative(payoff.strike(), forward, stdDev, discount, displacement));
 }
Exemplo n.º 8
0
 public static double blackFormulaImpliedStdDevApproximation(PlainVanillaPayoff payoff,
                                                             double forward,
                                                             double blackPrice,
                                                             double discount,
                                                             double displacement)
 {
     return(blackFormulaImpliedStdDevApproximation(payoff.optionType(),
                                                   payoff.strike(), forward, blackPrice, discount, displacement));
 }
        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;
            }
        }
Exemplo n.º 10
0
 public static double blackFormulaImpliedStdDev(PlainVanillaPayoff payoff,
                                                double forward,
                                                double blackPrice,
                                                double discount,
                                                double displacement,
                                                double guess,
                                                double accuracy,
                                                int maxIterations = 100)
 {
     return(blackFormulaImpliedStdDev(payoff.optionType(), payoff.strike(),
                                      forward, blackPrice, discount, displacement, guess, accuracy, maxIterations));
 }
Exemplo n.º 11
0
        protected override PathPricer <IPath> pathPricer()
        {
            PlainVanillaPayoff payoff = arguments_.payoff as PlainVanillaPayoff;

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

            GeneralizedBlackScholesProcess process = process_ as GeneralizedBlackScholesProcess;

            Utils.QL_REQUIRE(process != null, () => "Black-Scholes process required");

            return(new EuropeanPathPricer(payoff.optionType(), payoff.strike(),
                                          process.riskFreeRate().link.discount(timeGrid().Last())));
        }
Exemplo n.º 12
0
        protected PathPricer <IPath> mc_looback_path_pricer(ContinuousFixedLookbackOption.Arguments args,
                                                            GeneralizedBlackScholesProcess process,
                                                            double discount)
        {
            PlainVanillaPayoff payoff = args.payoff as PlainVanillaPayoff;

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


            return(new LookbackFixedPathPricer(payoff.optionType(),
                                               payoff.strike(),
                                               discount));
        }
Exemplo n.º 13
0
        protected override PathPricer <IPath> pathPricer()
        {
            PlainVanillaPayoff payoff = arguments_.payoff as PlainVanillaPayoff;

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

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

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

            // do this with template parameters?
            if (isBiased_)
            {
                return(new BiasedBarrierPathPricer(arguments_.barrierType,
                                                   arguments_.barrier,
                                                   arguments_.rebate,
                                                   payoff.optionType(),
                                                   payoff.strike(),
                                                   discounts));
            }
            else
            {
                IRNG sequenceGen = new RandomSequenceGenerator <MersenneTwisterUniformRng>(grid.size() - 1, 5);
                return(new BarrierPathPricer(arguments_.barrierType,
                                             arguments_.barrier,
                                             arguments_.rebate,
                                             payoff.optionType(),
                                             payoff.strike(),
                                             discounts,
                                             process_,
                                             sequenceGen));
            }
        }
        // conversion to pricing engine
        protected override PathPricer <IPath> pathPricer()
        {
            PlainVanillaPayoff payoff = (PlainVanillaPayoff)(this.arguments_.payoff);

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

            EuropeanExercise exercise = (EuropeanExercise)this.arguments_.exercise;

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

            return((PathPricer <IPath>) new GeometricAPOPathPricer(
                       payoff.optionType(),
                       payoff.strike(),
                       this.process_.riskFreeRate().link.discount(
                           this.timeGrid().Last()),
                       this.arguments_.runningAccumulator.GetValueOrDefault(),
                       this.arguments_.pastFixings.GetValueOrDefault()));
        }
Exemplo n.º 15
0
        public override void calculate()
        {
            // this is a european option pricer
            Utils.QL_REQUIRE(arguments_.exercise.type() == Exercise.Type.European, () => "not an European option");

            // plain vanilla
            PlainVanillaPayoff payoff = arguments_.payoff as PlainVanillaPayoff;

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

            HestonProcess process = model_.link.process();

            double riskFreeDiscount = process.riskFreeRate().link.discount(arguments_.exercise.lastDate());
            double dividendDiscount = process.dividendYield().link.discount(arguments_.exercise.lastDate());

            double spotPrice = process.s0().link.value();

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

            double strikePrice = payoff.strike();
            double term        = process.time(arguments_.exercise.lastDate());

            double?resultsValue = null;

            doCalculation(riskFreeDiscount,
                          dividendDiscount,
                          spotPrice,
                          strikePrice,
                          term,
                          model_.link.kappa(),
                          model_.link.theta(),
                          model_.link.sigma(),
                          model_.link.v0(),
                          model_.link.rho(),
                          payoff,
                          integration_,
                          cpxLog_,
                          this,
                          ref resultsValue,
                          ref evaluations_);
            results_.value = resultsValue;
        }
Exemplo n.º 16
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();
        }
Exemplo n.º 17
0
        public override void calculate()
        {
            // First: tests on types
            Utils.QL_REQUIRE(arguments_.exercise.type() == Exercise.Type.European, () =>
                             "not an European Option");

            PlainVanillaPayoff payoff = arguments_.payoff as PlainVanillaPayoff;

            Utils.QL_REQUIRE(payoff != null, () => "not a plain-vanilla payoff");

            // forward values - futures, so b=0
            double forward1 = process1_.stateVariable().link.value();
            double forward2 = process2_.stateVariable().link.value();

            Date exerciseDate = arguments_.exercise.lastDate();

            // Volatilities
            double sigma1 = process1_.blackVolatility().link.blackVol(exerciseDate,
                                                                      forward1);
            double sigma2 = process2_.blackVolatility().link.blackVol(exerciseDate,
                                                                      forward2);

            double riskFreeDiscount = process1_.riskFreeRate().link.discount(exerciseDate);

            double strike = payoff.strike();

            // Unique F (forward) value for pricing
            double F = forward1 / (forward2 + strike);

            // Its volatility
            double sigma =
                Math.Sqrt(Math.Pow(sigma1, 2)
                          + Math.Pow((sigma2 * (forward2 / (forward2 + strike))), 2)
                          - 2 * rho_.link.value() * sigma1 * sigma2 * (forward2 / (forward2 + strike)));

            // Day counter and Dates handling variables
            DayCounter rfdc = process1_.riskFreeRate().link.dayCounter();
            double     t    = rfdc.yearFraction(process1_.riskFreeRate().link.referenceDate(),
                                                arguments_.exercise.lastDate());

            // Black-Scholes solution values
            double d1 = (Math.Log(F) + 0.5 * Math.Pow(sigma,
                                                      2) * t) / (sigma * Math.Sqrt(t));
            double d2 = d1 - sigma * Math.Sqrt(t);

            NormalDistribution           pdf = new NormalDistribution();
            CumulativeNormalDistribution cum = new CumulativeNormalDistribution();
            double Nd1  = cum.value(d1);
            double Nd2  = cum.value(d2);
            double NMd1 = cum.value(-d1);
            double NMd2 = cum.value(-d2);

            Option.Type optionType = payoff.optionType();

            if (optionType == Option.Type.Call)
            {
                results_.value = riskFreeDiscount * (F * Nd1 - Nd2) * (forward2 + strike);
            }
            else
            {
                results_.value = riskFreeDiscount * (NMd2 - F * NMd1) * (forward2 + strike);
            }

            double?callValue = optionType == Option.Type.Call ? results_.value :
                               riskFreeDiscount * (F * Nd1 - Nd2) * (forward2 + strike);

            results_.theta = (Math.Log(riskFreeDiscount) / t) * callValue +
                             riskFreeDiscount * (forward1 * sigma) / (2 * Math.Sqrt(t)) * pdf.value(d1);
        }
        public override void calculate()
        {
            // this is an european option pricer
            Utils.QL_REQUIRE(arguments_.exercise.type() == Exercise.Type.European, () => "not an European option");

            // plain vanilla
            PlainVanillaPayoff payoff = arguments_.payoff as PlainVanillaPayoff;

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

            double v0        = model_.link.v0();
            double spotPrice = model_.link.s0();

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

            double strike = payoff.strike();
            double term   = model_.link.riskFreeRate().link.dayCounter().yearFraction(
                model_.link.riskFreeRate().link.referenceDate(), arguments_.exercise.lastDate());
            double riskFreeDiscount = model_.link.riskFreeRate().link.discount(arguments_.exercise.lastDate());
            double dividendDiscount = model_.link.dividendYield().link.discount(arguments_.exercise.lastDate());

            //average values
            TimeGrid timeGrid = model_.link.timeGrid();
            int      n = timeGrid.size() - 1;
            double   kappaAvg = 0.0, thetaAvg = 0.0, sigmaAvg = 0.0, rhoAvg = 0.0;

            for (int i = 1; i <= n; ++i)
            {
                double t = 0.5 * (timeGrid[i - 1] + timeGrid[i]);
                kappaAvg += model_.link.kappa(t);
                thetaAvg += model_.link.theta(t);
                sigmaAvg += model_.link.sigma(t);
                rhoAvg   += model_.link.rho(t);
            }
            kappaAvg /= n;
            thetaAvg /= n;
            sigmaAvg /= n;
            rhoAvg   /= n;

            double c_inf = Math.Min(10.0, Math.Max(0.0001,
                                                   Math.Sqrt(1.0 - Math.Pow(rhoAvg, 2)) / sigmaAvg)) * (v0 + kappaAvg * thetaAvg * term);

            double p1 = integration_.calculate(c_inf,
                                               new Fj_Helper(model_, term, strike, 1).value) / Const.M_PI;

            double p2 = integration_.calculate(c_inf,
                                               new Fj_Helper(model_, term, strike, 2).value) / Const.M_PI;

            switch (payoff.optionType())
            {
            case Option.Type.Call:
                results_.value = spotPrice * dividendDiscount * (p1 + 0.5)
                                 - strike * riskFreeDiscount * (p2 + 0.5);
                break;

            case Option.Type.Put:
                results_.value = spotPrice * dividendDiscount * (p1 - 0.5)
                                 - strike * riskFreeDiscount * (p2 - 0.5);
                break;

            default:
                Utils.QL_FAIL("unknown option type");
                break;
            }
        }
Exemplo n.º 19
0
        public override void calculate()
        {
            PlainVanillaPayoff payoff = arguments_.payoff as PlainVanillaPayoff;

            Utils.QL_REQUIRE(payoff != null, () => "non-plain payoff given");
            Utils.QL_REQUIRE(payoff.strike() > 0.0, () => "strike must be positive");

            double strike = payoff.strike();
            double spot   = process_.x0();

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

            Barrier.Type barrierType = arguments_.barrierType;

            switch (payoff.optionType())
            {
            case Option.Type.Call:
                switch (barrierType)
                {
                case Barrier.Type.DownIn:
                    if (strike >= barrier())
                    {
                        results_.value = C(1, 1) + E(1);
                    }
                    else
                    {
                        results_.value = A(1) - B(1) + D(1, 1) + E(1);
                    }
                    break;

                case Barrier.Type.UpIn:
                    if (strike >= barrier())
                    {
                        results_.value = A(1) + E(-1);
                    }
                    else
                    {
                        results_.value = B(1) - C(-1, 1) + D(-1, 1) + E(-1);
                    }
                    break;

                case Barrier.Type.DownOut:
                    if (strike >= barrier())
                    {
                        results_.value = A(1) - C(1, 1) + F(1);
                    }
                    else
                    {
                        results_.value = B(1) - D(1, 1) + F(1);
                    }
                    break;

                case Barrier.Type.UpOut:
                    if (strike >= barrier())
                    {
                        results_.value = F(-1);
                    }
                    else
                    {
                        results_.value = A(1) - B(1) + C(-1, 1) - D(-1, 1) + F(-1);
                    }
                    break;
                }
                break;

            case Option.Type.Put:
                switch (barrierType)
                {
                case Barrier.Type.DownIn:
                    if (strike >= barrier())
                    {
                        results_.value = B(-1) - C(1, -1) + D(1, -1) + E(1);
                    }
                    else
                    {
                        results_.value = A(-1) + E(1);
                    }
                    break;

                case Barrier.Type.UpIn:
                    if (strike >= barrier())
                    {
                        results_.value = A(-1) - B(-1) + D(-1, -1) + E(-1);
                    }
                    else
                    {
                        results_.value = C(-1, -1) + E(-1);
                    }
                    break;

                case Barrier.Type.DownOut:
                    if (strike >= barrier())
                    {
                        results_.value = A(-1) - B(-1) + C(1, -1) - D(1, -1) + F(1);
                    }
                    else
                    {
                        results_.value = F(1);
                    }
                    break;

                case Barrier.Type.UpOut:
                    if (strike >= barrier())
                    {
                        results_.value = B(-1) - D(-1, -1) + F(-1);
                    }
                    else
                    {
                        results_.value = A(-1) - C(-1, -1) + F(-1);
                    }
                    break;
                }
                break;

            default:
                Utils.QL_FAIL("unknown type");
                break;
            }
        }
Exemplo n.º 20
0
        public override void calculate()
        {
            Utils.QL_REQUIRE(arguments_.averageType == Average.Type.Geometric, () => "not a geometric average option");
            Utils.QL_REQUIRE(arguments_.exercise.type() == Exercise.Type.European, () => "not an European Option");

            Date exercise = arguments_.exercise.lastDate();

            PlainVanillaPayoff payoff = arguments_.payoff as PlainVanillaPayoff;

            Utils.QL_REQUIRE(payoff != null, () => "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();

            Utils.QL_REQUIRE(spot > 0.0, () => "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 (Exception /*Error*/)
            {
                results_.theta = null;
            }
        }
Exemplo n.º 21
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");

            PlainVanillaPayoff payoff = arguments_.payoff as PlainVanillaPayoff;

            Utils.QL_REQUIRE(payoff != null, () => "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();

            Utils.QL_REQUIRE(spot > 0.0, () => "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);
            }
        }
Exemplo n.º 22
0
        public override void calculate()
        {
            DayCounter rfdc   = process_.riskFreeRate().link.dayCounter();
            DayCounter divdc  = process_.dividendYield().link.dayCounter();
            DayCounter voldc  = process_.blackVolatility().link.dayCounter();
            Calendar   volcal = process_.blackVolatility().link.calendar();

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

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

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

            PlainVanillaPayoff payoff = arguments_.payoff as PlainVanillaPayoff;

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

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

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

            TimeGrid grid = new TimeGrid(maturity, timeSteps_);

            T tree = FastActivator <T> .Create().factory(bs, maturity, timeSteps_, payoff.strike());

            BlackScholesLattice <T> lattice = new BlackScholesLattice <T>(tree, r, maturity, timeSteps_);

            DiscretizedVanillaOption option = new DiscretizedVanillaOption(arguments_, process_, grid);

            option.initialize(lattice, maturity);

            // Partial derivatives calculated from various points in the
            // binomial tree (Odegaard)

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

            Utils.QL_REQUIRE(va2.size() == 3, () => "Expect 3 nodes in grid at second step");
            double p2h = va2[2];                   // high-price
            double s2  = lattice.underlying(2, 2); // high price

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

            Utils.QL_REQUIRE(va.size() == 2, () => "Expect 2 nodes in grid at first step");
            double p1 = va[1];

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

            // Calculate partial derivatives
            double delta0 = (p1 - p0) / (s1 - s0);  // dp/ds
            double delta1 = (p2h - p1) / (s2 - s1); // dp/ds

            // Store results
            results_.value = p0;
            results_.delta = delta0;
            results_.gamma = 2.0 * (delta1 - delta0) / (s2 - s0); //d(delta)/ds
            results_.theta = Utils.blackScholesTheta(process_,
                                                     results_.value.GetValueOrDefault(),
                                                     results_.delta.GetValueOrDefault(),
                                                     results_.gamma.GetValueOrDefault());
        }
Exemplo n.º 23
0
        public override void calculate()
        {
            PlainVanillaPayoff payoff = arguments_.payoff as PlainVanillaPayoff;

            Utils.QL_REQUIRE(payoff != null, () => "non-plain payoff given");
            Utils.QL_REQUIRE(payoff.strike() > 0.0, () => "strike must be positive");

            double K = payoff.strike();
            double S = process_.x0();

            Utils.QL_REQUIRE(S >= 0.0, () => "negative or null underlying given");
            Utils.QL_REQUIRE(!triggered(S), () => "barrier touched");

            DoubleBarrier.Type barrierType = arguments_.barrierType;
            Utils.QL_REQUIRE(barrierType == DoubleBarrier.Type.KnockOut ||
                             barrierType == DoubleBarrier.Type.KnockIn, () =>
                             "only KnockIn and KnockOut options supported");

            double L      = arguments_.barrier_lo.GetValueOrDefault();
            double H      = arguments_.barrier_hi.GetValueOrDefault();
            double K_up   = Math.Min(H, K);
            double K_down = Math.Max(L, K);
            double T      = residualTime();
            double rd     = riskFreeRate();
            double dd     = riskFreeDiscount();
            double rf     = dividendYield();
            double df     = dividendDiscount();
            double vol    = volatility();
            double mu     = rd - rf - vol * vol / 2.0;
            double sgn    = mu > 0 ? 1.0 : (mu < 0 ? -1.0 : 0.0);
            //rebate
            double R_L = arguments_.rebate.GetValueOrDefault();
            double R_H = arguments_.rebate.GetValueOrDefault();

            //european option
            EuropeanOption europeanOption         = new EuropeanOption(payoff, arguments_.exercise);
            IPricingEngine analyticEuropeanEngine = new AnalyticEuropeanEngine(process_);

            europeanOption.setPricingEngine(analyticEuropeanEngine);
            double european = europeanOption.NPV();

            double barrierOut = 0;
            double rebateIn   = 0;

            for (int n = -series_; n < series_; n++)
            {
                double d1      = D(S / H * Math.Pow(L / H, 2.0 * n), vol * vol + mu, vol, T);
                double d2      = d1 - vol * Math.Sqrt(T);
                double g1      = D(H / S * Math.Pow(L / H, 2.0 * n - 1.0), vol * vol + mu, vol, T);
                double g2      = g1 - vol * Math.Sqrt(T);
                double h1      = D(S / H * Math.Pow(L / H, 2.0 * n - 1.0), vol * vol + mu, vol, T);
                double h2      = h1 - vol * Math.Sqrt(T);
                double k1      = D(L / S * Math.Pow(L / H, 2.0 * n - 1.0), vol * vol + mu, vol, T);
                double k2      = k1 - vol * Math.Sqrt(T);
                double d1_down = D(S / K_down * Math.Pow(L / H, 2.0 * n), vol * vol + mu, vol, T);
                double d2_down = d1_down - vol * Math.Sqrt(T);
                double d1_up   = D(S / K_up * Math.Pow(L / H, 2.0 * n), vol * vol + mu, vol, T);
                double d2_up   = d1_up - vol * Math.Sqrt(T);
                double k1_down = D((H * H) / (K_down * S) * Math.Pow(L / H, 2.0 * n), vol * vol + mu, vol, T);
                double k2_down = k1_down - vol * Math.Sqrt(T);
                double k1_up   = D((H * H) / (K_up * S) * Math.Pow(L / H, 2.0 * n), vol * vol + mu, vol, T);
                double k2_up   = k1_up - vol * Math.Sqrt(T);

                if (payoff.optionType() == Option.Type.Call)
                {
                    barrierOut += Math.Pow(L / H, 2.0 * n * mu / (vol * vol)) *
                                  (df * S * Math.Pow(L / H, 2.0 * n) * (f_.value(d1_down) - f_.value(d1))
                                   - dd * K * (f_.value(d2_down) - f_.value(d2))
                                   - df * Math.Pow(L / H, 2.0 * n) * H * H / S * Math.Pow(H / S, 2.0 * mu / (vol * vol)) * (f_.value(k1_down) - f_.value(k1))
                                   + dd * K * Math.Pow(H / S, 2.0 * mu / (vol * vol)) * (f_.value(k2_down) - f_.value(k2)));
                }
                else if (payoff.optionType() == Option.Type.Put)
                {
                    barrierOut += Math.Pow(L / H, 2.0 * n * mu / (vol * vol)) *
                                  (dd * K * (f_.value(h2) - f_.value(d2_up))
                                   - df * S * Math.Pow(L / H, 2.0 * n) * (f_.value(h1) - f_.value(d1_up))
                                   - dd * K * Math.Pow(H / S, 2.0 * mu / (vol * vol)) * (f_.value(g2) - f_.value(k2_up))
                                   + df * Math.Pow(L / H, 2.0 * n) * H * H / S * Math.Pow(H / S, 2.0 * mu / (vol * vol)) * (f_.value(g1) - f_.value(k1_up)));
                }
                else
                {
                    Utils.QL_FAIL("option type not recognized");
                }

                double v1 = D(H / S * Math.Pow(H / L, 2.0 * n), -mu, vol, T);
                double v2 = D(H / S * Math.Pow(H / L, 2.0 * n), mu, vol, T);
                double v3 = D(S / L * Math.Pow(H / L, 2.0 * n), -mu, vol, T);
                double v4 = D(S / L * Math.Pow(H / L, 2.0 * n), mu, vol, T);
                rebateIn += dd * R_H * sgn * (Math.Pow(L / H, 2.0 * n * mu / (vol * vol)) * f_.value(sgn * v1) - Math.Pow(H / S, 2.0 * mu / (vol * vol)) * f_.value(-sgn * v2))
                            + dd * R_L * sgn * (Math.Pow(L / S, 2.0 * mu / (vol * vol)) * f_.value(-sgn * v3) - Math.Pow(H / L, 2.0 * n * mu / (vol * vol)) * f_.value(sgn * v4));
            }

            //rebate paid at maturity
            if (barrierType == DoubleBarrier.Type.KnockOut)
            {
                results_.value = barrierOut;
            }
            else
            {
                results_.value = european - barrierOut;
            }

            results_.additionalResults["vanilla"]    = european;
            results_.additionalResults["barrierOut"] = barrierOut;
            results_.additionalResults["barrierIn"]  = european - barrierOut;
        }
Exemplo n.º 24
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");

            BasketPayoff basket_payoff = arguments_.payoff as BasketPayoff;

            MinBasketPayoff min_basket = arguments_.payoff as MinBasketPayoff;

            MaxBasketPayoff max_basket = arguments_.payoff as MaxBasketPayoff;

            Utils.QL_REQUIRE(min_basket != null || max_basket != null, () => "unknown basket type");

            PlainVanillaPayoff payoff = basket_payoff.basePayoff() as PlainVanillaPayoff;

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

            double strike = payoff.strike();

            double variance1 = process1_.blackVolatility().link.blackVariance(exercise.lastDate(), strike);
            double variance2 = process2_.blackVolatility().link.blackVariance(exercise.lastDate(), strike);

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

            // cannot handle non zero dividends, so don't believe this...
            double dividendDiscount1 = process1_.dividendYield().link.discount(exercise.lastDate());
            double dividendDiscount2 = process2_.dividendYield().link.discount(exercise.lastDate());

            double forward1 = process1_.stateVariable().link.value() * dividendDiscount1 / riskFreeDiscount;
            double forward2 = process2_.stateVariable().link.value() * dividendDiscount2 / riskFreeDiscount;

            if (max_basket != null)
            {
                switch (payoff.optionType())
                {
                // euro call on a two asset max basket
                case Option.Type.Call:
                    results_.value = euroTwoAssetMaxBasketCall(forward1, forward2, strike,
                                                               riskFreeDiscount,
                                                               variance1, variance2,
                                                               rho_);

                    break;

                // euro put on a two asset max basket
                case Option.Type.Put:
                    results_.value = strike * riskFreeDiscount -
                                     euroTwoAssetMaxBasketCall(forward1, forward2, 0.0,
                                                               riskFreeDiscount,
                                                               variance1, variance2, rho_) +
                                     euroTwoAssetMaxBasketCall(forward1, forward2, strike,
                                                               riskFreeDiscount,
                                                               variance1, variance2, rho_);
                    break;

                default:
                    Utils.QL_FAIL("unknown option type");
                    break;
                }
            }
            else if (min_basket != null)
            {
                switch (payoff.optionType())
                {
                // euro call on a two asset min basket
                case Option.Type.Call:
                    results_.value = euroTwoAssetMinBasketCall(forward1, forward2, strike,
                                                               riskFreeDiscount,
                                                               variance1, variance2,
                                                               rho_);
                    break;

                // euro put on a two asset min basket
                case Option.Type.Put:
                    results_.value = strike * riskFreeDiscount -
                                     euroTwoAssetMinBasketCall(forward1, forward2, 0.0,
                                                               riskFreeDiscount,
                                                               variance1, variance2, rho_) +
                                     euroTwoAssetMinBasketCall(forward1, forward2, strike,
                                                               riskFreeDiscount,
                                                               variance1, variance2, rho_);
                    break;

                default:
                    Utils.QL_FAIL("unknown option type");
                    break;
                }
            }
            else
            {
                Utils.QL_FAIL("unknown type");
            }
        }
        public override void calculate()
        {
            Utils.QL_REQUIRE(arguments_.exercise.type() == Exercise.Type.European, () =>
                             "this engine handles only european options");

            PlainVanillaPayoff payoff = arguments_.payoff as PlainVanillaPayoff;

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

            double strike = payoff.strike();

            Utils.QL_REQUIRE(strike > 0.0, () => "strike must be positive");

            double spot = underlying();

            Utils.QL_REQUIRE(spot >= 0.0, () => "negative or null underlying given");
            Utils.QL_REQUIRE(!triggered(spot), () => "barrier(s) already touched");

            DoubleBarrier.Type barrierType = arguments_.barrierType;

            if (triggered(spot))
            {
                if (barrierType == DoubleBarrier.Type.KnockIn)
                {
                    results_.value = vanillaEquivalent(); // knocked in
                }
                else
                {
                    results_.value = 0.0; // knocked out
                }
            }
            else
            {
                switch (payoff.optionType())
                {
                case Option.Type.Call:
                    switch (barrierType)
                    {
                    case DoubleBarrier.Type.KnockIn:
                        results_.value = callKI();
                        break;

                    case DoubleBarrier.Type.KnockOut:
                        results_.value = callKO();
                        break;

                    case DoubleBarrier.Type.KIKO:
                    case DoubleBarrier.Type.KOKI:
                        Utils.QL_FAIL("unsupported double-barrier type: " + barrierType);
                        break;

                    default:
                        Utils.QL_FAIL("unknown double-barrier type: " + barrierType);
                        break;
                    }
                    break;

                case Option.Type.Put:
                    switch (barrierType)
                    {
                    case DoubleBarrier.Type.KnockIn:
                        results_.value = putKI();
                        break;

                    case DoubleBarrier.Type.KnockOut:
                        results_.value = putKO();
                        break;

                    case DoubleBarrier.Type.KIKO:
                    case DoubleBarrier.Type.KOKI:
                        Utils.QL_FAIL("unsupported double-barrier type: " + barrierType);
                        break;

                    default:
                        Utils.QL_FAIL("unknown double-barrier type: " + barrierType);
                        break;
                    }
                    break;

                default:
                    Utils.QL_FAIL("unknown type");
                    break;
                }
            }
        }
        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());
        }