internal static CmsPeriod sutCoupon() { FixedIborSwapConvention conv = INDEX.Template.Convention; ResolvedSwap swap = conv.toTrade(FIXING, START, END, BuySell.BUY, 1d, 0.01).Product.resolve(REF_DATA); return(CmsPeriod.builder().currency(GBP).notional(NOTIONAL).startDate(START).endDate(END).unadjustedStartDate(START_UNADJUSTED).unadjustedEndDate(END_UNADJUSTED).yearFraction(YEAR_FRACTION).paymentDate(PAYMENT).fixingDate(FIXING).dayCount(ACT_360).index(INDEX).underlyingSwap(swap).build()); }
internal static CmsPeriod sut2() { FixedIborSwapConvention conv = INDEX.Template.Convention; ResolvedSwap swap = conv.toTrade(FIXING.plusDays(1), START.plusDays(1), END.plusDays(1), BuySell.BUY, 1d, 1d).Product.resolve(REF_DATA); return(CmsPeriod.builder().currency(EUR).notional(NOTIONAL + 1).startDate(START.plusDays(1)).endDate(END.plusDays(1)).unadjustedStartDate(START_UNADJUSTED.plusDays(1)).unadjustedEndDate(END_UNADJUSTED.plusDays(1)).yearFraction(YEAR_FRACTION + 0.01).paymentDate(PAYMENT.plusDays(1)).fixingDate(FIXING.plusDays(1)).floorlet(STRIKE).dayCount(ACT_365F).index(SwapIndices.EUR_EURIBOR_1100_5Y).underlyingSwap(swap).build()); }
/// <summary> /// Computes the adjustment to the forward rate for a CMS coupon. /// <para> /// The adjustment to the forward rate, is the quantity that need to be added to the forward rate to obtain the /// adjusted forward rate. The adjusted forward rate is the number which used in the same formula used for /// Ibor coupon pricing (forward * notional * accrual factor * discount factor) will provide the correct present value. /// </para> /// <para> /// For cap or floor the result is the adjustment to the forward rate for the coupon equivalent to the cap/floor, /// i.e. the coupon with the same dates and index but with no cap or floor strike. /// /// </para> /// </summary> /// <param name="cmsPeriod"> the CMS period, which should be of the type <seealso cref="CmsPeriodType#COUPON"/> </param> /// <param name="provider"> the rates provider </param> /// <param name="swaptionVolatilities"> the swaption volatilities </param> /// <returns> the adjusted forward rate </returns> public double adjustmentToForwardRate(CmsPeriod cmsPeriod, RatesProvider provider, SabrSwaptionVolatilities swaptionVolatilities) { CmsPeriod coupon = cmsPeriod.toCouponEquivalent(); double adjustedForwardRate = this.adjustedForwardRate(coupon, provider, swaptionVolatilities); double forward = swapPricer.parRate(coupon.UnderlyingSwap, provider); return(adjustedForwardRate - forward); }
public virtual void test_builder_multiCurrencyIndex() { CmsPeriod period3 = CmsPeriodTest.sut2(); assertThrowsIllegalArg(() => ResolvedCmsLeg.builder().payReceive(RECEIVE).cmsPeriods(PERIOD_1, period3).build()); CmsPeriod period4 = CmsPeriodTest.sutCoupon(); assertThrowsIllegalArg(() => ResolvedCmsLeg.builder().payReceive(RECEIVE).cmsPeriods(PERIOD_1, period4).build()); }
/// <summary> /// Computes the adjusted forward rate for a CMS coupon. /// <para> /// The adjusted forward rate, is the number such that, multiplied by the notional, the year fraction and the payment /// date discount factor, it produces the present value. In other terms, it is the number which used in the same /// formula used for Ibor coupon pricing will provide the correct present value. /// </para> /// <para> /// For period already fixed, this number will be equal to the swap index fixing. /// </para> /// <para> /// For cap or floor the result is the adjusted forward rate for the coupon equivalent to the cap/floor, /// i.e. the coupon with the same dates and index but with no cap or floor strike. /// /// </para> /// </summary> /// <param name="cmsPeriod"> the CMS period, which should be of the type <seealso cref="CmsPeriodType#COUPON"/> </param> /// <param name="provider"> the rates provider </param> /// <param name="swaptionVolatilities"> the swaption volatilities </param> /// <returns> the adjusted forward rate </returns> public double adjustedForwardRate(CmsPeriod cmsPeriod, RatesProvider provider, SabrSwaptionVolatilities swaptionVolatilities) { CmsPeriod coupon = cmsPeriod.toCouponEquivalent(); Currency ccy = cmsPeriod.Currency; double dfPayment = provider.discountFactor(ccy, coupon.PaymentDate); double pv = presentValue(coupon, provider, swaptionVolatilities).Amount; return(pv / (coupon.Notional * coupon.YearFraction * dfPayment)); }
//------------------------------------------------------------------------- /// <summary> /// Computes the present value curve sensitivity by simple forward rate estimation. /// </summary> /// <param name="cmsPeriod"> the CMS </param> /// <param name="provider"> the rates provider </param> /// <returns> the present value sensitivity </returns> public virtual PointSensitivityBuilder presentValueSensitivity(CmsPeriod cmsPeriod, RatesProvider provider) { Currency ccy = cmsPeriod.Currency; LocalDate valuationDate = provider.ValuationDate; if (valuationDate.isAfter(cmsPeriod.PaymentDate)) { return(PointSensitivityBuilder.none()); } LocalDate fixingDate = cmsPeriod.FixingDate; double dfPayment = provider.discountFactor(ccy, cmsPeriod.PaymentDate); if (!fixingDate.isAfter(valuationDate)) { // Using fixing double?fixedRate = provider.timeSeries(cmsPeriod.Index).get(fixingDate); if (fixedRate.HasValue) { double payoff = 0d; switch (cmsPeriod.CmsPeriodType) { case CAPLET: payoff = Math.Max(fixedRate.Value - cmsPeriod.Strike, 0d); break; case FLOORLET: payoff = Math.Max(cmsPeriod.Strike - fixedRate.Value, 0d); break; case COUPON: payoff = fixedRate.Value; break; default: throw new System.ArgumentException("unsupported CMS type"); } return(provider.discountFactors(ccy).zeroRatePointSensitivity(cmsPeriod.PaymentDate).multipliedBy(payoff * cmsPeriod.Notional * cmsPeriod.YearFraction)); } else if (fixingDate.isBefore(valuationDate)) { throw new System.ArgumentException(Messages.format("Unable to get fixing for {} on date {}, no time-series supplied", cmsPeriod.Index, fixingDate)); } } if (!cmsPeriod.CmsPeriodType.Equals(CmsPeriodType.COUPON)) { throw new System.ArgumentException("Unable to price cap or floor in this pricer"); } // Using forward ResolvedSwap swap = cmsPeriod.UnderlyingSwap; ZeroRateSensitivity dfPaymentdr = provider.discountFactors(ccy).zeroRatePointSensitivity(cmsPeriod.PaymentDate); double forward = swapPricer.parRate(swap, provider); PointSensitivityBuilder forwardSensi = swapPricer.parRateSensitivity(swap, provider); return(forwardSensi.multipliedBy(dfPayment).combinedWith(dfPaymentdr.multipliedBy(forward)).multipliedBy(cmsPeriod.Notional * cmsPeriod.YearFraction)); }
/// <summary> /// Computes the forward rate associated to the swap underlying the CMS period. /// <para> /// Returns a value only if the period has not fixed yet. If the fixing date is on or before the valuation date, /// an <seealso cref="IllegalArgumentException"/> is thrown. /// /// </para> /// </summary> /// <param name="cmsPeriod"> the CMS </param> /// <param name="provider"> the rates provider </param> /// <returns> the forward rate </returns> public virtual double forwardRate(CmsPeriod cmsPeriod, RatesProvider provider) { LocalDate fixingDate = cmsPeriod.FixingDate; LocalDate valuationDate = provider.ValuationDate; if (!fixingDate.isAfter(valuationDate)) { // Using fixing throw new System.ArgumentException("Forward rate is availaible only for valuation date after the fixing date"); } ResolvedSwap swap = cmsPeriod.UnderlyingSwap; return(swapPricer.parRate(swap, provider)); }
public virtual void test_resolve() { CmsLeg baseFloor = CmsLeg.builder().floorSchedule(FLOOR).index(INDEX).notional(NOTIONAL).payReceive(PAY).paymentSchedule(SCHEDULE_EUR).build(); ResolvedCmsLeg resolvedFloor = baseFloor.resolve(REF_DATA); LocalDate end1 = LocalDate.of(2016, 10, 21); LocalDate fixing1 = EUR_EURIBOR_6M.calculateFixingFromEffective(START, REF_DATA); LocalDate fixing2 = EUR_EURIBOR_6M.calculateFixingFromEffective(end1, REF_DATA); LocalDate fixing3 = EUR_EURIBOR_6M.calculateFixingFromEffective(END, REF_DATA); LocalDate endDate = SCHEDULE_EUR.calculatedEndDate().adjusted(REF_DATA); CmsPeriod period1 = CmsPeriod.builder().currency(EUR).floorlet(FLOOR.InitialValue).notional(-NOTIONAL.InitialValue).index(INDEX).startDate(START).endDate(end1).unadjustedStartDate(START).unadjustedEndDate(end1).fixingDate(fixing1).paymentDate(end1).yearFraction(EUR_EURIBOR_6M.DayCount.yearFraction(START, end1)).dayCount(EUR_EURIBOR_6M.DayCount).underlyingSwap(createUnderlyingSwap(fixing1)).build(); CmsPeriod period2 = CmsPeriod.builder().currency(EUR).floorlet(FLOOR.Steps[0].Value.ModifyingValue).notional(-NOTIONAL.Steps[0].Value.ModifyingValue).index(INDEX).startDate(end1).endDate(endDate).unadjustedStartDate(end1).unadjustedEndDate(END).fixingDate(fixing2).paymentDate(endDate).yearFraction(EUR_EURIBOR_6M.DayCount.yearFraction(end1, endDate)).dayCount(EUR_EURIBOR_6M.DayCount).underlyingSwap(createUnderlyingSwap(fixing2)).build(); assertEquals(resolvedFloor.Currency, EUR); assertEquals(resolvedFloor.StartDate, baseFloor.StartDate.adjusted(REF_DATA)); assertEquals(resolvedFloor.EndDate, baseFloor.EndDate.adjusted(REF_DATA)); assertEquals(resolvedFloor.Index, INDEX); assertEquals(resolvedFloor.PayReceive, PAY); assertEquals(resolvedFloor.CmsPeriods.size(), 2); assertEquals(resolvedFloor.CmsPeriods.get(0), period1); assertEquals(resolvedFloor.CmsPeriods.get(1), period2); CmsLeg baseFloorEnd = CmsLeg.builder().floorSchedule(FLOOR).fixingRelativeTo(FixingRelativeTo.PERIOD_END).index(INDEX).notional(NOTIONAL).payReceive(PAY).paymentSchedule(SCHEDULE_EUR).build(); ResolvedCmsLeg resolvedFloorEnd = baseFloorEnd.resolve(REF_DATA); CmsPeriod period1End = CmsPeriod.builder().currency(EUR).floorlet(FLOOR.InitialValue).notional(-NOTIONAL.InitialValue).index(INDEX).startDate(START).endDate(end1).unadjustedStartDate(START).unadjustedEndDate(end1).fixingDate(fixing2).paymentDate(end1).yearFraction(EUR_EURIBOR_6M.DayCount.yearFraction(START, end1)).dayCount(EUR_EURIBOR_6M.DayCount).underlyingSwap(createUnderlyingSwap(fixing2)).build(); CmsPeriod period2End = CmsPeriod.builder().currency(EUR).floorlet(FLOOR.Steps[0].Value.ModifyingValue).notional(-NOTIONAL.Steps[0].Value.ModifyingValue).index(INDEX).startDate(end1).endDate(endDate).unadjustedStartDate(end1).unadjustedEndDate(END).fixingDate(fixing3).paymentDate(endDate).yearFraction(EUR_EURIBOR_6M.DayCount.yearFraction(end1, endDate)).dayCount(EUR_EURIBOR_6M.DayCount).underlyingSwap(createUnderlyingSwap(fixing3)).build(); assertEquals(resolvedFloorEnd.Currency, EUR); assertEquals(resolvedFloorEnd.StartDate, baseFloor.StartDate.adjusted(REF_DATA)); assertEquals(resolvedFloorEnd.EndDate, baseFloor.EndDate.adjusted(REF_DATA)); assertEquals(resolvedFloorEnd.Index, INDEX); assertEquals(resolvedFloorEnd.PayReceive, PAY); assertEquals(resolvedFloorEnd.CmsPeriods.size(), 2); assertEquals(resolvedFloorEnd.CmsPeriods.get(0), period1End); assertEquals(resolvedFloorEnd.CmsPeriods.get(1), period2End); CmsLeg baseCap = CmsLeg.builder().index(INDEX).capSchedule(CAP).notional(NOTIONAL).payReceive(PAY).paymentSchedule(SCHEDULE_EUR).paymentDateOffset(PAYMENT_OFFSET).build(); ResolvedCmsLeg resolvedCap = baseCap.resolve(REF_DATA); CmsPeriod periodCap1 = CmsPeriod.builder().currency(EUR).notional(-NOTIONAL.InitialValue).index(INDEX).caplet(CAP.InitialValue).startDate(START).endDate(end1).unadjustedStartDate(START).unadjustedEndDate(end1).fixingDate(fixing1).paymentDate(PAYMENT_OFFSET.adjust(end1, REF_DATA)).yearFraction(EUR_EURIBOR_6M.DayCount.yearFraction(START, end1)).dayCount(EUR_EURIBOR_6M.DayCount).underlyingSwap(createUnderlyingSwap(fixing1)).build(); CmsPeriod periodCap2 = CmsPeriod.builder().currency(EUR).notional(-NOTIONAL.Steps[0].Value.ModifyingValue).index(INDEX).caplet(CAP.InitialValue).startDate(end1).endDate(endDate).unadjustedStartDate(end1).unadjustedEndDate(END).fixingDate(fixing2).paymentDate(PAYMENT_OFFSET.adjust(endDate, REF_DATA)).yearFraction(EUR_EURIBOR_6M.DayCount.yearFraction(end1, endDate)).dayCount(EUR_EURIBOR_6M.DayCount).underlyingSwap(createUnderlyingSwap(fixing2)).build(); assertEquals(resolvedCap.Currency, EUR); assertEquals(resolvedCap.StartDate, baseCap.StartDate.adjusted(REF_DATA)); assertEquals(resolvedCap.EndDate, baseCap.EndDate.adjusted(REF_DATA)); assertEquals(resolvedCap.Index, INDEX); assertEquals(resolvedCap.PayReceive, PAY); assertEquals(resolvedCap.CmsPeriods.size(), 2); assertEquals(resolvedCap.CmsPeriods.get(0), periodCap1); assertEquals(resolvedCap.CmsPeriods.get(1), periodCap2); }
public virtual void test_toCouponEquivalent() { CmsPeriod caplet = sutCap(); CmsPeriod cpnEquivalent = caplet.toCouponEquivalent(); assertEquals(cpnEquivalent.CmsPeriodType, CmsPeriodType.COUPON); assertEquals(caplet.Currency, cpnEquivalent.Currency); assertEquals(caplet.StartDate, cpnEquivalent.StartDate); assertEquals(caplet.EndDate, cpnEquivalent.EndDate); assertEquals(caplet.UnadjustedStartDate, cpnEquivalent.UnadjustedStartDate); assertEquals(caplet.UnadjustedEndDate, cpnEquivalent.UnadjustedEndDate); assertEquals(caplet.FixingDate, cpnEquivalent.FixingDate); assertEquals(caplet.PaymentDate, cpnEquivalent.PaymentDate); assertEquals(caplet.Index, cpnEquivalent.Index); assertEquals(caplet.Notional, cpnEquivalent.Notional); assertEquals(caplet.YearFraction, cpnEquivalent.YearFraction); assertEquals(caplet.DayCount, cpnEquivalent.DayCount); }
/// <summary> /// Explains the present value of the CMS period. /// <para> /// This returns explanatory information about the calculation. /// /// </para> /// </summary> /// <param name="period"> the product </param> /// <param name="ratesProvider"> the rates provider </param> /// <param name="swaptionVolatilities"> the volatilities </param> /// <param name="builder"> the builder to populate </param> public void explainPresentValue(CmsPeriod period, RatesProvider ratesProvider, SabrSwaptionVolatilities swaptionVolatilities, ExplainMapBuilder builder) { string type = period.CmsPeriodType.ToString(); Currency ccy = period.Currency; LocalDate paymentDate = period.PaymentDate; builder.put(ExplainKey.ENTRY_TYPE, "Cms" + type + "Period"); builder.put(ExplainKey.STRIKE_VALUE, period.Strike); builder.put(ExplainKey.NOTIONAL, CurrencyAmount.of(ccy, period.Notional)); builder.put(ExplainKey.PAYMENT_DATE, period.PaymentDate); builder.put(ExplainKey.DISCOUNT_FACTOR, ratesProvider.discountFactor(ccy, paymentDate)); builder.put(ExplainKey.START_DATE, period.StartDate); builder.put(ExplainKey.END_DATE, period.EndDate); builder.put(ExplainKey.FIXING_DATE, period.FixingDate); builder.put(ExplainKey.ACCRUAL_YEAR_FRACTION, period.YearFraction); builder.put(ExplainKey.PRESENT_VALUE, presentValue(period, ratesProvider, swaptionVolatilities)); builder.put(ExplainKey.FORWARD_RATE, swapPricer.parRate(period.UnderlyingSwap, ratesProvider)); builder.put(ExplainKey.CONVEXITY_ADJUSTED_RATE, adjustedForwardRate(period, ratesProvider, swaptionVolatilities)); }
public virtual void test_builder_coupon() { CmsPeriod testCoupon = sutCoupon(); assertFalse(testCoupon.Caplet.HasValue); assertFalse(testCoupon.Floorlet.HasValue); assertEquals(testCoupon.CmsPeriodType, CmsPeriodType.COUPON); assertEquals(testCoupon.Currency, GBP); assertEquals(testCoupon.StartDate, START); assertEquals(testCoupon.EndDate, END); assertEquals(testCoupon.UnadjustedStartDate, START_UNADJUSTED); assertEquals(testCoupon.UnadjustedEndDate, END_UNADJUSTED); assertEquals(testCoupon.FixingDate, FIXING); assertEquals(testCoupon.PaymentDate, PAYMENT); assertEquals(testCoupon.Index, INDEX); assertEquals(testCoupon.Notional, NOTIONAL); assertEquals(testCoupon.YearFraction, YEAR_FRACTION); assertEquals(testCoupon.DayCount, ACT_360); assertEquals(testCoupon.Strike, 0d); }
public virtual void test_builder_floor() { CmsPeriod testFloorlet = sutFloor(); assertFalse(testFloorlet.Caplet.HasValue); assertEquals(testFloorlet.Floorlet.Value, STRIKE); assertEquals(testFloorlet.CmsPeriodType, CmsPeriodType.FLOORLET); assertEquals(testFloorlet.Currency, GBP); assertEquals(testFloorlet.StartDate, START); assertEquals(testFloorlet.EndDate, END); assertEquals(testFloorlet.UnadjustedStartDate, START_UNADJUSTED); assertEquals(testFloorlet.UnadjustedEndDate, END_UNADJUSTED); assertEquals(testFloorlet.FixingDate, FIXING); assertEquals(testFloorlet.PaymentDate, PAYMENT); assertEquals(testFloorlet.Index, INDEX); assertEquals(testFloorlet.Notional, NOTIONAL); assertEquals(testFloorlet.YearFraction, YEAR_FRACTION); assertEquals(testFloorlet.DayCount, ACT_360); assertEquals(testFloorlet.Strike, STRIKE); }
public CmsDeltaIntegrantProvider(SabrExtrapolationReplicationCmsPeriodPricer outerInstance, CmsPeriod cmsPeriod, ResolvedSwap swap, SabrSwaptionVolatilities swaptionVolatilities, double forward, double strike, double timeToExpiry, double tenor, double cutOffStrike, double eta) : base(outerInstance, cmsPeriod, swap, swaptionVolatilities, forward, strike, timeToExpiry, tenor, cutOffStrike, eta) { this.outerInstance = outerInstance; this.nnp_Renamed = nnp(forward); }
public CmsIntegrantProvider(SabrExtrapolationReplicationCmsPeriodPricer outerInstance, CmsPeriod cmsPeriod, ResolvedSwap swap, SabrSwaptionVolatilities swaptionVolatilities, double forward, double strike, double timeToExpiry, double tenor, double cutOffStrike, double eta) { this.outerInstance = outerInstance; ResolvedSwapLeg fixedLeg = swap.getLegs(SwapLegType.FIXED).get(0); this.nbFixedPeriod = fixedLeg.PaymentPeriods.size(); this.nbFixedPaymentYear = (int)(long)Math.Round(1d / ((RatePaymentPeriod)fixedLeg.PaymentPeriods.get(0)).AccrualPeriods.get(0).YearFraction, MidpointRounding.AwayFromZero); this.tau = 1d / nbFixedPaymentYear; this.eta = eta; SabrFormulaData sabrPoint = SabrFormulaData.of(swaptionVolatilities.alpha(timeToExpiry, tenor), swaptionVolatilities.beta(timeToExpiry, tenor), swaptionVolatilities.rho(timeToExpiry, tenor), swaptionVolatilities.nu(timeToExpiry, tenor)); this.shift = swaptionVolatilities.shift(timeToExpiry, tenor); this.sabrExtrapolation = SabrExtrapolationRightFunction.of(forward + shift, timeToExpiry, sabrPoint, cutOffStrike + shift, outerInstance.mu); this.putCall = cmsPeriod.CmsPeriodType.Equals(CmsPeriodType.FLOORLET) ? PutCall.PUT : PutCall.CALL; this.strike = strike; this.factor = g(forward) / h(forward); this.g0 = new double[4]; g0[0] = nbFixedPeriod * tau; g0[1] = -0.5 * nbFixedPeriod * (nbFixedPeriod + 1.0d) * tau * tau; g0[2] = -2.0d / 3.0d * g0[1] * (nbFixedPeriod + 2.0d) * tau; g0[3] = -3.0d / 4.0d * g0[2] * (nbFixedPeriod + 2.0d) * tau; }
/// <summary> /// Computes the present value sensitivity to strike by replication in SABR framework with extrapolation on the right. /// </summary> /// <param name="cmsPeriod"> the CMS </param> /// <param name="provider"> the rates provider </param> /// <param name="swaptionVolatilities"> the swaption volatilities </param> /// <returns> the present value sensitivity </returns> public double presentValueSensitivityStrike(CmsPeriod cmsPeriod, RatesProvider provider, SabrSwaptionVolatilities swaptionVolatilities) { ArgChecker.isFalse(cmsPeriod.CmsPeriodType.Equals(CmsPeriodType.COUPON), "presentValueSensitivityStrike is not relevant for CMS coupon"); Currency ccy = cmsPeriod.Currency; SwapIndex index = cmsPeriod.Index; if (provider.ValuationDate.isAfter(cmsPeriod.PaymentDate)) { return(0d); } ResolvedSwap swap = cmsPeriod.UnderlyingSwap; double dfPayment = provider.discountFactor(ccy, cmsPeriod.PaymentDate); ZonedDateTime valuationDate = swaptionVolatilities.ValuationDateTime; LocalDate fixingDate = cmsPeriod.FixingDate; double tenor = swaptionVolatilities.tenor(swap.StartDate, swap.EndDate); ZonedDateTime expiryDate = fixingDate.atTime(index.FixingTime).atZone(index.FixingZone); double expiryTime = swaptionVolatilities.relativeTime(expiryDate); double strike = cmsPeriod.Strike; double shift = swaptionVolatilities.shift(expiryTime, tenor); if (!fixingDate.isAfter(valuationDate.toLocalDate())) { double?fixedRate = provider.timeSeries(cmsPeriod.Index).get(fixingDate); if (fixedRate.HasValue) { double payoff = 0d; switch (cmsPeriod.CmsPeriodType) { case CAPLET: payoff = fixedRate.Value >= strike ? -1d : 0d; break; case FLOORLET: payoff = fixedRate.Value < strike ? 1d : 0d; break; default: throw new System.ArgumentException("unsupported CMS type"); } return(payoff * cmsPeriod.Notional * cmsPeriod.YearFraction * dfPayment); } else if (fixingDate.isBefore(valuationDate.toLocalDate())) { throw new System.ArgumentException(Messages.format("Unable to get fixing for {} on date {}, no time-series supplied", cmsPeriod.Index, fixingDate)); } } double forward = swapPricer.parRate(swap, provider); double eta = index.Template.Convention.FixedLeg.DayCount.relativeYearFraction(cmsPeriod.PaymentDate, swap.StartDate); CmsIntegrantProvider intProv = new CmsIntegrantProvider(this, cmsPeriod, swap, swaptionVolatilities, forward, strike, expiryTime, tenor, cutOffStrike, eta); double factor = dfPayment * intProv.g(forward) / intProv.h(forward); RungeKuttaIntegrator1D integrator = new RungeKuttaIntegrator1D(ABS_TOL, REL_TOL_STRIKE, NUM_ITER); double[] kpkpp = intProv.kpkpp(strike); double firstPart; double thirdPart; System.Func <double, double> integrant = intProv.integrantDualDelta(); if (intProv.PutCall.Call) { firstPart = -kpkpp[0] * intProv.bs(strike); thirdPart = integrateCall(integrator, integrant, swaptionVolatilities, forward, strike, expiryTime, tenor); } else { firstPart = -kpkpp[0] * intProv.bs(strike); thirdPart = -integrator.integrate(integrant, -shift + ZERO_SHIFT, strike).Value; } double secondPart = intProv.k(strike) * intProv.SabrExtrapolation.priceDerivativeStrike(strike + shift, intProv.PutCall); return(cmsPeriod.Notional * cmsPeriod.YearFraction * factor * (firstPart + secondPart + thirdPart)); }
/// <summary> /// Computes the present value sensitivity to SABR parameters by replication in SABR framework with extrapolation on the right. /// </summary> /// <param name="cmsPeriod"> the CMS </param> /// <param name="provider"> the rates provider </param> /// <param name="swaptionVolatilities"> the swaption volatilities </param> /// <returns> the present value sensitivity </returns> public PointSensitivityBuilder presentValueSensitivityModelParamsSabr(CmsPeriod cmsPeriod, RatesProvider provider, SabrSwaptionVolatilities swaptionVolatilities) { Currency ccy = cmsPeriod.Currency; SwapIndex index = cmsPeriod.Index; ResolvedSwap swap = cmsPeriod.UnderlyingSwap; double dfPayment = provider.discountFactor(ccy, cmsPeriod.PaymentDate); ZonedDateTime valuationDate = swaptionVolatilities.ValuationDateTime; LocalDate fixingDate = cmsPeriod.FixingDate; ZonedDateTime expiryDate = fixingDate.atTime(index.FixingTime).atZone(index.FixingZone); double tenor = swaptionVolatilities.tenor(swap.StartDate, swap.EndDate); if (provider.ValuationDate.isAfter(cmsPeriod.PaymentDate)) { return(PointSensitivityBuilder.none()); } if (!fixingDate.isAfter(valuationDate.toLocalDate())) { double?fixedRate = provider.timeSeries(cmsPeriod.Index).get(fixingDate); if (fixedRate.HasValue) { return(PointSensitivityBuilder.none()); } else if (fixingDate.isBefore(valuationDate.toLocalDate())) { throw new System.ArgumentException(Messages.format("Unable to get fixing for {} on date {}, no time-series supplied", cmsPeriod.Index, fixingDate)); } } double expiryTime = swaptionVolatilities.relativeTime(expiryDate); double shift = swaptionVolatilities.shift(expiryTime, tenor); double strikeCpn = cmsPeriod.CmsPeriodType.Equals(CmsPeriodType.COUPON) ? -shift : cmsPeriod.Strike; double forward = swapPricer.parRate(swap, provider); double eta = index.Template.Convention.FixedLeg.DayCount.relativeYearFraction(cmsPeriod.PaymentDate, swap.StartDate); CmsIntegrantProvider intProv = new CmsIntegrantProvider(this, cmsPeriod, swap, swaptionVolatilities, forward, strikeCpn, expiryTime, tenor, cutOffStrike, eta); double factor = dfPayment / intProv.h(forward) * intProv.g(forward); double factor2 = factor * intProv.k(strikeCpn); double[] strikePartPrice = intProv.SabrExtrapolation.priceAdjointSabr(Math.Max(0d, strikeCpn + shift), intProv.PutCall).Derivatives.multipliedBy(factor2).toArray(); RungeKuttaIntegrator1D integrator = new RungeKuttaIntegrator1D(ABS_TOL, REL_TOL_VEGA, NUM_ITER); double[] totalSensi = new double[4]; for (int loopparameter = 0; loopparameter < 4; loopparameter++) { double integralPart = 0d; System.Func <double, double> integrant = intProv.integrantVega(loopparameter); try { if (intProv.PutCall.Call) { integralPart = dfPayment * integrateCall(integrator, integrant, swaptionVolatilities, forward, strikeCpn, expiryTime, tenor); } else { integralPart = -dfPayment *integrator.integrate(integrant, -shift + ZERO_SHIFT, strikeCpn); } } catch (Exception e) { throw new Exception(e); } totalSensi[loopparameter] = (strikePartPrice[loopparameter] + integralPart) * cmsPeriod.Notional * cmsPeriod.YearFraction; } SwaptionVolatilitiesName name = swaptionVolatilities.Name; return(PointSensitivityBuilder.of(SwaptionSabrSensitivity.of(name, expiryTime, tenor, ALPHA, ccy, totalSensi[0]), SwaptionSabrSensitivity.of(name, expiryTime, tenor, BETA, ccy, totalSensi[1]), SwaptionSabrSensitivity.of(name, expiryTime, tenor, RHO, ccy, totalSensi[2]), SwaptionSabrSensitivity.of(name, expiryTime, tenor, NU, ccy, totalSensi[3]))); }
//------------------------------------------------------------------------- /// <summary> /// Computes the present value curve sensitivity by replication in SABR framework with extrapolation on the right. /// </summary> /// <param name="cmsPeriod"> the CMS </param> /// <param name="provider"> the rates provider </param> /// <param name="swaptionVolatilities"> the swaption volatilities </param> /// <returns> the present value sensitivity </returns> public PointSensitivityBuilder presentValueSensitivityRates(CmsPeriod cmsPeriod, RatesProvider provider, SabrSwaptionVolatilities swaptionVolatilities) { Currency ccy = cmsPeriod.Currency; if (provider.ValuationDate.isAfter(cmsPeriod.PaymentDate)) { return(PointSensitivityBuilder.none()); } SwapIndex index = cmsPeriod.Index; ResolvedSwap swap = cmsPeriod.UnderlyingSwap; double dfPayment = provider.discountFactor(ccy, cmsPeriod.PaymentDate); ZonedDateTime valuationDate = swaptionVolatilities.ValuationDateTime; LocalDate fixingDate = cmsPeriod.FixingDate; double expiryTime = swaptionVolatilities.relativeTime(fixingDate.atTime(index.FixingTime).atZone(index.FixingZone)); double tenor = swaptionVolatilities.tenor(swap.StartDate, swap.EndDate); double shift = swaptionVolatilities.shift(expiryTime, tenor); double strikeCpn = cmsPeriod.CmsPeriodType.Equals(CmsPeriodType.COUPON) ? -shift : cmsPeriod.Strike; if (!fixingDate.isAfter(valuationDate.toLocalDate())) { double?fixedRate = provider.timeSeries(cmsPeriod.Index).get(fixingDate); if (fixedRate.HasValue) { double payoff = payOff(cmsPeriod.CmsPeriodType, strikeCpn, fixedRate.Value); return(provider.discountFactors(ccy).zeroRatePointSensitivity(cmsPeriod.PaymentDate).multipliedBy(payoff * cmsPeriod.Notional * cmsPeriod.YearFraction)); } else if (fixingDate.isBefore(valuationDate.toLocalDate())) { throw new System.ArgumentException(Messages.format("Unable to get fixing for {} on date {}, no time-series supplied", cmsPeriod.Index, fixingDate)); } } double forward = swapPricer.parRate(swap, provider); double eta = index.Template.Convention.FixedLeg.DayCount.relativeYearFraction(cmsPeriod.PaymentDate, swap.StartDate); CmsDeltaIntegrantProvider intProv = new CmsDeltaIntegrantProvider(this, cmsPeriod, swap, swaptionVolatilities, forward, strikeCpn, expiryTime, tenor, cutOffStrike, eta); RungeKuttaIntegrator1D integrator = new RungeKuttaIntegrator1D(ABS_TOL, REL_TOL, NUM_ITER); double[] bs = intProv.bsbsp(strikeCpn); double[] n = intProv.Nnp; double strikePartPrice = intProv.k(strikeCpn) * n[0] * bs[0]; double integralPartPrice = 0d; double integralPart = 0d; System.Func <double, double> integrant = intProv.integrant(); System.Func <double, double> integrantDelta = intProv.integrantDelta(); try { if (intProv.PutCall.Call) { integralPartPrice = integrateCall(integrator, integrant, swaptionVolatilities, forward, strikeCpn, expiryTime, tenor); integralPart = dfPayment * integrateCall(integrator, integrantDelta, swaptionVolatilities, forward, strikeCpn, expiryTime, tenor); } else { integralPartPrice = -integrator.integrate(integrant, -shift + ZERO_SHIFT, strikeCpn).Value; integralPart = -dfPayment *integrator.integrate(integrantDelta, -shift, strikeCpn); } } catch (Exception e) { throw new MathException(e); } double deltaPD = strikePartPrice + integralPartPrice; if (cmsPeriod.CmsPeriodType.Equals(CmsPeriodType.COUPON)) { deltaPD -= shift; } deltaPD *= cmsPeriod.Notional * cmsPeriod.YearFraction; double strikePart = dfPayment * intProv.k(strikeCpn) * (n[1] * bs[0] + n[0] * bs[1]); double deltaFwd = (strikePart + integralPart) * cmsPeriod.Notional * cmsPeriod.YearFraction; PointSensitivityBuilder sensiFwd = swapPricer.parRateSensitivity(swap, provider).multipliedBy(deltaFwd); PointSensitivityBuilder sensiDf = provider.discountFactors(ccy).zeroRatePointSensitivity(cmsPeriod.PaymentDate).multipliedBy(deltaPD); return(sensiFwd.combinedWith(sensiDf)); }
public virtual void test_builder_nonNullCapFloor() { assertThrowsIllegalArg(() => CmsPeriod.builder().caplet(STRIKE).floorlet(STRIKE).startDate(START).endDate(END).index(INDEX).notional(NOTIONAL).yearFraction(YEAR_FRACTION).dayCount(ACT_360).build()); }
//------------------------------------------------------------------------- /// <summary> /// Computes the present value by replication in SABR framework with extrapolation on the right. /// </summary> /// <param name="cmsPeriod"> the CMS </param> /// <param name="provider"> the rates provider </param> /// <param name="swaptionVolatilities"> the swaption volatilities </param> /// <returns> the present value </returns> public CurrencyAmount presentValue(CmsPeriod cmsPeriod, RatesProvider provider, SabrSwaptionVolatilities swaptionVolatilities) { Currency ccy = cmsPeriod.Currency; if (provider.ValuationDate.isAfter(cmsPeriod.PaymentDate)) { return(CurrencyAmount.zero(ccy)); } SwapIndex index = cmsPeriod.Index; ResolvedSwap swap = cmsPeriod.UnderlyingSwap; double dfPayment = provider.discountFactor(ccy, cmsPeriod.PaymentDate); ZonedDateTime valuationDate = swaptionVolatilities.ValuationDateTime; LocalDate fixingDate = cmsPeriod.FixingDate; double expiryTime = swaptionVolatilities.relativeTime(fixingDate.atTime(index.FixingTime).atZone(index.FixingZone)); double tenor = swaptionVolatilities.tenor(swap.StartDate, swap.EndDate); double shift = swaptionVolatilities.shift(expiryTime, tenor); double strikeCpn = cmsPeriod.CmsPeriodType.Equals(CmsPeriodType.COUPON) ? -shift : cmsPeriod.Strike; if (!fixingDate.isAfter(valuationDate.toLocalDate())) { double?fixedRate = provider.timeSeries(cmsPeriod.Index).get(fixingDate); if (fixedRate.HasValue) { double payoff = payOff(cmsPeriod.CmsPeriodType, strikeCpn, fixedRate.Value); return(CurrencyAmount.of(ccy, dfPayment * payoff * cmsPeriod.Notional * cmsPeriod.YearFraction)); } else if (fixingDate.isBefore(valuationDate.toLocalDate())) { throw new System.ArgumentException(Messages.format("Unable to get fixing for {} on date {}, no time-series supplied", cmsPeriod.Index, fixingDate)); } } double forward = swapPricer.parRate(swap, provider); if (expiryTime < MIN_TIME) { double payoff = payOff(cmsPeriod.CmsPeriodType, strikeCpn, forward); return(CurrencyAmount.of(ccy, dfPayment * payoff * cmsPeriod.Notional * cmsPeriod.YearFraction)); } double eta = index.Template.Convention.FixedLeg.DayCount.relativeYearFraction(cmsPeriod.PaymentDate, swap.StartDate); CmsIntegrantProvider intProv = new CmsIntegrantProvider(this, cmsPeriod, swap, swaptionVolatilities, forward, strikeCpn, expiryTime, tenor, cutOffStrike, eta); double factor = dfPayment / intProv.h(forward) * intProv.g(forward); double strikePart = factor * intProv.k(strikeCpn) * intProv.bs(strikeCpn); RungeKuttaIntegrator1D integrator = new RungeKuttaIntegrator1D(ABS_TOL, REL_TOL, NUM_ITER); double integralPart = 0d; System.Func <double, double> integrant = intProv.integrant(); try { if (intProv.PutCall.Call) { integralPart = dfPayment * integrateCall(integrator, integrant, swaptionVolatilities, forward, strikeCpn, expiryTime, tenor); } else { integralPart = -dfPayment *integrator.integrate(integrant, -shift + ZERO_SHIFT, strikeCpn); } } catch (Exception e) { throw new MathException(e); } double priceCMS = (strikePart + integralPart); if (cmsPeriod.CmsPeriodType.Equals(CmsPeriodType.COUPON)) { priceCMS -= dfPayment * shift; } priceCMS *= cmsPeriod.Notional * cmsPeriod.YearFraction; return(CurrencyAmount.of(ccy, priceCMS)); }
//------------------------------------------------------------------------- /// <summary> /// Computes the present value by replication in SABR framework with extrapolation on the right. /// </summary> /// <param name="cmsPeriod"> the CMS </param> /// <param name="provider"> the rates provider </param> /// <param name="swaptionVolatilities"> the swaption volatilities </param> /// <returns> the present value </returns> public CurrencyAmount presentValue(CmsPeriod cmsPeriod, RatesProvider provider, SwaptionVolatilities swaptionVolatilities) { Currency ccy = cmsPeriod.Currency; LocalDate valuationDate = provider.ValuationDate; if (valuationDate.isAfter(cmsPeriod.PaymentDate)) { return(CurrencyAmount.zero(ccy)); } LocalDate fixingDate = cmsPeriod.FixingDate; double dfPayment = provider.discountFactor(ccy, cmsPeriod.PaymentDate); if (!fixingDate.isAfter(valuationDate)) { // Using fixing double?fixedRate = provider.timeSeries(cmsPeriod.Index).get(fixingDate); if (fixedRate.HasValue) { double payoff = 0d; switch (cmsPeriod.CmsPeriodType) { case CAPLET: payoff = Math.Max(fixedRate.Value - cmsPeriod.Strike, 0d); break; case FLOORLET: payoff = Math.Max(cmsPeriod.Strike - fixedRate.Value, 0d); break; case COUPON: payoff = fixedRate.Value; break; default: throw new System.ArgumentException("unsupported CMS type"); } return(CurrencyAmount.of(ccy, payoff * dfPayment * cmsPeriod.Notional * cmsPeriod.YearFraction)); } else if (fixingDate.isBefore(valuationDate)) { throw new System.ArgumentException(Messages.format("Unable to get fixing for {} on date {}, no time-series supplied", cmsPeriod.Index, fixingDate)); } } if (!cmsPeriod.CmsPeriodType.Equals(CmsPeriodType.COUPON)) { throw new System.ArgumentException("Unable to price cap or floor in this pricer"); } // Using forward SwapIndex index = cmsPeriod.Index; ResolvedSwap swap = cmsPeriod.UnderlyingSwap; ResolvedSwapLeg fixedLeg = swap.getLegs(SwapLegType.FIXED).get(0); int nbFixedPaymentYear = (int)(long)Math.Round(1d / ((RatePaymentPeriod)fixedLeg.PaymentPeriods.get(0)).AccrualPeriods.get(0).YearFraction, MidpointRounding.AwayFromZero); int nbFixedPeriod = fixedLeg.PaymentPeriods.size(); double forward = swapPricer.parRate(swap, provider); double tenor = swaptionVolatilities.tenor(swap.StartDate, swap.EndDate); double expiryTime = swaptionVolatilities.relativeTime(fixingDate.atTime(index.FixingTime).atZone(index.FixingZone)); double volatility = swaptionVolatilities.volatility(expiryTime, tenor, forward, forward); ValueDerivatives annuityDerivatives = swapPricer.LegPricer.annuityCash2(nbFixedPaymentYear, nbFixedPeriod, volatility); double forwardAdjustment = -0.5 * forward * forward * volatility * volatility * expiryTime * annuityDerivatives.getDerivative(1) / annuityDerivatives.getDerivative(0); return(CurrencyAmount.of(ccy, (forward + forwardAdjustment) * dfPayment * cmsPeriod.Notional * cmsPeriod.YearFraction)); }