public void test_cashFlowEquivalentAndSensitivity_compounding() { RatePaymentPeriod iborCmp = RatePaymentPeriod.builder() .paymentDate(PAYMENT2) .accrualPeriods(IBOR1, IBOR2) .dayCount(ACT_365F) .currency(GBP) .notional(-NOTIONAL) .build(); ExpandedSwapLeg iborLegCmp = ExpandedSwapLeg.builder().type(IBOR).payReceive(PAY).paymentPeriods(iborCmp).build(); Swap swap1 = Swap.builder().legs(iborLegCmp, FIXED_LEG).build(); assertThrowsIllegalArg( () -> CashFlowEquivalentCalculator.cashFlowEquivalentAndSensitivitySwap( swap1.expand(), PROVIDER)); RatePaymentPeriod fixedCmp = RatePaymentPeriod.builder() .paymentDate(PAYMENT2) .accrualPeriods(FIXED1, FIXED2) .dayCount(ACT_365F) .currency(GBP) .notional(NOTIONAL) .build(); ExpandedSwapLeg fixedLegCmp = ExpandedSwapLeg.builder().type(FIXED).payReceive(RECEIVE).paymentPeriods(fixedCmp).build(); Swap swap2 = Swap.builder().legs(IBOR_LEG, fixedLegCmp).build(); assertThrowsIllegalArg( () -> CashFlowEquivalentCalculator.cashFlowEquivalentAndSensitivitySwap( swap2.expand(), PROVIDER)); }
/** * Calculates the present value sensitivity of the swaption product. * * <p>The present value sensitivity of the product is the sensitivity of the present value to the * underlying curves. * * @param swaption the swaption product * @param ratesProvider the rates provider * @param volatilityProvider the normal volatility provider * @return the present value curve sensitivity of the swap product */ public PointSensitivityBuilder presentValueSensitivityStickyStrike( SwaptionProduct swaption, RatesProvider ratesProvider, NormalVolatilitySwaptionProvider volatilityProvider) { ExpandedSwaption expanded = swaption.expand(); validate(ratesProvider, expanded, volatilityProvider); ZonedDateTime expiryDateTime = expanded.getExpiryDateTime(); double expiry = volatilityProvider.relativeTime(expiryDateTime); ExpandedSwap underlying = expanded.getUnderlying(); ExpandedSwapLeg fixedLeg = fixedLeg(underlying); if (expiry < 0.0d) { // Option has expired already return PointSensitivityBuilder.none(); } double forward = swapPricer.parRate(underlying, ratesProvider); double pvbp = swapPricer.getLegPricer().pvbp(fixedLeg, ratesProvider); double strike = swapPricer.getLegPricer().couponEquivalent(fixedLeg, ratesProvider, pvbp); double tenor = volatilityProvider.tenor(fixedLeg.getStartDate(), fixedLeg.getEndDate()); double volatility = volatilityProvider.getVolatility(expiryDateTime, tenor, strike, forward); NormalFunctionData normalData = NormalFunctionData.of(forward, 1.0d, volatility); boolean isCall = (fixedLeg.getPayReceive() == PayReceive.PAY); // Payer at strike is exercise when rate > strike, i.e. call on rate EuropeanVanillaOption option = EuropeanVanillaOption.of(strike, expiry, isCall ? PutCall.CALL : PutCall.PUT); // option required to pass the strike (in case the swap has non-constant coupon). // Backward sweep PointSensitivityBuilder pvbpDr = swapPricer.getLegPricer().pvbpSensitivity(fixedLeg, ratesProvider); PointSensitivityBuilder forwardDr = swapPricer.parRateSensitivity(underlying, ratesProvider); ValueDerivatives pv = NORMAL.getPriceAdjoint(option, normalData); double sign = (expanded.getLongShort() == LongShort.LONG) ? 1.0 : -1.0; return pvbpDr .multipliedBy(pv.getValue() * sign * Math.signum(pvbp)) .combinedWith(forwardDr.multipliedBy(pv.getDerivative(0) * Math.abs(pvbp) * sign)); }
/** * Computes the implied Normal volatility of the swaption. * * @param swaption the product to price * @param ratesProvider the rates provider * @param volatilityProvider the normal volatility provider * @return the present value of the swap product */ public double impliedVolatility( SwaptionProduct swaption, RatesProvider ratesProvider, NormalVolatilitySwaptionProvider volatilityProvider) { ExpandedSwaption expanded = swaption.expand(); validate(ratesProvider, expanded, volatilityProvider); ZonedDateTime expiryDateTime = expanded.getExpiryDateTime(); double expiry = volatilityProvider.relativeTime(expiryDateTime); ExpandedSwap underlying = expanded.getUnderlying(); ExpandedSwapLeg fixedLeg = fixedLeg(underlying); ArgChecker.isTrue( expiry >= 0.0d, "option should be before expiry to compute an implied volatility"); double forward = swapPricer.parRate(underlying, ratesProvider); double pvbp = swapPricer.getLegPricer().pvbp(fixedLeg, ratesProvider); double strike = swapPricer.getLegPricer().couponEquivalent(fixedLeg, ratesProvider, pvbp); double tenor = volatilityProvider.tenor(fixedLeg.getStartDate(), fixedLeg.getEndDate()); return volatilityProvider.getVolatility(expiryDateTime, tenor, strike, forward); }
// ------------------------------------------------------------------------- public void test_cashFlowEquivalentAndSensitivity() { Swap swap = Swap.builder().legs(IBOR_LEG, FIXED_LEG).build(); ImmutableMap<NotionalExchange, PointSensitivityBuilder> computedFull = CashFlowEquivalentCalculator.cashFlowEquivalentAndSensitivitySwap(swap.expand(), PROVIDER); ImmutableList<NotionalExchange> keyComputedFull = computedFull.keySet().asList(); ImmutableList<PointSensitivityBuilder> valueComputedFull = computedFull.values().asList(); ImmutableMap<NotionalExchange, PointSensitivityBuilder> computedIborLeg = CashFlowEquivalentCalculator.cashFlowEquivalentAndSensitivityIborLeg( IBOR_LEG.expand(), PROVIDER); ImmutableMap<NotionalExchange, PointSensitivityBuilder> computedFixedLeg = CashFlowEquivalentCalculator.cashFlowEquivalentAndSensitivityFixedLeg( FIXED_LEG.expand(), PROVIDER); assertEquals(computedFixedLeg.keySet().asList(), keyComputedFull.subList(0, 2)); assertEquals(computedIborLeg.keySet().asList(), keyComputedFull.subList(2, 6)); assertEquals(computedFixedLeg.values().asList(), valueComputedFull.subList(0, 2)); assertEquals(computedIborLeg.values().asList(), valueComputedFull.subList(2, 6)); double eps = 1.0e-7; RatesFiniteDifferenceSensitivityCalculator calc = new RatesFiniteDifferenceSensitivityCalculator(eps); int size = keyComputedFull.size(); for (int i = 0; i < size; ++i) { final int index = i; CurveCurrencyParameterSensitivities expected = calc.sensitivity( PROVIDER, p -> ((NotionalExchange) CashFlowEquivalentCalculator.cashFlowEquivalentSwap(swap.expand(), p) .getPaymentEvents() .get(index)) .getPaymentAmount()); PointSensitivityBuilder point = computedFull.get( CashFlowEquivalentCalculator.cashFlowEquivalentSwap(swap.expand(), PROVIDER) .getPaymentEvents() .get(index)); CurveCurrencyParameterSensitivities computed = PROVIDER.curveParameterSensitivity(point.build()); assertTrue(computed.equalWithTolerance(expected, eps * NOTIONAL)); } }
/** * Calculates the present value of the swaption product. * * <p>The result is expressed using the currency of the swapion. * * @param swaption the product to price * @param ratesProvider the rates provider * @param volatilityProvider the normal volatility provider * @return the present value of the swaption product */ public CurrencyAmount presentValue( SwaptionProduct swaption, RatesProvider ratesProvider, NormalVolatilitySwaptionProvider volatilityProvider) { ExpandedSwaption expanded = swaption.expand(); validate(ratesProvider, expanded, volatilityProvider); ZonedDateTime expiryDateTime = expanded.getExpiryDateTime(); double expiry = volatilityProvider.relativeTime(expiryDateTime); ExpandedSwap underlying = expanded.getUnderlying(); ExpandedSwapLeg fixedLeg = fixedLeg(underlying); if (expiry < 0.0d) { // Option has expired already return CurrencyAmount.of(fixedLeg.getCurrency(), 0.0d); } double forward = swapPricer.parRate(underlying, ratesProvider); double pvbp = swapPricer.getLegPricer().pvbp(fixedLeg, ratesProvider); double strike = swapPricer.getLegPricer().couponEquivalent(fixedLeg, ratesProvider, pvbp); double tenor = volatilityProvider.tenor(fixedLeg.getStartDate(), fixedLeg.getEndDate()); double volatility = volatilityProvider.getVolatility(expiryDateTime, tenor, strike, forward); NormalFunctionData normalData = NormalFunctionData.of(forward, Math.abs(pvbp), volatility); boolean isCall = (fixedLeg.getPayReceive() == PayReceive.PAY); // Payer at strike is exercise when rate > strike, i.e. call on rate EuropeanVanillaOption option = EuropeanVanillaOption.of(strike, expiry, isCall ? PutCall.CALL : PutCall.PUT); // option required to pass the strike (in case the swap has non-constant coupon). Function1D<NormalFunctionData, Double> func = NORMAL.getPriceFunction(option); double pv = func.evaluate(normalData) * ((expanded.getLongShort() == LongShort.LONG) ? 1.0 : -1.0); return CurrencyAmount.of(fixedLeg.getCurrency(), pv); }
/** Test {@link CashFlowEquivalentCalculator}. */ @Test public class CashFlowEquivalentCalculatorTest { // setup private static final LocalDate PAYMENT1 = date(2014, 10, 6); private static final LocalDate START1 = date(2014, 7, 2); private static final LocalDate END1 = date(2014, 10, 2); private static final LocalDate FIXING1 = date(2014, 6, 30); private static final double PAY_YC1 = 0.251; private static final LocalDate PAYMENT2 = date(2015, 1, 4); private static final LocalDate START2 = date(2014, 10, 2); private static final LocalDate END2 = date(2015, 1, 2); private static final LocalDate FIXING2 = date(2014, 9, 30); private static final double PAY_YC2 = 0.249; private static final double RATE = 0.0123d; private static final double NOTIONAL = 100_000_000; // accrual periods private static final RateAccrualPeriod IBOR1 = RateAccrualPeriod.builder() .startDate(START1) .endDate(END1) .rateObservation(IborRateObservation.of(GBP_LIBOR_3M, FIXING1)) .yearFraction(PAY_YC1) .build(); private static final RateAccrualPeriod IBOR2 = RateAccrualPeriod.builder() .startDate(START2) .endDate(END2) .rateObservation(IborRateObservation.of(GBP_LIBOR_3M, FIXING2)) .yearFraction(PAY_YC2) .build(); private static final RateAccrualPeriod FIXED1 = RateAccrualPeriod.builder() .startDate(START1) .endDate(END1) .rateObservation(FixedRateObservation.of(RATE)) .yearFraction(PAY_YC1) .build(); private static final RateAccrualPeriod FIXED2 = RateAccrualPeriod.builder() .startDate(START2) .endDate(END2) .rateObservation(FixedRateObservation.of(RATE)) .yearFraction(PAY_YC2) .build(); // Ibor leg private static final RatePaymentPeriod IBOR_RATE_PAYMENT1 = RatePaymentPeriod.builder() .paymentDate(PAYMENT1) .accrualPeriods(IBOR1) .dayCount(ACT_365F) .currency(GBP) .notional(-NOTIONAL) .build(); private static final RatePaymentPeriod IBOR_RATE_PAYMENT2 = RatePaymentPeriod.builder() .paymentDate(PAYMENT2) .accrualPeriods(IBOR2) .dayCount(ACT_365F) .currency(GBP) .notional(-NOTIONAL) .build(); private static final ExpandedSwapLeg IBOR_LEG = ExpandedSwapLeg.builder() .type(IBOR) .payReceive(PAY) .paymentPeriods(IBOR_RATE_PAYMENT1, IBOR_RATE_PAYMENT2) .build(); // fixed leg private static final RatePaymentPeriod FIXED_RATE_PAYMENT1 = RatePaymentPeriod.builder() .paymentDate(PAYMENT1) .accrualPeriods(FIXED1) .dayCount(ACT_365F) .currency(GBP) .notional(NOTIONAL) .build(); private static final RatePaymentPeriod FIXED_RATE_PAYMENT2 = RatePaymentPeriod.builder() .paymentDate(PAYMENT2) .accrualPeriods(FIXED2) .dayCount(ACT_365F) .currency(GBP) .notional(NOTIONAL) .build(); private static final ExpandedSwapLeg FIXED_LEG = ExpandedSwapLeg.builder() .type(FIXED) .payReceive(RECEIVE) .paymentPeriods(FIXED_RATE_PAYMENT1, FIXED_RATE_PAYMENT2) .build(); private static final ImmutableRatesProvider PROVIDER = RatesProviderDataSets.MULTI_GBP; private static final double TOLERANCE_PV = 1.0E-2; public void test_cashFlowEquivalent() { Swap swap = Swap.builder().legs(IBOR_LEG, FIXED_LEG).build(); ExpandedSwapLeg computed = CashFlowEquivalentCalculator.cashFlowEquivalentSwap(swap.expand(), PROVIDER); ExpandedSwapLeg computedIborLeg = CashFlowEquivalentCalculator.cashFlowEquivalentIborLeg(IBOR_LEG.expand(), PROVIDER); ExpandedSwapLeg computedFixedLeg = CashFlowEquivalentCalculator.cashFlowEquivalentFixedLeg(FIXED_LEG.expand(), PROVIDER); assertEquals(computedFixedLeg.getPaymentEvents(), computed.getPaymentEvents().subList(0, 2)); assertEquals(computedIborLeg.getPaymentEvents(), computed.getPaymentEvents().subList(2, 6)); // expected payments from fixed leg NotionalExchange fixedPayment1 = NotionalExchange.of(PAYMENT1, CurrencyAmount.of(GBP, NOTIONAL * RATE * PAY_YC1)); NotionalExchange fixedPayment2 = NotionalExchange.of(PAYMENT2, CurrencyAmount.of(GBP, NOTIONAL * RATE * PAY_YC2)); // expected payments from ibor leg LocalDate fixingSTART1 = GBP_LIBOR_3M.calculateEffectiveFromFixing(FIXING1); double fixedYearFraction1 = GBP_LIBOR_3M .getDayCount() .relativeYearFraction( fixingSTART1, GBP_LIBOR_3M.calculateMaturityFromEffective(fixingSTART1)); double beta1 = (1d + fixedYearFraction1 * PROVIDER.iborIndexRates(GBP_LIBOR_3M).rate(FIXING1)) * PROVIDER.discountFactor(GBP, PAYMENT1) / PROVIDER.discountFactor(GBP, fixingSTART1); NotionalExchange iborPayment11 = NotionalExchange.of( fixingSTART1, CurrencyAmount.of(GBP, -NOTIONAL * beta1 * PAY_YC1 / fixedYearFraction1)); NotionalExchange iborPayment12 = NotionalExchange.of( PAYMENT1, CurrencyAmount.of(GBP, NOTIONAL * PAY_YC1 / fixedYearFraction1)); LocalDate fixingSTART2 = GBP_LIBOR_3M.calculateEffectiveFromFixing(FIXING2); double fixedYearFraction2 = GBP_LIBOR_3M .getDayCount() .relativeYearFraction( fixingSTART2, GBP_LIBOR_3M.calculateMaturityFromEffective(fixingSTART2)); double beta2 = (1d + fixedYearFraction2 * PROVIDER.iborIndexRates(GBP_LIBOR_3M).rate(FIXING2)) * PROVIDER.discountFactor(GBP, PAYMENT2) / PROVIDER.discountFactor(GBP, fixingSTART2); NotionalExchange iborPayment21 = NotionalExchange.of( fixingSTART2, CurrencyAmount.of(GBP, -NOTIONAL * beta2 * PAY_YC2 / fixedYearFraction2)); NotionalExchange iborPayment22 = NotionalExchange.of( PAYMENT2, CurrencyAmount.of(GBP, NOTIONAL * PAY_YC2 / fixedYearFraction2)); ExpandedSwapLeg expected = ExpandedSwapLeg.builder() .type(OTHER) .payReceive(RECEIVE) .paymentEvents( fixedPayment1, fixedPayment2, iborPayment11, iborPayment12, iborPayment21, iborPayment22) .build(); double eps = 1.0e-12; assertEquals(computed.getPaymentEvents().size(), expected.getPaymentEvents().size()); for (int i = 0; i < 6; ++i) { NotionalExchange payCmp = (NotionalExchange) computed.getPaymentEvents().get(i); NotionalExchange payExp = (NotionalExchange) expected.getPaymentEvents().get(i); assertEquals(payCmp.getCurrency(), payExp.getCurrency()); assertEquals(payCmp.getPaymentDate(), payExp.getPaymentDate()); assertTrue( DoubleMath.fuzzyEquals( payCmp.getPaymentAmount().getAmount(), payExp.getPaymentAmount().getAmount(), NOTIONAL * eps)); } } public void test_cashFlowEquivalent_pv() { Swap swap = Swap.builder().legs(IBOR_LEG, FIXED_LEG).build(); ExpandedSwapLeg cfe = CashFlowEquivalentCalculator.cashFlowEquivalentSwap(swap.expand(), PROVIDER); DiscountingSwapLegPricer pricerLeg = DiscountingSwapLegPricer.DEFAULT; DiscountingSwapProductPricer pricerSwap = DiscountingSwapProductPricer.DEFAULT; CurrencyAmount pvCfe = pricerLeg.presentValue(cfe, PROVIDER); MultiCurrencyAmount pvSwap = pricerSwap.presentValue(swap, PROVIDER); assertEquals(pvCfe.getAmount(), pvSwap.getAmount(GBP).getAmount(), TOLERANCE_PV); } public void test_cashFlowEquivalent_compounding() { RatePaymentPeriod iborCmp = RatePaymentPeriod.builder() .paymentDate(PAYMENT2) .accrualPeriods(IBOR1, IBOR2) .dayCount(ACT_365F) .currency(GBP) .notional(-NOTIONAL) .build(); ExpandedSwapLeg iborLegCmp = ExpandedSwapLeg.builder().type(IBOR).payReceive(PAY).paymentPeriods(iborCmp).build(); Swap swap1 = Swap.builder().legs(iborLegCmp, FIXED_LEG).build(); assertThrowsIllegalArg( () -> CashFlowEquivalentCalculator.cashFlowEquivalentSwap(swap1.expand(), PROVIDER)); RatePaymentPeriod fixedCmp = RatePaymentPeriod.builder() .paymentDate(PAYMENT2) .accrualPeriods(FIXED1, FIXED2) .dayCount(ACT_365F) .currency(GBP) .notional(NOTIONAL) .build(); ExpandedSwapLeg fixedLegCmp = ExpandedSwapLeg.builder().type(FIXED).payReceive(RECEIVE).paymentPeriods(fixedCmp).build(); Swap swap2 = Swap.builder().legs(IBOR_LEG, fixedLegCmp).build(); assertThrowsIllegalArg( () -> CashFlowEquivalentCalculator.cashFlowEquivalentSwap(swap2.expand(), PROVIDER)); } public void test_cashFlowEquivalent_wrongSwap() { Swap swap1 = Swap.builder().legs(IBOR_LEG, FIXED_LEG, IBOR_LEG).build(); assertThrowsIllegalArg( () -> CashFlowEquivalentCalculator.cashFlowEquivalentSwap(swap1.expand(), PROVIDER)); Swap swap2 = Swap.builder().legs(FIXED_LEG, FIXED_LEG).build(); assertThrowsIllegalArg( () -> CashFlowEquivalentCalculator.cashFlowEquivalentSwap(swap2.expand(), PROVIDER)); Swap swap3 = Swap.builder() .legs( FIXED_LEG, CashFlowEquivalentCalculator.cashFlowEquivalentIborLeg(IBOR_LEG, PROVIDER)) .build(); assertThrowsIllegalArg( () -> CashFlowEquivalentCalculator.cashFlowEquivalentSwap(swap3.expand(), PROVIDER)); } // ------------------------------------------------------------------------- public void test_cashFlowEquivalentAndSensitivity() { Swap swap = Swap.builder().legs(IBOR_LEG, FIXED_LEG).build(); ImmutableMap<NotionalExchange, PointSensitivityBuilder> computedFull = CashFlowEquivalentCalculator.cashFlowEquivalentAndSensitivitySwap(swap.expand(), PROVIDER); ImmutableList<NotionalExchange> keyComputedFull = computedFull.keySet().asList(); ImmutableList<PointSensitivityBuilder> valueComputedFull = computedFull.values().asList(); ImmutableMap<NotionalExchange, PointSensitivityBuilder> computedIborLeg = CashFlowEquivalentCalculator.cashFlowEquivalentAndSensitivityIborLeg( IBOR_LEG.expand(), PROVIDER); ImmutableMap<NotionalExchange, PointSensitivityBuilder> computedFixedLeg = CashFlowEquivalentCalculator.cashFlowEquivalentAndSensitivityFixedLeg( FIXED_LEG.expand(), PROVIDER); assertEquals(computedFixedLeg.keySet().asList(), keyComputedFull.subList(0, 2)); assertEquals(computedIborLeg.keySet().asList(), keyComputedFull.subList(2, 6)); assertEquals(computedFixedLeg.values().asList(), valueComputedFull.subList(0, 2)); assertEquals(computedIborLeg.values().asList(), valueComputedFull.subList(2, 6)); double eps = 1.0e-7; RatesFiniteDifferenceSensitivityCalculator calc = new RatesFiniteDifferenceSensitivityCalculator(eps); int size = keyComputedFull.size(); for (int i = 0; i < size; ++i) { final int index = i; CurveCurrencyParameterSensitivities expected = calc.sensitivity( PROVIDER, p -> ((NotionalExchange) CashFlowEquivalentCalculator.cashFlowEquivalentSwap(swap.expand(), p) .getPaymentEvents() .get(index)) .getPaymentAmount()); PointSensitivityBuilder point = computedFull.get( CashFlowEquivalentCalculator.cashFlowEquivalentSwap(swap.expand(), PROVIDER) .getPaymentEvents() .get(index)); CurveCurrencyParameterSensitivities computed = PROVIDER.curveParameterSensitivity(point.build()); assertTrue(computed.equalWithTolerance(expected, eps * NOTIONAL)); } } public void test_cashFlowEquivalentAndSensitivity_compounding() { RatePaymentPeriod iborCmp = RatePaymentPeriod.builder() .paymentDate(PAYMENT2) .accrualPeriods(IBOR1, IBOR2) .dayCount(ACT_365F) .currency(GBP) .notional(-NOTIONAL) .build(); ExpandedSwapLeg iborLegCmp = ExpandedSwapLeg.builder().type(IBOR).payReceive(PAY).paymentPeriods(iborCmp).build(); Swap swap1 = Swap.builder().legs(iborLegCmp, FIXED_LEG).build(); assertThrowsIllegalArg( () -> CashFlowEquivalentCalculator.cashFlowEquivalentAndSensitivitySwap( swap1.expand(), PROVIDER)); RatePaymentPeriod fixedCmp = RatePaymentPeriod.builder() .paymentDate(PAYMENT2) .accrualPeriods(FIXED1, FIXED2) .dayCount(ACT_365F) .currency(GBP) .notional(NOTIONAL) .build(); ExpandedSwapLeg fixedLegCmp = ExpandedSwapLeg.builder().type(FIXED).payReceive(RECEIVE).paymentPeriods(fixedCmp).build(); Swap swap2 = Swap.builder().legs(IBOR_LEG, fixedLegCmp).build(); assertThrowsIllegalArg( () -> CashFlowEquivalentCalculator.cashFlowEquivalentAndSensitivitySwap( swap2.expand(), PROVIDER)); } public void test_cashFlowEquivalentAndSensitivity_wrongSwap() { Swap swap1 = Swap.builder().legs(IBOR_LEG, FIXED_LEG, IBOR_LEG).build(); assertThrowsIllegalArg( () -> CashFlowEquivalentCalculator.cashFlowEquivalentAndSensitivitySwap( swap1.expand(), PROVIDER)); Swap swap2 = Swap.builder().legs(FIXED_LEG, FIXED_LEG).build(); assertThrowsIllegalArg( () -> CashFlowEquivalentCalculator.cashFlowEquivalentAndSensitivitySwap( swap2.expand(), PROVIDER)); Swap swap3 = Swap.builder() .legs( FIXED_LEG, CashFlowEquivalentCalculator.cashFlowEquivalentIborLeg(IBOR_LEG, PROVIDER)) .build(); assertThrowsIllegalArg( () -> CashFlowEquivalentCalculator.cashFlowEquivalentAndSensitivitySwap( swap3.expand(), PROVIDER)); } }
public void test_cashFlowEquivalent() { Swap swap = Swap.builder().legs(IBOR_LEG, FIXED_LEG).build(); ExpandedSwapLeg computed = CashFlowEquivalentCalculator.cashFlowEquivalentSwap(swap.expand(), PROVIDER); ExpandedSwapLeg computedIborLeg = CashFlowEquivalentCalculator.cashFlowEquivalentIborLeg(IBOR_LEG.expand(), PROVIDER); ExpandedSwapLeg computedFixedLeg = CashFlowEquivalentCalculator.cashFlowEquivalentFixedLeg(FIXED_LEG.expand(), PROVIDER); assertEquals(computedFixedLeg.getPaymentEvents(), computed.getPaymentEvents().subList(0, 2)); assertEquals(computedIborLeg.getPaymentEvents(), computed.getPaymentEvents().subList(2, 6)); // expected payments from fixed leg NotionalExchange fixedPayment1 = NotionalExchange.of(PAYMENT1, CurrencyAmount.of(GBP, NOTIONAL * RATE * PAY_YC1)); NotionalExchange fixedPayment2 = NotionalExchange.of(PAYMENT2, CurrencyAmount.of(GBP, NOTIONAL * RATE * PAY_YC2)); // expected payments from ibor leg LocalDate fixingSTART1 = GBP_LIBOR_3M.calculateEffectiveFromFixing(FIXING1); double fixedYearFraction1 = GBP_LIBOR_3M .getDayCount() .relativeYearFraction( fixingSTART1, GBP_LIBOR_3M.calculateMaturityFromEffective(fixingSTART1)); double beta1 = (1d + fixedYearFraction1 * PROVIDER.iborIndexRates(GBP_LIBOR_3M).rate(FIXING1)) * PROVIDER.discountFactor(GBP, PAYMENT1) / PROVIDER.discountFactor(GBP, fixingSTART1); NotionalExchange iborPayment11 = NotionalExchange.of( fixingSTART1, CurrencyAmount.of(GBP, -NOTIONAL * beta1 * PAY_YC1 / fixedYearFraction1)); NotionalExchange iborPayment12 = NotionalExchange.of( PAYMENT1, CurrencyAmount.of(GBP, NOTIONAL * PAY_YC1 / fixedYearFraction1)); LocalDate fixingSTART2 = GBP_LIBOR_3M.calculateEffectiveFromFixing(FIXING2); double fixedYearFraction2 = GBP_LIBOR_3M .getDayCount() .relativeYearFraction( fixingSTART2, GBP_LIBOR_3M.calculateMaturityFromEffective(fixingSTART2)); double beta2 = (1d + fixedYearFraction2 * PROVIDER.iborIndexRates(GBP_LIBOR_3M).rate(FIXING2)) * PROVIDER.discountFactor(GBP, PAYMENT2) / PROVIDER.discountFactor(GBP, fixingSTART2); NotionalExchange iborPayment21 = NotionalExchange.of( fixingSTART2, CurrencyAmount.of(GBP, -NOTIONAL * beta2 * PAY_YC2 / fixedYearFraction2)); NotionalExchange iborPayment22 = NotionalExchange.of( PAYMENT2, CurrencyAmount.of(GBP, NOTIONAL * PAY_YC2 / fixedYearFraction2)); ExpandedSwapLeg expected = ExpandedSwapLeg.builder() .type(OTHER) .payReceive(RECEIVE) .paymentEvents( fixedPayment1, fixedPayment2, iborPayment11, iborPayment12, iborPayment21, iborPayment22) .build(); double eps = 1.0e-12; assertEquals(computed.getPaymentEvents().size(), expected.getPaymentEvents().size()); for (int i = 0; i < 6; ++i) { NotionalExchange payCmp = (NotionalExchange) computed.getPaymentEvents().get(i); NotionalExchange payExp = (NotionalExchange) expected.getPaymentEvents().get(i); assertEquals(payCmp.getCurrency(), payExp.getCurrency()); assertEquals(payCmp.getPaymentDate(), payExp.getPaymentDate()); assertTrue( DoubleMath.fuzzyEquals( payCmp.getPaymentAmount().getAmount(), payExp.getPaymentAmount().getAmount(), NOTIONAL * eps)); } }