Beispiel #1
0
        /*! Black style formula when forward is normal rather than
         * log-normal. This is essentially the model of Bachelier.
         *
         *  \warning Bachelier model needs absolute volatility, not
         *     percentage volatility. Standard deviation is
         *     absoluteVolatility*sqrt(timeToMaturity)
         */
        public static double bachelierBlackFormula(Option.Type optionType,
                                                   double strike,
                                                   double forward,
                                                   double stdDev,
                                                   double discount = 1.0)
        {
            QL_REQUIRE(stdDev >= 0.0, () =>
                       "stdDev (" + stdDev + ") must be non-negative");
            QL_REQUIRE(discount > 0.0, () =>
                       "discount (" + discount + ") must be positive");
            double d = (forward - strike) * (int)optionType, h = d / stdDev;

            if (stdDev.IsEqual(0.0))
            {
                return(discount * Math.Max(d, 0.0));
            }
            CumulativeNormalDistribution phi = new CumulativeNormalDistribution();
            double result = discount * (stdDev * phi.derivative(h) + d * phi.value(h));

            QL_REQUIRE(result >= 0.0, () =>
                       "negative value (" + result + ") for " +
                       stdDev + " stdDev, " +
                       optionType + " option, " +
                       strike + " strike , " +
                       forward + " forward");
            return(result);
        }
Beispiel #2
0
        public static double blackFormulaStdDevDerivative(double strike,
                                                          double forward,
                                                          double stdDev,
                                                          double discount,
                                                          double displacement)
        {
            checkParameters(strike, forward, displacement);

            if (stdDev < 0.0)
            {
                throw new ArgumentException("stdDev (" + stdDev + ") must be non-negative");
            }

            if (discount <= 0.0)
            {
                throw new ArgumentException("discount (" + discount + ") must be positive");
            }

            forward = forward + displacement;
            strike  = strike + displacement;

            if (stdDev == 0.0 || strike == 0)
            {
                return(0.0);
            }

            double d1 = Math.Log(forward / strike) / stdDev + .5 * stdDev;
            CumulativeNormalDistribution phi = new CumulativeNormalDistribution();

            return(discount * forward * phi.derivative(d1));
        }
Beispiel #3
0
        public static double bachelierBlackFormula(Option.Type optionType, double strike, double forward, double stdDev, double discount)
        {
            if (stdDev < 0.0)
            {
                throw new ArgumentException("stdDev (" + stdDev + ") must be non-negative");
            }

            if (discount <= 0.0)
            {
                throw new ArgumentException("discount (" + discount + ") must be positive");
            }

            double d = (forward - strike) * (int)optionType;
            double h = d / stdDev;

            if (stdDev == 0.0)
            {
                return(discount * Math.Max(d, 0.0));
            }

            CumulativeNormalDistribution phi = new CumulativeNormalDistribution();
            double result = discount * (stdDev * phi.derivative(h) + d * phi.value(h));

            if (!(result >= 0.0))
            {
                throw new ApplicationException("negative value (" + result + ") for " +
                                               stdDev + " stdDev, " +
                                               optionType + " option, " +
                                               strike + " strike , " +
                                               forward + " forward");
            }

            return(result);
        }
Beispiel #4
0
        public static double bachelierBlackFormula( Option.Type optionType,
            double strike,
            double forward,
            double stdDev,
            double discount)
        {
            if ( stdDev < 0.0 )
                throw new ArgumentException( "stdDev (" + stdDev + ") must be non-negative" );

            if ( discount <= 0.0 )
                throw new ArgumentException( "discount (" + discount + ") must be positive" );

            double d = ( forward - strike ) * (int)optionType;
            double h = d / stdDev;

            if ( stdDev == 0.0 )
                return discount * Math.Max( d, 0.0 );

            CumulativeNormalDistribution phi = new CumulativeNormalDistribution();

            double result = discount * ( stdDev * phi.derivative( h ) + d * phi.value( h ) );

            if ( !( result >= 0.0 ) )
                throw new ApplicationException( "negative value (" + result + ") for " +
                        stdDev + " stdDev, " +
                        optionType + " option, " +
                        strike + " strike , " +
                        forward + " forward" );

            return result;
        }
