//------------------------------------------------------------------------- /// <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 strike = calculateStrike(fixedLeg); if (expiry < 0d) { // Option has expired already return(PointSensitivityBuilder.none()); } double forward = SwapPricer.parRate(underlying, ratesProvider); double volatility = swaptionVolatilities.volatility(expiry, tenor, strike, forward); double numeraire = calculateNumeraire(swaption, fixedLeg, forward, ratesProvider); DoubleArray derivative = swaptionVolatilities.volatilityAdjoint(expiry, tenor, strike, forward).Derivatives; double vega = numeraire * swaption.LongShort.sign() * BlackFormulaRepository.vega(forward + shift, strike + shift, expiry, volatility); // 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 virtual void test_cashFlowEquivalent_pv() { ResolvedSwap swap = ResolvedSwap.of(IBOR_LEG, FIXED_LEG); ResolvedSwapLeg cfe = CashFlowEquivalentCalculator.cashFlowEquivalentSwap(swap, PROVIDER); DiscountingSwapLegPricer pricerLeg = DiscountingSwapLegPricer.DEFAULT; DiscountingSwapProductPricer pricerSwap = DiscountingSwapProductPricer.DEFAULT; CurrencyAmount pvCfe = pricerLeg.presentValue(cfe, PROVIDER); MultiCurrencyAmount pvSwap = pricerSwap.presentValue(swap, PROVIDER); assertEquals(pvCfe.Amount, pvSwap.getAmount(GBP).Amount, TOLERANCE_PV); }
public virtual void test_legInitialNotional() { ResolvedSwapLeg firstLeg = SWAP_TRADE.Product.Legs.get(0); ResolvedSwapLeg secondLeg = SWAP_TRADE.Product.Legs.get(1); Currency ccy = firstLeg.Currency; RatePaymentPeriod firstPaymentPeriod = (RatePaymentPeriod)firstLeg.PaymentPeriods.get(0); double notional = firstPaymentPeriod.Notional; LegAmounts expected = LegAmounts.of(SwapLegAmount.of(firstLeg, CurrencyAmount.of(ccy, notional)), SwapLegAmount.of(secondLeg, CurrencyAmount.of(ccy, notional))); assertEquals(SwapMeasureCalculations.DEFAULT.legInitialNotional(SWAP_TRADE), expected); }
public virtual void test_cashFlowEquivalentAndSensitivity_compounding() { RatePaymentPeriod iborCmp = RatePaymentPeriod.builder().paymentDate(PAYMENT2).accrualPeriods(IBOR1, IBOR2).dayCount(ACT_365F).currency(GBP).notional(-NOTIONAL).build(); ResolvedSwapLeg iborLegCmp = ResolvedSwapLeg.builder().type(IBOR).payReceive(PAY).paymentPeriods(iborCmp).build(); ResolvedSwap swap1 = ResolvedSwap.of(iborLegCmp, FIXED_LEG); assertThrowsIllegalArg(() => CashFlowEquivalentCalculator.cashFlowEquivalentAndSensitivitySwap(swap1, PROVIDER)); RatePaymentPeriod fixedCmp = RatePaymentPeriod.builder().paymentDate(PAYMENT2).accrualPeriods(FIXED1, FIXED2).dayCount(ACT_365F).currency(GBP).notional(NOTIONAL).build(); ResolvedSwapLeg fixedLegCmp = ResolvedSwapLeg.builder().type(FIXED).payReceive(RECEIVE).paymentPeriods(fixedCmp).build(); ResolvedSwap swap2 = ResolvedSwap.of(IBOR_LEG, fixedLegCmp); assertThrowsIllegalArg(() => CashFlowEquivalentCalculator.cashFlowEquivalentAndSensitivitySwap(swap2, PROVIDER)); }
public virtual void test_of() { SwapPaymentPeriod pp = mock(typeof(SwapPaymentPeriod)); when(pp.Currency).thenReturn(Currency.GBP); ResolvedSwapLeg leg = ResolvedSwapLeg.builder().type(SwapLegType.FIXED).payReceive(PayReceive.PAY).paymentPeriods(pp).build(); SwapLegAmount legAmount = SwapLegAmount.of(leg, CurrencyAmount.of(Currency.GBP, 10)); SwapLegAmount test = legAmount.convertedTo(Currency.USD, FxRate.of(Currency.GBP, Currency.USD, 1.6)); assertThat(test.Amount.Currency).isEqualTo(Currency.USD); assertThat(test.Amount.Amount).isEqualTo(16.0); assertThat(test.PayReceive).isEqualTo(legAmount.PayReceive); assertThat(test.Type).isEqualTo(legAmount.Type); assertThat(test.Currency).isEqualTo(legAmount.Currency); }
public virtual void test_cashFlowEquivalent() { ResolvedSwap swap = ResolvedSwap.of(IBOR_LEG, FIXED_LEG); ResolvedSwapLeg computed = CashFlowEquivalentCalculator.cashFlowEquivalentSwap(swap, PROVIDER); ResolvedSwapLeg computedIborLeg = CashFlowEquivalentCalculator.cashFlowEquivalentIborLeg(IBOR_LEG, PROVIDER); ResolvedSwapLeg computedFixedLeg = CashFlowEquivalentCalculator.cashFlowEquivalentFixedLeg(FIXED_LEG, PROVIDER); assertEquals(computedFixedLeg.PaymentEvents, computed.PaymentEvents.subList(0, 2)); assertEquals(computedIborLeg.PaymentEvents, computed.PaymentEvents.subList(2, 6)); // expected payments from fixed leg NotionalExchange fixedPayment1 = NotionalExchange.of(CurrencyAmount.of(GBP, NOTIONAL * RATE * PAY_YC1), PAYMENT1); NotionalExchange fixedPayment2 = NotionalExchange.of(CurrencyAmount.of(GBP, NOTIONAL * RATE * PAY_YC2), PAYMENT2); // expected payments from ibor leg LocalDate fixingSTART1 = GBP_LIBOR_3M.calculateEffectiveFromFixing(FIXING1, REF_DATA); double fixedYearFraction1 = GBP_LIBOR_3M.DayCount.relativeYearFraction(fixingSTART1, GBP_LIBOR_3M.calculateMaturityFromEffective(fixingSTART1, REF_DATA)); double beta1 = (1d + fixedYearFraction1 * PROVIDER.iborIndexRates(GBP_LIBOR_3M).rate(GBP_LIBOR_3M_COMP1.Observation)) * PROVIDER.discountFactor(GBP, PAYMENT1) / PROVIDER.discountFactor(GBP, fixingSTART1); NotionalExchange iborPayment11 = NotionalExchange.of(CurrencyAmount.of(GBP, -NOTIONAL * beta1 * PAY_YC1 / fixedYearFraction1), fixingSTART1); NotionalExchange iborPayment12 = NotionalExchange.of(CurrencyAmount.of(GBP, NOTIONAL * PAY_YC1 / fixedYearFraction1), PAYMENT1); LocalDate fixingSTART2 = GBP_LIBOR_3M.calculateEffectiveFromFixing(FIXING2, REF_DATA); double fixedYearFraction2 = GBP_LIBOR_3M.DayCount.relativeYearFraction(fixingSTART2, GBP_LIBOR_3M.calculateMaturityFromEffective(fixingSTART2, REF_DATA)); double beta2 = (1d + fixedYearFraction2 * PROVIDER.iborIndexRates(GBP_LIBOR_3M).rate(GBP_LIBOR_3M_COMP2.Observation)) * PROVIDER.discountFactor(GBP, PAYMENT2) / PROVIDER.discountFactor(GBP, fixingSTART2); NotionalExchange iborPayment21 = NotionalExchange.of(CurrencyAmount.of(GBP, -NOTIONAL * beta2 * PAY_YC2 / fixedYearFraction2), fixingSTART2); NotionalExchange iborPayment22 = NotionalExchange.of(CurrencyAmount.of(GBP, NOTIONAL * PAY_YC2 / fixedYearFraction2), PAYMENT2); ResolvedSwapLeg expected = ResolvedSwapLeg.builder().type(OTHER).payReceive(RECEIVE).paymentEvents(fixedPayment1, fixedPayment2, iborPayment11, iborPayment12, iborPayment21, iborPayment22).build(); double eps = 1.0e-12; assertEquals(computed.PaymentEvents.size(), expected.PaymentEvents.size()); for (int i = 0; i < 6; ++i) { NotionalExchange payCmp = (NotionalExchange)computed.PaymentEvents.get(i); NotionalExchange payExp = (NotionalExchange)expected.PaymentEvents.get(i); assertEquals(payCmp.Currency, payExp.Currency); assertEquals(payCmp.PaymentDate, payExp.PaymentDate); assertTrue(DoubleMath.fuzzyEquals(payCmp.PaymentAmount.Amount, payExp.PaymentAmount.Amount, NOTIONAL * eps)); } }