protected override void performCalculations() { Calendar calendar = index_.fixingCalendar(); int fixingDays = index_.fixingDays(); Date exerciseDate = exerciseDate_; if (exerciseDate == null) { exerciseDate = calendar.advance(termStructure_.link.referenceDate(), maturity_, index_.businessDayConvention()); } Date startDate = calendar.advance(exerciseDate, fixingDays, TimeUnit.Days, index_.businessDayConvention()); Date endDate = endDate_; if (endDate == null) { endDate = calendar.advance(startDate, length_, index_.businessDayConvention()); } Schedule fixedSchedule = new Schedule(startDate, endDate, fixedLegTenor_, calendar, index_.businessDayConvention(), index_.businessDayConvention(), DateGeneration.Rule.Forward, false); Schedule floatSchedule = new Schedule(startDate, endDate, index_.tenor(), calendar, index_.businessDayConvention(), index_.businessDayConvention(), DateGeneration.Rule.Forward, false); IPricingEngine swapEngine = new DiscountingSwapEngine(termStructure_, false); VanillaSwap.Type type = VanillaSwap.Type.Receiver; VanillaSwap temp = new VanillaSwap(VanillaSwap.Type.Receiver, nominal_, fixedSchedule, 0.0, fixedLegDayCounter_, floatSchedule, index_, 0.0, floatingLegDayCounter_); temp.setPricingEngine(swapEngine); double forward = temp.fairRate(); if (!strike_.HasValue) { exerciseRate_ = forward; } else { exerciseRate_ = strike_.Value; type = strike_ <= forward ? VanillaSwap.Type.Receiver : VanillaSwap.Type.Payer; // ensure that calibration instrument is out of the money } swap_ = new VanillaSwap(type, nominal_, fixedSchedule, exerciseRate_, fixedLegDayCounter_, floatSchedule, index_, 0.0, floatingLegDayCounter_); swap_.setPricingEngine(swapEngine); Exercise exercise = new EuropeanExercise(exerciseDate); swaption_ = new Swaption(swap_, exercise); base.performCalculations(); }
public override void calculate() { Utils.QL_REQUIRE(arguments_.exercise.type() == Exercise.Type.European, () => "not an European Option"); EuropeanExercise exercise = arguments_.exercise as EuropeanExercise; Utils.QL_REQUIRE(exercise != null, () => "not an European Option"); BasketPayoff basket_payoff = arguments_.payoff as BasketPayoff; MinBasketPayoff min_basket = arguments_.payoff as MinBasketPayoff; MaxBasketPayoff max_basket = arguments_.payoff as MaxBasketPayoff; Utils.QL_REQUIRE(min_basket != null || max_basket != null, () => "unknown basket type"); PlainVanillaPayoff payoff = basket_payoff.basePayoff() as PlainVanillaPayoff; Utils.QL_REQUIRE(payoff != null, () => "non-plain payoff given"); double strike = payoff.strike(); double variance1 = process1_.blackVolatility().link.blackVariance(exercise.lastDate(), strike); double variance2 = process2_.blackVolatility().link.blackVariance(exercise.lastDate(), strike); double riskFreeDiscount = process1_.riskFreeRate().link.discount(exercise.lastDate()); // cannot handle non zero dividends, so don't believe this... double dividendDiscount1 = process1_.dividendYield().link.discount(exercise.lastDate()); double dividendDiscount2 = process2_.dividendYield().link.discount(exercise.lastDate()); double forward1 = process1_.stateVariable().link.value() * dividendDiscount1 / riskFreeDiscount; double forward2 = process2_.stateVariable().link.value() * dividendDiscount2 / riskFreeDiscount; if (max_basket != null) { switch (payoff.optionType()) { // euro call on a two asset max basket case Option.Type.Call: results_.value = euroTwoAssetMaxBasketCall(forward1, forward2, strike, riskFreeDiscount, variance1, variance2, rho_); break; // euro put on a two asset max basket case Option.Type.Put: results_.value = strike * riskFreeDiscount - euroTwoAssetMaxBasketCall(forward1, forward2, 0.0, riskFreeDiscount, variance1, variance2, rho_) + euroTwoAssetMaxBasketCall(forward1, forward2, strike, riskFreeDiscount, variance1, variance2, rho_); break; default: Utils.QL_FAIL("unknown option type"); break; } } else if (min_basket != null) { switch (payoff.optionType()) { // euro call on a two asset min basket case Option.Type.Call: results_.value = euroTwoAssetMinBasketCall(forward1, forward2, strike, riskFreeDiscount, variance1, variance2, rho_); break; // euro put on a two asset min basket case Option.Type.Put: results_.value = strike * riskFreeDiscount - euroTwoAssetMinBasketCall(forward1, forward2, 0.0, riskFreeDiscount, variance1, variance2, rho_) + euroTwoAssetMinBasketCall(forward1, forward2, strike, riskFreeDiscount, variance1, variance2, rho_); break; default: Utils.QL_FAIL("unknown option type"); break; } } else { Utils.QL_FAIL("unknown type"); } }
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); }
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 CliquetOption(PercentageStrikePayoff payoff, EuropeanExercise maturity, List <Date> resetDates) : base(payoff, maturity) { resetDates_ = new List <Date>(resetDates); }