/** * Creates metadata for a surface providing Black expiry-strike volatility. * <p> * The x-values represent time to expiry year fractions as defined by the specified day count. * The y-values represent strike * The z-values represent Black volatility. * * @param name the surface name * @param dayCount the day count * @return the surface metadata */ public static SurfaceMetadata blackVolatilityByExpiryStrike(String name, DayCount dayCount) { return blackVolatilityByExpiryStrike(SurfaceName.of(name), dayCount); }
@Override public SurfaceMetadata createMetadata(RawOptionData capFloorData) { SurfaceMetadata metadata; if (capFloorData.getDataType().equals(BLACK_VOLATILITY)) { metadata = Surfaces.blackVolatilityByExpiryStrike(name.getName(), dayCount); } else if (capFloorData.getDataType().equals(NORMAL_VOLATILITY)) { metadata = Surfaces.normalVolatilityByExpiryStrike(name.getName(), dayCount); } else { throw new IllegalArgumentException("Data type not supported"); } return metadata; }
@Override public SurfaceMetadata createMetadata(RawOptionData capFloorData) { SurfaceMetadata metadata; if (capFloorData.getDataType().equals(BLACK_VOLATILITY)) { metadata = Surfaces.blackVolatilityByExpiryStrike(name.getName(), dayCount); } else if (capFloorData.getDataType().equals(NORMAL_VOLATILITY)) { metadata = Surfaces.normalVolatilityByExpiryStrike(name.getName(), dayCount); } else { throw new IllegalArgumentException("Data type not supported"); } return metadata; }
@Override public SurfaceMetadata createMetadata(RawOptionData capFloorData) { SurfaceMetadata metadata; if (capFloorData.getDataType().equals(BLACK_VOLATILITY)) { metadata = Surfaces.blackVolatilityByExpiryStrike(name.getName(), dayCount); } else if (capFloorData.getDataType().equals(NORMAL_VOLATILITY)) { metadata = Surfaces.normalVolatilityByExpiryStrike(name.getName(), dayCount); } else { throw new IllegalArgumentException("Data type not supported"); } return metadata; }
@Override public SurfaceMetadata createMetadata(RawOptionData capFloorData) { List<GenericVolatilitySurfacePeriodParameterMetadata> list = new ArrayList<>(); ImmutableList<Period> expiries = capFloorData.getExpiries(); int nExpiries = expiries.size(); DoubleArray strikes = capFloorData.getStrikes(); int nStrikes = strikes.size(); for (int i = 0; i < nExpiries; ++i) { for (int j = 0; j < nStrikes; ++j) { if (Double.isFinite(capFloorData.getData().get(i, j))) { list.add(GenericVolatilitySurfacePeriodParameterMetadata.of(expiries.get(i), SimpleStrike.of(strikes.get(j)))); } } } SurfaceMetadata metadata; if (capFloorData.getDataType().equals(ValueType.BLACK_VOLATILITY)) { metadata = Surfaces.blackVolatilityByExpiryStrike(name.getName(), dayCount); } else if (capFloorData.getDataType().equals(ValueType.NORMAL_VOLATILITY)) { metadata = Surfaces.normalVolatilityByExpiryStrike(name.getName(), dayCount); } else { throw new IllegalArgumentException("Data type not supported"); } return metadata.withParameterMetadata(list); }
public void blackVolatilityByExpiryStrike_string() { SurfaceMetadata test = Surfaces.blackVolatilityByExpiryStrike(NAME, ACT_360); SurfaceMetadata expected = DefaultSurfaceMetadata.builder() .surfaceName(SURFACE_NAME) .xValueType(ValueType.YEAR_FRACTION) .yValueType(ValueType.STRIKE) .zValueType(ValueType.BLACK_VOLATILITY) .dayCount(ACT_360) .build(); assertEquals(test, expected); }
public void test_createMetadata() { DirectIborCapletFloorletVolatilityDefinition base = DirectIborCapletFloorletVolatilityDefinition.of( NAME, USD_LIBOR_3M, ACT_ACT_ISDA, LAMBDA_EXPIRY, LAMBDA_STRIKE, INTERPOLATOR); assertEquals(base.createMetadata(SAMPLE_BLACK), Surfaces.blackVolatilityByExpiryStrike(NAME.getName(), ACT_ACT_ISDA)); assertEquals(base.createMetadata(SAMPLE_NORMAL), Surfaces.normalVolatilityByExpiryStrike(NAME.getName(), ACT_ACT_ISDA)); assertThrowsIllegalArg(() -> base.createMetadata(RawOptionData.of(EXPIRIES, STRIKES, STRIKE, DATA, ValueType.PRICE))); }
public void test_createMetadata() { SabrIborCapletFloorletVolatilityCalibrationDefinition base = SabrIborCapletFloorletVolatilityCalibrationDefinition.ofFixedBeta( NAME, USD_LIBOR_3M, ACT_365F, BETA_RHO, ALPHA_KNOTS, BETA_RHO_KNOTS, NU_KNOTS, DOUBLE_QUADRATIC, FLAT, LINEAR, HAGAN); assertEquals(base.createMetadata(SAMPLE_BLACK), Surfaces.blackVolatilityByExpiryStrike(NAME.getName(), ACT_365F)); assertEquals(base.createMetadata(SAMPLE_NORMAL), Surfaces.normalVolatilityByExpiryStrike(NAME.getName(), ACT_365F)); assertThrowsIllegalArg(() -> base.createMetadata(RawOptionData.of(EXPIRIES, STRIKES, STRIKE, DATA, ValueType.PRICE))); }
public void blackVolatilityByExpiryStrike_surfaceName() { SurfaceMetadata test = Surfaces.blackVolatilityByExpiryStrike(SURFACE_NAME, ACT_360); SurfaceMetadata expected = DefaultSurfaceMetadata.builder() .surfaceName(SURFACE_NAME) .xValueType(ValueType.YEAR_FRACTION) .yValueType(ValueType.STRIKE) .zValueType(ValueType.BLACK_VOLATILITY) .dayCount(ACT_360) .build(); assertEquals(test, expected); }
public void test_createMetadata_black() { SabrIborCapletFloorletVolatilityBootstrapDefinition base = SabrIborCapletFloorletVolatilityBootstrapDefinition.ofFixedBeta( NAME, USD_LIBOR_3M, ACT_ACT_ISDA, 0.5, LINEAR, FLAT, FLAT, SabrVolatilityFormula.hagan()); RawOptionData capData = RawOptionData.of( ImmutableList.of(Period.ofYears(1), Period.ofYears(5)), DoubleArray.of(0.005, 0.01, 0.015), ValueType.STRIKE, DoubleMatrix.copyOf(new double[][] {{0.15, 0.12, 0.13}, {0.1, 0.08, 0.09}}), ValueType.BLACK_VOLATILITY); SurfaceMetadata expected = Surfaces.blackVolatilityByExpiryStrike(NAME.getName(), ACT_ACT_ISDA); SurfaceMetadata computed = base.createMetadata(capData); assertEquals(computed, expected); }
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); }
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);
public void recovery_test_flat() { DoubleArray initial = DoubleArray.of(0.4, 0.95, 0.5, 0.05); SabrIborCapletFloorletVolatilityCalibrationDefinition definition = SabrIborCapletFloorletVolatilityCalibrationDefinition.ofFixedBeta( NAME, USD_LIBOR_3M, ACT_ACT_ISDA, ALPHA_KNOTS, BETA_RHO_KNOTS, NU_KNOTS, initial, LINEAR, FLAT, FLAT, HAGAN); 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); SabrIborCapletFloorletVolatilities resVol = (SabrIborCapletFloorletVolatilities) 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_SABR.presentValue(caps.get(j), RATES_PROVIDER, resVol).getAmount(); assertEquals(priceOrg, priceCalib, Math.max(priceOrg, 1d) * TOL); } } }
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);
public void test_createMetadata_black() { SurfaceIborCapletFloorletVolatilityBootstrapDefinition base = SurfaceIborCapletFloorletVolatilityBootstrapDefinition.of( NAME, USD_LIBOR_3M, ACT_ACT_ISDA, LINEAR, DOUBLE_QUADRATIC); RawOptionData capData = RawOptionData.of( ImmutableList.of(Period.ofYears(1), Period.ofYears(5)), DoubleArray.of(0.005, 0.01, 0.015), ValueType.STRIKE, DoubleMatrix.copyOf(new double[][] {{0.15, 0.12, 0.13}, {0.1, 0.08, 0.09}}), ValueType.BLACK_VOLATILITY); List<GenericVolatilitySurfacePeriodParameterMetadata> list = new ArrayList<>(); list.add(GenericVolatilitySurfacePeriodParameterMetadata.of(Period.ofYears(1), SimpleStrike.of(0.005))); list.add(GenericVolatilitySurfacePeriodParameterMetadata.of(Period.ofYears(1), SimpleStrike.of(0.01))); list.add(GenericVolatilitySurfacePeriodParameterMetadata.of(Period.ofYears(1), SimpleStrike.of(0.015))); list.add(GenericVolatilitySurfacePeriodParameterMetadata.of(Period.ofYears(5), SimpleStrike.of(0.005))); list.add(GenericVolatilitySurfacePeriodParameterMetadata.of(Period.ofYears(5), SimpleStrike.of(0.01))); list.add(GenericVolatilitySurfacePeriodParameterMetadata.of(Period.ofYears(5), SimpleStrike.of(0.015))); SurfaceMetadata expected = Surfaces.blackVolatilityByExpiryStrike( NAME.getName(), ACT_ACT_ISDA).withParameterMetadata(list); SurfaceMetadata computed = base.createMetadata(capData); assertEquals(computed, expected); }
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);
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);
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_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_presentValueSensitivity() { PointSensitivityBuilder pointCaplet = PRICER.presentValueSensitivityRatesStickyModel(CAPLET_LONG, RATES, VOLS); CurrencyParameterSensitivities computedCaplet = RATES.parameterSensitivity(pointCaplet.build()); PointSensitivityBuilder pointFloorlet = PRICER.presentValueSensitivityRatesStickyModel(FLOORLET_SHORT, RATES, VOLS); CurrencyParameterSensitivities computedFloorlet = RATES.parameterSensitivity(pointFloorlet.build()); CurrencyParameterSensitivities expectedCaplet = FD_CAL.sensitivity(RATES, p -> PRICER_BASE.presentValue(CAPLET_LONG, p, VOLS)); CurrencyParameterSensitivities expectedFloorlet = FD_CAL.sensitivity(RATES, p -> PRICER_BASE.presentValue(FLOORLET_SHORT, p, VOLS)); assertTrue(computedCaplet.equalWithTolerance(expectedCaplet, EPS_FD * NOTIONAL * 50d)); assertTrue(computedFloorlet.equalWithTolerance(expectedFloorlet, EPS_FD * NOTIONAL * 50d)); // consistency with shifted Black PointSensitivityBuilder pointCapletBase = PRICER.presentValueSensitivityRates(CAPLET_LONG, RATES, VOLS); PointSensitivityBuilder pointFloorletBase = PRICER.presentValueSensitivityRates(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); ShiftedBlackIborCapletFloorletExpiryStrikeVolatilities vols = ShiftedBlackIborCapletFloorletExpiryStrikeVolatilities.of( EUR_EURIBOR_3M, VALUATION, ConstantSurface.of("constVol", volatility) .withMetadata(Surfaces.blackVolatilityByExpiryStrike("costVol", DayCounts.ACT_ACT_ISDA)), IborCapletFloorletSabrRateVolatilityDataSet.CURVE_CONST_SHIFT); PointSensitivityBuilder pointCapletExp = PRICER_BASE.presentValueSensitivityRates(CAPLET_LONG, RATES, vols); PointSensitivityBuilder pointFloorletExp = PRICER_BASE.presentValueSensitivityRates(FLOORLET_SHORT, RATES, vols); assertEquals(pointCapletBase, pointCapletExp); assertEquals(pointFloorletBase, pointFloorletExp); }