//------------------------------------------------------------------------- /// <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)); }