/** * Copyright (C) 2015 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.strata.pricer.swaption; import static com.opengamma.strata.basics.currency.Currency.EUR; import static com.opengamma.strata.basics.currency.Currency.USD; import static com.opengamma.strata.basics.date.DayCounts.ACT_ACT_ISDA; import static com.opengamma.strata.basics.index.IborIndices.EUR_EURIBOR_6M; import static com.opengamma.strata.basics.index.IborIndices.USD_LIBOR_3M; import static com.opengamma.strata.market.curve.interpolator.CurveInterpolators.LINEAR; import static com.opengamma.strata.product.swap.SwapIndices.EUR_EURIBOR_1100_5Y; import java.time.LocalDate; import java.time.ZoneOffset; import java.time.ZonedDateTime; import java.util.ArrayList; import java.util.List; import com.opengamma.strata.collect.array.DoubleArray; import com.opengamma.strata.collect.timeseries.LocalDateDoubleTimeSeries; import com.opengamma.strata.market.ValueType; import com.opengamma.strata.market.curve.CurveMetadata; import com.opengamma.strata.market.curve.CurveName; import com.opengamma.strata.market.curve.Curves; import com.opengamma.strata.market.curve.InterpolatedNodalCurve; import com.opengamma.strata.market.curve.interpolator.CurveInterpolator; import com.opengamma.strata.market.curve.interpolator.CurveInterpolators; import com.opengamma.strata.market.param.ParameterMetadata; import com.opengamma.strata.market.surface.ConstantSurface; import com.opengamma.strata.market.surface.DefaultSurfaceMetadata; import com.opengamma.strata.market.surface.InterpolatedNodalSurface; import com.opengamma.strata.market.surface.SurfaceMetadata; import com.opengamma.strata.market.surface.Surfaces; import com.opengamma.strata.market.surface.interpolator.GridSurfaceInterpolator; import com.opengamma.strata.market.surface.interpolator.SurfaceInterpolator; import com.opengamma.strata.pricer.model.SabrInterestRateParameters; import com.opengamma.strata.pricer.model.SabrVolatilityFormula; import com.opengamma.strata.pricer.rate.ImmutableRatesProvider; import com.opengamma.strata.product.swap.type.FixedIborSwapConvention; import com.opengamma.strata.product.swap.type.FixedIborSwapConventions; /** * Data sets for testing SABR model for swaptions. */ public class SwaptionSabrRateVolatilityDataSet { /* * Interpolators */ private static final CurveInterpolator INTERPOLATOR = CurveInterpolators.LINEAR; private static final SurfaceInterpolator INTERPOLATOR_2D = GridSurfaceInterpolator.of(LINEAR, LINEAR); /* * Data set used to test the pricers for physical delivery swaption. */ static final FixedIborSwapConvention SWAP_CONVENTION_USD = FixedIborSwapConventions.USD_FIXED_6M_LIBOR_3M; private static final double[] TIME_DSC_USD = new double[] {0.0027397260273972603, 0.005479452054794521, 0.0958904109589041, 0.1726027397260274, 0.26301369863013696, 0.5123287671232877, 0.7643835616438356, 1.0164383561643835, 2.0135040047907777, 3.010958904109589, 4.010958904109589, 5.016438356164383, 6.016236245227937, 7.013698630136986, 8.01095890410959, 9.01095890410959, 10.010771764353619}; private static final double[] RATE_DSC_USD = new double[] {0.0017743012430444162, 0.0016475657039787027, 8.00944979276571E-4, 7.991342366517293E-4, 7.769429292812209E-4, 8.011052753850106E-4, 8.544769819435054E-4, 0.0010101196182894087, 0.0025295133435066005, 0.005928027386129847, 0.009984669002766438, 0.013910233828705014, 0.017362472692574276, 0.02026566836808523, 0.02272069332675379, 0.024782351990410997, 0.026505391310201288}; private static final CurveName NAME_DSC_USD = CurveName.of("USD-DSCON"); static final CurveMetadata META_DSC_USD = Curves.zeroRates(NAME_DSC_USD, ACT_ACT_ISDA); static final InterpolatedNodalCurve CURVE_DSC_USD = InterpolatedNodalCurve.of( META_DSC_USD, DoubleArray.copyOf(TIME_DSC_USD), DoubleArray.copyOf(RATE_DSC_USD), INTERPOLATOR); private static final double[] TIME_FWD_USD = new double[] {0.25205479452054796, 0.5013698630136987, 0.7534246575342466, 1.010958904109589, 2.0107717643536196, 3.0054794520547947, 4.005479452054795, 5.005479452054795, 7.010958904109589, 10.005307283479302, 12.01095890410959, 15.005479452054795, 20.005479452054793, 25.008219178082193, 30.01077176435362}; private static final double[] RATE_FWD_USD = new double[] {0.002377379439054076, 0.002418692953929592, 0.002500627386941208, 0.002647539893522339, 0.0044829589913700256, 0.008123927669512542, 0.012380488135102518, 0.01644838699856555, 0.023026212753825423, 0.02933978147314773, 0.03208786808445587, 0.03475307015968317, 0.03689179443401795, 0.03776622232525561, 0.03810645431268746}; private static final CurveName NAME_FWD_USD = CurveName.of("USD-LIBOR3M"); static final CurveMetadata META_FWD_USD = Curves.zeroRates(NAME_FWD_USD, ACT_ACT_ISDA); static final InterpolatedNodalCurve CURVE_FWD_USD = InterpolatedNodalCurve.of( META_FWD_USD, DoubleArray.copyOf(TIME_FWD_USD), DoubleArray.copyOf(RATE_FWD_USD), INTERPOLATOR); private static final double[] EXPIRY_NODE_USD = new double[] { 0.0, 0.0, 0.0, 0.5, 0.5, 0.5, 1, 1, 1, 2, 2, 2, 5, 5, 5, 10, 10, 10}; private static final double[] TENOR_NODE_USD = new double[] { 1, 5, 10, 1, 5, 10, 1, 5, 10, 1, 5, 10, 1, 5, 10, 1, 5, 10}; private static final double[] ALPHA_NODE_USD = new double[] { 0.05, 0.05, 0.06, 0.05, 0.05, 0.06, 0.05, 0.05, 0.06, 0.05, 0.05, 0.06, 0.05, 0.05, 0.06, 0.05, 0.05, 0.06}; private static final double[] BETA_NODE_USD = new double[] { 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5}; private static final double[] RHO_NODE_USD = new double[] { -0.25, -0.25, -0.25, -0.25, -0.25, -0.25, -0.25, -0.25, 0, -0.25, -0.25, 0, -0.25, -0.25, 0, -0.25, -0.25, 0}; private static final double[] NU_NODE_USD = new double[] { 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.3, 0.5, 0.5, 0.3, 0.5, 0.5, 0.3, 0.5, 0.5, 0.3}; static final SwaptionVolatilitiesName NAME = SwaptionVolatilitiesName.of("Test-SABR"); static final SurfaceMetadata META_ALPHA = Surfaces.sabrParameterByExpiryTenor("Test-SABR-Alpha", ACT_ACT_ISDA, ValueType.SABR_ALPHA); private static final InterpolatedNodalSurface SURFACE_ALPHA_USD = InterpolatedNodalSurface.of( META_ALPHA, DoubleArray.copyOf(EXPIRY_NODE_USD), DoubleArray.copyOf(TENOR_NODE_USD), DoubleArray.copyOf(ALPHA_NODE_USD), INTERPOLATOR_2D); private static final List<ParameterMetadata> PARAMETER_META_LIST_USD; static { int n = EXPIRY_NODE_USD.length; PARAMETER_META_LIST_USD = new ArrayList<ParameterMetadata>(n); for (int i = 0; i < n; ++i) { PARAMETER_META_LIST_USD.add(SwaptionSurfaceExpiryTenorParameterMetadata.of(EXPIRY_NODE_USD[i], TENOR_NODE_USD[i])); } } static final SurfaceMetadata META_BETA_USD = Surfaces.sabrParameterByExpiryTenor("Test-SABR-Beta", ACT_ACT_ISDA, ValueType.SABR_BETA) .withParameterMetadata(PARAMETER_META_LIST_USD); private static final InterpolatedNodalSurface SURFACE_BETA_USD = InterpolatedNodalSurface.of( META_BETA_USD, DoubleArray.copyOf(EXPIRY_NODE_USD), DoubleArray.copyOf(TENOR_NODE_USD), DoubleArray.copyOf(BETA_NODE_USD), INTERPOLATOR_2D); static final SurfaceMetadata META_RHO = Surfaces.sabrParameterByExpiryTenor("Test-SABR-Rho", ACT_ACT_ISDA, ValueType.SABR_RHO); private static final InterpolatedNodalSurface SURFACE_RHO_USD = InterpolatedNodalSurface.of( META_RHO, DoubleArray.copyOf(EXPIRY_NODE_USD), DoubleArray.copyOf(TENOR_NODE_USD), DoubleArray.copyOf(RHO_NODE_USD), INTERPOLATOR_2D); static final SurfaceMetadata META_NU = Surfaces.sabrParameterByExpiryTenor("Test-SABR-Nu", ACT_ACT_ISDA, ValueType.SABR_NU); private static final InterpolatedNodalSurface SURFACE_NU_USD = InterpolatedNodalSurface.of( META_NU, DoubleArray.copyOf(EXPIRY_NODE_USD), DoubleArray.copyOf(TENOR_NODE_USD), DoubleArray.copyOf(NU_NODE_USD), INTERPOLATOR_2D); static final SabrInterestRateParameters SABR_PARAM_USD = SabrInterestRateParameters.of( SURFACE_ALPHA_USD, SURFACE_BETA_USD, SURFACE_RHO_USD, SURFACE_NU_USD, SabrVolatilityFormula.hagan()); static final double SHIFT = 0.025; private static final DefaultSurfaceMetadata META_SHIFT = DefaultSurfaceMetadata.of("Test-SABR-Shift"); private static final ConstantSurface SURFACE_SHIFT_USD = ConstantSurface.of(META_SHIFT, SHIFT); static final SabrInterestRateParameters SABR_PARAM_SHIFT_USD = SabrInterestRateParameters.of( SURFACE_ALPHA_USD, SURFACE_BETA_USD, SURFACE_RHO_USD, SURFACE_NU_USD, SURFACE_SHIFT_USD, SabrVolatilityFormula.hagan()); /** * Obtains {@code ImmutableRatesProvider} for specified valuation date. * * @param valuationDate the valuation date * @return the rates provider */ public static ImmutableRatesProvider getRatesProviderUsd(LocalDate valuationDate) { return ImmutableRatesProvider.builder(valuationDate) .discountCurve(USD, CURVE_DSC_USD) .iborIndexCurve(USD_LIBOR_3M, CURVE_FWD_USD) .build(); } /** * Obtains {@code SABRVolatilitySwaptionProvider} for specified valuation date. * * @param valuationDate the valuation date * @param shift nonzero shift if true, zero shift otherwise * @return the volatility provider */ public static SabrParametersSwaptionVolatilities getVolatilitiesUsd(LocalDate valuationDate, boolean shift) { ZonedDateTime dateTime = valuationDate.atStartOfDay(ZoneOffset.UTC); return shift ? SabrParametersSwaptionVolatilities.of(NAME, SWAP_CONVENTION_USD, dateTime, SABR_PARAM_SHIFT_USD) : SabrParametersSwaptionVolatilities.of(NAME, SWAP_CONVENTION_USD, dateTime, SABR_PARAM_USD); } /* * Data set used to test the pricers for cash settled swaption. */ static final FixedIborSwapConvention SWAP_CONVENTION_EUR = FixedIborSwapConventions.EUR_FIXED_1Y_EURIBOR_6M; private static final double[] TIME_DSC_EUR = new double[] {0.0, 0.5, 1.0, 2.0, 5.0, 10.0}; private static final double[] RATE_DSC_EUR = new double[] {0.0150, 0.0125, 0.0150, 0.0175, 0.0150, 0.0150}; private static final CurveName NAME_DSC_EUR = CurveName.of("EUR Dsc"); static final CurveMetadata META_DSC_EUR = Curves.zeroRates(NAME_DSC_EUR, ACT_ACT_ISDA); public static final InterpolatedNodalCurve CURVE_DSC_EUR = InterpolatedNodalCurve.of( META_DSC_EUR, DoubleArray.copyOf(TIME_DSC_EUR), DoubleArray.copyOf(RATE_DSC_EUR), INTERPOLATOR); private static final double[] TIME_FWD_EUR = new double[] {0.0, 0.5, 1.0, 2.0, 5.0, 10.0}; private static final double[] RATE_FWD_EUR = new double[] {0.0150, 0.0125, 0.0150, 0.0175, 0.0150, 0.0150}; private static final CurveName NAME_FWD_EUR = CurveName.of("EUR EURIBOR 6M"); static final CurveMetadata META_FWD_EUR = Curves.zeroRates(NAME_FWD_EUR, ACT_ACT_ISDA); public static final InterpolatedNodalCurve CURVE_FWD_EUR = InterpolatedNodalCurve.of( META_FWD_EUR, DoubleArray.copyOf(TIME_FWD_EUR), DoubleArray.copyOf(RATE_FWD_EUR), INTERPOLATOR); private static final double[] BETA_EXPIRY_NODE_EUR = new double[] { 0, 0, 0, 0, 0.5, 0.5, 0.5, 0.5, 1, 1, 1, 1, 2, 2, 2, 2, 5, 5, 5, 5, 10, 10, 10, 10, 100, 100, 100, 100}; private static final double[] BETA_TENOR_NODE_EUR = new double[] { 0, 1, 10, 100, 0, 1, 10, 100, 0, 1, 10, 100, 0, 1, 10, 100, 0, 1, 10, 100, 0, 1, 10, 100, 0, 1, 10, 100}; private static final InterpolatedNodalSurface SURFACE_ALPHA_EUR = InterpolatedNodalSurface.of( Surfaces.sabrParameterByExpiryTenor("Test-SABR-Alpha", ACT_ACT_ISDA, ValueType.SABR_ALPHA), DoubleArray.of(0, 0, 0, 0, 0.5, 0.5, 0.5, 0.5, 1, 1, 1, 1, 2, 2, 2, 2, 5, 5, 5, 5, 10, 10, 10, 10), DoubleArray.of(0, 1, 10, 100, 0, 1, 10, 100, 0, 1, 10, 100, 0, 1, 10, 100, 0, 1, 10, 100, 0, 1, 10, 100), DoubleArray.of( 0.05, 0.05, 0.06, 0.06, 0.05, 0.05, 0.06, 0.06, 0.05, 0.05, 0.06, 0.06, 0.05, 0.05, 0.06, 0.06, 0.05, 0.05, 0.06, 0.06, 0.05, 0.05, 0.06, 0.06), INTERPOLATOR_2D); private static final List<ParameterMetadata> PARAMETER_META_LIST_EUR; static { int n = BETA_TENOR_NODE_EUR.length; PARAMETER_META_LIST_EUR = new ArrayList<ParameterMetadata>(n); for (int i = 0; i < n; ++i) { PARAMETER_META_LIST_EUR.add(SwaptionSurfaceExpiryTenorParameterMetadata.of(BETA_EXPIRY_NODE_EUR[i], BETA_TENOR_NODE_EUR[i])); } } static final SurfaceMetadata META_BETA_EUR = Surfaces.sabrParameterByExpiryTenor("Test-SABR-Beta", ACT_ACT_ISDA, ValueType.SABR_BETA) .withParameterMetadata(PARAMETER_META_LIST_EUR); private static final InterpolatedNodalSurface SURFACE_BETA_EUR = InterpolatedNodalSurface.of( META_BETA_EUR, DoubleArray.copyOf(BETA_EXPIRY_NODE_EUR), DoubleArray.copyOf(BETA_TENOR_NODE_EUR), DoubleArray.copyOf(new double[] {0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5}), INTERPOLATOR_2D); private static final InterpolatedNodalSurface SURFACE_RHO_EUR = InterpolatedNodalSurface.of( Surfaces.sabrParameterByExpiryTenor("Test-SABR-Rho", ACT_ACT_ISDA, ValueType.SABR_RHO), DoubleArray.of( 0, 0, 0, 0, 0.5, 0.5, 0.5, 0.5, 1, 1, 1, 1, 2, 2, 2, 2, 5, 5, 5, 5, 10, 10, 10, 10, 100, 100, 100, 100), DoubleArray.of( 0, 1, 10, 100, 0, 1, 10, 100, 0, 1, 10, 100, 0, 1, 10, 100, 0, 1, 10, 100, 0, 1, 10, 100, 0, 1, 10, 100), DoubleArray.of( -0.25, -0.25, 0, 0, -0.25, -0.25, 0, 0, -0.25, -0.25, 0, 0, -0.25, -0.25, 0, 0, -0.25, -0.25, 0, 0, -0.25, -0.25, 0, 0, -0.25, -0.25, 0, 0), INTERPOLATOR_2D); private static final InterpolatedNodalSurface SURFACE_NU_EUR = InterpolatedNodalSurface.of( Surfaces.sabrParameterByExpiryTenor("Test-SABR-Nu", ACT_ACT_ISDA, ValueType.SABR_NU), DoubleArray.of( 0, 0, 0, 0, 0.5, 0.5, 0.5, 0.5, 1, 1, 1, 1, 2, 2, 2, 2, 5, 5, 5, 5, 10, 10, 10, 10, 100, 100, 100, 100), DoubleArray.of( 0, 1, 10, 100, 0, 1, 10, 100, 0, 1, 10, 100, 0, 1, 10, 100, 0, 1, 10, 100, 0, 1, 10, 100, 0, 1, 10, 100), DoubleArray.of( 0.50, 0.50, 0.30, 0.30, 0.50, 0.50, 0.30, 0.30, 0.50, 0.50, 0.30, 0.30, 0.50, 0.50, 0.30, 0.30, 0.50, 0.50, 0.30, 0.30, 0.50, 0.50, 0.30, 0.30, 0.50, 0.50, 0.30, 0.30), INTERPOLATOR_2D); private static final ConstantSurface SURFACE_SHIFT_EUR = ConstantSurface.of(META_SHIFT, SHIFT); static final SabrInterestRateParameters SABR_PARAM_EUR = SabrInterestRateParameters.of( SURFACE_ALPHA_EUR, SURFACE_BETA_EUR, SURFACE_RHO_EUR, SURFACE_NU_EUR, SabrVolatilityFormula.hagan()); static final SabrInterestRateParameters SABR_PARAM_SHIFT_EUR = SabrInterestRateParameters.of(SURFACE_ALPHA_EUR, SURFACE_BETA_EUR, SURFACE_RHO_EUR, SURFACE_NU_EUR, SURFACE_SHIFT_EUR, SabrVolatilityFormula.hagan()); /** * Obtains {@code ImmutableRatesProvider} for specified valuation date. * * @param valuationDate the valuation date * @return the rates provider */ public static ImmutableRatesProvider getRatesProviderEur(LocalDate valuationDate) { return ImmutableRatesProvider.builder(valuationDate) .discountCurve(EUR, CURVE_DSC_EUR) .iborIndexCurve(EUR_EURIBOR_6M, CURVE_FWD_EUR) .build(); } /** * Obtains {@code ImmutableRatesProvider} for specified valuation date and time series of swap index. * * @param valuationDate the valuation date * @param timeSeries the time series * @return the rates provider */ public static ImmutableRatesProvider getRatesProviderEur(LocalDate valuationDate, LocalDateDoubleTimeSeries timeSeries) { return ImmutableRatesProvider.builder(valuationDate) .discountCurve(EUR, CURVE_DSC_EUR) .iborIndexCurve(EUR_EURIBOR_6M, CURVE_FWD_EUR) .timeSeries(EUR_EURIBOR_1100_5Y, timeSeries) .build(); } /** * Obtains {@code SABRVolatilitySwaptionProvider} for specified valuation date. * * @param valuationDate the valuation date * @param shift nonzero shift if true, zero shift otherwise * @return the volatility provider */ public static SabrParametersSwaptionVolatilities getVolatilitiesEur(LocalDate valuationDate, boolean shift) { ZonedDateTime dateTime = valuationDate.atStartOfDay(ZoneOffset.UTC); return shift ? SabrParametersSwaptionVolatilities.of(NAME, SWAP_CONVENTION_EUR, dateTime, SABR_PARAM_SHIFT_EUR) : SabrParametersSwaptionVolatilities.of(NAME, SWAP_CONVENTION_EUR, dateTime, SABR_PARAM_EUR); } }