Beispiel #5
0
        public double nD2(double strike)     // n(d2)
        {
            double d2_   = 0.0;
            double n_d2_ = 0.0; // n(d2)

            if (stdDev_ >= Const.QL_EPSILON)
            {
                if (strike > 0)
                {
                    d2_ = Math.Log(forward_ / strike) / stdDev_ - 0.5 * stdDev_;
                    CumulativeNormalDistribution f = new CumulativeNormalDistribution();
                    n_d2_ = f.derivative(d2_);
                }
            }

            return(n_d2_);
        }
        //private double DXDstrike_;

        public AmericanPayoffAtExpiry(double spot, double discount, double dividendDiscount, double variance, StrikedTypePayoff payoff) {
            spot_ = spot;
            discount_ = discount;
            dividendDiscount_ = dividendDiscount;
            variance_ = variance;

            if (!(spot_ > 0.0))
                throw new ApplicationException("positive spot_ value required");

            forward_ = spot_ * dividendDiscount_ / discount_;

            if (!(discount_ > 0.0))
                throw new ApplicationException("positive discount required");

            if (!(dividendDiscount_ > 0.0))
                throw new ApplicationException("positive dividend discount_ required");

            if (!(variance_ >= 0.0))
                throw new ApplicationException("negative variance_ not allowed");

            stdDev_ = Math.Sqrt(variance_);

            Option.Type type = payoff.optionType();
            strike_ = payoff.strike();


            mu_ = Math.Log(dividendDiscount_ / discount_) / variance_ - 0.5;

            // binary cash-or-nothing payoff?
            CashOrNothingPayoff coo = payoff as CashOrNothingPayoff;
            if (coo != null) {
                K_ = coo.cashPayoff();
                //DKDstrike_ = 0.0;
            }

            // binary asset-or-nothing payoff?
            AssetOrNothingPayoff aoo = payoff as AssetOrNothingPayoff;
            if (aoo != null) {
                K_ = forward_;
                //DKDstrike_ = 0.0;
                mu_ += 1.0;
            }


            log_H_S_ = Math.Log(strike_ / spot_);

            double n_d1;
            double n_d2;
            double cum_d1_;
            double cum_d2_;
            if (variance_ >= Const.QL_EPSILON) {
                D1_ = log_H_S_ / stdDev_ + mu_ * stdDev_;
                D2_ = D1_ - 2.0 * mu_ * stdDev_;
                CumulativeNormalDistribution f = new CumulativeNormalDistribution();
                cum_d1_ = f.value(D1_);
                cum_d2_ = f.value(D2_);
                n_d1 = f.derivative(D1_);
                n_d2 = f.derivative(D2_);
            } else {
                if (log_H_S_ > 0) {
                    cum_d1_ = 1.0;
                    cum_d2_ = 1.0;
                } else {
                    cum_d1_ = 0.0;
                    cum_d2_ = 0.0;
                }
                n_d1 = 0.0;
                n_d2 = 0.0;
            }


            switch (type) {
                // up-and-in cash-(at-hit)-or-nothing option
                // a.k.a. american call with cash-or-nothing payoff
                case Option.Type.Call:
                    if (strike_ > spot_) {
                        alpha_ = 1.0 - cum_d2_; // N(-d2)
                        DalphaDd1_ = -n_d2; // -n( d2)
                        beta_ = 1.0 - cum_d1_; // N(-d1)
                        DbetaDd2_ = -n_d1; // -n( d1)
                    } else {
                        alpha_ = 0.5;
                        DalphaDd1_ = 0.0;
                        beta_ = 0.5;
                        DbetaDd2_ = 0.0;
                    }
                    break;
                // down-and-in cash-(at-hit)-or-nothing option
                // a.k.a. american put with cash-or-nothing payoff
                case Option.Type.Put:
                    if (strike_ < spot_) {
                        alpha_ = cum_d2_; // N(d2)
                        DalphaDd1_ = n_d2; // n(d2)
                        beta_ = cum_d1_; // N(d1)
                        DbetaDd2_ = n_d1; // n(d1)
                    } else {
                        alpha_ = 0.5;
                        DalphaDd1_ = 0.0;
                        beta_ = 0.5;
                        DbetaDd2_ = 0.0;
                    }
                    break;
                default:
                    throw new ApplicationException("invalid option type");
            }


            inTheMoney_ = (type == Option.Type.Call && strike_ < spot_) || (type == Option.Type.Put && strike_ > spot_);
            if (inTheMoney_) {
                Y_ = 1.0;
                X_ = 1.0;
                //DYDstrike_ = 0.0;
                //DXDstrike_ = 0.0;
            } else {
                Y_ = 1.0;
                X_ = Math.Pow((double)(strike_ / spot_), (double)(2.0 * mu_));
                //            DXDstrike_ = ......;
            }

        }
