/// <summary> /// Calibrate a single curve to 4 points. Use the resulting calibrated curves as starting point of the computation /// of a Jacobian. Compare the direct Jacobian and the one reconstructed from trades. /// </summary> public virtual void direct_one_curve() { /* Create trades */ IList <ResolvedTrade> trades = new List <ResolvedTrade>(); IList <LocalDate> nodeDates = new List <LocalDate>(); for (int looptenor = 0; looptenor < TENORS_STD_1.Length; looptenor++) { ResolvedSwapTrade t0 = EUR_FIXED_1Y_EURIBOR_6M.createTrade(VALUATION_DATE, TENORS_STD_1[looptenor], BuySell.BUY, 1.0, 0.0, REF_DATA).resolve(REF_DATA); double rate = MARKET_QUOTE.value(t0, MULTICURVE_EUR_SINGLE_CALIBRATED); ResolvedSwapTrade t = EUR_FIXED_1Y_EURIBOR_6M.createTrade(VALUATION_DATE, TENORS_STD_1[looptenor], BuySell.BUY, 1.0, rate, REF_DATA).resolve(REF_DATA); nodeDates.Add(t.Product.EndDate); trades.Add(t); } /* Par rate sensitivity */ System.Func <ResolvedTrade, CurrencyParameterSensitivities> sensitivityFunction = (t) => MULTICURVE_EUR_SINGLE_CALIBRATED.parameterSensitivity(PRICER_SWAP_PRODUCT.parRateSensitivity(((ResolvedSwapTrade)t).Product, MULTICURVE_EUR_SINGLE_CALIBRATED).build()); DoubleMatrix jiComputed = CurveSensitivityUtils.jacobianFromMarketQuoteSensitivities(LIST_CURVE_NAMES_1, trades, sensitivityFunction); DoubleMatrix jiExpected = MULTICURVE_EUR_SINGLE_CALIBRATED.findData(EUR_SINGLE_NAME).get().Metadata.findInfo(CurveInfoType.JACOBIAN).get().JacobianMatrix; /* Comparison */ assertEquals(jiComputed.rowCount(), jiExpected.rowCount()); assertEquals(jiComputed.columnCount(), jiExpected.columnCount()); for (int i = 0; i < jiComputed.rowCount(); i++) { for (int j = 0; j < jiComputed.columnCount(); j++) { assertEquals(jiComputed.get(i, j), jiExpected.get(i, j), TOLERANCE_JAC); } } }
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); } } }
/// <summary> /// Start from a generic zero-coupon curve. Compute the (inverse) Jacobian matrix using linear projection to a small /// number of points and the Jacobian utility. Compare the direct Jacobian obtained by calibrating a curve /// based on the trades with market quotes computed from the zero-coupon curve. /// </summary> public virtual void with_rebucketing_one_curve() { /* Create trades */ IList <ResolvedTrade> trades = new List <ResolvedTrade>(); IList <LocalDate> nodeDates = new List <LocalDate>(); double[] marketQuotes = new double[TENORS_STD_1.Length]; for (int looptenor = 0; looptenor < TENORS_STD_1.Length; looptenor++) { ResolvedSwapTrade t0 = EUR_FIXED_1Y_EURIBOR_6M.createTrade(VALUATION_DATE, TENORS_STD_1[looptenor], BuySell.BUY, 1.0, 0.0, REF_DATA).resolve(REF_DATA); marketQuotes[looptenor] = MARKET_QUOTE.value(t0, MULTICURVE_EUR_SINGLE_INPUT); ResolvedSwapTrade t = EUR_FIXED_1Y_EURIBOR_6M.createTrade(VALUATION_DATE, TENORS_STD_1[looptenor], BuySell.BUY, 1.0, marketQuotes[looptenor], REF_DATA).resolve(REF_DATA); nodeDates.Add(t.Product.EndDate); trades.Add(t); } System.Func <ResolvedTrade, CurrencyParameterSensitivities> sensitivityFunction = (t) => CurveSensitivityUtils.linearRebucketing(MULTICURVE_EUR_SINGLE_INPUT.parameterSensitivity(PRICER_SWAP_PRODUCT.parRateSensitivity(((ResolvedSwapTrade)t).Product, MULTICURVE_EUR_SINGLE_INPUT).build()), nodeDates, VALUATION_DATE); /* Market quotes for comparison */ IDictionary <QuoteId, double> mqCmp = new Dictionary <QuoteId, double>(); for (int looptenor = 0; looptenor < TENORS_STD_1.Length; looptenor++) { mqCmp[QuoteId.of(StandardId.of(OG_TICKER, TICKERS_STD_1[looptenor]))] = marketQuotes[looptenor]; } ImmutableMarketData marketQuotesObject = ImmutableMarketData.of(VALUATION_DATE, mqCmp); RatesProvider multicurveCmp = CALIBRATOR.calibrate(GROUPS_IN_1, marketQuotesObject, REF_DATA); /* Comparison */ DoubleMatrix jiComputed = CurveSensitivityUtils.jacobianFromMarketQuoteSensitivities(LIST_CURVE_NAMES_1, trades, sensitivityFunction); DoubleMatrix jiExpected = multicurveCmp.findData(EUR_SINGLE_NAME).get().Metadata.findInfo(CurveInfoType.JACOBIAN).get().JacobianMatrix; assertEquals(jiComputed.rowCount(), jiExpected.rowCount()); assertEquals(jiComputed.columnCount(), jiExpected.columnCount()); for (int i = 0; i < jiComputed.rowCount(); i++) { for (int j = 0; j < jiComputed.columnCount(); j++) { assertEquals(jiComputed.get(i, j), jiExpected.get(i, j), TOLERANCE_JAC_APPROX); // The comparison is not perfect due to the incoherences introduced by the re-bucketing } } }
/// <summary> /// Calibrate a single curve to 4 points. Use the resulting calibrated curves as starting point of the computation /// of a Jacobian. Compare the direct Jacobian and the one reconstructed from trades. /// </summary> public virtual void direct_two_curves() { JacobianCalibrationMatrix jiObject = MULTICURVE_EUR_2_CALIBRATED.findData(EUR_DSCON_OIS).get().Metadata.findInfo(CurveInfoType.JACOBIAN).get(); ImmutableList <CurveParameterSize> order = jiObject.Order; // To obtain the order of the curves in the jacobian /* Create trades */ IList <ResolvedTrade> tradesDsc = new List <ResolvedTrade>(); for (int looptenor = 0; looptenor < TENORS_STD_2_OIS.Length; looptenor++) { ResolvedSwapTrade t0 = EUR_FIXED_1Y_EONIA_OIS.createTrade(VALUATION_DATE, TENORS_STD_2_OIS[looptenor], BuySell.BUY, 1.0, 0.0, REF_DATA).resolve(REF_DATA); double rate = MARKET_QUOTE.value(t0, MULTICURVE_EUR_2_CALIBRATED); ResolvedSwapTrade t = EUR_FIXED_1Y_EONIA_OIS.createTrade(VALUATION_DATE, TENORS_STD_2_OIS[looptenor], BuySell.BUY, 1.0, rate, REF_DATA).resolve(REF_DATA); tradesDsc.Add(t); } IList <ResolvedTrade> tradesE3 = new List <ResolvedTrade>(); // Fixing IborFixingDepositConvention c = IborFixingDepositConvention.of(EUR_EURIBOR_6M); ResolvedIborFixingDepositTrade fix0 = c.createTrade(VALUATION_DATE, EUR_EURIBOR_6M.Tenor.Period, BuySell.BUY, 1.0, 0.0, REF_DATA).resolve(REF_DATA); double rateFixing = MARKET_QUOTE.value(fix0, MULTICURVE_EUR_2_CALIBRATED); ResolvedIborFixingDepositTrade fix = c.createTrade(VALUATION_DATE, EUR_EURIBOR_6M.Tenor.Period, BuySell.BUY, 1.0, rateFixing, REF_DATA).resolve(REF_DATA); tradesE3.Add(fix); // IRS for (int looptenor = 0; looptenor < TENORS_STD_2_IRS.Length; looptenor++) { ResolvedSwapTrade t0 = EUR_FIXED_1Y_EURIBOR_6M.createTrade(VALUATION_DATE, TENORS_STD_2_IRS[looptenor], BuySell.BUY, 1.0, 0.0, REF_DATA).resolve(REF_DATA); double rate = MARKET_QUOTE.value(t0, MULTICURVE_EUR_2_CALIBRATED); ResolvedSwapTrade t = EUR_FIXED_1Y_EURIBOR_6M.createTrade(VALUATION_DATE, TENORS_STD_2_IRS[looptenor], BuySell.BUY, 1.0, rate, REF_DATA).resolve(REF_DATA); tradesE3.Add(t); } IList <ResolvedTrade> trades = new List <ResolvedTrade>(); if (order.get(0).Name.Equals(EUR_DSCON_OIS)) { ((IList <ResolvedTrade>)trades).AddRange(tradesDsc); ((IList <ResolvedTrade>)trades).AddRange(tradesE3); } else { ((IList <ResolvedTrade>)trades).AddRange(tradesE3); ((IList <ResolvedTrade>)trades).AddRange(tradesDsc); } /* Par rate sensitivity */ System.Func <ResolvedTrade, CurrencyParameterSensitivities> sensitivityFunction = (t) => MULTICURVE_EUR_2_CALIBRATED.parameterSensitivity((t is ResolvedSwapTrade) ? PRICER_SWAP_PRODUCT.parRateSensitivity(((ResolvedSwapTrade)t).Product, MULTICURVE_EUR_2_CALIBRATED).build() : PRICER_IBORFIX_PRODUCT.parRateSensitivity(((ResolvedIborFixingDepositTrade)t).Product, MULTICURVE_EUR_2_CALIBRATED)); DoubleMatrix jiComputed = CurveSensitivityUtils.jacobianFromMarketQuoteSensitivities(order, trades, sensitivityFunction); DoubleMatrix jiExpectedDsc = MULTICURVE_EUR_2_CALIBRATED.findData(EUR_DSCON_OIS).get().Metadata.getInfo(CurveInfoType.JACOBIAN).JacobianMatrix; DoubleMatrix jiExpectedE3 = MULTICURVE_EUR_2_CALIBRATED.findData(EUR_EURIBOR6M_IRS).get().Metadata.getInfo(CurveInfoType.JACOBIAN).JacobianMatrix; /* Comparison */ assertEquals(jiComputed.rowCount(), jiExpectedDsc.rowCount() + jiExpectedE3.rowCount()); assertEquals(jiComputed.columnCount(), jiExpectedDsc.columnCount()); assertEquals(jiComputed.columnCount(), jiExpectedE3.columnCount()); int shiftDsc = order.get(0).Name.Equals(EUR_DSCON_OIS) ? 0 : jiExpectedE3.rowCount(); for (int i = 0; i < jiExpectedDsc.rowCount(); i++) { for (int j = 0; j < jiExpectedDsc.columnCount(); j++) { assertEquals(jiComputed.get(i + shiftDsc, j), jiExpectedDsc.get(i, j), TOLERANCE_JAC); } } int shiftE3 = order.get(0).Name.Equals(EUR_DSCON_OIS) ? jiExpectedDsc.rowCount() : 0; for (int i = 0; i < jiExpectedE3.rowCount(); i++) { for (int j = 0; j < jiExpectedDsc.columnCount(); j++) { assertEquals(jiComputed.get(i + shiftE3, j), jiExpectedE3.get(i, j), TOLERANCE_JAC); } } }
//------------------------------------------------------------------------- /// <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> /// Runs the calibration of SABR on swaptions and print on the console the present value, bucketed PV01 and /// the bucketed Vega of a 18M x 4Y swaption. /// </summary> /// <param name="args"> -s to use the spares data </param> public static void Main(string[] args) { long start, end; // Swaption description BuySell payer = BuySell.BUY; Period expiry = Period.ofMonths(18); double notional = 1_000_000; double strike = 0.0100; Tenor tenor = Tenor.TENOR_4Y; LocalDate expiryDate = EUR_FIXED_1Y_EURIBOR_6M.FloatingLeg.StartDateBusinessDayAdjustment.adjust(CALIBRATION_DATE.plus(expiry), REF_DATA); SwapTrade underlying = EUR_FIXED_1Y_EURIBOR_6M.createTrade(expiryDate, tenor, payer, notional, strike, REF_DATA); Swaption swaption = Swaption.builder().expiryDate(AdjustableDate.of(expiryDate)).expiryTime(LocalTime.of(11, 0x0)).expiryZone(ZoneId.of("Europe/Berlin")).underlying(underlying.Product).longShort(LongShort.LONG).swaptionSettlement(PhysicalSwaptionSettlement.DEFAULT).build(); ResolvedSwaption resolvedSwaption = swaption.resolve(REF_DATA); // select data TenorRawOptionData data = DATA_FULL; if (args.Length > 0) { if (args[0].Equals("-s")) { data = DATA_SPARSE; } } start = DateTimeHelper.CurrentUnixTimeMillis(); // Curve calibration RatesProvider multicurve = CALIBRATOR.calibrate(CONFIGS, MARKET_QUOTES, REF_DATA); end = DateTimeHelper.CurrentUnixTimeMillis(); Console.WriteLine("Curve calibration time: " + (end - start) + " ms."); // SABR calibration start = DateTimeHelper.CurrentUnixTimeMillis(); 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("SABR-Shift", shift); SabrParametersSwaptionVolatilities sabr = SABR_CALIBRATION.calibrateWithFixedBetaAndShift(DEFINITION, CALIBRATION_TIME, data, multicurve, betaSurface, shiftSurface); end = DateTimeHelper.CurrentUnixTimeMillis(); Console.WriteLine("SABR calibration time: " + (end - start) + " ms."); // Price and risk Console.WriteLine("Risk measures: "); start = DateTimeHelper.CurrentUnixTimeMillis(); CurrencyAmount pv = SWAPTION_PRICER.presentValue(resolvedSwaption, multicurve, sabr); Console.WriteLine(" |-> PV: " + pv.ToString()); PointSensitivities deltaPts = SWAPTION_PRICER.presentValueSensitivityRatesStickyModel(resolvedSwaption, multicurve, sabr).build(); CurrencyParameterSensitivities deltaBucketed = multicurve.parameterSensitivity(deltaPts); Console.WriteLine(" |-> Delta bucketed: " + deltaBucketed.ToString()); PointSensitivities vegaPts = SWAPTION_PRICER.presentValueSensitivityModelParamsSabr(resolvedSwaption, multicurve, sabr).build(); Console.WriteLine(" |-> Vega point: " + vegaPts.ToString()); CurrencyParameterSensitivities vegaBucketed = sabr.parameterSensitivity(vegaPts); for (int i = 0; i < vegaBucketed.size(); i++) { Console.WriteLine(" |-> Vega bucketed: " + vegaBucketed.Sensitivities.get(i)); } end = DateTimeHelper.CurrentUnixTimeMillis(); Console.WriteLine("PV and risk time: " + (end - start) + " ms."); }