Example #1
0
 public static double bachelierBlackFormula(PlainVanillaPayoff payoff,
                                            double forward,
                                            double stdDev,
                                            double discount = 1.0)
 {
     return(bachelierBlackFormula(payoff.optionType(), payoff.strike(), forward, stdDev, discount));
 }
Example #2
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;
            }
        }
Example #3
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));
        }
Example #4
0
 public static double blackFormulaCashItmProbability(PlainVanillaPayoff payoff,
                                                     double forward,
                                                     double stdDev,
                                                     double displacement = 0.0)
 {
     return(blackFormulaCashItmProbability(payoff.optionType(),
                                           payoff.strike(), forward, stdDev, displacement));
 }
Example #5
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));
 }
Example #6
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));
 }
Example #7
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())));
        }
Example #8
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));
            }
        }
Example #9
0
        protected override double blackVolImpl(double t, double strike)
        {
            HestonProcess process = hestonModel_.link.process();

            double df        = process.riskFreeRate().link.discount(t, true);
            double div       = process.dividendYield().link.discount(t, true);
            double spotPrice = process.s0().link.value();

            double fwd = spotPrice
                         * process.dividendYield().link.discount(t, true)
                         / process.riskFreeRate().link.discount(t, true);

            var payoff = new PlainVanillaPayoff(fwd > strike ? Option.Type.Put : Option.Type.Call, strike);

            double kappa = hestonModel_.link.kappa();
            double theta = hestonModel_.link.theta();
            double rho   = hestonModel_.link.rho();
            double sigma = hestonModel_.link.sigma();
            double v0    = hestonModel_.link.v0();

            AnalyticHestonEngine.ComplexLogFormula cpxLogFormula = AnalyticHestonEngine.ComplexLogFormula.Gatheral;

            AnalyticHestonEngine hestonEnginePtr = null;

            double?npv         = null;
            int    evaluations = 0;

            AnalyticHestonEngine.doCalculation(
                df, div, spotPrice, strike, t,
                kappa, theta, sigma, v0, rho,
                payoff, integration_, cpxLogFormula,
                hestonEnginePtr, ref npv, ref evaluations);

            if (npv <= 0.0)
            {
                return(Math.Sqrt(theta));
            }

            Brent solver = new Brent();

            solver.setMaxEvaluations(10000);
            double guess    = Math.Sqrt(theta);
            double accuracy = Const.QL_EPSILON;

            var f = new ImpliedVolHelper(payoff.optionType(), strike, fwd, t, df, npv.Value);

            return(solver.solve(f, accuracy, guess, 0.01));
        }
Example #10
0
        // 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()));
        }
Example #11
0
        protected override PathPricer <IPath> pathPricer()
        {
            PlainVanillaPayoff payoff = arguments_.payoff as PlainVanillaPayoff;

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

            GeneralizedBlackScholesProcess process = process_ as GeneralizedBlackScholesProcess;

            if (process == null)
            {
                throw new ApplicationException("Black-Scholes process required");
            }

            return(new EuropeanPathPricer(payoff.optionType(), payoff.strike(),
                                          process.riskFreeRate().link.discount(timeGrid().Last())));
        }
        protected override PathPricer <IPath> pathPricer()
        {
            PlainVanillaPayoff payoff = (PlainVanillaPayoff)(this.arguments_.payoff);

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

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

            if (exercise == null)
            {
                throw new ApplicationException("wrong exercise given");
            }

            return((PathPricer <IPath>) new ArithmeticASOPathPricer(
                       payoff.optionType(),
                       this.process_.riskFreeRate().link.discount(this.timeGrid().Last()),
                       this.arguments_.runningAccumulator.GetValueOrDefault(),
                       this.arguments_.pastFixings.GetValueOrDefault()));
        }
Example #13
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();
        }
        protected override PathPricer <IPath> controlPathPricer()
        {
            PlainVanillaPayoff payoff = (PlainVanillaPayoff)this.arguments_.payoff;

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

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

            if (exercise == null)
            {
                throw new Exception("wrong exercise given");
            }

            // for seasoned option the geometric strike might be rescaled
            // to obtain an equivalent arithmetic strike.
            // Any change applied here MUST be applied to the analytic engine too
            return((PathPricer <IPath>) new GeometricAPOPathPricer(
                       payoff.optionType(),
                       payoff.strike(),
                       this.process_.riskFreeRate().link.discount(this.timeGrid().Last())));
        }
