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() { /* both DTS, YTS ref dates and pricing date consistency * checks? settlement... */ Utils.QL_REQUIRE(!discountCurve_.empty(), () => "no discount term structure set"); Utils.QL_REQUIRE(!defaultTS_.empty(), () => "no ctpty default term structure set"); Utils.QL_REQUIRE(!swaptionletEngine_.empty(), () => "no swap option engine set"); Date priceDate = defaultTS_.link.referenceDate(); double cumOptVal = 0.0, cumPutVal = 0.0; // Vanilla swap so 0 leg is floater int index = 0; Date nextFD = arguments_.fixedPayDates[index]; Date swapletStart = priceDate; while (nextFD < priceDate) { index++; nextFD = arguments_.fixedPayDates[index]; } // Compute fair spread for strike value: // copy args into the non risky engine Swap.Arguments noCVAArgs = baseSwapEngine_.link.getArguments() as Swap.Arguments; noCVAArgs.legs = this.arguments_.legs; noCVAArgs.payer = this.arguments_.payer; baseSwapEngine_.link.calculate(); double baseSwapRate = ((FixedRateCoupon)arguments_.legs[0][0]).rate(); Swap.Results vSResults = baseSwapEngine_.link.getResults() as Swap.Results; double?baseSwapFairRate = -baseSwapRate * vSResults.legNPV[1] / vSResults.legNPV[0]; double?baseSwapNPV = vSResults.value; VanillaSwap.Type reversedType = arguments_.type == VanillaSwap.Type.Payer ? VanillaSwap.Type.Receiver : VanillaSwap.Type.Payer; // Swaplet options summatory: while (nextFD != arguments_.fixedPayDates.Last()) { // iFD coupon not fixed, create swaptionlet: IborIndex swapIndex = ((FloatingRateCoupon)arguments_.legs[1][0]).index() as IborIndex; // Alternatively one could cap this period to, say, 1M Period baseSwapsTenor = new Period(arguments_.fixedPayDates.Last().serialNumber() - swapletStart.serialNumber(), TimeUnit.Days); VanillaSwap swaplet = new MakeVanillaSwap(baseSwapsTenor, swapIndex, baseSwapFairRate) .withType(arguments_.type) .withNominal(arguments_.nominal) .withEffectiveDate(swapletStart) .withTerminationDate(arguments_.fixedPayDates.Last()).value(); VanillaSwap revSwaplet = new MakeVanillaSwap(baseSwapsTenor, swapIndex, baseSwapFairRate) .withType(reversedType) .withNominal(arguments_.nominal) .withEffectiveDate(swapletStart) .withTerminationDate(arguments_.fixedPayDates.Last()).value(); Swaption swaptionlet = new Swaption(swaplet, new EuropeanExercise(swapletStart)); Swaption putSwaplet = new Swaption(revSwaplet, new EuropeanExercise(swapletStart)); swaptionlet.setPricingEngine(swaptionletEngine_.currentLink()); putSwaplet.setPricingEngine(swaptionletEngine_.currentLink()); // atm underlying swap means that the value of put = value // call so this double pricing is not needed cumOptVal += swaptionlet.NPV() * defaultTS_.link.defaultProbability( swapletStart, nextFD); cumPutVal += putSwaplet.NPV() * invstDTS_.link.defaultProbability(swapletStart, nextFD); swapletStart = nextFD; index++; nextFD = arguments_.fixedPayDates[index]; } results_.value = baseSwapNPV - (1.0 - ctptyRecoveryRate_) * cumOptVal + (1.0 - invstRecoveryRate_) * cumPutVal; results_.fairRate = -baseSwapRate * (vSResults.legNPV[1] - (1.0 - ctptyRecoveryRate_) * cumOptVal + (1.0 - invstRecoveryRate_) * cumPutVal) / vSResults.legNPV[0]; }