Beispiel #7
0
        // public BlackCalculator(StrikedTypePayoff payoff, double forward, double stdDev, double discount = 1.0) {
        public BlackCalculator(StrikedTypePayoff payoff, double forward, double stdDev, double discount)
        {
            strike_   = payoff.strike();
            forward_  = forward;
            stdDev_   = stdDev;
            discount_ = discount;
            variance_ = stdDev * stdDev;

            if (!(forward > 0.0))
            {
                throw new ApplicationException("positive forward value required: " + forward + " not allowed");
            }

            if (!(stdDev >= 0.0))
            {
                throw new ApplicationException("non-negative standard deviation required: " + stdDev + " not allowed");
            }

            if (!(discount > 0.0))
            {
                throw new ApplicationException("positive discount required: " + discount + " not allowed");
            }

            if (stdDev_ >= Const.QL_Epsilon)
            {
                if (strike_ == 0.0)
                {
                    n_d1_   = 0.0;
                    n_d2_   = 0.0;
                    cum_d1_ = 1.0;
                    cum_d2_ = 1.0;
                }
                else
                {
                    D1_ = Math.Log(forward / strike_) / stdDev_ + 0.5 * stdDev_;
                    D2_ = D1_ - stdDev_;
                    CumulativeNormalDistribution f = new CumulativeNormalDistribution();
                    cum_d1_ = f.value(D1_);
                    cum_d2_ = f.value(D2_);
                    n_d1_   = f.derivative(D1_);
                    n_d2_   = f.derivative(D2_);
                }
            }
            else
            {
                if (forward > strike_)
                {
                    cum_d1_ = 1.0;
                    cum_d2_ = 1.0;
                }
                else
                {
                    cum_d1_ = 0.0;
                    cum_d2_ = 0.0;
                }
                n_d1_ = 0.0;
                n_d2_ = 0.0;
            }

            X_         = strike_;
            DXDstrike_ = 1.0;

            // the following one will probably disappear as soon as
            // super-share will be properly handled
            DXDs_ = 0.0;

            // this part is always executed.
            // in case of plain-vanilla payoffs, it is also the only part
            // which is executed.
            switch (payoff.optionType())
            {
            case Option.Type.Call:
                alpha_     = cum_d1_;     //  N(d1)
                DalphaDd1_ = n_d1_;       //  n(d1)
                beta_      = -cum_d2_;    // -N(d2)
                DbetaDd2_  = -n_d2_;      // -n(d2)
                break;

            case Option.Type.Put:
                alpha_     = -1.0 + cum_d1_;  // -N(-d1)
                DalphaDd1_ = n_d1_;           //  n( d1)
                beta_      = 1.0 - cum_d2_;   //  N(-d2)
                DbetaDd2_  = -n_d2_;          // -n( d2)
                break;

            default:
                throw new ArgumentException("invalid option type");
            }

            // now dispatch on type.

            Calculator calc = new Calculator(this);

            payoff.accept(calc);
        }
        public AmericanPayoffAtHit(double spot, double discount, double dividendDiscount, double variance, StrikedTypePayoff payoff) {
            spot_ = spot;
            discount_ = discount;
            dividendDiscount_ = dividendDiscount;
            variance_ = variance;

            if (!(spot_ > 0.0))
                throw new ApplicationException("positive spot value required");

            if (!(discount_ > 0.0))
                throw new ApplicationException("positive discount required");

            if (!(dividendDiscount_ > 0.0))
                throw new ApplicationException("positive dividend discount required");

            if (!(variance_ >= 0.0))
                throw new ApplicationException("negative variance not allowed");

            stdDev_ = Math.Sqrt(variance_);

            Option.Type type = payoff.optionType();
            strike_ = payoff.strike();


            log_H_S_ = Math.Log(strike_ / spot_);

            double n_d1;
            double n_d2;
            double cum_d1_;
            double cum_d2_;
            if (variance_ >= Const.QL_Epsilon) {
                if (discount_ == 0.0 && dividendDiscount_ == 0.0) {
                    mu_ = -0.5;
                    lambda_ = 0.5;
                } else if (discount_ == 0.0) {
                    throw new ApplicationException("null discount not handled yet");
                } else {
                    mu_ = Math.Log(dividendDiscount_ / discount_) / variance_ - 0.5;
                    lambda_ = Math.Sqrt(mu_ * mu_ - 2.0 * Math.Log(discount_) / variance_);
                }
                D1_ = log_H_S_ / stdDev_ + lambda_ * stdDev_;
                D2_ = D1_ - 2.0 * lambda_ * stdDev_;
                CumulativeNormalDistribution f = new CumulativeNormalDistribution();
                cum_d1_ = f.value(D1_);
                cum_d2_ = f.value(D2_);
                n_d1 = f.derivative(D1_);
                n_d2 = f.derivative(D2_);
            } else {
                // not tested yet
                mu_ = Math.Log(dividendDiscount_ / discount_) / variance_ - 0.5;
                lambda_ = Math.Sqrt(mu_ * mu_ - 2.0 * Math.Log(discount_) / variance_);
                if (log_H_S_ > 0) {
                    cum_d1_ = 1.0;
                    cum_d2_ = 1.0;
                } else {
                    cum_d1_ = 0.0;
                    cum_d2_ = 0.0;
                }
                n_d1 = 0.0;
                n_d2 = 0.0;
            }


            switch (type) {
                // up-and-in cash-(at-hit)-or-nothing option
                // a.k.a. american call with cash-or-nothing payoff
                case Option.Type.Call:
                    if (strike_ > spot_) {
                        alpha_ = 1.0 - cum_d1_; // N(-d1)
                        DalphaDd1_ = -n_d1; // -n( d1)
                        beta_ = 1.0 - cum_d2_; // N(-d2)
                        DbetaDd2_ = -n_d2; // -n( d2)
                    } else {
                        alpha_ = 0.5;
                        DalphaDd1_ = 0.0;
                        beta_ = 0.5;
                        DbetaDd2_ = 0.0;
                    }
                    break;
                // down-and-in cash-(at-hit)-or-nothing option
                // a.k.a. american put with cash-or-nothing payoff
                case Option.Type.Put:
                    if (strike_ < spot_) {
                        alpha_ = cum_d1_; // N(d1)
                        DalphaDd1_ = n_d1; // n(d1)
                        beta_ = cum_d2_; // N(d2)
                        DbetaDd2_ = n_d2; // n(d2)
                    } else {
                        alpha_ = 0.5;
                        DalphaDd1_ = 0.0;
                        beta_ = 0.5;
                        DbetaDd2_ = 0.0;
                    }
                    break;
                default:
                    throw new ApplicationException("invalid option type");
            }


            muPlusLambda_ = mu_ + lambda_;
            muMinusLambda_ = mu_ - lambda_;
            inTheMoney_ = (type == Option.Type.Call && strike_ < spot_) || (type == Option.Type.Put && strike_ > spot_);

            if (inTheMoney_) {
                forward_ = 1.0;
                X_ = 1.0;
                DXDstrike_ = 0.0;
            } else {
                forward_ = Math.Pow(strike_ / spot_, muPlusLambda_);
                X_ = Math.Pow(strike_ / spot_, muMinusLambda_);
                //            DXDstrike_ = ......;
            }


            // Binary Cash-Or-Nothing payoff?
            CashOrNothingPayoff coo = payoff as CashOrNothingPayoff;
            if (coo != null) {
                K_ = coo.cashPayoff();
                DKDstrike_ = 0.0;
            }

            // Binary Asset-Or-Nothing payoff?
            AssetOrNothingPayoff aoo = payoff as AssetOrNothingPayoff;

            if (aoo != null) {
                if (inTheMoney_) {
                    K_ = spot_;
                    DKDstrike_ = 0.0;
                } else {
                    K_ = aoo.strike();
                    DKDstrike_ = 1.0;
                }
            }
        }