Example #15
0
 public static double bachelierBlackFormula( PlainVanillaPayoff payoff,
     double forward,
     double stdDev,
     double discount)
 {
     return bachelierBlackFormula( payoff.optionType(),
       payoff.strike(), forward, stdDev, discount );
 }
Example #16
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;
        }
        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());
        }
Example #18
0
        public override void calculate()
        {
            PlainVanillaPayoff payoff = arguments_.payoff as PlainVanillaPayoff;

            if (payoff == null)
            {
                throw new ApplicationException("non-plain payoff given");
            }
            if (!(payoff.strike() > 0.0))
            {
                throw new ApplicationException("strike must be positive");
            }

            // 추가된 부분.. 2014-07-23
            this.partiRate_ = arguments_.partiRate;

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

            if (!(spot >= 0.0))
            {
                throw new ApplicationException("negative or null underlying given");
            }
            if (triggered(spot))
            {
                throw new ApplicationException("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:
                throw new ApplicationException("unknown type");
            }
        }
        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");

            Utils.QL_REQUIRE(arguments_.runningAccumulator > 0.0, () =>
                             "positive running product required: " + arguments_.runningAccumulator + "not allowed");

            double runningLog  = Math.Log(arguments_.runningAccumulator.GetValueOrDefault());
            int?   pastFixings = arguments_.pastFixings;

            Utils.QL_REQUIRE(pastFixings == 0, () => "past fixings currently not managed");

            PlainVanillaPayoff payoff = arguments_.payoff as PlainVanillaPayoff;

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

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

            List <double> fixingTimes = new List <double>();

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

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

            double pastWeight   = pastFixings.GetValueOrDefault() / N;
            double futureWeight = 1.0 - pastWeight;

            double timeSum = 0;

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

            double residualTime = rfdc.yearFraction(arguments_.fixingDates[pastFixings.GetValueOrDefault()],
                                                    arguments_.exercise.lastDate());


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

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

            double volatility = process_.blackVolatility().link.blackVol(arguments_.exercise.lastDate(), underlying);

            Date   exDate       = arguments_.exercise.lastDate();
            double dividendRate = process_.dividendYield().link.zeroRate(exDate, divdc,
                                                                         Compounding.Continuous, Frequency.NoFrequency).value();

            double riskFreeRate = process_.riskFreeRate().link.zeroRate(exDate, rfdc,
                                                                        Compounding.Continuous, Frequency.NoFrequency).value();

            double nu = riskFreeRate - dividendRate - 0.5 * volatility * volatility;

            double temp = 0.0;

            for (int i = pastFixings.GetValueOrDefault() + 1; i < numberOfFixings; i++)
            {
                temp += fixingTimes[i - pastFixings.GetValueOrDefault() - 1] * (N - i);
            }
            double variance       = volatility * volatility / N / N * (timeSum + 2.0 * temp);
            double covarianceTerm = volatility * volatility / N * timeSum;
            double sigmaSum_2     = variance + volatility * volatility * residualTime - 2.0 * covarianceTerm;

            int    M = (pastFixings.GetValueOrDefault() == 0 ? 1 : pastFixings.GetValueOrDefault());
            double runningLogAverage = runningLog / M;

            double muG = pastWeight * runningLogAverage +
                         futureWeight * Math.Log(underlying) +
                         nu * timeSum / N;

            CumulativeNormalDistribution f = new CumulativeNormalDistribution();

            double y1 = (Math.Log(underlying) +
                         (riskFreeRate - dividendRate) * residualTime -
                         muG - variance / 2.0 + sigmaSum_2 / 2.0)
                        / Math.Sqrt(sigmaSum_2);
            double y2 = y1 - Math.Sqrt(sigmaSum_2);

            switch (payoff.optionType())
            {
            case Option.Type.Call:
                results_.value = underlying * Math.Exp(-dividendRate * residualTime)
                                 * f.value(y1) - Math.Exp(muG + variance / 2.0 - riskFreeRate * residualTime) * f.value(y2);
                break;

            case Option.Type.Put:
                results_.value = -underlying *Math.Exp(-dividendRate *residualTime)
                                 * f.value(-y1) + Math.Exp(muG + variance / 2.0 - riskFreeRate * residualTime) * f.value(-y2);

                break;

            default:
                Utils.QL_FAIL("invalid option type");
                break;
            }
        }
Example #20
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);
            }
        }
Example #21
0
        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;
            }
        }
Example #22
0
        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;
                }
            }
        }
Example #23
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);
        }
Example #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");
            }
        }
Example #25
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;
            }
        }