public virtual void test_relativeTime() { SabrParametersSwaptionVolatilities prov = SabrParametersSwaptionVolatilities.of(NAME, CONV, DATE_TIME, PARAM); double test1 = prov.relativeTime(DATE_TIME); assertEquals(test1, 0d); double test2 = prov.relativeTime(DATE_TIME.plusYears(2)); double test3 = prov.relativeTime(DATE_TIME.minusYears(2)); assertEquals(test2, -test3, 1e-2); }
private const double TOLERANCE_PRICE_CALIBRATION_LS = 5.0E-4; // Calibration Least Square; result not exact //JAVA TO C# CONVERTER TODO TASK: Most Java annotations will not have direct .NET equivalent attributes: //ORIGINAL LINE: @Test public void normal_cube() public virtual void normal_cube() { double beta = 0.50; Surface betaSurface = ConstantSurface.of("Beta", beta).withMetadata(DefaultSurfaceMetadata.builder().xValueType(ValueType.YEAR_FRACTION).yValueType(ValueType.YEAR_FRACTION).zValueType(ValueType.SABR_BETA).surfaceName("Beta").build()); double shift = 0.0300; Surface shiftSurface = ConstantSurface.of("Shift", shift).withMetadata(DefaultSurfaceMetadata.builder().xValueType(ValueType.YEAR_FRACTION).yValueType(ValueType.YEAR_FRACTION).surfaceName("Shift").build()); SabrParametersSwaptionVolatilities calibrated = SABR_CALIBRATION.calibrateWithFixedBetaAndShift(DEFINITION, CALIBRATION_TIME, DATA_SPARSE, MULTICURVE, betaSurface, shiftSurface); for (int looptenor = 0; looptenor < TENORS.size(); looptenor++) { double tenor = TENORS.get(looptenor).get(ChronoUnit.YEARS); for (int loopexpiry = 0; loopexpiry < EXPIRIES.size(); loopexpiry++) { LocalDate expiry = EUR_FIXED_1Y_EURIBOR_6M.FloatingLeg.StartDateBusinessDayAdjustment.adjust(CALIBRATION_DATE.plus(EXPIRIES.get(loopexpiry)), REF_DATA); LocalDate effectiveDate = EUR_FIXED_1Y_EURIBOR_6M.calculateSpotDateFromTradeDate(expiry, REF_DATA); LocalDate endDate = effectiveDate.plus(TENORS.get(looptenor)); SwapTrade swap = EUR_FIXED_1Y_EURIBOR_6M.toTrade(CALIBRATION_DATE, effectiveDate, endDate, BuySell.BUY, 1.0, 0.0); double parRate = SWAP_PRICER.parRate(swap.resolve(REF_DATA).Product, MULTICURVE); ZonedDateTime expiryDateTime = expiry.atTime(11, 0).atZone(ZoneId.of("Europe/Berlin")); double time = calibrated.relativeTime(expiryDateTime); for (int loopmoney = 0; loopmoney < MONEYNESS.size(); loopmoney++) { if (!double.IsNaN(DATA_ARRAY_SPARSE[looptenor][loopexpiry][loopmoney])) { double strike = parRate + MONEYNESS.get(loopmoney); double volBlack = calibrated.volatility(expiryDateTime, tenor, strike, parRate); double priceComputed = BlackFormulaRepository.price(parRate + shift, parRate + MONEYNESS.get(loopmoney) + shift, time, volBlack, true); double priceNormal = NormalFormulaRepository.price(parRate, parRate + MONEYNESS.get(loopmoney), time, DATA_ARRAY_SPARSE[looptenor][loopexpiry][loopmoney], PutCall.CALL); assertEquals(priceComputed, priceNormal, TOLERANCE_PRICE_CALIBRATION_LS); } } } } }
//JAVA TO C# CONVERTER TODO TASK: Most Java annotations will not have direct .NET equivalent attributes: //ORIGINAL LINE: @Test(enabled = true) public void log_normal_atm() public virtual void log_normal_atm() { double beta = 0.50; Surface betaSurface = ConstantSurface.of("Beta", beta).withMetadata(DefaultSurfaceMetadata.builder().xValueType(ValueType.YEAR_FRACTION).yValueType(ValueType.YEAR_FRACTION).zValueType(ValueType.SABR_BETA).surfaceName("Beta").build()); double shift = 0.0000; Surface shiftSurface = ConstantSurface.of("Shift", shift).withMetadata(DefaultSurfaceMetadata.builder().xValueType(ValueType.YEAR_FRACTION).yValueType(ValueType.YEAR_FRACTION).surfaceName("Shift").build()); SabrParametersSwaptionVolatilities calibratedSmile = SABR_CALIBRATION.calibrateWithFixedBetaAndShift(DEFINITION, CALIBRATION_TIME, DATA_SPARSE, MULTICURVE, betaSurface, shiftSurface); SabrParametersSwaptionVolatilities calibratedAtm = SABR_CALIBRATION.calibrateAlphaWithAtm(NAME_SABR, calibratedSmile, MULTICURVE, ATM_LOGNORMAL_SIMPLE, TENORS_SIMPLE, EXPIRIES_SIMPLE_2, INTERPOLATOR_2D); int nbExp = EXPIRIES_SIMPLE_2.size(); int nbTenor = TENORS_SIMPLE.size(); for (int loopexpiry = 0; loopexpiry < nbExp; loopexpiry++) { for (int looptenor = 0; looptenor < nbTenor; looptenor++) { double tenor = TENORS_SIMPLE.get(looptenor).get(ChronoUnit.YEARS); LocalDate expiry = EUR_FIXED_1Y_EURIBOR_6M.FloatingLeg.StartDateBusinessDayAdjustment.adjust(CALIBRATION_DATE.plus(EXPIRIES_SIMPLE_2.get(loopexpiry)), REF_DATA); LocalDate effectiveDate = EUR_FIXED_1Y_EURIBOR_6M.calculateSpotDateFromTradeDate(expiry, REF_DATA); LocalDate endDate = effectiveDate.plus(TENORS_SIMPLE.get(looptenor)); SwapTrade swap = EUR_FIXED_1Y_EURIBOR_6M.toTrade(CALIBRATION_DATE, effectiveDate, endDate, BuySell.BUY, 1.0, 0.0); double parRate = SWAP_PRICER.parRate(swap.resolve(REF_DATA).Product, MULTICURVE); ZonedDateTime expiryDateTime = expiry.atTime(11, 0).atZone(ZoneId.of("Europe/Berlin")); double time = calibratedAtm.relativeTime(expiryDateTime); double volBlack = calibratedAtm.volatility(expiryDateTime, tenor, parRate, parRate); double priceComputed = calibratedAtm.price(time, tenor, PutCall.CALL, parRate, parRate, volBlack); double priceBlack = BlackFormulaRepository.price(parRate, parRate, time, DATA_LOGNORMAL_ATM_SIMPLE[looptenor + loopexpiry * nbTenor], true); assertEquals(priceComputed, priceBlack, TOLERANCE_PRICE_CALIBRATION_ROOT); } } }
//------------------------------------------------------------------------- public virtual void test_presentValue() { CurrencyAmount computedRec = SWAPTION_PRICER.presentValue(SWAPTION_REC_LONG, RATE_PROVIDER, VOLS); CurrencyAmount computedPay = SWAPTION_PRICER.presentValue(SWAPTION_PAY_SHORT, RATE_PROVIDER, VOLS); double forward = SWAP_PRICER.parRate(RSWAP_REC, RATE_PROVIDER); double pvbp = SWAP_PRICER.LegPricer.pvbp(RSWAP_REC.getLegs(SwapLegType.FIXED).get(0), RATE_PROVIDER); double volatility = VOLS.volatility(SWAPTION_REC_LONG.Expiry, TENOR_YEAR, RATE, forward); double maturity = VOLS.relativeTime(SWAPTION_REC_LONG.Expiry); double expectedRec = pvbp * BlackFormulaRepository.price(forward + SwaptionSabrRateVolatilityDataSet.SHIFT, RATE + SwaptionSabrRateVolatilityDataSet.SHIFT, maturity, volatility, false); double expectedPay = -pvbp *BlackFormulaRepository.price(forward + SwaptionSabrRateVolatilityDataSet.SHIFT, RATE + SwaptionSabrRateVolatilityDataSet.SHIFT, maturity, volatility, true); assertEquals(computedRec.Currency, USD); assertEquals(computedRec.Amount, expectedRec, NOTIONAL * TOL); assertEquals(computedPay.Currency, USD); assertEquals(computedPay.Amount, expectedPay, NOTIONAL * TOL); }
public virtual void test_parameterSensitivity_multi() { double[] points1 = new double[] { 2.24, 3.45, -2.12, -0.56 }; double[] points2 = new double[] { -0.145, 1.01, -5.0, -11.0 }; double[] points3 = new double[] { 1.3, -4.32, 2.1, -7.18 }; SabrParametersSwaptionVolatilities prov = SabrParametersSwaptionVolatilities.of(NAME, CONV, DATE_TIME, PARAM); double expiryTime0 = prov.relativeTime(TEST_OPTION_EXPIRY[0]); double expiryTime3 = prov.relativeTime(TEST_OPTION_EXPIRY[3]); for (int i = 0; i < NB_TEST; i++) { PointSensitivities sensi1 = PointSensitivities.of(SwaptionSabrSensitivity.of(NAME, expiryTime0, TEST_TENOR[i], ALPHA, USD, points1[0]), SwaptionSabrSensitivity.of(NAME, expiryTime0, TEST_TENOR[i], BETA, USD, points1[1]), SwaptionSabrSensitivity.of(NAME, expiryTime0, TEST_TENOR[i], RHO, USD, points1[2]), SwaptionSabrSensitivity.of(NAME, expiryTime0, TEST_TENOR[i], NU, USD, points1[3])); PointSensitivities sensi2 = PointSensitivities.of(SwaptionSabrSensitivity.of(NAME, expiryTime0, TEST_TENOR[i], ALPHA, USD, points2[0]), SwaptionSabrSensitivity.of(NAME, expiryTime0, TEST_TENOR[i], BETA, USD, points2[1]), SwaptionSabrSensitivity.of(NAME, expiryTime0, TEST_TENOR[i], RHO, USD, points2[2]), SwaptionSabrSensitivity.of(NAME, expiryTime0, TEST_TENOR[i], NU, USD, points2[3])); PointSensitivities sensi3 = PointSensitivities.of(SwaptionSabrSensitivity.of(NAME, expiryTime3, TEST_TENOR[i], ALPHA, USD, points3[0]), SwaptionSabrSensitivity.of(NAME, expiryTime3, TEST_TENOR[i], BETA, USD, points3[1]), SwaptionSabrSensitivity.of(NAME, expiryTime3, TEST_TENOR[i], RHO, USD, points3[2]), SwaptionSabrSensitivity.of(NAME, expiryTime3, TEST_TENOR[i], NU, USD, points3[3])); PointSensitivities sensis = sensi1.combinedWith(sensi2).combinedWith(sensi3).normalized(); CurrencyParameterSensitivities computed = prov.parameterSensitivity(sensis); CurrencyParameterSensitivities expected = prov.parameterSensitivity(sensi1).combinedWith(prov.parameterSensitivity(sensi2)).combinedWith(prov.parameterSensitivity(sensi3)); DoubleArrayMath.fuzzyEquals(computed.getSensitivity(PARAM.AlphaSurface.Name, USD).Sensitivity.toArray(), expected.getSensitivity(PARAM.AlphaSurface.Name, USD).Sensitivity.toArray(), TOLERANCE_VOL); DoubleArrayMath.fuzzyEquals(computed.getSensitivity(PARAM.BetaSurface.Name, USD).Sensitivity.toArray(), expected.getSensitivity(PARAM.BetaSurface.Name, USD).Sensitivity.toArray(), TOLERANCE_VOL); DoubleArrayMath.fuzzyEquals(computed.getSensitivity(PARAM.RhoSurface.Name, USD).Sensitivity.toArray(), expected.getSensitivity(PARAM.RhoSurface.Name, USD).Sensitivity.toArray(), TOLERANCE_VOL); DoubleArrayMath.fuzzyEquals(computed.getSensitivity(PARAM.NuSurface.Name, USD).Sensitivity.toArray(), expected.getSensitivity(PARAM.NuSurface.Name, USD).Sensitivity.toArray(), TOLERANCE_VOL); } }
public virtual void test_volatility() { SabrParametersSwaptionVolatilities prov = SabrParametersSwaptionVolatilities.of(NAME, CONV, 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_TENOR[i], TEST_STRIKE[j], TEST_FORWARD); double volComputed = prov.volatility(TEST_OPTION_EXPIRY[i], TEST_TENOR[i], TEST_STRIKE[j], TEST_FORWARD); assertEquals(volComputed, volExpected, TOLERANCE_VOL); } } }
public virtual void test_parameterSensitivity() { double alphaSensi = 2.24, betaSensi = 3.45, rhoSensi = -2.12, nuSensi = -0.56; SabrParametersSwaptionVolatilities prov = SabrParametersSwaptionVolatilities.of(NAME, CONV, DATE_TIME, PARAM); for (int i = 0; i < NB_TEST; i++) { double expiryTime = prov.relativeTime(TEST_OPTION_EXPIRY[i]); PointSensitivities point = PointSensitivities.of(SwaptionSabrSensitivity.of(NAME, expiryTime, TEST_TENOR[i], ALPHA, USD, alphaSensi), SwaptionSabrSensitivity.of(NAME, expiryTime, TEST_TENOR[i], BETA, USD, betaSensi), SwaptionSabrSensitivity.of(NAME, expiryTime, TEST_TENOR[i], RHO, USD, rhoSensi), SwaptionSabrSensitivity.of(NAME, expiryTime, TEST_TENOR[i], NU, USD, nuSensi)); CurrencyParameterSensitivities sensiComputed = prov.parameterSensitivity(point); UnitParameterSensitivity alphaSensitivities = prov.Parameters.AlphaSurface.zValueParameterSensitivity(expiryTime, TEST_TENOR[i]); UnitParameterSensitivity betaSensitivities = prov.Parameters.BetaSurface.zValueParameterSensitivity(expiryTime, TEST_TENOR[i]); UnitParameterSensitivity rhoSensitivities = prov.Parameters.RhoSurface.zValueParameterSensitivity(expiryTime, TEST_TENOR[i]); UnitParameterSensitivity nuSensitivities = prov.Parameters.NuSurface.zValueParameterSensitivity(expiryTime, TEST_TENOR[i]); CurrencyParameterSensitivity alphaSensiObj = sensiComputed.getSensitivity(SwaptionSabrRateVolatilityDataSet.META_ALPHA.SurfaceName, USD); CurrencyParameterSensitivity betaSensiObj = sensiComputed.getSensitivity(SwaptionSabrRateVolatilityDataSet.META_BETA_USD.SurfaceName, USD); CurrencyParameterSensitivity rhoSensiObj = sensiComputed.getSensitivity(SwaptionSabrRateVolatilityDataSet.META_RHO.SurfaceName, USD); CurrencyParameterSensitivity nuSensiObj = sensiComputed.getSensitivity(SwaptionSabrRateVolatilityDataSet.META_NU.SurfaceName, USD); DoubleArray alphaNodeSensiComputed = alphaSensiObj.Sensitivity; DoubleArray betaNodeSensiComputed = betaSensiObj.Sensitivity; DoubleArray rhoNodeSensiComputed = rhoSensiObj.Sensitivity; DoubleArray nuNodeSensiComputed = nuSensiObj.Sensitivity; assertEquals(alphaSensitivities.Sensitivity.size(), alphaNodeSensiComputed.size()); assertEquals(betaSensitivities.Sensitivity.size(), betaNodeSensiComputed.size()); assertEquals(rhoSensitivities.Sensitivity.size(), rhoNodeSensiComputed.size()); assertEquals(nuSensitivities.Sensitivity.size(), nuNodeSensiComputed.size()); for (int k = 0; k < alphaNodeSensiComputed.size(); ++k) { assertEquals(alphaNodeSensiComputed.get(k), alphaSensitivities.Sensitivity.get(k) * alphaSensi, TOLERANCE_VOL); } for (int k = 0; k < betaNodeSensiComputed.size(); ++k) { assertEquals(betaNodeSensiComputed.get(k), betaSensitivities.Sensitivity.get(k) * betaSensi, TOLERANCE_VOL); } for (int k = 0; k < rhoNodeSensiComputed.size(); ++k) { assertEquals(rhoNodeSensiComputed.get(k), rhoSensitivities.Sensitivity.get(k) * rhoSensi, TOLERANCE_VOL); } for (int k = 0; k < nuNodeSensiComputed.size(); ++k) { assertEquals(nuNodeSensiComputed.get(k), nuSensitivities.Sensitivity.get(k) * nuSensi, TOLERANCE_VOL); } } }
//------------------------------------------------------------------------- /// <summary> /// Runs the calibration of swaptions and print the calibrated smile results on the console. /// </summary> /// <param name="args"> -s to use the sparse data, i.e. a cube with missing data points </param> public static void Main(string[] args) { // select data TenorRawOptionData data = DATA_FULL; if (args.Length > 0) { if (args[0].Equals("-s")) { data = DATA_SPARSE; } } Console.WriteLine("Start calibration"); double beta = 0.50; SurfaceMetadata betaMetadata = DefaultSurfaceMetadata.builder().xValueType(ValueType.YEAR_FRACTION).yValueType(ValueType.YEAR_FRACTION).zValueType(ValueType.SABR_BETA).surfaceName("Beta").build(); Surface betaSurface = ConstantSurface.of(betaMetadata, beta); double shift = 0.0300; Surface shiftSurface = ConstantSurface.of("Shift", shift); SabrParametersSwaptionVolatilities calibrated = SABR_CALIBRATION.calibrateWithFixedBetaAndShift(DEFINITION, CALIBRATION_TIME, data, MULTICURVE, betaSurface, shiftSurface); Console.WriteLine("End calibration"); /* Graph calibration */ int nbStrikesGraph = 50; double moneyMin = -0.0250; double moneyMax = +0.0300; double[] moneyGraph = new double[nbStrikesGraph + 1]; for (int i = 0; i < nbStrikesGraph + 1; i++) { moneyGraph[i] = moneyMin + i * (moneyMax - moneyMin) / nbStrikesGraph; } //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[][][] strikesGraph = new double[NB_TENORS][NB_EXPIRIES][nbStrikesGraph + 1]; double[][][] strikesGraph = RectangularArrays.ReturnRectangularDoubleArray(NB_TENORS, NB_EXPIRIES, nbStrikesGraph + 1); //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[][][] volLNGraph = new double[NB_TENORS][NB_EXPIRIES][nbStrikesGraph + 1]; double[][][] volLNGraph = RectangularArrays.ReturnRectangularDoubleArray(NB_TENORS, NB_EXPIRIES, nbStrikesGraph + 1); //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[][][] volNGraph = new double[NB_TENORS][NB_EXPIRIES][nbStrikesGraph + 1]; double[][][] volNGraph = RectangularArrays.ReturnRectangularDoubleArray(NB_TENORS, NB_EXPIRIES, nbStrikesGraph + 1); //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[][] parRate = new double[NB_TENORS][NB_EXPIRIES]; double[][] parRate = RectangularArrays.ReturnRectangularDoubleArray(NB_TENORS, NB_EXPIRIES); for (int looptenor = 0; looptenor < TENORS.size(); looptenor++) { double tenor = TENORS.get(looptenor).get(ChronoUnit.YEARS); for (int loopexpiry = 0; loopexpiry < EXPIRIES.size(); loopexpiry++) { LocalDate expiry = EUR_FIXED_1Y_EURIBOR_6M.FloatingLeg.StartDateBusinessDayAdjustment.adjust(CALIBRATION_DATE.plus(EXPIRIES.get(loopexpiry)), REF_DATA); LocalDate effectiveDate = EUR_FIXED_1Y_EURIBOR_6M.calculateSpotDateFromTradeDate(expiry, REF_DATA); LocalDate endDate = effectiveDate.plus(TENORS.get(looptenor)); SwapTrade swap = EUR_FIXED_1Y_EURIBOR_6M.toTrade(CALIBRATION_DATE, effectiveDate, endDate, BuySell.BUY, 1.0, 0.0); parRate[looptenor][loopexpiry] = SWAP_PRICER.parRate(swap.resolve(REF_DATA).Product, MULTICURVE); ZonedDateTime expiryDateTime = expiry.atTime(11, 0).atZone(ZoneId.of("Europe/Berlin")); double time = calibrated.relativeTime(expiryDateTime); for (int i = 0; i < nbStrikesGraph + 1; i++) { strikesGraph[looptenor][loopexpiry][i] = parRate[looptenor][loopexpiry] + moneyGraph[i]; volLNGraph[looptenor][loopexpiry][i] = calibrated.volatility(expiryDateTime, tenor, strikesGraph[looptenor][loopexpiry][i], parRate[looptenor][loopexpiry]); volNGraph[looptenor][loopexpiry][i] = NormalFormulaRepository.impliedVolatilityFromBlackApproximated(parRate[looptenor][loopexpiry] + shift, strikesGraph[looptenor][loopexpiry][i] + shift, time, volLNGraph[looptenor][loopexpiry][i]); } } } /* Graph export */ string svn = "Moneyness"; for (int looptenor = 0; looptenor < TENORS.size(); looptenor++) { for (int loopexpiry = 0; loopexpiry < EXPIRIES.size(); loopexpiry++) { svn = svn + ", Strike_" + EXPIRIES.get(loopexpiry).ToString() + "x" + TENORS.get(looptenor).ToString() + ", NormalVol_" + EXPIRIES.get(loopexpiry).ToString() + "x" + TENORS.get(looptenor).ToString(); } } svn = svn + "\n"; for (int i = 0; i < nbStrikesGraph + 1; i++) { svn = svn + moneyGraph[i]; for (int looptenor = 0; looptenor < TENORS.size(); looptenor++) { for (int loopexpiry = 0; loopexpiry < EXPIRIES.size(); loopexpiry++) { svn = svn + ", " + strikesGraph[looptenor][loopexpiry][i]; svn = svn + ", " + volNGraph[looptenor][loopexpiry][i]; } } svn = svn + "\n"; } Console.WriteLine(svn); }
/// <summary> /// Check that the sensitivities of parameters with respect to data is stored in the metadata. /// Compare the sensitivities to a finite difference approximation. /// This test is relatively slow as it calibrates the full surface multiple times. /// </summary> //JAVA TO C# CONVERTER TODO TASK: Most Java annotations will not have direct .NET equivalent attributes: //ORIGINAL LINE: @Test public void log_normal_cube_sensitivity() public virtual void log_normal_cube_sensitivity() { double beta = 1.0; Surface betaSurface = ConstantSurface.of("Beta", beta).withMetadata(DefaultSurfaceMetadata.builder().xValueType(ValueType.YEAR_FRACTION).yValueType(ValueType.YEAR_FRACTION).zValueType(ValueType.SABR_BETA).surfaceName("Beta").build()); double shift = 0.0000; Surface shiftSurface = ConstantSurface.of("Shift", shift).withMetadata(DefaultSurfaceMetadata.builder().xValueType(ValueType.YEAR_FRACTION).yValueType(ValueType.YEAR_FRACTION).surfaceName("Shift").build()); SabrParametersSwaptionVolatilities calibrated = SABR_CALIBRATION.calibrateWithFixedBetaAndShift(DEFINITION, CALIBRATION_TIME, DATA_SPARSE, MULTICURVE, betaSurface, shiftSurface); double fdShift = 1.0E-5; SurfaceMetadata alphaMetadata = calibrated.Parameters.AlphaSurface.Metadata; Optional <IList <ParameterMetadata> > alphaParameterMetadataOption = alphaMetadata.ParameterMetadata; assertTrue(alphaParameterMetadataOption.Present); IList <ParameterMetadata> alphaParameterMetadata = alphaParameterMetadataOption.get(); IList <DoubleArray> alphaJacobian = calibrated.DataSensitivityAlpha.get(); SurfaceMetadata rhoMetadata = calibrated.Parameters.RhoSurface.Metadata; Optional <IList <ParameterMetadata> > rhoParameterMetadataOption = rhoMetadata.ParameterMetadata; assertTrue(rhoParameterMetadataOption.Present); IList <ParameterMetadata> rhoParameterMetadata = rhoParameterMetadataOption.get(); IList <DoubleArray> rhoJacobian = calibrated.DataSensitivityRho.get(); SurfaceMetadata nuMetadata = calibrated.Parameters.NuSurface.Metadata; Optional <IList <ParameterMetadata> > nuParameterMetadataOption = nuMetadata.ParameterMetadata; assertTrue(nuParameterMetadataOption.Present); IList <ParameterMetadata> nuParameterMetadata = nuParameterMetadataOption.get(); IList <DoubleArray> nuJacobian = calibrated.DataSensitivityNu.get(); int surfacePointIndex = 0; for (int loopexpiry = 0; loopexpiry < EXPIRIES.Count; loopexpiry++) { for (int looptenor = 0; looptenor < TENORS.Count; looptenor++) { Tenor tenor = TENORS[looptenor]; double tenorYears = tenor.get(ChronoUnit.YEARS); LocalDate expiry = EUR_FIXED_1Y_EURIBOR_6M.FloatingLeg.StartDateBusinessDayAdjustment.adjust(CALIBRATION_DATE.plus(EXPIRIES[loopexpiry]), REF_DATA); ZonedDateTime expiryDateTime = expiry.atTime(11, 0).atZone(ZoneId.of("Europe/Berlin")); double time = calibrated.relativeTime(expiryDateTime); Pair <DoubleArray, DoubleArray> ds = DATA_SPARSE.getData(tenor).availableSmileAtExpiry(EXPIRIES[loopexpiry]); if (!ds.First.Empty) { int availableDataIndex = 0; ParameterMetadata alphaPM = alphaParameterMetadata[surfacePointIndex]; assertTrue(alphaPM is SwaptionSurfaceExpiryTenorParameterMetadata); SwaptionSurfaceExpiryTenorParameterMetadata pmAlphaSabr = (SwaptionSurfaceExpiryTenorParameterMetadata)alphaPM; assertEquals(tenorYears, pmAlphaSabr.Tenor); assertEquals(time, pmAlphaSabr.YearFraction, TOLERANCE_EXPIRY); DoubleArray alphaSensitivityToData = alphaJacobian[surfacePointIndex]; ParameterMetadata rhoPM = rhoParameterMetadata[surfacePointIndex]; assertTrue(rhoPM is SwaptionSurfaceExpiryTenorParameterMetadata); SwaptionSurfaceExpiryTenorParameterMetadata pmRhoSabr = (SwaptionSurfaceExpiryTenorParameterMetadata)rhoPM; assertEquals(tenorYears, pmRhoSabr.Tenor); assertEquals(time, pmRhoSabr.YearFraction, TOLERANCE_EXPIRY); DoubleArray rhoSensitivityToData = rhoJacobian[surfacePointIndex]; ParameterMetadata nuPM = nuParameterMetadata[surfacePointIndex]; assertTrue(nuPM is SwaptionSurfaceExpiryTenorParameterMetadata); SwaptionSurfaceExpiryTenorParameterMetadata pmNuSabr = (SwaptionSurfaceExpiryTenorParameterMetadata)nuPM; assertEquals(tenorYears, pmNuSabr.Tenor); assertEquals(time, pmNuSabr.YearFraction, TOLERANCE_EXPIRY); DoubleArray nuSensitivityToData = nuJacobian[surfacePointIndex]; for (int loopmoney = 0; loopmoney < MONEYNESS.size(); loopmoney++) { if (!double.IsNaN(DATA_LOGNORMAL[looptenor][loopexpiry][loopmoney])) { double[] alphaShifted = new double[2]; double[] rhoShifted = new double[2]; double[] nuShifted = new double[2]; for (int loopsign = 0; loopsign < 2; loopsign++) { TenorRawOptionData dataShifted = SabrSwaptionCalibratorSmileTestUtils.rawDataShiftPoint(TENORS, EXPIRIES, ValueType.SIMPLE_MONEYNESS, MONEYNESS, ValueType.BLACK_VOLATILITY, DATA_LOGNORMAL, looptenor, loopexpiry, loopmoney, (2 * loopsign - 1) * fdShift); SabrParametersSwaptionVolatilities calibratedShifted = SABR_CALIBRATION.calibrateWithFixedBetaAndShift(DEFINITION, CALIBRATION_TIME, dataShifted, MULTICURVE, betaSurface, shiftSurface); alphaShifted[loopsign] = calibratedShifted.Parameters.AlphaSurface.zValue(time, tenorYears); rhoShifted[loopsign] = calibratedShifted.Parameters.RhoSurface.zValue(time, tenorYears); nuShifted[loopsign] = calibratedShifted.Parameters.NuSurface.zValue(time, tenorYears); } double alphaSensitivityComputed = alphaSensitivityToData.get(availableDataIndex); double alphaSensitivityExpected = (alphaShifted[1] - alphaShifted[0]) / (2 * fdShift); checkAcceptable(alphaSensitivityComputed, alphaSensitivityExpected, TOLERANCE_PARAM_SENSITIVITY, "Alpha: " + looptenor + " / " + loopexpiry + " / " + loopmoney); double rhoSensitivityComputed = rhoSensitivityToData.get(availableDataIndex); double rhoSensitivityExpected = (rhoShifted[1] - rhoShifted[0]) / (2 * fdShift); checkAcceptable(rhoSensitivityComputed, rhoSensitivityExpected, TOLERANCE_PARAM_SENSITIVITY, "Rho: " + looptenor + " / " + loopexpiry + " / " + loopmoney); double nuSensitivityComputed = nuSensitivityToData.get(availableDataIndex); double nuSensitivityExpected = (nuShifted[1] - nuShifted[0]) / (2 * fdShift); checkAcceptable(nuSensitivityComputed, nuSensitivityExpected, TOLERANCE_PARAM_SENSITIVITY, "Nu: " + looptenor + " / " + loopexpiry + " / " + loopmoney); availableDataIndex++; } } surfacePointIndex++; } } } }