public override void validate() { PercentageStrikePayoff moneyness = payoff as PercentageStrikePayoff; Utils.QL_REQUIRE(moneyness != null, () => "wrong payoff type"); Utils.QL_REQUIRE(moneyness.strike() > 0.0, () => "negative or zero moneyness given"); Utils.QL_REQUIRE(accruedCoupon == null || accruedCoupon >= 0.0, () => "negative accrued coupon"); Utils.QL_REQUIRE(localCap == null || localCap >= 0.0, () => "negative local cap"); Utils.QL_REQUIRE(localFloor == null || localFloor >= 0.0, () => "negative local floor"); Utils.QL_REQUIRE(globalCap == null || globalCap >= 0.0, () => "negative global cap"); Utils.QL_REQUIRE(globalFloor == null || globalFloor >= 0.0, () => "negative global floor"); Utils.QL_REQUIRE(!resetDates.empty(), () => "no reset dates given"); for (int i = 0; i < resetDates.Count; ++i) { Utils.QL_REQUIRE(exercise.lastDate() > resetDates[i], () => "reset date greater or equal to maturity"); Utils.QL_REQUIRE(i == 0 || resetDates[i] > resetDates[i - 1], () => "unsorted reset dates"); } }
public CliquetOption(PercentageStrikePayoff payoff, EuropeanExercise maturity, List <Date> resetDates) : base(payoff, maturity) { resetDates_ = new List <Date>(resetDates); }
public override void calculate() { Utils.QL_REQUIRE(arguments_.accruedCoupon == null && arguments_.lastFixing == null, () => "this engine cannot price options already started"); Utils.QL_REQUIRE(arguments_.localCap == null && arguments_.localFloor == null && arguments_.globalCap == null && arguments_.globalFloor == null, () => "this engine cannot price capped/floored options"); Utils.QL_REQUIRE(arguments_.exercise.type() == Exercise.Type.European, () => "not an European option"); PercentageStrikePayoff moneyness = arguments_.payoff as PercentageStrikePayoff; Utils.QL_REQUIRE(moneyness != null, () => "wrong payoff given"); List <Date> resetDates = arguments_.resetDates; resetDates.Add(arguments_.exercise.lastDate()); double underlying = process_.stateVariable().link.value(); Utils.QL_REQUIRE(underlying > 0.0, () => "negative or null underlying"); StrikedTypePayoff payoff = new PlainVanillaPayoff(moneyness.optionType(), 1.0); results_.value = 0.0; results_.delta = results_.gamma = 0.0; results_.theta = 0.0; results_.rho = results_.dividendRho = 0.0; results_.vega = 0.0; for (int i = 1; i < resetDates.Count; i++) { double discount = process_.riskFreeRate().link.discount(resetDates[i - 1]); double rDiscount = process_.riskFreeRate().link.discount(resetDates[i]) / process_.riskFreeRate().link.discount(resetDates[i - 1]); double qDiscount = process_.dividendYield().link.discount(resetDates[i]) / process_.dividendYield().link.discount(resetDates[i - 1]); double forward = (1.0 / moneyness.strike()) * qDiscount / rDiscount; double variance = process_.blackVolatility().link.blackForwardVariance( resetDates[i - 1], resetDates[i], underlying * moneyness.strike()); BlackCalculator black = new BlackCalculator(payoff, forward, Math.Sqrt(variance), rDiscount); DayCounter rfdc = process_.riskFreeRate().link.dayCounter(); DayCounter divdc = process_.dividendYield().link.dayCounter(); DayCounter voldc = process_.blackVolatility().link.dayCounter(); results_.value += discount * moneyness.strike() * black.value(); results_.delta += 0.0; results_.gamma += 0.0; results_.theta += process_.riskFreeRate().link.forwardRate( resetDates[i - 1], resetDates[i], rfdc, Compounding.Continuous, Frequency.NoFrequency).value() * discount * moneyness.strike() * black.value(); double dt = rfdc.yearFraction(resetDates[i - 1], resetDates[i]); double t = rfdc.yearFraction(process_.riskFreeRate().link.referenceDate(), resetDates[i - 1]); results_.rho += discount * moneyness.strike() * (black.rho(dt) - t * black.value()); dt = divdc.yearFraction(resetDates[i - 1], resetDates[i]); results_.dividendRho += discount * moneyness.strike() * black.dividendRho(dt); dt = voldc.yearFraction(resetDates[i - 1], resetDates[i]); results_.vega += discount * moneyness.strike() * black.vega(dt); } }