//------------------------------------------------------------------------- /// <summary> /// Calculates the present value sensitivity of the swaption to the rate curves. /// <para> /// The present value sensitivity is computed in a "sticky strike" style, i.e. the sensitivity to the /// curve nodes with the volatility at the swaption strike unchanged. This sensitivity does not include a potential /// change of volatility due to the implicit change of forward rate or moneyness. /// /// </para> /// </summary> /// <param name="swaption"> the swaption </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 presentValueSensitivityRatesStickyStrike(ResolvedSwaption swaption, RatesProvider ratesProvider, SwaptionVolatilities swaptionVolatilities) { validate(swaption, ratesProvider, swaptionVolatilities); double expiry = swaptionVolatilities.relativeTime(swaption.Expiry); 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 volatility = swaptionVolatilities.volatility(expiry, tenor, strike, forward); PutCall putCall = PutCall.ofPut(fixedLeg.PayReceive.Receive); double price = swaptionVolatilities.price(expiry, tenor, putCall, strike, forward, volatility); double delta = swaptionVolatilities.priceDelta(expiry, tenor, putCall, strike, forward, volatility); // Backward sweep 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 + annuityCashDr * price)).combinedWith(discountSettleSensi.multipliedBy(sign * annuityCash * price))); }
//------------------------------------------------------------------------- /// <summary> /// Calculates the present value sensitivity of the swaption to the rate curves. /// <para> /// The present value sensitivity is computed in a "sticky strike" style, i.e. the sensitivity to the /// curve nodes with the volatility at the swaption strike unchanged. This sensitivity does not include a potential /// change of volatility due to the implicit change of forward rate or moneyness. /// /// </para> /// </summary> /// <param name="swaption"> the swaption </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 presentValueSensitivityRatesStickyStrike(ResolvedSwaption swaption, RatesProvider ratesProvider, SwaptionVolatilities swaptionVolatilities) { validate(swaption, ratesProvider, swaptionVolatilities); double expiry = swaptionVolatilities.relativeTime(swaption.Expiry); 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 volatility = swaptionVolatilities.volatility(expiry, tenor, strike, forward); PutCall putCall = PutCall.ofPut(fixedLeg.PayReceive.Receive); double price = swaptionVolatilities.price(expiry, tenor, putCall, strike, forward, volatility); double delta = swaptionVolatilities.priceDelta(expiry, tenor, putCall, strike, forward, volatility); // Backward sweep PointSensitivityBuilder pvbpDr = SwapPricer.LegPricer.pvbpSensitivity(fixedLeg, ratesProvider); PointSensitivityBuilder forwardDr = SwapPricer.parRateSensitivity(underlying, ratesProvider); double sign = swaption.LongShort.sign(); return(pvbpDr.multipliedBy(price * sign * Math.Sign(pvbp)).combinedWith(forwardDr.multipliedBy(delta * Math.Abs(pvbp) * sign))); }
//------------------------------------------------------------------------- /// <summary> /// Computes the implied volatility of the swaption. /// </summary> /// <param name="swaption"> the swaption </param> /// <param name="ratesProvider"> the rates provider </param> /// <param name="swaptionVolatilities"> the volatilities </param> /// <returns> the implied volatility associated with the swaption </returns> public virtual double impliedVolatility(ResolvedSwaption swaption, RatesProvider ratesProvider, SwaptionVolatilities swaptionVolatilities) { validate(swaption, ratesProvider, swaptionVolatilities); double expiry = swaptionVolatilities.relativeTime(swaption.Expiry); ResolvedSwap underlying = swaption.Underlying; ResolvedSwapLeg fixedLeg = this.fixedLeg(underlying); ArgChecker.isTrue(expiry >= 0d, "Option must be before expiry to compute an implied volatility"); double forward = SwapPricer.parRate(underlying, ratesProvider); double strike = calculateStrike(fixedLeg); double tenor = swaptionVolatilities.tenor(fixedLeg.StartDate, fixedLeg.EndDate); return(swaptionVolatilities.volatility(expiry, tenor, strike, forward)); }
//------------------------------------------------------------------------- /// <summary> /// Calculates the present value of the swaption. /// <para> /// The result is expressed using the currency of the swaption. /// /// </para> /// </summary> /// <param name="swaption"> the swaption </param> /// <param name="ratesProvider"> the rates provider </param> /// <param name="swaptionVolatilities"> the volatilities </param> /// <returns> the present value </returns> public virtual CurrencyAmount presentValue(ResolvedSwaption swaption, RatesProvider ratesProvider, SwaptionVolatilities swaptionVolatilities) { validate(swaption, ratesProvider, swaptionVolatilities); double expiry = swaptionVolatilities.relativeTime(swaption.Expiry); ResolvedSwap underlying = swaption.Underlying; ResolvedSwapLeg fixedLeg = this.fixedLeg(underlying); if (expiry < 0d) { // Option has expired already return(CurrencyAmount.of(fixedLeg.Currency, 0d)); } double forward = swapPricer.parRate(underlying, ratesProvider); double numeraire = calculateNumeraire(swaption, fixedLeg, forward, ratesProvider); double strike = calculateStrike(fixedLeg); double tenor = swaptionVolatilities.tenor(fixedLeg.StartDate, fixedLeg.EndDate); double volatility = swaptionVolatilities.volatility(expiry, tenor, strike, forward); PutCall putCall = PutCall.ofPut(fixedLeg.PayReceive.Receive); double price = numeraire * swaptionVolatilities.price(expiry, tenor, putCall, strike, forward, volatility); return(CurrencyAmount.of(fixedLeg.Currency, price * swaption.LongShort.sign())); }
//------------------------------------------------------------------------- /// <summary> /// Calculates the present value sensitivity to the implied volatility of the swaption. /// <para> /// The sensitivity to the implied volatility is also called vega. /// /// </para> /// </summary> /// <param name="swaption"> the swaption </param> /// <param name="ratesProvider"> the rates provider </param> /// <param name="swaptionVolatilities"> the volatilities </param> /// <returns> the point sensitivity to the volatility </returns> public virtual SwaptionSensitivity presentValueSensitivityModelParamsVolatility(ResolvedSwaption swaption, RatesProvider ratesProvider, SwaptionVolatilities 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 pvbp = SwapPricer.LegPricer.pvbp(fixedLeg, ratesProvider); double strike = SwapPricer.LegPricer.couponEquivalent(fixedLeg, ratesProvider, pvbp); if (expiry < 0d) { // Option has expired already return(SwaptionSensitivity.of(swaptionVolatilities.Name, expiry, tenor, strike, 0d, fixedLeg.Currency, 0d)); } double forward = SwapPricer.parRate(underlying, ratesProvider); double numeraire = Math.Abs(pvbp); double volatility = swaptionVolatilities.volatility(expiry, tenor, strike, forward); PutCall putCall = PutCall.ofPut(fixedLeg.PayReceive.Receive); double vega = numeraire * swaptionVolatilities.priceVega(expiry, tenor, putCall, strike, forward, volatility); return(SwaptionSensitivity.of(swaptionVolatilities.Name, expiry, tenor, strike, forward, fixedLeg.Currency, vega * swaption.LongShort.sign())); }
//------------------------------------------------------------------------- /// <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)); }