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; } }
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; } }