//-------------------------------------------------------------------------
        /// <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)));
        }
        //-------------------------------------------------------------------------
        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);
        }
Beispiel #3
0
        public virtual void test_futuresConvexityFactorAdjoint()
        {
            HullWhiteOneFactorPiecewiseConstantParametersProvider provider = HullWhiteOneFactorPiecewiseConstantParametersProvider.of(PARAMETERS, ACT_360, DATE_TIME);
            LocalDate        data1    = LocalDate.of(2015, 5, 14);
            LocalDate        data2    = LocalDate.of(2015, 5, 20);
            LocalDate        data3    = LocalDate.of(2015, 8, 20);
            ValueDerivatives computed = provider.futuresConvexityFactorAdjoint(data1, data2, data3);
            ValueDerivatives expected = HullWhiteOneFactorPiecewiseConstantInterestRateModel.DEFAULT.futuresConvexityFactorAdjoint(PARAMETERS, ACT_360.relativeYearFraction(VAL_DATE, data1), ACT_360.relativeYearFraction(VAL_DATE, data2), ACT_360.relativeYearFraction(VAL_DATE, data3));

            assertEquals(computed, expected);
        }
Beispiel #4
0
        //-------------------------------------------------------------------------
        public virtual void coverage()
        {
            DeformedSurface test1 = DeformedSurface.of(METADATA, SURFACE_ORG, FUNCTION);

            coverImmutableBean(test1);
            Surface         surface1 = InterpolatedNodalSurface.of(DefaultSurfaceMetadata.of("TestSurface1"), XVALUES, YVALUES, ZVALUES, INTERPOLATOR);
            DeformedSurface test2    = DeformedSurface.of(DefaultSurfaceMetadata.of("DeformedTestSurface1"), surface1, (DoublesPair x) =>
            {
                return(ValueDerivatives.of(surface1.zValue(x), surface1.zValueParameterSensitivity(x).Sensitivity));
            });

            coverBeanEquals(test1, test2);
        }
Beispiel #5
0
        public virtual void implied_volatility_adjoint()
        {
            double shiftFd = 1.0E-6;

            for (int i = 0; i < N; i++)
            {
                double           impliedVol    = NormalFormulaRepository.impliedVolatilityFromBlackApproximated(FORWARD, STRIKES[i], T, SIGMA_BLACK[i]);
                ValueDerivatives impliedVolAdj = NormalFormulaRepository.impliedVolatilityFromBlackApproximatedAdjoint(FORWARD, STRIKES[i], T, SIGMA_BLACK[i]);
                assertEquals(impliedVolAdj.Value, impliedVol, TOLERANCE_VOL);
                double impliedVolP            = NormalFormulaRepository.impliedVolatilityFromBlackApproximated(FORWARD, STRIKES[i], T, SIGMA_BLACK[i] + shiftFd);
                double impliedVolM            = NormalFormulaRepository.impliedVolatilityFromBlackApproximated(FORWARD, STRIKES[i], T, SIGMA_BLACK[i] - shiftFd);
                double derivativeApproximated = (impliedVolP - impliedVolM) / (2 * shiftFd);
                assertEquals(impliedVolAdj.Derivatives.size(), 1);
                assertEquals(impliedVolAdj.getDerivative(0), derivativeApproximated, TOLERANCE_VOL);
            }
        }
Beispiel #6
0
        public virtual void test_zValue()
        {
            double                   tol            = 1.0e-14;
            double                   x              = 2.5;
            double                   y              = 1.44;
            DeformedSurface          test           = DeformedSurface.of(METADATA, SURFACE_ORG, FUNCTION);
            double                   computedValue1 = test.zValue(x, y);
            double                   computedValue2 = test.zValue(DoublesPair.of(x, y));
            UnitParameterSensitivity computedSensi1 = test.zValueParameterSensitivity(x, y);
            UnitParameterSensitivity computedSensi2 = test.zValueParameterSensitivity(DoublesPair.of(x, y));
            ValueDerivatives         expected       = FUNCTION.apply(DoublesPair.of(x, y));

            assertEquals(computedValue1, expected.Value);
            assertEquals(computedValue2, expected.Value);
            assertTrue(DoubleArrayMath.fuzzyEquals(computedSensi1.Sensitivity.toArray(), expected.Derivatives.toArray(), tol));
            assertTrue(DoubleArrayMath.fuzzyEquals(computedSensi2.Sensitivity.toArray(), expected.Derivatives.toArray(), tol));
        }
