//-------------------------------------------------------------------------
        /// <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);
        }
Пример #4
0
        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));
            }
        }