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; } }
public override void calculate() { AmericanExercise ex = arguments_.exercise as AmericanExercise; Utils.QL_REQUIRE(ex != null, () => "non-American exercise given"); Utils.QL_REQUIRE(ex.payoffAtExpiry(), () => "payoff must be at expiry"); Utils.QL_REQUIRE(ex.dates()[0] <= process_.blackVolatility().link.referenceDate(), () => "American option with window exercise not handled yet"); StrikedTypePayoff payoff = arguments_.payoff as StrikedTypePayoff; Utils.QL_REQUIRE(payoff != null, () => "non-striked payoff given"); double spot = process_.stateVariable().link.value(); Utils.QL_REQUIRE(spot > 0.0, () => "negative or null underlying given"); double variance = process_.blackVolatility().link.blackVariance(ex.lastDate(), payoff.strike()); double?barrier = arguments_.barrier; Utils.QL_REQUIRE(barrier > 0.0, () => "positive barrier value required"); Barrier.Type barrierType = arguments_.barrierType; // KO degenerate cases if ((barrierType == Barrier.Type.DownOut && spot <= barrier) || (barrierType == Barrier.Type.UpOut && spot >= barrier)) { // knocked out, no value results_.value = 0; results_.delta = 0; results_.gamma = 0; results_.vega = 0; results_.theta = 0; results_.rho = 0; results_.dividendRho = 0; return; } // KI degenerate cases if ((barrierType == Barrier.Type.DownIn && spot <= barrier) || (barrierType == Barrier.Type.UpIn && spot >= barrier)) { // knocked in - is a digital european Exercise exercise = new EuropeanExercise(arguments_.exercise.lastDate()); IPricingEngine engine = new AnalyticEuropeanEngine(process_); VanillaOption opt = new VanillaOption(payoff, exercise); opt.setPricingEngine(engine); results_.value = opt.NPV(); results_.delta = opt.delta(); results_.gamma = opt.gamma(); results_.vega = opt.vega(); results_.theta = opt.theta(); results_.rho = opt.rho(); results_.dividendRho = opt.dividendRho(); return; } double riskFreeDiscount = process_.riskFreeRate().link.discount(ex.lastDate()); AnalyticBinaryBarrierEngine_helper helper = new AnalyticBinaryBarrierEngine_helper( process_, payoff, ex, arguments_); results_.value = helper.payoffAtExpiry(spot, variance, riskFreeDiscount); }