Beispiel #9
0
        //private double DXDstrike_;

        public AmericanPayoffAtExpiry(double spot, double discount, double dividendDiscount, double variance, StrikedTypePayoff payoff)
        {
            spot_             = spot;
            discount_         = discount;
            dividendDiscount_ = dividendDiscount;
            variance_         = variance;

            if (!(spot_ > 0.0))
            {
                throw new ApplicationException("positive spot_ value required");
            }

            forward_ = spot_ * dividendDiscount_ / discount_;

            if (!(discount_ > 0.0))
            {
                throw new ApplicationException("positive discount required");
            }

            if (!(dividendDiscount_ > 0.0))
            {
                throw new ApplicationException("positive dividend discount_ required");
            }

            if (!(variance_ >= 0.0))
            {
                throw new ApplicationException("negative variance_ not allowed");
            }

            stdDev_ = Math.Sqrt(variance_);

            Option.Type type = payoff.optionType();
            strike_ = payoff.strike();


            mu_ = Math.Log(dividendDiscount_ / discount_) / variance_ - 0.5;

            // binary cash-or-nothing payoff?
            CashOrNothingPayoff coo = payoff as CashOrNothingPayoff;

            if (coo != null)
            {
                K_ = coo.cashPayoff();
                //DKDstrike_ = 0.0;
            }

            // binary asset-or-nothing payoff?
            AssetOrNothingPayoff aoo = payoff as AssetOrNothingPayoff;

            if (aoo != null)
            {
                K_ = forward_;
                //DKDstrike_ = 0.0;
                mu_ += 1.0;
            }


            log_H_S_ = Math.Log(strike_ / spot_);

            double n_d1;
            double n_d2;
            double cum_d1_;
            double cum_d2_;

            if (variance_ >= Const.QL_Epsilon)
            {
                D1_ = log_H_S_ / stdDev_ + mu_ * stdDev_;
                D2_ = D1_ - 2.0 * mu_ * stdDev_;
                CumulativeNormalDistribution f = new CumulativeNormalDistribution();
                cum_d1_ = f.value(D1_);
                cum_d2_ = f.value(D2_);
                n_d1    = f.derivative(D1_);
                n_d2    = f.derivative(D2_);
            }
            else
            {
                if (log_H_S_ > 0)
                {
                    cum_d1_ = 1.0;
                    cum_d2_ = 1.0;
                }
                else
                {
                    cum_d1_ = 0.0;
                    cum_d2_ = 0.0;
                }
                n_d1 = 0.0;
                n_d2 = 0.0;
            }


            switch (type)
            {
            // up-and-in cash-(at-hit)-or-nothing option
            // a.k.a. american call with cash-or-nothing payoff
            case Option.Type.Call:
                if (strike_ > spot_)
                {
                    alpha_     = 1.0 - cum_d2_; // N(-d2)
                    DalphaDd1_ = -n_d2;         // -n( d2)
                    beta_      = 1.0 - cum_d1_; // N(-d1)
                    DbetaDd2_  = -n_d1;         // -n( d1)
                }
                else
                {
                    alpha_     = 0.5;
                    DalphaDd1_ = 0.0;
                    beta_      = 0.5;
                    DbetaDd2_  = 0.0;
                }
                break;

            // down-and-in cash-(at-hit)-or-nothing option
            // a.k.a. american put with cash-or-nothing payoff
            case Option.Type.Put:
                if (strike_ < spot_)
                {
                    alpha_     = cum_d2_; // N(d2)
                    DalphaDd1_ = n_d2;    // n(d2)
                    beta_      = cum_d1_; // N(d1)
                    DbetaDd2_  = n_d1;    // n(d1)
                }
                else
                {
                    alpha_     = 0.5;
                    DalphaDd1_ = 0.0;
                    beta_      = 0.5;
                    DbetaDd2_  = 0.0;
                }
                break;

            default:
                throw new ApplicationException("invalid option type");
            }


            inTheMoney_ = (type == Option.Type.Call && strike_ < spot_) || (type == Option.Type.Put && strike_ > spot_);
            if (inTheMoney_)
            {
                Y_ = 1.0;
                X_ = 1.0;
                //DYDstrike_ = 0.0;
                //DXDstrike_ = 0.0;
            }
            else
            {
                Y_ = 1.0;
                X_ = Math.Pow((double)(strike_ / spot_), (double)(2.0 * mu_));
                //            DXDstrike_ = ......;
            }
        }
        // critical commodity price
        //public static double criticalPrice(StrikedTypePayoff payoff, double riskFreeDiscount, double dividendDiscount,
        //                                   double variance, double tolerance = 1e-6);
        public static double criticalPrice(StrikedTypePayoff payoff, double riskFreeDiscount, double dividendDiscount,
                                           double variance, double tolerance)
        {
            // Calculation of seed value, Si
            double n= 2.0*Math.Log(dividendDiscount/riskFreeDiscount)/(variance);
            double m=-2.0*Math.Log(riskFreeDiscount)/(variance);
            double bT = Math.Log(dividendDiscount/riskFreeDiscount);

            double qu, Su, h, Si;
            switch (payoff.optionType()) {
                case Option.Type.Call:
                    qu = (-(n-1.0) + Math.Sqrt(((n-1.0)*(n-1.0)) + 4.0*m))/2.0;
                    Su = payoff.strike() / (1.0 - 1.0/qu);
                    h = -(bT + 2.0*Math.Sqrt(variance)) * payoff.strike() /
                        (Su - payoff.strike());
                    Si = payoff.strike() + (Su - payoff.strike()) *
                        (1.0 - Math.Exp(h));
                    break;
                case Option.Type.Put:
                    qu = (-(n-1.0) - Math.Sqrt(((n-1.0)*(n-1.0)) + 4.0*m))/2.0;
                    Su = payoff.strike() / (1.0 - 1.0/qu);
                    h = (bT - 2.0*Math.Sqrt(variance)) * payoff.strike() /
                        (payoff.strike() - Su);
                    Si = Su + (payoff.strike() - Su) * Math.Exp(h);
                    break;
                default:
                    throw new ArgumentException("unknown option type");
            }

            // Newton Raphson algorithm for finding critical price Si
            double Q, LHS, RHS, bi;
            double forwardSi = Si * dividendDiscount / riskFreeDiscount;
            double d1 = (Math.Log(forwardSi/payoff.strike()) + 0.5*variance) /
                Math.Sqrt(variance);
            CumulativeNormalDistribution cumNormalDist = new CumulativeNormalDistribution();
            double K = (riskFreeDiscount!=1.0 ? -2.0*Math.Log(riskFreeDiscount)/
                (variance*(1.0-riskFreeDiscount)) : 0.0);
            double temp = Utils.blackFormula(payoff.optionType(), payoff.strike(),
                    forwardSi, Math.Sqrt(variance))*riskFreeDiscount;
            switch (payoff.optionType()) {
                case Option.Type.Call:
                    Q = (-(n-1.0) + Math.Sqrt(((n-1.0)*(n-1.0)) + 4 * K)) / 2;
                    LHS = Si - payoff.strike();
                    RHS = temp + (1 - dividendDiscount * cumNormalDist.value(d1)) * Si / Q;
                    bi = dividendDiscount * cumNormalDist.value(d1) * (1 - 1 / Q) +
                        (1 - dividendDiscount *
                         cumNormalDist.derivative(d1) / Math.Sqrt(variance)) / Q;
                    while (Math.Abs(LHS - RHS)/payoff.strike() > tolerance) {
                        Si = (payoff.strike() + RHS - bi * Si) / (1 - bi);
                        forwardSi = Si * dividendDiscount / riskFreeDiscount;
                        d1 = (Math.Log(forwardSi/payoff.strike())+0.5*variance)
                            /Math.Sqrt(variance);
                        LHS = Si - payoff.strike();
                        double temp2 = Utils.blackFormula(payoff.optionType(), payoff.strike(),
                            forwardSi, Math.Sqrt(variance))*riskFreeDiscount;
                        RHS = temp2 + (1 - dividendDiscount * cumNormalDist.value(d1)) * Si / Q;
                        bi = dividendDiscount * cumNormalDist.value(d1) * (1 - 1 / Q)
                            + (1 - dividendDiscount *
                               cumNormalDist.derivative(d1) / Math.Sqrt(variance))
                            / Q;
                    }
                    break;
                case Option.Type.Put:
                    Q = (-(n-1.0) - Math.Sqrt(((n-1.0)*(n-1.0)) + 4 * K)) / 2;
                    LHS = payoff.strike() - Si;
                    RHS = temp - (1 - dividendDiscount * cumNormalDist.value(-d1)) * Si / Q;
                    bi = -dividendDiscount * cumNormalDist.value(-d1) * (1 - 1 / Q)
                        - (1 + dividendDiscount * cumNormalDist.derivative(-d1)
                           / Math.Sqrt(variance)) / Q;
                    while (Math.Abs(LHS - RHS)/payoff.strike() > tolerance) {
                        Si = (payoff.strike() - RHS + bi * Si) / (1 + bi);
                        forwardSi = Si * dividendDiscount / riskFreeDiscount;
                        d1 = (Math.Log(forwardSi/payoff.strike())+0.5*variance)
                            /Math.Sqrt(variance);
                        LHS = payoff.strike() - Si;
                        double temp2 = Utils.blackFormula(payoff.optionType(), payoff.strike(),
                            forwardSi, Math.Sqrt(variance))*riskFreeDiscount;
                        RHS = temp2 - (1 - dividendDiscount * cumNormalDist.value(-d1)) * Si / Q;
                        bi = -dividendDiscount * cumNormalDist.value(-d1) * (1 - 1 / Q)
                            - (1 + dividendDiscount * cumNormalDist.derivative(-d1)
                               / Math.Sqrt(variance)) / Q;
                    }
                    break;
                default:
                    throw new ArgumentException("unknown option type");
            }

            return Si;
        }
