예제 #1
0
            public void visit(AssetOrNothingPayoff payoff)
            {
                black_.beta_ = black_.DbetaDd2_ = 0.0;
                switch (payoff.optionType())
                {
                case Option.Type.Call:
                    black_.alpha_     = black_.cum_d1_;
                    black_.DalphaDd1_ = black_.n_d1_;
                    break;

                case Option.Type.Put:
                    black_.alpha_     = 1.0 - black_.cum_d1_;
                    black_.DalphaDd1_ = -black_.n_d1_;
                    break;

                default:
                    Utils.QL_FAIL("invalid option type");
                    break;
                }
            }
예제 #2
0
        public AmericanPayoffAtHit(double spot, double discount, double dividendDiscount, double variance, StrikedTypePayoff payoff)
        {
            spot_             = spot;
            discount_         = discount;
            dividendDiscount_ = dividendDiscount;
            variance_         = variance;

            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();


            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_.IsEqual(0.0) && dividendDiscount_.IsEqual(0.0))
                {
                    mu_     = -0.5;
                    lambda_ = 0.5;
                }
                else if (discount_.IsEqual(0.0))
                {
                    Utils.QL_FAIL("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:
                Utils.QL_FAIL("invalid option type");
                break;
            }


            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;
            }
            else
            {
                forward_ = Math.Pow(strike_ / spot_, muPlusLambda_);
                X_       = Math.Pow(strike_ / spot_, muMinusLambda_);
            }


            // 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)
            {
                if (inTheMoney_)
                {
                    K_ = spot_;
                }
                else
                {
                    K_ = aoo.strike();
                }
            }
        }
        public double payoffAtExpiry(double spot, double variance, double discount)
        {
            double dividendDiscount = process_.dividendYield().link.discount(exercise_.lastDate());

            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");

            Option.Type type    = payoff_.optionType();
            double      strike  = payoff_.strike();
            double?     barrier = arguments_.barrier;

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

            double stdDev = Math.Sqrt(variance);
            double mu     = Math.Log(dividendDiscount / discount) / variance - 0.5;
            double K      = 0;

            // 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)
            {
                mu += 1.0;
                K   = spot * dividendDiscount / discount; // forward
            }

            double log_S_X   = Math.Log(spot / strike);
            double log_S_H   = Math.Log(spot / barrier.GetValueOrDefault());
            double log_H_S   = Math.Log(barrier.GetValueOrDefault() / spot);
            double log_H2_SX = Math.Log(barrier.GetValueOrDefault() * barrier.GetValueOrDefault() / (spot * strike));
            double H_S_2mu   = Math.Pow(barrier.GetValueOrDefault() / spot, 2 * mu);

            double eta = (barrierType == Barrier.Type.DownIn ||
                          barrierType == Barrier.Type.DownOut ? 1.0 : -1.0);
            double phi = (type == Option.Type.Call ? 1.0 : -1.0);

            double x1, x2, y1, y2;
            double cum_x1, cum_x2, cum_y1, cum_y2;

            if (variance >= Const.QL_EPSILON)
            {
                // we calculate using mu*stddev instead of (mu+1)*stddev
                // because cash-or-nothing don't need it. asset-or-nothing
                // mu is really mu+1
                x1 = phi * (log_S_X / stdDev + mu * stdDev);
                x2 = phi * (log_S_H / stdDev + mu * stdDev);
                y1 = eta * (log_H2_SX / stdDev + mu * stdDev);
                y2 = eta * (log_H_S / stdDev + mu * stdDev);

                CumulativeNormalDistribution f = new CumulativeNormalDistribution();
                cum_x1 = f.value(x1);
                cum_x2 = f.value(x2);
                cum_y1 = f.value(y1);
                cum_y2 = f.value(y2);
            }
            else
            {
                if (log_S_X > 0)
                {
                    cum_x1 = 1.0;
                }
                else
                {
                    cum_x1 = 0.0;
                }
                if (log_S_H > 0)
                {
                    cum_x2 = 1.0;
                }
                else
                {
                    cum_x2 = 0.0;
                }
                if (log_H2_SX > 0)
                {
                    cum_y1 = 1.0;
                }
                else
                {
                    cum_y1 = 0.0;
                }
                if (log_H_S > 0)
                {
                    cum_y2 = 1.0;
                }
                else
                {
                    cum_y2 = 0.0;
                }
            }

            double alpha = 0;

            switch (barrierType)
            {
            case Barrier.Type.DownIn:
                if (type == Option.Type.Call)
                {
                    // down-in and call
                    if (strike >= barrier)
                    {
                        // B3 (eta=1, phi=1)
                        alpha = H_S_2mu * cum_y1;
                    }
                    else
                    {
                        // B1-B2+B4 (eta=1, phi=1)
                        alpha = cum_x1 - cum_x2 + H_S_2mu * cum_y2;
                    }
                }
                else
                {
                    // down-in and put
                    if (strike >= barrier)
                    {
                        // B2-B3+B4 (eta=1, phi=-1)
                        alpha = cum_x2 + H_S_2mu * (-cum_y1 + cum_y2);
                    }
                    else
                    {
                        // B1 (eta=1, phi=-1)
                        alpha = cum_x1;
                    }
                }
                break;

            case Barrier.Type.UpIn:
                if (type == Option.Type.Call)
                {
                    // up-in and call
                    if (strike >= barrier)
                    {
                        // B1 (eta=-1, phi=1)
                        alpha = cum_x1;
                    }
                    else
                    {
                        // B2-B3+B4 (eta=-1, phi=1)
                        alpha = cum_x2 + H_S_2mu * (-cum_y1 + cum_y2);
                    }
                }
                else
                {
                    // up-in and put
                    if (strike >= barrier)
                    {
                        // B1-B2+B4 (eta=-1, phi=-1)
                        alpha = cum_x1 - cum_x2 + H_S_2mu * cum_y2;
                    }
                    else
                    {
                        // B3 (eta=-1, phi=-1)
                        alpha = H_S_2mu * cum_y1;
                    }
                }
                break;

            case Barrier.Type.DownOut:
                if (type == Option.Type.Call)
                {
                    // down-out and call
                    if (strike >= barrier)
                    {
                        // B1-B3 (eta=1, phi=1)
                        alpha = cum_x1 - H_S_2mu * cum_y1;
                    }
                    else
                    {
                        // B2-B4 (eta=1, phi=1)
                        alpha = cum_x2 - H_S_2mu * cum_y2;
                    }
                }
                else
                {
                    // down-out and put
                    if (strike >= barrier)
                    {
                        // B1-B2+B3-B4 (eta=1, phi=-1)
                        alpha = cum_x1 - cum_x2 + H_S_2mu * (cum_y1 - cum_y2);
                    }
                    else
                    {
                        // always 0
                        alpha = 0;
                    }
                }
                break;

            case Barrier.Type.UpOut:
                if (type == Option.Type.Call)
                {
                    // up-out and call
                    if (strike >= barrier)
                    {
                        // always 0
                        alpha = 0;
                    }
                    else
                    {
                        // B1-B2+B3-B4 (eta=-1, phi=1)
                        alpha = cum_x1 - cum_x2 + H_S_2mu * (cum_y1 - cum_y2);
                    }
                }
                else
                {
                    // up-out and put
                    if (strike >= barrier)
                    {
                        // B2-B4 (eta=-1, phi=-1)
                        alpha = cum_x2 - H_S_2mu * cum_y2;
                    }
                    else
                    {
                        // B1-B3 (eta=-1, phi=-1)
                        alpha = cum_x1 - H_S_2mu * cum_y1;
                    }
                }
                break;

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

            return(discount * K * alpha);
        }
        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_.IsEqual(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;
            }
        }