/** * Creates a constant surface with a specific value. * * @param name the surface name * @param zValue the constant z-value * @return the surface */ public static ConstantSurface of(String name, double zValue) { return of(SurfaceName.of(name), zValue); }
public void test_serialization() { ConstantSurface test = ConstantSurface.of(SURFACE_NAME, VALUE); assertSerialization(test); }
public void test_of_String() { ConstantSurface test = ConstantSurface.of(NAME, VALUE); assertThat(test.getName()).isEqualTo(SURFACE_NAME); assertThat(test.getZValue()).isEqualTo(VALUE); assertThat(test.getParameterCount()).isEqualTo(1); assertThat(test.getParameter(0)).isEqualTo(VALUE); assertThat(test.getParameterMetadata(0)).isEqualTo(ParameterMetadata.empty()); assertThat(test.withParameter(0, 2d)).isEqualTo(ConstantSurface.of(NAME, 2d)); assertThat(test.withPerturbation((i, v, m) -> v + 1d)).isEqualTo(ConstantSurface.of(NAME, VALUE + 1d)); assertThat(test.getMetadata()).isEqualTo(METADATA); assertThat(test.withMetadata(METADATA2)).isEqualTo(ConstantSurface.of(METADATA2, VALUE)); }
public void test_of_SurfaceName() { ConstantSurface test = ConstantSurface.of(SURFACE_NAME, VALUE); assertThat(test.getName()).isEqualTo(SURFACE_NAME); assertThat(test.getZValue()).isEqualTo(VALUE); assertThat(test.getParameterCount()).isEqualTo(1); assertThat(test.getParameter(0)).isEqualTo(VALUE); assertThat(test.getParameterMetadata(0)).isEqualTo(ParameterMetadata.empty()); assertThat(test.withParameter(0, 2d)).isEqualTo(ConstantSurface.of(NAME, 2d)); assertThat(test.withPerturbation((i, v, m) -> v + 1d)).isEqualTo(ConstantSurface.of(NAME, VALUE + 1d)); assertThat(test.getMetadata()).isEqualTo(METADATA); assertThat(test.withMetadata(METADATA2)).isEqualTo(ConstantSurface.of(METADATA2, VALUE)); }
public void test_of_SurfaceMetadata() { ConstantSurface test = ConstantSurface.of(METADATA, VALUE); assertThat(test.getName()).isEqualTo(SURFACE_NAME); assertThat(test.getZValue()).isEqualTo(VALUE); assertThat(test.getParameterCount()).isEqualTo(1); assertThat(test.getParameter(0)).isEqualTo(VALUE); assertThat(test.getParameterMetadata(0)).isEqualTo(ParameterMetadata.empty()); assertThat(test.withParameter(0, 2d)).isEqualTo(ConstantSurface.of(NAME, 2d)); assertThat(test.withPerturbation((i, v, m) -> v + 1d)).isEqualTo(ConstantSurface.of(NAME, VALUE + 1d)); assertThat(test.getMetadata()).isEqualTo(METADATA); assertThat(test.withMetadata(METADATA2)).isEqualTo(ConstantSurface.of(METADATA2, VALUE)); }
public void flatVolTest() { double constantVol = 0.15; ConstantSurface impliedVolSurface = ConstantSurface.of("impliedVol", constantVol); Function<Double, Double> zeroRate = new Function<Double, Double>() { @Override public Double apply(Double x) { return 0.05d; } }; Function<Double, Double> zeroRate1 = new Function<Double, Double>() { @Override public Double apply(Double x) { return 0.02d; } }; double[] strikes = new double[] {90d, 100d, 115d }; for (double strike : strikes) { for (double time : TEST_TIMES) { DeformedSurface localVolSurface = CALC.localVolatilityFromImpliedVolatility(impliedVolSurface, 100d, zeroRate, zeroRate1); assertEquals(localVolSurface.zValue(time, strike), constantVol); } } }
public void test_lookup() { ConstantSurface test = ConstantSurface.of(SURFACE_NAME, VALUE); assertThat(test.zValue(0d, 0d)).isEqualTo(VALUE); assertThat(test.zValue(-10d, 10d)).isEqualTo(VALUE); assertThat(test.zValue(100d, -100d)).isEqualTo(VALUE); assertThat(test.zValueParameterSensitivity(0d, 0d).getSensitivity().get(0)).isEqualTo(1d); assertThat(test.zValueParameterSensitivity(-10d, 10d).getSensitivity().get(0)).isEqualTo(1d); assertThat(test.zValueParameterSensitivity(100d, -100d).getSensitivity().get(0)).isEqualTo(1d); }
public void present_value_sensitivityBlackVolatility_FD() { double shiftVol = 1.0E-4; Surface surfaceUp = ConstantSurface.of( SwaptionBlackVolatilityDataSets.META_DATA, SwaptionBlackVolatilityDataSets.VOLATILITY + shiftVol); Surface surfaceDw = ConstantSurface.of( SwaptionBlackVolatilityDataSets.META_DATA, SwaptionBlackVolatilityDataSets.VOLATILITY - shiftVol); CurrencyAmount pvP = PRICER_SWAPTION_BLACK.presentValue(SWAPTION_LONG_PAY, MULTI_USD, BlackSwaptionExpiryTenorVolatilities.of( BLACK_VOLS_CST_USD.getConvention(), VAL_DATE.atStartOfDay(ZoneOffset.UTC), surfaceUp)); CurrencyAmount pvM = PRICER_SWAPTION_BLACK.presentValue(SWAPTION_LONG_PAY, MULTI_USD, BlackSwaptionExpiryTenorVolatilities.of( BLACK_VOLS_CST_USD.getConvention(), VAL_DATE.atStartOfDay(ZoneOffset.UTC), surfaceDw)); double pvnvsFd = (pvP.getAmount() - pvM.getAmount()) / (2 * shiftVol); SwaptionSensitivity pvnvsAd = PRICER_SWAPTION_BLACK .presentValueSensitivityModelParamsVolatility(SWAPTION_LONG_PAY, MULTI_USD, BLACK_VOLS_CST_USD); assertEquals(pvnvsAd.getCurrency(), USD); assertEquals(pvnvsAd.getSensitivity(), pvnvsFd, TOLERANCE_PV_VEGA); assertEquals(pvnvsAd.getVolatilitiesName(), BLACK_VOLS_CST_USD.getName()); assertEquals(pvnvsAd.getExpiry(), BLACK_VOLS_CST_USD.relativeTime(SWAPTION_LONG_PAY.getExpiry())); assertEquals(pvnvsAd.getTenor(), SWAP_TENOR_YEAR, TOLERANCE_RATE); assertEquals(pvnvsAd.getStrike(), STRIKE, TOLERANCE_RATE); double forward = PRICER_SWAP.parRate(RSWAP_REC, MULTI_USD); assertEquals(pvnvsAd.getForward(), forward, TOLERANCE_RATE); }
public void flatVolTest() { double tol = 2.0e-2; double constantVol = 0.15; ConstantSurface impliedVolSurface = ConstantSurface.of("impliedVol", constantVol); Function<Double, Double> zeroRate = new Function<Double, Double>() { @Override public Double apply(Double x) { return 0.05d; } }; Function<Double, Double> zeroRate1 = new Function<Double, Double>() { @Override public Double apply(Double x) { return 0.02d; } }; ImpliedTrinomialTreeLocalVolatilityCalculator calc = new ImpliedTrinomialTreeLocalVolatilityCalculator(45, 1d, INTERP_TIMESQ_LINEAR); InterpolatedNodalSurface localVolSurface = calc.localVolatilityFromImpliedVolatility(impliedVolSurface, 100d, zeroRate, zeroRate1); assertEquals(localVolSurface.getZValues().stream().filter(d -> !DoubleMath.fuzzyEquals(d, constantVol, tol)).count(), 0); }
public void recovery_test_flat() { SurfaceIborCapletFloorletVolatilityBootstrapDefinition definition = SurfaceIborCapletFloorletVolatilityBootstrapDefinition.of( IborCapletFloorletVolatilitiesName.of("test"), USD_LIBOR_3M, ACT_ACT_ISDA, LINEAR, LINEAR); DoubleArray strikes = createBlackStrikes(); RawOptionData data = RawOptionData.of( createBlackMaturities(), strikes, ValueType.STRIKE, createFullFlatBlackDataMatrix(), ValueType.BLACK_VOLATILITY); IborCapletFloorletVolatilityCalibrationResult res = CALIBRATOR.calibrate(definition, CALIBRATION_TIME, data, RATES_PROVIDER); BlackIborCapletFloorletExpiryStrikeVolatilities resVol = (BlackIborCapletFloorletExpiryStrikeVolatilities) res.getVolatilities(); for (int i = 0; i < NUM_BLACK_STRIKES; ++i) { Pair<List<ResolvedIborCapFloorLeg>, List<Double>> capsAndVols = getCapsFlatBlackVols(i); List<ResolvedIborCapFloorLeg> caps = capsAndVols.getFirst(); List<Double> vols = capsAndVols.getSecond(); int nCaps = caps.size(); for (int j = 0; j < nCaps; ++j) { ConstantSurface volSurface = ConstantSurface.of( Surfaces.blackVolatilityByExpiryStrike("test", ACT_ACT_ISDA), vols.get(j)); BlackIborCapletFloorletExpiryStrikeVolatilities constVol = BlackIborCapletFloorletExpiryStrikeVolatilities.of( USD_LIBOR_3M, CALIBRATION_TIME, volSurface); double priceOrg = LEG_PRICER_BLACK.presentValue(caps.get(j), RATES_PROVIDER, constVol).getAmount(); double priceCalib = LEG_PRICER_BLACK.presentValue(caps.get(j), RATES_PROVIDER, resVol).getAmount(); assertEquals(priceOrg, priceCalib, Math.max(priceOrg, 1d) * TOL); } } assertEquals(res.getChiSquare(), 0d); }
public void test_lookup_byPair() { ConstantSurface test = ConstantSurface.of(SURFACE_NAME, VALUE); assertThat(test.zValue(DoublesPair.of(0d, 0d))).isEqualTo(VALUE); assertThat(test.zValue(DoublesPair.of(-10d, 10d))).isEqualTo(VALUE); assertThat(test.zValue(DoublesPair.of(100d, -100d))).isEqualTo(VALUE); assertThat(test.zValueParameterSensitivity(DoublesPair.of(0d, 0d)).getSensitivity().get(0)).isEqualTo(1d); assertThat(test.zValueParameterSensitivity(DoublesPair.of(-10d, 10d)).getSensitivity().get(0)).isEqualTo(1d); assertThat(test.zValueParameterSensitivity(DoublesPair.of(100d, -100d)).getSensitivity().get(0)).isEqualTo(1d); }
public void recovery_test_normal2() { SurfaceIborCapletFloorletVolatilityBootstrapDefinition definition = SurfaceIborCapletFloorletVolatilityBootstrapDefinition.of( IborCapletFloorletVolatilitiesName.of("test"), USD_LIBOR_3M, ACT_ACT_ISDA, LINEAR, DOUBLE_QUADRATIC); DoubleArray strikes = createNormalEquivStrikes(); RawOptionData data = RawOptionData.of( createNormalEquivMaturities(), strikes, ValueType.STRIKE, createFullNormalEquivDataMatrix(), ValueType.NORMAL_VOLATILITY); IborCapletFloorletVolatilityCalibrationResult res = CALIBRATOR.calibrate(definition, CALIBRATION_TIME, data, RATES_PROVIDER); NormalIborCapletFloorletExpiryStrikeVolatilities resVol = (NormalIborCapletFloorletExpiryStrikeVolatilities) res.getVolatilities(); for (int i = 0; i < strikes.size(); ++i) { Pair<List<ResolvedIborCapFloorLeg>, List<Double>> capsAndVols = getCapsNormalEquivVols(i); List<ResolvedIborCapFloorLeg> caps = capsAndVols.getFirst(); List<Double> vols = capsAndVols.getSecond(); int nCaps = caps.size(); for (int j = 0; j < nCaps; ++j) { ConstantSurface volSurface = ConstantSurface.of( Surfaces.normalVolatilityByExpiryStrike("test", ACT_ACT_ISDA), vols.get(j)); NormalIborCapletFloorletExpiryStrikeVolatilities constVol = NormalIborCapletFloorletExpiryStrikeVolatilities.of( USD_LIBOR_3M, CALIBRATION_TIME, volSurface); double priceOrg = LEG_PRICER_NORMAL.presentValue(caps.get(j), RATES_PROVIDER, constVol).getAmount(); double priceCalib = LEG_PRICER_NORMAL.presentValue(caps.get(j), RATES_PROVIDER, resVol).getAmount(); assertEquals(priceOrg, priceCalib, Math.max(priceOrg, 1d) * TOL); } } assertEquals(res.getChiSquare(), 0d); }
public void recovery_test_normal2_shift() { SurfaceIborCapletFloorletVolatilityBootstrapDefinition definition = SurfaceIborCapletFloorletVolatilityBootstrapDefinition.of( IborCapletFloorletVolatilitiesName.of("test"), USD_LIBOR_3M, ACT_ACT_ISDA, LINEAR, DOUBLE_QUADRATIC, ConstantCurve.of("Black shift", 0.02)); DoubleArray strikes = createNormalEquivStrikes(); RawOptionData data = RawOptionData.of( createNormalEquivMaturities(), strikes, ValueType.STRIKE, createFullNormalEquivDataMatrix(), ValueType.NORMAL_VOLATILITY); IborCapletFloorletVolatilityCalibrationResult res = CALIBRATOR.calibrate(definition, CALIBRATION_TIME, data, RATES_PROVIDER); ShiftedBlackIborCapletFloorletExpiryStrikeVolatilities resVol = (ShiftedBlackIborCapletFloorletExpiryStrikeVolatilities) res.getVolatilities(); for (int i = 0; i < strikes.size(); ++i) { Pair<List<ResolvedIborCapFloorLeg>, List<Double>> capsAndVols = getCapsNormalEquivVols(i); List<ResolvedIborCapFloorLeg> caps = capsAndVols.getFirst(); List<Double> vols = capsAndVols.getSecond(); int nCaps = caps.size(); for (int j = 0; j < nCaps; ++j) { ConstantSurface volSurface = ConstantSurface.of( Surfaces.normalVolatilityByExpiryStrike("test", ACT_ACT_ISDA), vols.get(j)); NormalIborCapletFloorletExpiryStrikeVolatilities constVol = NormalIborCapletFloorletExpiryStrikeVolatilities.of( USD_LIBOR_3M, CALIBRATION_TIME, volSurface); double priceOrg = LEG_PRICER_NORMAL.presentValue(caps.get(j), RATES_PROVIDER, constVol).getAmount(); double priceCalib = LEG_PRICER_BLACK.presentValue(caps.get(j), RATES_PROVIDER, resVol).getAmount(); assertEquals(priceOrg, priceCalib, Math.max(priceOrg, 1d) * TOL); } } assertEquals(res.getChiSquare(), 0d); }
public void negativeRates() { double shift = 0.05; Surface surface = ConstantSurface.of("shfit", shift); SabrInterestRateParameters params = SabrInterestRateParameters.of(ALPHA_SURFACE, BETA_SURFACE, RHO_SURFACE, NU_SURFACE, surface, FORMULA); double expiry = 2.0; double tenor = 3.0; assertEquals(params.alpha(expiry, tenor), ALPHA_SURFACE.zValue(expiry, tenor)); assertEquals(params.beta(expiry, tenor), BETA_SURFACE.zValue(expiry, tenor)); assertEquals(params.rho(expiry, tenor), RHO_SURFACE.zValue(expiry, tenor)); assertEquals(params.nu(expiry, tenor), NU_SURFACE.zValue(expiry, tenor)); double strike = -0.02; double forward = 0.015; double alpha = ALPHA_SURFACE.zValue(expiry, tenor); double beta = BETA_SURFACE.zValue(expiry, tenor); double rho = RHO_SURFACE.zValue(expiry, tenor); double nu = NU_SURFACE.zValue(expiry, tenor); assertEquals(params.volatility(expiry, tenor, strike, forward), FORMULA.volatility(forward + shift, strike + shift, expiry, alpha, beta, rho, nu)); double[] adjCmp = params.volatilityAdjoint(expiry, tenor, strike, forward).getDerivatives().toArray(); double[] adjExp = FORMULA.volatilityAdjoint( forward + shift, strike + shift, expiry, alpha, beta, rho, nu).getDerivatives().toArray(); for (int i = 0; i < 4; ++i) { assertEquals(adjCmp[i], adjExp[i]); } }
public 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); Function<Double, Double> zeroRate = new Function<Double, Double>() { @Override public Double apply(Double x) { return 0d; } }; Function<DoublesPair, ValueDerivatives> func = new Function<DoublesPair, ValueDerivatives>() { @Override public ValueDerivatives apply(DoublesPair x) { double price = BlackFormulaRepository.price(spot, x.getSecond(), x.getFirst(), 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.getZValues().stream().filter(d -> !DoubleMath.fuzzyEquals(d, constantVol, tol)).count(), 0); }
public void recovery_test_blackCurve() { SurfaceIborCapletFloorletVolatilityBootstrapDefinition definition = SurfaceIborCapletFloorletVolatilityBootstrapDefinition.of( IborCapletFloorletVolatilitiesName.of("test"), USD_LIBOR_3M, ACT_ACT_ISDA, LINEAR, LINEAR); DoubleArray strikes = createBlackStrikes(); for (int i = 0; i < strikes.size(); ++i) { Pair<List<Period>, DoubleMatrix> trimedData = trimData(createBlackMaturities(), createBlackDataMatrixForStrike(i)); RawOptionData data = RawOptionData.of( trimedData.getFirst(), DoubleArray.of(strikes.get(i)), ValueType.STRIKE, trimedData.getSecond(), ValueType.BLACK_VOLATILITY); IborCapletFloorletVolatilityCalibrationResult res = CALIBRATOR.calibrate(definition, CALIBRATION_TIME, data, RATES_PROVIDER); BlackIborCapletFloorletExpiryStrikeVolatilities resVol = (BlackIborCapletFloorletExpiryStrikeVolatilities) res.getVolatilities(); Pair<List<ResolvedIborCapFloorLeg>, List<Double>> capsAndVols = getCapsBlackVols(i); List<ResolvedIborCapFloorLeg> caps = capsAndVols.getFirst(); List<Double> vols = capsAndVols.getSecond(); int nCaps = caps.size(); for (int j = 0; j < nCaps; ++j) { ConstantSurface volSurface = ConstantSurface.of( Surfaces.blackVolatilityByExpiryStrike("test", ACT_ACT_ISDA), vols.get(j)); BlackIborCapletFloorletExpiryStrikeVolatilities constVol = BlackIborCapletFloorletExpiryStrikeVolatilities.of( USD_LIBOR_3M, CALIBRATION_TIME, volSurface); double priceOrg = LEG_PRICER_BLACK.presentValue(caps.get(j), RATES_PROVIDER, constVol).getAmount(); double priceCalib = LEG_PRICER_BLACK.presentValue(caps.get(j), RATES_PROVIDER, resVol).getAmount(); assertEquals(priceOrg, priceCalib, Math.max(priceOrg, 1d) * TOL); } } }
public void test_presentValueSensitivityRatesStickyStrike() { SwaptionVolatilities volSabr = SwaptionSabrRateVolatilityDataSet.getVolatilitiesEur(VAL_DATE_TIME.toLocalDate(), false); double impliedVol = PRICER.impliedVolatility(SWAPTION_REC_LONG, RATE_PROVIDER, volSabr); SurfaceMetadata blackMeta = Surfaces.blackVolatilityByExpiryTenor("CST", VOLS.getDayCount()); SwaptionVolatilities volCst = BlackSwaptionExpiryTenorVolatilities.of( VOLS.getConvention(), VOLS.getValuationDateTime(), ConstantSurface.of(blackMeta, impliedVol)); // To obtain a constant volatility surface which create a sticky strike sensitivity PointSensitivityBuilder pointRec = PRICER.presentValueSensitivityRatesStickyStrike(SWAPTION_REC_LONG, RATE_PROVIDER, volSabr); CurrencyParameterSensitivities computedRec = RATE_PROVIDER.parameterSensitivity(pointRec.build()); CurrencyParameterSensitivities expectedRec = FD_CAL.sensitivity(RATE_PROVIDER, (p) -> PRICER.presentValue(SWAPTION_REC_LONG, (p), volCst)); assertTrue(computedRec.equalWithTolerance(expectedRec, NOTIONAL * FD_EPS * 300d)); PointSensitivityBuilder pointPay = PRICER.presentValueSensitivityRatesStickyStrike(SWAPTION_PAY_SHORT, RATE_PROVIDER, volSabr); CurrencyParameterSensitivities computedPay = RATE_PROVIDER.parameterSensitivity(pointPay.build()); CurrencyParameterSensitivities expectedPay = FD_CAL.sensitivity(RATE_PROVIDER, (p) -> PRICER.presentValue(SWAPTION_PAY_SHORT, (p), volCst)); assertTrue(computedPay.equalWithTolerance(expectedPay, NOTIONAL * FD_EPS * 300d)); }
public void test_presentValue_formula() { CurrencyAmount computedCaplet = PRICER.presentValue(CAPLET_LONG, RATES, VOLS); CurrencyAmount computedFloorlet = PRICER.presentValue(FLOORLET_SHORT, RATES, VOLS); double forward = RATES.iborIndexRates(EUR_EURIBOR_3M).rate(RATE_COMP.getObservation()); double expiry = VOLS.relativeTime(CAPLET_LONG.getFixingDateTime()); double volatility = VOLS.volatility(expiry, STRIKE, forward); double df = RATES.discountFactor(EUR, CAPLET_LONG.getPaymentDate()); double expectedCaplet = NOTIONAL * df * CAPLET_LONG.getYearFraction() * BlackFormulaRepository.price( forward + SHIFT, STRIKE + SHIFT, expiry, volatility, CALL.isCall()); double expectedFloorlet = -NOTIONAL * df * FLOORLET_SHORT.getYearFraction() * BlackFormulaRepository.price( forward + SHIFT, STRIKE + SHIFT, expiry, volatility, PUT.isCall()); assertEquals(computedCaplet.getCurrency(), EUR); assertEquals(computedCaplet.getAmount(), expectedCaplet, NOTIONAL * TOL); assertEquals(computedFloorlet.getCurrency(), EUR); assertEquals(computedFloorlet.getAmount(), expectedFloorlet, NOTIONAL * TOL); // consistency with shifted Black ShiftedBlackIborCapletFloorletExpiryStrikeVolatilities vols = ShiftedBlackIborCapletFloorletExpiryStrikeVolatilities.of( EUR_EURIBOR_3M, VALUATION, ConstantSurface.of("constVol", volatility) .withMetadata(Surfaces.blackVolatilityByExpiryStrike("costVol", DayCounts.ACT_ACT_ISDA)), IborCapletFloorletSabrRateVolatilityDataSet.CURVE_CONST_SHIFT); CurrencyAmount computedCapletBlack = PRICER_BASE.presentValue(CAPLET_LONG, RATES, vols); CurrencyAmount computedFloorletBlack = PRICER_BASE.presentValue(FLOORLET_SHORT, RATES, vols); assertEquals(computedCaplet.getAmount(), computedCapletBlack.getAmount(), NOTIONAL * TOL); assertEquals(computedFloorlet.getAmount(), computedFloorletBlack.getAmount(), NOTIONAL * TOL); }
public void test_presentValueSensitivityRatesStickyModel_stickyStrike() { SwaptionVolatilities volSabr = SwaptionSabrRateVolatilityDataSet.getVolatilitiesUsd(VAL_DATE, false); double impliedVol = SWAPTION_PRICER.impliedVolatility(SWAPTION_REC_LONG, RATE_PROVIDER, volSabr); SurfaceMetadata blackMeta = Surfaces.blackVolatilityByExpiryTenor("CST", VOLS.getDayCount()); SwaptionVolatilities volCst = BlackSwaptionExpiryTenorVolatilities.of( VOLS.getConvention(), VOLS.getValuationDateTime(), ConstantSurface.of(blackMeta, impliedVol)); // To obtain a constant volatility surface which create a sticky strike sensitivity PointSensitivityBuilder pointRec = SWAPTION_PRICER.presentValueSensitivityRatesStickyStrike(SWAPTION_REC_LONG, RATE_PROVIDER, volSabr); CurrencyParameterSensitivities computedRec = RATE_PROVIDER.parameterSensitivity(pointRec.build()); CurrencyParameterSensitivities expectedRec = FD_CAL.sensitivity(RATE_PROVIDER, (p) -> SWAPTION_PRICER.presentValue(SWAPTION_REC_LONG, (p), volCst)); assertTrue(computedRec.equalWithTolerance(expectedRec, NOTIONAL * FD_EPS * 100d)); PointSensitivityBuilder pointPay = SWAPTION_PRICER.presentValueSensitivityRatesStickyStrike(SWAPTION_PAY_SHORT, RATE_PROVIDER, volSabr); CurrencyParameterSensitivities computedPay = RATE_PROVIDER.parameterSensitivity(pointPay.build()); CurrencyParameterSensitivities expectedPay = FD_CAL.sensitivity(RATE_PROVIDER, (p) -> SWAPTION_PRICER.presentValue(SWAPTION_PAY_SHORT, (p), volCst)); assertTrue(computedPay.equalWithTolerance(expectedPay, NOTIONAL * FD_EPS * 100d)); }