Beispiel #11
0
        // public BlackCalculator(StrikedTypePayoff payoff, double forward, double stdDev, double discount = 1.0) {
        public BlackCalculator(StrikedTypePayoff payoff, double forward, double stdDev, double discount) {
            strike_ = payoff.strike();
            forward_ = forward;
            stdDev_ = stdDev;
            discount_ = discount;
            variance_ = stdDev*stdDev;

            if (!(forward>0.0))
                throw new ApplicationException("positive forward value required: " + forward + " not allowed");

            if (!(stdDev>=0.0))
                throw new ApplicationException("non-negative standard deviation required: " + stdDev + " not allowed");

            if (!(discount>0.0))
                throw new ApplicationException("positive discount required: " + discount + " not allowed");

            if (stdDev_>=Const.QL_EPSILON) {
                if (strike_==0.0) {
                    n_d1_ = 0.0;
                    n_d2_ = 0.0;
                    cum_d1_ = 1.0;
                    cum_d2_= 1.0;
                } else {
                    D1_ = Math.Log(forward/strike_)/stdDev_ + 0.5*stdDev_;
                    D2_ = D1_-stdDev_;
                    CumulativeNormalDistribution f = new CumulativeNormalDistribution();
                    cum_d1_ = f.value(D1_);
                    cum_d2_= f.value(D2_);
                    n_d1_ = f.derivative(D1_);
                    n_d2_ = f.derivative(D2_);
                }
            } else {
                if (forward>strike_) {
                    cum_d1_ = 1.0;
                    cum_d2_= 1.0;
                } else {
                    cum_d1_ = 0.0;
                    cum_d2_= 0.0;
                }
                n_d1_ = 0.0;
                n_d2_ = 0.0;
            }

            X_ = strike_;
            DXDstrike_ = 1.0;

            // the following one will probably disappear as soon as
            // super-share will be properly handled
            DXDs_ = 0.0;

            // this part is always executed.
            // in case of plain-vanilla payoffs, it is also the only part
            // which is executed.
            switch (payoff.optionType()) {
                case Option.Type.Call:
                    alpha_     =  cum_d1_;//  N(d1)
                    DalphaDd1_ =    n_d1_;//  n(d1)
                    beta_      = -cum_d2_;// -N(d2)
                    DbetaDd2_  = -  n_d2_;// -n(d2)
                    break;
                case Option.Type.Put:
                    alpha_     = -1.0+cum_d1_;// -N(-d1)
                    DalphaDd1_ =        n_d1_;//  n( d1)
                    beta_      =  1.0-cum_d2_;//  N(-d2)
                    DbetaDd2_  =     -  n_d2_;// -n( d2)
                    break;
                default:
                    throw new ArgumentException("invalid option type");
            }

            // now dispatch on type.

            Calculator calc = new Calculator(this);
            payoff.accept(calc);
        }
        // critical commodity price
        //public static double criticalPrice(StrikedTypePayoff payoff, double riskFreeDiscount, double dividendDiscount,
        //                                   double variance, double tolerance = 1e-6);
        public static double criticalPrice(StrikedTypePayoff payoff, double riskFreeDiscount, double dividendDiscount,
                                           double variance, double tolerance)
        {
            // Calculation of seed value, Si
            double n  = 2.0 * Math.Log(dividendDiscount / riskFreeDiscount) / (variance);
            double m  = -2.0 * Math.Log(riskFreeDiscount) / (variance);
            double bT = Math.Log(dividendDiscount / riskFreeDiscount);

            double qu, Su, h, Si;

            switch (payoff.optionType())
            {
            case Option.Type.Call:
                qu = (-(n - 1.0) + Math.Sqrt(((n - 1.0) * (n - 1.0)) + 4.0 * m)) / 2.0;
                Su = payoff.strike() / (1.0 - 1.0 / qu);
                h  = -(bT + 2.0 * Math.Sqrt(variance)) * payoff.strike() /
                     (Su - payoff.strike());
                Si = payoff.strike() + (Su - payoff.strike()) *
                     (1.0 - Math.Exp(h));
                break;

            case Option.Type.Put:
                qu = (-(n - 1.0) - Math.Sqrt(((n - 1.0) * (n - 1.0)) + 4.0 * m)) / 2.0;
                Su = payoff.strike() / (1.0 - 1.0 / qu);
                h  = (bT - 2.0 * Math.Sqrt(variance)) * payoff.strike() /
                     (payoff.strike() - Su);
                Si = Su + (payoff.strike() - Su) * Math.Exp(h);
                break;

            default:
                throw new ArgumentException("unknown option type");
            }


            // Newton Raphson algorithm for finding critical price Si
            double Q, LHS, RHS, bi;
            double forwardSi = Si * dividendDiscount / riskFreeDiscount;
            double d1        = (Math.Log(forwardSi / payoff.strike()) + 0.5 * variance) /
                               Math.Sqrt(variance);
            CumulativeNormalDistribution cumNormalDist = new CumulativeNormalDistribution();
            double K = (riskFreeDiscount != 1.0 ? -2.0 * Math.Log(riskFreeDiscount) /
                        (variance * (1.0 - riskFreeDiscount)) : 0.0);
            double temp = Utils.blackFormula(payoff.optionType(), payoff.strike(),
                                             forwardSi, Math.Sqrt(variance)) * riskFreeDiscount;

            switch (payoff.optionType())
            {
            case Option.Type.Call:
                Q   = (-(n - 1.0) + Math.Sqrt(((n - 1.0) * (n - 1.0)) + 4 * K)) / 2;
                LHS = Si - payoff.strike();
                RHS = temp + (1 - dividendDiscount * cumNormalDist.value(d1)) * Si / Q;
                bi  = dividendDiscount * cumNormalDist.value(d1) * (1 - 1 / Q) +
                      (1 - dividendDiscount *
                       cumNormalDist.derivative(d1) / Math.Sqrt(variance)) / Q;
                while (Math.Abs(LHS - RHS) / payoff.strike() > tolerance)
                {
                    Si        = (payoff.strike() + RHS - bi * Si) / (1 - bi);
                    forwardSi = Si * dividendDiscount / riskFreeDiscount;
                    d1        = (Math.Log(forwardSi / payoff.strike()) + 0.5 * variance)
                                / Math.Sqrt(variance);
                    LHS = Si - payoff.strike();
                    double temp2 = Utils.blackFormula(payoff.optionType(), payoff.strike(),
                                                      forwardSi, Math.Sqrt(variance)) * riskFreeDiscount;
                    RHS = temp2 + (1 - dividendDiscount * cumNormalDist.value(d1)) * Si / Q;
                    bi  = dividendDiscount * cumNormalDist.value(d1) * (1 - 1 / Q)
                          + (1 - dividendDiscount *
                             cumNormalDist.derivative(d1) / Math.Sqrt(variance))
                          / Q;
                }
                break;

            case Option.Type.Put:
                Q   = (-(n - 1.0) - Math.Sqrt(((n - 1.0) * (n - 1.0)) + 4 * K)) / 2;
                LHS = payoff.strike() - Si;
                RHS = temp - (1 - dividendDiscount * cumNormalDist.value(-d1)) * Si / Q;
                bi  = -dividendDiscount *cumNormalDist.value(-d1) * (1 - 1 / Q)
                      - (1 + dividendDiscount * cumNormalDist.derivative(-d1)
                         / Math.Sqrt(variance)) / Q;

                while (Math.Abs(LHS - RHS) / payoff.strike() > tolerance)
                {
                    Si        = (payoff.strike() - RHS + bi * Si) / (1 + bi);
                    forwardSi = Si * dividendDiscount / riskFreeDiscount;
                    d1        = (Math.Log(forwardSi / payoff.strike()) + 0.5 * variance)
                                / Math.Sqrt(variance);
                    LHS = payoff.strike() - Si;
                    double temp2 = Utils.blackFormula(payoff.optionType(), payoff.strike(),
                                                      forwardSi, Math.Sqrt(variance)) * riskFreeDiscount;
                    RHS = temp2 - (1 - dividendDiscount * cumNormalDist.value(-d1)) * Si / Q;
                    bi  = -dividendDiscount *cumNormalDist.value(-d1) * (1 - 1 / Q)
                          - (1 + dividendDiscount * cumNormalDist.derivative(-d1)
                             / Math.Sqrt(variance)) / Q;
                }
                break;

            default:
                throw new ArgumentException("unknown option type");
            }

            return(Si);
        }
        public AmericanPayoffAtExpiry(double spot, double discount, double dividendDiscount, double variance,
                                      StrikedTypePayoff payoff, bool knock_in = true)
        {
            spot_             = spot;
            discount_         = discount;
            dividendDiscount_ = dividendDiscount;
            variance_         = variance;
            knock_in_         = knock_in;

            Utils.QL_REQUIRE(spot_ > 0.0, () => "positive spot value required");
            Utils.QL_REQUIRE(discount_ > 0.0, () => "positive discount required");
            Utils.QL_REQUIRE(dividendDiscount_ > 0.0, () => "positive dividend discount required");
            Utils.QL_REQUIRE(variance_ >= 0.0, () => "negative variance not allowed");

            stdDev_ = Math.Sqrt(variance_);
            Option.Type type = payoff.optionType();
            strike_  = payoff.strike();
            forward_ = spot_ * dividendDiscount_ / discount_;

            mu_ = Math.Log(dividendDiscount_ / discount_) / variance_ - 0.5;

            // binary cash-or-nothing payoff?
            CashOrNothingPayoff coo = payoff as CashOrNothingPayoff;

            if (coo != null)
            {
                K_ = coo.cashPayoff();
            }

            // binary asset-or-nothing payoff?
            AssetOrNothingPayoff aoo = payoff as AssetOrNothingPayoff;

            if (aoo != null)
            {
                K_   = forward_;
                mu_ += 1.0;
            }


            log_H_S_ = Math.Log(strike_ / spot_);
            double log_S_H_ = Math.Log(spot_ / strike_);

            double eta = 0.0;
            double phi = 0.0;

            switch (type)
            {
            case Option.Type.Call:
                if (knock_in_)
                {
                    // up-and-in cash-(at-expiry)-or-nothing option
                    // a.k.a. american call with cash-or-nothing payoff
                    eta = -1.0;
                    phi = 1.0;
                }
                else
                {
                    // up-and-out cash-(at-expiry)-or-nothing option
                    eta = -1.0;
                    phi = -1.0;
                }
                break;

            case Option.Type.Put:
                if (knock_in_)
                {
                    // down-and-in cash-(at-expiry)-or-nothing option
                    // a.k.a. american put with cash-or-nothing payoff
                    eta = 1.0;
                    phi = -1.0;
                }
                else
                {
                    // down-and-out cash-(at-expiry)-or-nothing option
                    eta = 1.0;
                    phi = 1.0;
                }
                break;

            default:
                Utils.QL_FAIL("invalid option type");
                break;
            }


            if (variance_ >= Const.QL_EPSILON)
            {
                D1_ = phi * (log_S_H_ / stdDev_ + mu_ * stdDev_);
                D2_ = eta * (log_H_S_ / stdDev_ + mu_ * stdDev_);
                CumulativeNormalDistribution f = new CumulativeNormalDistribution();
                cum_d1_ = f.value(D1_);
                cum_d2_ = f.value(D2_);
                n_d1_   = f.derivative(D1_);
                n_d2_   = f.derivative(D2_);
            }
            else
            {
                if (log_S_H_ * phi > 0)
                {
                    cum_d1_ = 1.0;
                }
                else
                {
                    cum_d1_ = 0.0;
                }

                if (log_H_S_ * eta > 0)
                {
                    cum_d2_ = 1.0;
                }
                else
                {
                    cum_d2_ = 0.0;
                }

                n_d1_ = 0.0;
                n_d2_ = 0.0;
            }

            switch (type)
            {
            case Option.Type.Call:
                if (strike_ <= spot_)
                {
                    if (knock_in_)
                    {
                        // up-and-in cash-(at-expiry)-or-nothing option
                        // a.k.a. american call with cash-or-nothing payoff
                        cum_d1_ = 0.5;
                        cum_d2_ = 0.5;
                    }
                    else
                    {
                        // up-and-out cash-(at-expiry)-or-nothing option
                        // already knocked out
                        cum_d1_ = 0.0;
                        cum_d2_ = 0.0;
                    }
                    n_d1_ = 0.0;
                    n_d2_ = 0.0;
                }
                break;

            case Option.Type.Put:
                if (strike_ >= spot_)
                {
                    if (knock_in_)
                    {
                        // down-and-in cash-(at-expiry)-or-nothing option
                        // a.k.a. american put with cash-or-nothing payoff
                        cum_d1_ = 0.5;
                        cum_d2_ = 0.5;
                    }
                    else
                    {
                        // down-and-out cash-(at-expiry)-or-nothing option
                        // already knocked out
                        cum_d1_ = 0.0;
                        cum_d2_ = 0.0;
                    }
                    n_d1_ = 0.0;
                    n_d2_ = 0.0;
                }
                break;

            default:
                Utils.QL_FAIL("invalid option type");
                break;
            }


            inTheMoney_ = (type == Option.Type.Call && strike_ < spot_) ||
                          (type == Option.Type.Put && strike_ > spot_);
            if (inTheMoney_)
            {
                X_ = 1.0;
                Y_ = 1.0;
            }
            else
            {
                X_ = 1.0;
                if (cum_d2_ == 0.0)
                {
                    Y_ = 0.0; // check needed on some extreme cases
                }
                else
                {
                    Y_ = Math.Pow((strike_ / spot_), (2.0 * mu_));
                }
            }
            if (!knock_in_)
            {
                Y_ *= -1.0;
            }
        }
