//-------------------------------------------------------------------------
        /// <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))));
        }
        /// <summary>
        /// Calculates the price sensitivity to the Black volatility used for the pricing of the bond future option
        /// based on the price of the underlying future.
        /// </summary>
        /// <param name="futureOption">  the option product </param>
        /// <param name="discountingProvider">  the discounting provider </param>
        /// <param name="volatilities">  the volatilities </param>
        /// <param name="futurePrice">  the underlying future price </param>
        /// <returns> the sensitivity </returns>
        public BondFutureOptionSensitivity priceSensitivityModelParamsVolatility(ResolvedBondFutureOption futureOption, LegalEntityDiscountingProvider discountingProvider, BlackBondFutureVolatilities volatilities, double futurePrice)
        {
            ArgChecker.isTrue(futureOption.PremiumStyle.Equals(FutureOptionPremiumStyle.DAILY_MARGIN), "Premium style should be DAILY_MARGIN");
            double             strike       = futureOption.StrikePrice;
            ResolvedBondFuture future       = futureOption.UnderlyingFuture;
            double             volatility   = volatilities.volatility(futureOption.Expiry, future.LastTradeDate, strike, futurePrice);
            double             timeToExpiry = volatilities.relativeTime(futureOption.Expiry);
            double             vega         = BlackFormulaRepository.vega(futurePrice, strike, timeToExpiry, volatility);

            return(BondFutureOptionSensitivity.of(volatilities.Name, timeToExpiry, future.LastTradeDate, strike, futurePrice, future.Currency, vega));
        }
Example #4
0
        //-------------------------------------------------------------------------
        private double[] weights(double forward, double strike, double[] strikes, double timeToExpiry, double atmVol)
        {
//JAVA TO C# CONVERTER NOTE: The following call to the 'RectangularArrays' helper class reproduces the rectangular array initialization that is automatic in Java:
//ORIGINAL LINE: double[][] mat = new double[3][3];
            double[][] mat = RectangularArrays.ReturnRectangularDoubleArray(3, 3);
            double[]   vec = new double[3];
            for (int i = 0; i < 3; ++i)
            {
                mat[0][i] = BlackFormulaRepository.vega(forward, strikes[i], timeToExpiry, atmVol);
                mat[1][i] = BlackFormulaRepository.vanna(forward, strikes[i], timeToExpiry, atmVol);
                mat[2][i] = BlackFormulaRepository.volga(forward, strikes[i], timeToExpiry, atmVol);
            }
            vec[0] = BlackFormulaRepository.vega(forward, strike, timeToExpiry, atmVol);
            vec[1] = BlackFormulaRepository.vanna(forward, strike, timeToExpiry, atmVol);
            vec[2] = BlackFormulaRepository.volga(forward, strike, timeToExpiry, atmVol);
            DecompositionResult res = SVD.apply(DoubleMatrix.ofUnsafe(mat));

            return(res.solve(vec));
        }
        //-------------------------------------------------------------------------
        public virtual void test_vega_presentValueVega()
        {
            double         vegaCall       = PRICER.vega(CALL_OTM, RATES_PROVIDER, VOLS);
            CurrencyAmount pvVegaCall     = PRICER.presentValueVega(CALL_OTM, RATES_PROVIDER, VOLS);
            double         vegaPut        = PRICER.vega(PUT_ITM, RATES_PROVIDER, VOLS);
            CurrencyAmount pvVegaPut      = PRICER.presentValueVega(PUT_ITM, RATES_PROVIDER, VOLS);
            double         timeToExpiry   = VOLS.relativeTime(EXPIRY);
            double         dfDom          = RATES_PROVIDER.discountFactor(USD, PAYMENT_DATE);
            double         forward        = PRICER.DiscountingFxSingleProductPricer.forwardFxRate(FX_PRODUCT_HIGH, RATES_PROVIDER).fxRate(CURRENCY_PAIR);
            double         vol            = SMILE_TERM.volatility(timeToExpiry, STRIKE_RATE_HIGH, forward);
            double         expectedVega   = dfDom * BlackFormulaRepository.vega(forward, STRIKE_RATE_HIGH, timeToExpiry, vol);
            double         expectedPvVega = -NOTIONAL *dfDom *BlackFormulaRepository.vega(forward, STRIKE_RATE_HIGH, timeToExpiry, vol);

            assertEquals(vegaCall, expectedVega, TOL);
            assertEquals(pvVegaCall.Currency, USD);
            assertEquals(pvVegaCall.Amount, expectedPvVega, NOTIONAL * TOL);
            assertEquals(vegaPut, expectedVega, TOL);
            assertEquals(pvVegaPut.Currency, USD);
            assertEquals(pvVegaPut.Amount, -expectedPvVega, NOTIONAL * TOL);
        }