Beispiel #7
0
        /// <summary>
        /// Tests the strikes computations.
        /// </summary>
        public virtual void strike()
        {
            double[]    strike     = SMILE.strike(FORWARD).toArrayUnsafe();
            DoubleArray volatility = SMILE.Volatility;
            int         nbDelta    = DELTA.size();

            for (int loopdelta = 0; loopdelta < nbDelta; loopdelta++)
            {
                ValueDerivatives dPut = BlackFormulaRepository.priceAdjoint(FORWARD, strike[loopdelta], TIME_TO_EXPIRY, volatility.get(loopdelta), false);
                assertEquals(-DELTA.get(loopdelta), dPut.getDerivative(0), 1e-8, "Strike: Put " + loopdelta);
                ValueDerivatives dCall = BlackFormulaRepository.priceAdjoint(FORWARD, strike[2 * nbDelta - loopdelta], TIME_TO_EXPIRY, volatility.get(2 * nbDelta - loopdelta), true);
                assertEquals(DELTA.get(loopdelta), dCall.getDerivative(0), 1e-8, "Strike: Call " + loopdelta);
            }
            ValueDerivatives dPut  = BlackFormulaRepository.priceAdjoint(FORWARD, strike[nbDelta], TIME_TO_EXPIRY, volatility.get(nbDelta), false);
            ValueDerivatives dCall = BlackFormulaRepository.priceAdjoint(FORWARD, strike[nbDelta], TIME_TO_EXPIRY, volatility.get(nbDelta), true);

            assertEquals(0.0, dCall.getDerivative(0) + dPut.getDerivative(0), 1e-8, "Strike: ATM");
        }
        public virtual void test_volatility()
        {
            SabrParametersIborCapletFloorletVolatilities prov = SabrParametersIborCapletFloorletVolatilities.of(NAME, EUR_EURIBOR_3M, DATE_TIME, PARAM);

            for (int i = 0; i < NB_TEST; i++)
            {
                for (int j = 0; j < NB_STRIKE; ++j)
                {
                    double expiryTime  = prov.relativeTime(TEST_OPTION_EXPIRY[i]);
                    double volExpected = PARAM.volatility(expiryTime, TEST_STRIKE[j], TEST_FORWARD);
                    double volComputed = prov.volatility(TEST_OPTION_EXPIRY[i], TEST_STRIKE[j], TEST_FORWARD);
                    assertEquals(volComputed, volExpected, TOLERANCE_VOL);
                    ValueDerivatives volAdjExpected = PARAM.volatilityAdjoint(expiryTime, TEST_STRIKE[j], TEST_FORWARD);
                    ValueDerivatives volAdjComputed = prov.volatilityAdjoint(expiryTime, TEST_STRIKE[j], TEST_FORWARD);
                    assertEquals(volAdjComputed.Value, volExpected, TOLERANCE_VOL);
                    assertTrue(DoubleArrayMath.fuzzyEquals(volAdjComputed.Derivatives.toArray(), volAdjExpected.Derivatives.toArray(), TOLERANCE_VOL));
                }
            }
        }
Beispiel #9
0
        //-------------------------------------------------------------------------
        /// <summary>
        /// Evaluates the function and its first derivative.
        /// <para>
        /// The dimension of {@code PiecewisePolynomialResult} must be 1.
        ///
        /// </para>
        /// </summary>
        /// <param name="pp">  the PiecewisePolynomialResult </param>
        /// <param name="xKey">  the key </param>
        /// <returns> the value and derivative </returns>
        public virtual ValueDerivatives evaluateAndDifferentiate(PiecewisePolynomialResult pp, double xKey)
        {
            ArgChecker.notNull(pp, "null pp");
            ArgChecker.isFalse(double.IsNaN(xKey), "xKey containing NaN");
            ArgChecker.isFalse(double.IsInfinity(xKey), "xKey containing Infinity");

            if (pp.Dimensions > 1)
            {
                throw new System.NotSupportedException();
            }

            DoubleArray knots    = pp.Knots;
            int         nKnots   = knots.size();
            int         interval = FunctionUtils.getLowerBoundIndex(knots, xKey);

            if (interval == nKnots - 1)
            {
                interval--;   // there is 1 less interval that knots
            }

            double      s      = xKey - knots.get(interval);
            DoubleArray coefs  = pp.CoefMatrix.row(interval);
            int         nCoefs = coefs.size();

            double resValue = coefs.get(0);
            double resDeriv = coefs.get(0) * (nCoefs - 1);

            for (int i = 1; i < nCoefs - 1; i++)
            {
                resValue *= s;
                resValue += coefs.get(i);
                resDeriv *= s;
                resDeriv += coefs.get(i) * (nCoefs - i - 1);
                ArgChecker.isFalse(double.IsInfinity(resValue), "Too large input");
                ArgChecker.isFalse(double.IsNaN(resValue), "Too large input");
            }
            resValue *= s;
            resValue += coefs.get(nCoefs - 1);

            return(ValueDerivatives.of(resValue, DoubleArray.of(resDeriv)));
        }
        public virtual void flatVolPriceTest()
        {
            double          tol               = 2.0e-2;
            double          constantVol       = 0.15;
            double          spot              = 100d;
            double          maxTime           = 1d;
            int             nSteps            = 9;
            ConstantSurface impliedVolSurface = ConstantSurface.of("impliedVol", constantVol);

            System.Func <double, double> zeroRate = (double?x) =>
            {
                return(0d);
            };
            System.Func <DoublesPair, ValueDerivatives> func = (DoublesPair x) =>
            {
                double price = BlackFormulaRepository.price(spot, x.Second, x.First, constantVol, true);
                return(ValueDerivatives.of(price, DoubleArray.EMPTY));
            };
            DeformedSurface priceSurface = DeformedSurface.of(DefaultSurfaceMetadata.of("price"), impliedVolSurface, func);
            ImpliedTrinomialTreeLocalVolatilityCalculator calc = new ImpliedTrinomialTreeLocalVolatilityCalculator(nSteps, maxTime, INTERP_TIMESQ_LINEAR);
            InterpolatedNodalSurface localVolSurface           = calc.localVolatilityFromPrice(priceSurface, spot, zeroRate, zeroRate);

            assertEquals(localVolSurface.ZValues.Where(d => !DoubleMath.fuzzyEquals(d, constantVol, tol)).Count(), 0);
        }