Beispiel #14
0
        public AmericanPayoffAtHit(double spot, double discount, double dividendDiscount, double variance, StrikedTypePayoff payoff)
        {
            spot_             = spot;
            discount_         = discount;
            dividendDiscount_ = dividendDiscount;
            variance_         = variance;

            if (!(spot_ > 0.0))
            {
                throw new ApplicationException("positive spot value required");
            }

            if (!(discount_ > 0.0))
            {
                throw new ApplicationException("positive discount required");
            }

            if (!(dividendDiscount_ > 0.0))
            {
                throw new ApplicationException("positive dividend discount required");
            }

            if (!(variance_ >= 0.0))
            {
                throw new ApplicationException("negative variance not allowed");
            }

            stdDev_ = Math.Sqrt(variance_);

            Option.Type type = payoff.optionType();
            strike_ = payoff.strike();


            log_H_S_ = Math.Log(strike_ / spot_);

            double n_d1;
            double n_d2;
            double cum_d1_;
            double cum_d2_;

            if (variance_ >= Const.QL_Epsilon)
            {
                if (discount_ == 0.0 && dividendDiscount_ == 0.0)
                {
                    mu_     = -0.5;
                    lambda_ = 0.5;
                }
                else if (discount_ == 0.0)
                {
                    throw new ApplicationException("null discount not handled yet");
                }
                else
                {
                    mu_     = Math.Log(dividendDiscount_ / discount_) / variance_ - 0.5;
                    lambda_ = Math.Sqrt(mu_ * mu_ - 2.0 * Math.Log(discount_) / variance_);
                }
                D1_ = log_H_S_ / stdDev_ + lambda_ * stdDev_;
                D2_ = D1_ - 2.0 * lambda_ * stdDev_;
                CumulativeNormalDistribution f = new CumulativeNormalDistribution();
                cum_d1_ = f.value(D1_);
                cum_d2_ = f.value(D2_);
                n_d1    = f.derivative(D1_);
                n_d2    = f.derivative(D2_);
            }
            else
            {
                // not tested yet
                mu_     = Math.Log(dividendDiscount_ / discount_) / variance_ - 0.5;
                lambda_ = Math.Sqrt(mu_ * mu_ - 2.0 * Math.Log(discount_) / variance_);
                if (log_H_S_ > 0)
                {
                    cum_d1_ = 1.0;
                    cum_d2_ = 1.0;
                }
                else
                {
                    cum_d1_ = 0.0;
                    cum_d2_ = 0.0;
                }
                n_d1 = 0.0;
                n_d2 = 0.0;
            }


            switch (type)
            {
            // up-and-in cash-(at-hit)-or-nothing option
            // a.k.a. american call with cash-or-nothing payoff
            case Option.Type.Call:
                if (strike_ > spot_)
                {
                    alpha_     = 1.0 - cum_d1_; // N(-d1)
                    DalphaDd1_ = -n_d1;         // -n( d1)
                    beta_      = 1.0 - cum_d2_; // N(-d2)
                    DbetaDd2_  = -n_d2;         // -n( d2)
                }
                else
                {
                    alpha_     = 0.5;
                    DalphaDd1_ = 0.0;
                    beta_      = 0.5;
                    DbetaDd2_  = 0.0;
                }
                break;

            // down-and-in cash-(at-hit)-or-nothing option
            // a.k.a. american put with cash-or-nothing payoff
            case Option.Type.Put:
                if (strike_ < spot_)
                {
                    alpha_     = cum_d1_; // N(d1)
                    DalphaDd1_ = n_d1;    // n(d1)
                    beta_      = cum_d2_; // N(d2)
                    DbetaDd2_  = n_d2;    // n(d2)
                }
                else
                {
                    alpha_     = 0.5;
                    DalphaDd1_ = 0.0;
                    beta_      = 0.5;
                    DbetaDd2_  = 0.0;
                }
                break;

            default:
                throw new ApplicationException("invalid option type");
            }


            muPlusLambda_  = mu_ + lambda_;
            muMinusLambda_ = mu_ - lambda_;
            inTheMoney_    = (type == Option.Type.Call && strike_ < spot_) || (type == Option.Type.Put && strike_ > spot_);

            if (inTheMoney_)
            {
                forward_   = 1.0;
                X_         = 1.0;
                DXDstrike_ = 0.0;
            }
            else
            {
                forward_ = Math.Pow(strike_ / spot_, muPlusLambda_);
                X_       = Math.Pow(strike_ / spot_, muMinusLambda_);
                //            DXDstrike_ = ......;
            }


            // Binary Cash-Or-Nothing payoff?
            CashOrNothingPayoff coo = payoff as CashOrNothingPayoff;

            if (coo != null)
            {
                K_         = coo.cashPayoff();
                DKDstrike_ = 0.0;
            }

            // Binary Asset-Or-Nothing payoff?
            AssetOrNothingPayoff aoo = payoff as AssetOrNothingPayoff;

            if (aoo != null)
            {
                if (inTheMoney_)
                {
                    K_         = spot_;
                    DKDstrike_ = 0.0;
                }
                else
                {
                    K_         = aoo.strike();
                    DKDstrike_ = 1.0;
                }
            }
        }
Beispiel #15
0
        public static double blackFormulaStdDevDerivative( double strike,
            double forward,
            double stdDev,
            double discount,
            double displacement)
        {
            checkParameters( strike, forward, displacement );

            if ( stdDev < 0.0 )
                throw new ArgumentException( "stdDev (" + stdDev + ") must be non-negative" );

            if ( discount <= 0.0 )
                throw new ArgumentException( "discount (" + discount + ") must be positive" );

            forward = forward + displacement;
            strike = strike + displacement;

            if ( stdDev == 0.0  || strike == 0)
                    return 0.0;

            double d1 = Math.Log( forward / strike ) / stdDev + .5 * stdDev;
            CumulativeNormalDistribution phi = new CumulativeNormalDistribution();
            return discount * forward * phi.derivative( d1 );
        }