Example #6
0
        //-------------------------------------------------------------------------
        public virtual void test_presentValueSensitivityVolatility()
        {
            for (int i = 0; i < NB_STRIKES; ++i)
            {
                PointSensitivities   computedCall = PRICER.presentValueSensitivityModelParamsVolatility(CALLS[i], RATES_PROVIDER, VOLS).build();
                double               timeToExpiry = VOLS.relativeTime(EXPIRY);
                FxRate               forward      = FX_PRICER.forwardFxRate(UNDERLYING[i], RATES_PROVIDER);
                double               forwardRate  = forward.fxRate(CURRENCY_PAIR);
                double               strikeRate   = CALLS[i].Strike;
                SmileDeltaParameters smileAtTime  = VOLS.Smile.smileForExpiry(timeToExpiry);
                double[]             strikes      = smileAtTime.strike(forwardRate).toArray();
                double[]             vols         = smileAtTime.Volatility.toArray();
                double               df           = RATES_PROVIDER.discountFactor(USD, PAY);
                double[]             weights      = this.weights(forwardRate, strikeRate, strikes, timeToExpiry, vols[1]);
                double[]             vegas        = new double[3];
                vegas[2] = BlackFormulaRepository.vega(forwardRate, strikeRate, timeToExpiry, vols[1]) * df * NOTIONAL;
                for (int j = 0; j < 3; j += 2)
                {
                    vegas[2] -= weights[j] * NOTIONAL *df *BlackFormulaRepository.vega(forwardRate, strikes[j], timeToExpiry, vols[1]);
                }
                vegas[0] = weights[0] * NOTIONAL *df *BlackFormulaRepository.vega(forwardRate, strikes[0], timeToExpiry, vols[0]);

                vegas[1] = weights[2] * NOTIONAL *df *BlackFormulaRepository.vega(forwardRate, strikes[2], timeToExpiry, vols[2]);

                double[] expStrikes = new double[] { strikes[0], strikes[2], strikes[1] };
                for (int j = 0; j < 3; ++j)
                {
                    FxOptionSensitivity sensi = (FxOptionSensitivity)computedCall.Sensitivities.get(j);
                    assertEquals(sensi.Sensitivity, vegas[j], TOL * NOTIONAL);
                    assertEquals(sensi.Strike, expStrikes[j], TOL);
                    assertEquals(sensi.Forward, forwardRate, TOL);
                    assertEquals(sensi.Currency, USD);
                    assertEquals(sensi.CurrencyPair, CURRENCY_PAIR);
                    assertEquals(sensi.Expiry, timeToExpiry);
                }
            }
        }
        //-------------------------------------------------------------------------
        public virtual void test_presentValueSensitivityBlackVolatility()
        {
            FxOptionSensitivity computedCall = (FxOptionSensitivity)PRICER.presentValueSensitivityModelParamsVolatility(CALL_OTM, RATES_PROVIDER, VOLS);
            FxOptionSensitivity computedPut  = (FxOptionSensitivity)PRICER.presentValueSensitivityModelParamsVolatility(PUT_ITM, RATES_PROVIDER, VOLS);
            double timeToExpiry          = VOLS.relativeTime(EXPIRY);
            double df                    = RATES_PROVIDER.discountFactor(USD, PAYMENT_DATE);
            double forward               = PRICER.DiscountingFxSingleProductPricer.forwardFxRate(FX_PRODUCT_HIGH, RATES_PROVIDER).fxRate(CURRENCY_PAIR);
            double vol                   = SMILE_TERM.volatility(timeToExpiry, STRIKE_RATE_HIGH, forward);
            FxOptionSensitivity expected = FxOptionSensitivity.of(VOLS.Name, CURRENCY_PAIR, timeToExpiry, STRIKE_RATE_HIGH, forward, USD, -NOTIONAL * df * BlackFormulaRepository.vega(forward, STRIKE_RATE_HIGH, timeToExpiry, vol));

            assertTrue(computedCall.build().equalWithTolerance(expected.build(), NOTIONAL * TOL));
            assertTrue(computedPut.build().equalWithTolerance(expected.build().multipliedBy(-1d), NOTIONAL * TOL));
        }
        //-------------------------------------------------------------------------
        public virtual void test_presentValueSensitivityVolatility()
        {
            PointSensitivities pointCaplet   = PRICER.presentValueSensitivityModelParamsSabr(CAPLET_LONG, RATES, VOLS).build();
            PointSensitivities pointFloorlet = PRICER.presentValueSensitivityModelParamsSabr(FLOORLET_SHORT, RATES, VOLS).build();
            double             forward       = RATES.iborIndexRates(EUR_EURIBOR_3M).rate(RATE_COMP.Observation);
            double             expiry        = VOLS.relativeTime(CAPLET_LONG.FixingDateTime);
            ValueDerivatives   volSensi      = VOLS.Parameters.volatilityAdjoint(expiry, STRIKE, forward);
            double             df            = RATES.discountFactor(EUR, CAPLET_LONG.PaymentDate);
            double             vegaCaplet    = NOTIONAL * df * CAPLET_LONG.YearFraction * BlackFormulaRepository.vega(forward + SHIFT, STRIKE + SHIFT, expiry, volSensi.Value);
            double             vegaFloorlet  = -NOTIONAL *df *CAPLET_LONG.YearFraction *BlackFormulaRepository.vega(forward + SHIFT, STRIKE + SHIFT, expiry, volSensi.Value);

            assertSensitivity(pointCaplet, SabrParameterType.ALPHA, vegaCaplet * volSensi.getDerivative(2), TOL);
            assertSensitivity(pointCaplet, SabrParameterType.BETA, vegaCaplet * volSensi.getDerivative(3), TOL);
            assertSensitivity(pointCaplet, SabrParameterType.RHO, vegaCaplet * volSensi.getDerivative(4), TOL);
            assertSensitivity(pointCaplet, SabrParameterType.NU, vegaCaplet * volSensi.getDerivative(5), TOL);
            assertSensitivity(pointFloorlet, SabrParameterType.ALPHA, vegaFloorlet * volSensi.getDerivative(2), TOL);
            assertSensitivity(pointFloorlet, SabrParameterType.BETA, vegaFloorlet * volSensi.getDerivative(3), TOL);
            assertSensitivity(pointFloorlet, SabrParameterType.RHO, vegaFloorlet * volSensi.getDerivative(4), TOL);
            assertSensitivity(pointFloorlet, SabrParameterType.NU, vegaFloorlet * volSensi.getDerivative(5), TOL);
            PointSensitivities pointCapletVol = PRICER.presentValueSensitivityModelParamsVolatility(CAPLET_LONG, RATES, VOLS).build();
            // vol sensitivity in base class
            PointSensitivities            pointFloorletVol    = PRICER.presentValueSensitivityModelParamsVolatility(FLOORLET_SHORT, RATES, VOLS).build();
            IborCapletFloorletSensitivity pointCapletVolExp   = IborCapletFloorletSensitivity.of(VOLS.Name, expiry, STRIKE, forward, EUR, vegaCaplet);
            IborCapletFloorletSensitivity pointFloorletVolExp = IborCapletFloorletSensitivity.of(VOLS.Name, expiry, STRIKE, forward, EUR, vegaFloorlet);

            assertEquals(pointCapletVol.Sensitivities.get(0), pointCapletVolExp);
            assertEquals(pointFloorletVol.Sensitivities.get(0), pointFloorletVolExp);
        }