public AnalyticDoubleBarrierBinaryEngineHelper( GeneralizedBlackScholesProcess process, CashOrNothingPayoff payoff, DoubleBarrierOption.Arguments arguments) { process_ = process; payoff_ = payoff; arguments_ = arguments; }
public void visit(CashOrNothingPayoff payoff) { black_.alpha_ = black_.DalphaDd1_ = 0.0; black_.X_ = payoff.cashPayoff(); black_.DXDstrike_ = 0.0; switch (payoff.optionType()) { case Option.Type.Call: black_.beta_ = black_.cum_d2_; black_.DbetaDd2_ = black_.n_d2_; break; case Option.Type.Put: black_.beta_ = 1.0 - black_.cum_d2_; black_.DbetaDd2_ = -black_.n_d2_; break; default: throw new ArgumentException("invalid option type"); } }
//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_ = ......; } }
public void visit(CashOrNothingPayoff payoff) { black_.alpha_ = black_.DalphaDd1_ = 0.0; black_.X_ = payoff.cashPayoff(); black_.DXDstrike_ = 0.0; switch (payoff.optionType()) { case Option.Type.Call: black_.beta_ = black_.cum_d2_; black_.DbetaDd2_ = black_.n_d2_; break; case Option.Type.Put: black_.beta_ = 1.0-black_.cum_d2_; black_.DbetaDd2_ = -black_.n_d2_; break; default: throw new ArgumentException("invalid option type"); } }
public override void calculate() { // 1. Mesher StrikedTypePayoff payoff = arguments_.payoff as StrikedTypePayoff; double maturity = process_.time(arguments_.exercise.lastDate()); double?xMin = null; double?xMax = null; if (arguments_.barrierType == Barrier.Type.DownIn || arguments_.barrierType == Barrier.Type.DownOut) { xMin = Math.Log(arguments_.barrier.Value); } if (arguments_.barrierType == Barrier.Type.UpIn || arguments_.barrierType == Barrier.Type.UpOut) { xMax = Math.Log(arguments_.barrier.Value); } Fdm1dMesher equityMesher = new FdmBlackScholesMesher(xGrid_, process_, maturity, payoff.strike(), xMin, xMax); FdmMesher mesher = new FdmMesherComposite(equityMesher); // 2. Calculator StrikedTypePayoff rebatePayoff = new CashOrNothingPayoff(Option.Type.Call, 0.0, arguments_.rebate.Value); FdmInnerValueCalculator calculator = new FdmLogInnerValue(rebatePayoff, mesher, 0); // 3. Step conditions Utils.QL_REQUIRE(arguments_.exercise.type() == Exercise.Type.European, () => "only european style option are supported"); FdmStepConditionComposite conditions = FdmStepConditionComposite.vanillaComposite( arguments_.cashFlow, arguments_.exercise, mesher, calculator, process_.riskFreeRate().currentLink().referenceDate(), process_.riskFreeRate().currentLink().dayCounter()); // 4. Boundary conditions FdmBoundaryConditionSet boundaries = new FdmBoundaryConditionSet(); if (arguments_.barrierType == Barrier.Type.DownIn || arguments_.barrierType == Barrier.Type.DownOut) { boundaries.Add(new FdmDirichletBoundary(mesher, arguments_.rebate.Value, 0, FdmDirichletBoundary.Side.Lower)); } if (arguments_.barrierType == Barrier.Type.UpIn || arguments_.barrierType == Barrier.Type.UpOut) { boundaries.Add(new FdmDirichletBoundary(mesher, arguments_.rebate.Value, 0, FdmDirichletBoundary.Side.Upper)); } // 5. Solver FdmSolverDesc solverDesc = new FdmSolverDesc(); solverDesc.mesher = mesher; solverDesc.bcSet = boundaries; solverDesc.condition = conditions; solverDesc.calculator = calculator; solverDesc.maturity = maturity; solverDesc.dampingSteps = dampingSteps_; solverDesc.timeSteps = tGrid_; FdmBlackScholesSolver solver = new FdmBlackScholesSolver( new Handle <GeneralizedBlackScholesProcess>(process_), payoff.strike(), solverDesc, schemeDesc_, localVol_, illegalLocalVolOverwrite_); double spot = process_.x0(); results_.value = solver.valueAt(spot); results_.delta = solver.deltaAt(spot); results_.gamma = solver.gammaAt(spot); results_.theta = solver.thetaAt(spot); }
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; } }
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 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; } } }
public override void calculate() { if (arguments_.barrierType == DoubleBarrier.Type.KIKO || arguments_.barrierType == DoubleBarrier.Type.KOKI) { AmericanExercise ex = arguments_.exercise as AmericanExercise; Utils.QL_REQUIRE(ex != null, () => "KIKO/KOKI options must have American exercise"); Utils.QL_REQUIRE(ex.dates()[0] <= process_.blackVolatility().currentLink().referenceDate(), () => "American option with window exercise not handled yet"); } else { EuropeanExercise ex = arguments_.exercise as EuropeanExercise; Utils.QL_REQUIRE(ex != null, () => "non-European exercise given"); } CashOrNothingPayoff payoff = arguments_.payoff as CashOrNothingPayoff; Utils.QL_REQUIRE(payoff != null, () => "a cash-or-nothing payoff must be given"); double spot = process_.stateVariable().currentLink().value(); Utils.QL_REQUIRE(spot > 0.0, () => "negative or null underlying given"); double variance = process_.blackVolatility().currentLink().blackVariance( arguments_.exercise.lastDate(), payoff.strike()); double barrier_lo = arguments_.barrier_lo.Value; double barrier_hi = arguments_.barrier_hi.Value; DoubleBarrier.Type barrierType = arguments_.barrierType; Utils.QL_REQUIRE(barrier_lo > 0.0, () => "positive low barrier value required"); Utils.QL_REQUIRE(barrier_hi > 0.0, () => "positive high barrier value required"); Utils.QL_REQUIRE(barrier_lo < barrier_hi, () => "barrier_lo must be < barrier_hi"); Utils.QL_REQUIRE(barrierType == DoubleBarrier.Type.KnockIn || barrierType == DoubleBarrier.Type.KnockOut || barrierType == DoubleBarrier.Type.KIKO || barrierType == DoubleBarrier.Type.KOKI, () => "Unsupported barrier type"); // degenerate cases switch (barrierType) { case DoubleBarrier.Type.KnockOut: if (spot <= barrier_lo || spot >= barrier_hi) { // knocked out, no value results_.value = 0; results_.delta = 0; results_.gamma = 0; results_.vega = 0; results_.rho = 0; return; } break; case DoubleBarrier.Type.KnockIn: if (spot <= barrier_lo || spot >= barrier_hi) { // knocked in - pays results_.value = payoff.cashPayoff(); results_.delta = 0; results_.gamma = 0; results_.vega = 0; results_.rho = 0; return; } break; case DoubleBarrier.Type.KIKO: if (spot >= barrier_hi) { // knocked out, no value results_.value = 0; results_.delta = 0; results_.gamma = 0; results_.vega = 0; results_.rho = 0; return; } else if (spot <= barrier_lo) { // knocked in, pays results_.value = payoff.cashPayoff(); results_.delta = 0; results_.gamma = 0; results_.vega = 0; results_.rho = 0; return; } break; case DoubleBarrier.Type.KOKI: if (spot <= barrier_lo) { // knocked out, no value results_.value = 0; results_.delta = 0; results_.gamma = 0; results_.vega = 0; results_.rho = 0; return; } else if (spot >= barrier_hi) { // knocked in, pays results_.value = payoff.cashPayoff(); results_.delta = 0; results_.gamma = 0; results_.vega = 0; results_.rho = 0; return; } break; } AnalyticDoubleBarrierBinaryEngineHelper helper = new AnalyticDoubleBarrierBinaryEngineHelper(process_, payoff, arguments_); switch (barrierType) { case DoubleBarrier.Type.KnockOut: case DoubleBarrier.Type.KnockIn: results_.value = helper.payoffAtExpiry(spot, variance, barrierType); break; case DoubleBarrier.Type.KIKO: case DoubleBarrier.Type.KOKI: results_.value = helper.payoffKIKO(spot, variance, barrierType); break; default: results_.value = null; break; } }