//------------------------------------------------------------------------- /// <summary> /// Calculates the present value sensitivity of the swaption product to the rate curves. /// <para> /// The present value sensitivity is computed in a "sticky model parameter" style, i.e. the sensitivity to the /// curve nodes with the SABR model parameters unchanged. This sensitivity does not include a potential /// re-calibration of the model parameters to the raw market data. /// /// </para> /// </summary> /// <param name="swaption"> the swaption product </param> /// <param name="ratesProvider"> the rates provider </param> /// <param name="swaptionVolatilities"> the volatilities </param> /// <returns> the point sensitivity to the rate curves </returns> public virtual PointSensitivityBuilder presentValueSensitivityRatesStickyModel(ResolvedSwaption swaption, RatesProvider ratesProvider, SabrSwaptionVolatilities swaptionVolatilities) { validate(swaption, ratesProvider, swaptionVolatilities); ZonedDateTime expiryDateTime = swaption.Expiry; double expiry = swaptionVolatilities.relativeTime(expiryDateTime); ResolvedSwap underlying = swaption.Underlying; ResolvedSwapLeg fixedLeg = this.fixedLeg(underlying); if (expiry < 0d) { // Option has expired already return(PointSensitivityBuilder.none()); } double forward = SwapPricer.parRate(underlying, ratesProvider); double pvbp = SwapPricer.LegPricer.pvbp(fixedLeg, ratesProvider); double strike = SwapPricer.LegPricer.couponEquivalent(fixedLeg, ratesProvider, pvbp); double tenor = swaptionVolatilities.tenor(fixedLeg.StartDate, fixedLeg.EndDate); double shift = swaptionVolatilities.shift(expiry, tenor); ValueDerivatives volatilityAdj = swaptionVolatilities.volatilityAdjoint(expiry, tenor, strike, forward); bool isCall = fixedLeg.PayReceive.Pay; // Payer at strike is exercise when rate > strike, i.e. call on rate // Backward sweep PointSensitivityBuilder pvbpDr = SwapPricer.LegPricer.pvbpSensitivity(fixedLeg, ratesProvider); PointSensitivityBuilder forwardDr = SwapPricer.parRateSensitivity(underlying, ratesProvider); double shiftedForward = forward + shift; double shiftedStrike = strike + shift; double price = BlackFormulaRepository.price(shiftedForward, shiftedStrike, expiry, volatilityAdj.Value, isCall); double delta = BlackFormulaRepository.delta(shiftedForward, shiftedStrike, expiry, volatilityAdj.Value, isCall); double vega = BlackFormulaRepository.vega(shiftedForward, shiftedStrike, expiry, volatilityAdj.Value); double sign = swaption.LongShort.sign(); return(pvbpDr.multipliedBy(price * sign * Math.Sign(pvbp)).combinedWith(forwardDr.multipliedBy((delta + vega * volatilityAdj.getDerivative(0)) * Math.Abs(pvbp) * sign))); }
//------------------------------------------------------------------------- /// <summary> /// Calculates the present value sensitivity of the swaption product to the rate curves. /// <para> /// The present value sensitivity is computed in a "sticky model parameter" style, i.e. the sensitivity to the /// curve nodes with the SABR model parameters unchanged. This sensitivity does not include a potential /// re-calibration of the model parameters to the raw market data. /// /// </para> /// </summary> /// <param name="swaption"> the swaption product </param> /// <param name="ratesProvider"> the rates provider </param> /// <param name="swaptionVolatilities"> the volatilities </param> /// <returns> the point sensitivity to the rate curves </returns> public virtual PointSensitivityBuilder presentValueSensitivityRatesStickyModel(ResolvedSwaption swaption, RatesProvider ratesProvider, SabrSwaptionVolatilities swaptionVolatilities) { validate(swaption, ratesProvider, swaptionVolatilities); ZonedDateTime expiryDateTime = swaption.Expiry; double expiry = swaptionVolatilities.relativeTime(expiryDateTime); ResolvedSwap underlying = swaption.Underlying; ResolvedSwapLeg fixedLeg = this.fixedLeg(underlying); if (expiry < 0d) { // Option has expired already return(PointSensitivityBuilder.none()); } double forward = SwapPricer.parRate(underlying, ratesProvider); ValueDerivatives annuityDerivative = SwapPricer.LegPricer.annuityCashDerivative(fixedLeg, forward); double annuityCash = annuityDerivative.Value; double annuityCashDr = annuityDerivative.getDerivative(0); LocalDate settlementDate = ((CashSwaptionSettlement)swaption.SwaptionSettlement).SettlementDate; double discountSettle = ratesProvider.discountFactor(fixedLeg.Currency, settlementDate); double strike = calculateStrike(fixedLeg); double tenor = swaptionVolatilities.tenor(fixedLeg.StartDate, fixedLeg.EndDate); double shift = swaptionVolatilities.shift(expiry, tenor); ValueDerivatives volatilityAdj = swaptionVolatilities.volatilityAdjoint(expiry, tenor, strike, forward); bool isCall = fixedLeg.PayReceive.Pay; double shiftedForward = forward + shift; double shiftedStrike = strike + shift; double price = BlackFormulaRepository.price(shiftedForward, shiftedStrike, expiry, volatilityAdj.Value, isCall); double delta = BlackFormulaRepository.delta(shiftedForward, shiftedStrike, expiry, volatilityAdj.Value, isCall); double vega = BlackFormulaRepository.vega(shiftedForward, shiftedStrike, expiry, volatilityAdj.Value); PointSensitivityBuilder forwardSensi = SwapPricer.parRateSensitivity(underlying, ratesProvider); PointSensitivityBuilder discountSettleSensi = ratesProvider.discountFactors(fixedLeg.Currency).zeroRatePointSensitivity(settlementDate); double sign = swaption.LongShort.sign(); return(forwardSensi.multipliedBy(sign * discountSettle * (annuityCash * (delta + vega * volatilityAdj.getDerivative(0)) + annuityCashDr * price)).combinedWith(discountSettleSensi.multipliedBy(sign * annuityCash * price))); }
//------------------------------------------------------------------------- /// <summary> /// Calculates the present value sensitivity to the SABR model parameters of the swaption product. /// <para> /// The sensitivity of the present value to the SABR model parameters, alpha, beta, rho and nu. /// /// </para> /// </summary> /// <param name="swaption"> the swaption product </param> /// <param name="ratesProvider"> the rates provider </param> /// <param name="swaptionVolatilities"> the volatilities </param> /// <returns> the point sensitivity to the SABR model parameters </returns> public virtual PointSensitivityBuilder presentValueSensitivityModelParamsSabr(ResolvedSwaption swaption, RatesProvider ratesProvider, SabrSwaptionVolatilities swaptionVolatilities) { validate(swaption, ratesProvider, swaptionVolatilities); double expiry = swaptionVolatilities.relativeTime(swaption.Expiry); ResolvedSwap underlying = swaption.Underlying; ResolvedSwapLeg fixedLeg = this.fixedLeg(underlying); double tenor = swaptionVolatilities.tenor(fixedLeg.StartDate, fixedLeg.EndDate); double shift = swaptionVolatilities.shift(expiry, tenor); double pvbp = SwapPricer.LegPricer.pvbp(fixedLeg, ratesProvider); double strike = SwapPricer.LegPricer.couponEquivalent(fixedLeg, ratesProvider, pvbp); if (expiry < 0d) { // Option has expired already return(PointSensitivityBuilder.none()); } double forward = SwapPricer.parRate(underlying, ratesProvider); double volatility = swaptionVolatilities.volatility(expiry, tenor, strike, forward); DoubleArray derivative = swaptionVolatilities.volatilityAdjoint(expiry, tenor, strike, forward).Derivatives; // Backward sweep double vega = Math.Abs(pvbp) * BlackFormulaRepository.vega(forward + shift, strike + shift, expiry, volatility) * swaption.LongShort.sign(); // sensitivities Currency ccy = fixedLeg.Currency; SwaptionVolatilitiesName name = swaptionVolatilities.Name; return(PointSensitivityBuilder.of(SwaptionSabrSensitivity.of(name, expiry, tenor, ALPHA, ccy, vega * derivative.get(2)), SwaptionSabrSensitivity.of(name, expiry, tenor, BETA, ccy, vega * derivative.get(3)), SwaptionSabrSensitivity.of(name, expiry, tenor, RHO, ccy, vega * derivative.get(4)), SwaptionSabrSensitivity.of(name, expiry, tenor, NU, ccy, vega * derivative.get(5)))); }
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)); }
//------------------------------------------------------------------------- /// <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)); }