/**
* 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.USD;
import static com.opengamma.strata.collect.TestHelper.assertThrowsIllegalArg;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
import static org.testng.Assert.fail;
import java.time.LocalDate;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;
import org.testng.annotations.Test;
import com.opengamma.strata.basics.ReferenceData;
import com.opengamma.strata.basics.currency.CurrencyAmount;
import com.opengamma.strata.basics.currency.MultiCurrencyAmount;
import com.opengamma.strata.basics.date.AdjustableDate;
import com.opengamma.strata.basics.date.Tenor;
import com.opengamma.strata.collect.array.DoubleArray;
import com.opengamma.strata.collect.tuple.DoublesPair;
import com.opengamma.strata.market.model.SabrParameterType;
import com.opengamma.strata.market.param.CurrencyParameterSensitivities;
import com.opengamma.strata.market.param.CurrencyParameterSensitivity;
import com.opengamma.strata.market.param.ParameterMetadata;
import com.opengamma.strata.market.sensitivity.PointSensitivities;
import com.opengamma.strata.market.sensitivity.PointSensitivity;
import com.opengamma.strata.market.sensitivity.PointSensitivityBuilder;
import com.opengamma.strata.market.surface.ConstantSurface;
import com.opengamma.strata.market.surface.SurfaceMetadata;
import com.opengamma.strata.market.surface.Surfaces;
import com.opengamma.strata.pricer.impl.option.BlackFormulaRepository;
import com.opengamma.strata.pricer.rate.ImmutableRatesProvider;
import com.opengamma.strata.pricer.sensitivity.RatesFiniteDifferenceSensitivityCalculator;
import com.opengamma.strata.pricer.swap.DiscountingSwapProductPricer;
import com.opengamma.strata.product.common.BuySell;
import com.opengamma.strata.product.common.LongShort;
import com.opengamma.strata.product.swap.ResolvedSwap;
import com.opengamma.strata.product.swap.Swap;
import com.opengamma.strata.product.swap.SwapLegType;
import com.opengamma.strata.product.swaption.CashSwaptionSettlement;
import com.opengamma.strata.product.swaption.CashSwaptionSettlementMethod;
import com.opengamma.strata.product.swaption.PhysicalSwaptionSettlement;
import com.opengamma.strata.product.swaption.ResolvedSwaption;
import com.opengamma.strata.product.swaption.Swaption;
import com.opengamma.strata.product.swaption.SwaptionSettlement;
/**
* Test {@link SabrSwaptionPhysicalProductPricer}.
*/
@Test
public class SabrSwaptionPhysicalProductPricerTest {
private static final ReferenceData REF_DATA = ReferenceData.standard();
private static final LocalDate VAL_DATE = LocalDate.of(2014, 1, 22);
// swaptions
private static final double NOTIONAL = 100000000; //100m
private static final double RATE = 0.0350;
private static final int TENOR_YEAR = 7;
private static final Tenor TENOR = Tenor.ofYears(TENOR_YEAR);
private static final ZonedDateTime MATURITY_DATE = LocalDate.of(2016, 1, 22).atStartOfDay(ZoneOffset.UTC); // 2Y
private static final Swap SWAP_PAY = SwaptionSabrRateVolatilityDataSet.SWAP_CONVENTION_USD.createTrade(
MATURITY_DATE.toLocalDate(), TENOR, BuySell.BUY, NOTIONAL, RATE, REF_DATA).getProduct();
private static final ResolvedSwap RSWAP_PAY = SWAP_PAY.resolve(REF_DATA);
private static final Swap SWAP_REC = SwaptionSabrRateVolatilityDataSet.SWAP_CONVENTION_USD.createTrade(
MATURITY_DATE.toLocalDate(), TENOR, BuySell.SELL, NOTIONAL, RATE, REF_DATA).getProduct();
private static final ResolvedSwap RSWAP_REC = SWAP_REC.resolve(REF_DATA);
private static final SwaptionSettlement PHYSICAL_SETTLE = PhysicalSwaptionSettlement.DEFAULT;
private static final SwaptionSettlement CASH_SETTLE =
CashSwaptionSettlement.of(SWAP_REC.getStartDate().getUnadjusted(), CashSwaptionSettlementMethod.PAR_YIELD);
private static final ResolvedSwaption SWAPTION_PAY_LONG = Swaption.builder()
.expiryDate(AdjustableDate.of(MATURITY_DATE.toLocalDate()))
.expiryTime(MATURITY_DATE.toLocalTime())
.expiryZone(MATURITY_DATE.getZone())
.longShort(LongShort.LONG)
.swaptionSettlement(PHYSICAL_SETTLE)
.underlying(SWAP_PAY)
.build().
resolve(REF_DATA);
private static final ResolvedSwaption SWAPTION_PAY_SHORT = Swaption.builder()
.expiryDate(AdjustableDate.of(MATURITY_DATE.toLocalDate()))
.expiryTime(MATURITY_DATE.toLocalTime())
.expiryZone(MATURITY_DATE.getZone())
.longShort(LongShort.SHORT)
.swaptionSettlement(PHYSICAL_SETTLE)
.underlying(SWAP_PAY)
.build().
resolve(REF_DATA);
private static final ResolvedSwaption SWAPTION_REC_LONG = Swaption.builder()
.expiryDate(AdjustableDate.of(MATURITY_DATE.toLocalDate()))
.expiryTime(MATURITY_DATE.toLocalTime())
.expiryZone(MATURITY_DATE.getZone())
.longShort(LongShort.LONG)
.swaptionSettlement(PHYSICAL_SETTLE)
.underlying(SWAP_REC)
.build().
resolve(REF_DATA);
private static final ResolvedSwaption SWAPTION_REC_SHORT = Swaption.builder()
.expiryDate(AdjustableDate.of(MATURITY_DATE.toLocalDate()))
.expiryTime(MATURITY_DATE.toLocalTime())
.expiryZone(MATURITY_DATE.getZone())
.longShort(LongShort.SHORT)
.swaptionSettlement(PHYSICAL_SETTLE)
.underlying(SWAP_REC)
.build().
resolve(REF_DATA);
private static final ResolvedSwaption SWAPTION_CASH = Swaption.builder()
.expiryDate(AdjustableDate.of(MATURITY_DATE.toLocalDate()))
.expiryTime(MATURITY_DATE.toLocalTime())
.expiryZone(MATURITY_DATE.getZone())
.longShort(LongShort.LONG)
.swaptionSettlement(CASH_SETTLE)
.underlying(SWAP_REC)
.build().
resolve(REF_DATA);
// providers
private static final ImmutableRatesProvider RATE_PROVIDER =
SwaptionSabrRateVolatilityDataSet.getRatesProviderUsd(VAL_DATE);
private static final ImmutableRatesProvider RATE_PROVIDER_AT_MATURITY =
SwaptionSabrRateVolatilityDataSet.getRatesProviderUsd(MATURITY_DATE.toLocalDate());
private static final ImmutableRatesProvider RATE_PROVIDER_AFTER_MATURITY =
SwaptionSabrRateVolatilityDataSet.getRatesProviderUsd(MATURITY_DATE.toLocalDate().plusDays(1));
private static final SabrParametersSwaptionVolatilities VOLS =
SwaptionSabrRateVolatilityDataSet.getVolatilitiesUsd(VAL_DATE, true);
private static final SabrParametersSwaptionVolatilities VOLS_AT_MATURITY =
SwaptionSabrRateVolatilityDataSet.getVolatilitiesUsd(MATURITY_DATE.toLocalDate(), true);
private static final SabrParametersSwaptionVolatilities VOLS_AFTER_MATURITY =
SwaptionSabrRateVolatilityDataSet.getVolatilitiesUsd(MATURITY_DATE.toLocalDate().plusDays(1), true);
private static final SabrParametersSwaptionVolatilities VOLS_REGRESSION =
SwaptionSabrRateVolatilityDataSet.getVolatilitiesUsd(VAL_DATE, false);
// test parameters and calculator
private static final double TOL = 1.0e-13;
private static final double TOLERANCE_DELTA = 1.0E-2;
private static final double FD_EPS = 1.0e-6;
private static final double REGRESSION_TOL = 1.0e-4; // due to tenor computation difference
private static final SabrSwaptionPhysicalProductPricer SWAPTION_PRICER = SabrSwaptionPhysicalProductPricer.DEFAULT;
private static final DiscountingSwapProductPricer SWAP_PRICER = DiscountingSwapProductPricer.DEFAULT;
private static final RatesFiniteDifferenceSensitivityCalculator FD_CAL =
new RatesFiniteDifferenceSensitivityCalculator(FD_EPS);
//-------------------------------------------------------------------------
public void validate_physical_settlement() {
assertThrowsIllegalArg(() -> SWAPTION_PRICER.presentValue(SWAPTION_CASH, RATE_PROVIDER, VOLS));
}
//-------------------------------------------------------------------------
public 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.getLegPricer().pvbp(RSWAP_REC.getLegs(SwapLegType.FIXED).get(0), RATE_PROVIDER);
double volatility = VOLS.volatility(SWAPTION_REC_LONG.getExpiry(),
TENOR_YEAR, RATE, forward);
double maturity = VOLS.relativeTime(SWAPTION_REC_LONG.getExpiry());
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.getCurrency(), USD);
assertEquals(computedRec.getAmount(), expectedRec, NOTIONAL * TOL);
assertEquals(computedPay.getCurrency(), USD);
assertEquals(computedPay.getAmount(), expectedPay, NOTIONAL * TOL);
}
public void test_presentValue_atMaturity() {
CurrencyAmount computedRec =
SWAPTION_PRICER.presentValue(SWAPTION_REC_LONG, RATE_PROVIDER_AT_MATURITY, VOLS_AT_MATURITY);
CurrencyAmount computedPay =
SWAPTION_PRICER.presentValue(SWAPTION_PAY_SHORT, RATE_PROVIDER_AT_MATURITY, VOLS_AT_MATURITY);
double swapPV = SWAP_PRICER.presentValue(RSWAP_REC, RATE_PROVIDER_AT_MATURITY).getAmount(USD).getAmount();
assertEquals(computedRec.getAmount(), swapPV, NOTIONAL * TOL);
assertEquals(computedPay.getAmount(), 0d, NOTIONAL * TOL);
}
public void test_presentValue_afterExpiry() {
CurrencyAmount computedRec =
SWAPTION_PRICER.presentValue(SWAPTION_REC_LONG, RATE_PROVIDER_AFTER_MATURITY, VOLS_AFTER_MATURITY);
CurrencyAmount computedPay =
SWAPTION_PRICER.presentValue(SWAPTION_PAY_SHORT, RATE_PROVIDER_AFTER_MATURITY, VOLS_AFTER_MATURITY);
assertEquals(computedRec.getAmount(), 0d, NOTIONAL * TOL);
assertEquals(computedPay.getAmount(), 0d, NOTIONAL * TOL);
}
public void test_presentValue_parity() {
CurrencyAmount pvRecLong = SWAPTION_PRICER.presentValue(SWAPTION_REC_LONG, RATE_PROVIDER, VOLS);
CurrencyAmount pvRecShort = SWAPTION_PRICER.presentValue(SWAPTION_REC_SHORT, RATE_PROVIDER, VOLS);
CurrencyAmount pvPayLong = SWAPTION_PRICER.presentValue(SWAPTION_PAY_LONG, RATE_PROVIDER, VOLS);
CurrencyAmount pvPayShort = SWAPTION_PRICER.presentValue(SWAPTION_PAY_SHORT, RATE_PROVIDER, VOLS);
assertEquals(pvRecLong.getAmount(), -pvRecShort.getAmount(), NOTIONAL * TOL);
assertEquals(pvPayLong.getAmount(), -pvPayShort.getAmount(), NOTIONAL * TOL);
double swapPV = SWAP_PRICER.presentValue(RSWAP_PAY, RATE_PROVIDER).getAmount(USD).getAmount();
assertEquals(pvPayLong.getAmount() - pvRecLong.getAmount(), swapPV, NOTIONAL * TOL);
assertEquals(pvPayShort.getAmount() - pvRecShort.getAmount(), -swapPV, NOTIONAL * TOL);
}
public void test_presentValue_parity_atMaturity() {
CurrencyAmount pvRecLong =
SWAPTION_PRICER.presentValue(SWAPTION_REC_LONG, RATE_PROVIDER_AT_MATURITY, VOLS_AT_MATURITY);
CurrencyAmount pvRecShort =
SWAPTION_PRICER.presentValue(SWAPTION_REC_SHORT, RATE_PROVIDER_AT_MATURITY, VOLS_AT_MATURITY);
CurrencyAmount pvPayLong =
SWAPTION_PRICER.presentValue(SWAPTION_PAY_LONG, RATE_PROVIDER_AT_MATURITY, VOLS_AT_MATURITY);
CurrencyAmount pvPayShort =
SWAPTION_PRICER.presentValue(SWAPTION_PAY_SHORT, RATE_PROVIDER_AT_MATURITY, VOLS_AT_MATURITY);
assertEquals(pvRecLong.getAmount(), -pvRecShort.getAmount(), NOTIONAL * TOL);
assertEquals(pvPayLong.getAmount(), -pvPayShort.getAmount(), NOTIONAL * TOL);
double swapPV = SWAP_PRICER.presentValue(RSWAP_PAY, RATE_PROVIDER_AT_MATURITY).getAmount(USD).getAmount();
assertEquals(pvPayLong.getAmount() - pvRecLong.getAmount(), swapPV, NOTIONAL * TOL);
assertEquals(pvPayShort.getAmount() - pvRecShort.getAmount(), -swapPV, NOTIONAL * TOL);
}
//-------------------------------------------------------------------------
public void test_currencyExposure() {
MultiCurrencyAmount computedRec = SWAPTION_PRICER.currencyExposure(SWAPTION_REC_LONG, RATE_PROVIDER, VOLS);
MultiCurrencyAmount computedPay = SWAPTION_PRICER.currencyExposure(SWAPTION_PAY_SHORT, RATE_PROVIDER, VOLS);
PointSensitivityBuilder pointRec =
SWAPTION_PRICER.presentValueSensitivityRatesStickyModel(SWAPTION_REC_LONG, RATE_PROVIDER, VOLS);
MultiCurrencyAmount expectedRec = RATE_PROVIDER.currencyExposure(pointRec.build())
.plus(SWAPTION_PRICER.presentValue(SWAPTION_REC_LONG, RATE_PROVIDER, VOLS));
assertEquals(computedRec.size(), 1);
assertEquals(computedRec.getAmount(USD).getAmount(), expectedRec.getAmount(USD).getAmount(), NOTIONAL * TOL);
PointSensitivityBuilder pointPay =
SWAPTION_PRICER.presentValueSensitivityRatesStickyModel(SWAPTION_PAY_SHORT, RATE_PROVIDER, VOLS);
MultiCurrencyAmount expectedPay = RATE_PROVIDER.currencyExposure(pointPay.build())
.plus(SWAPTION_PRICER.presentValue(SWAPTION_PAY_SHORT, RATE_PROVIDER, VOLS));
assertEquals(computedPay.size(), 1);
assertEquals(computedPay.getAmount(USD).getAmount(), expectedPay.getAmount(USD).getAmount(), NOTIONAL * TOL);
}
public void test_currencyExposure_atMaturity() {
MultiCurrencyAmount computedRec = SWAPTION_PRICER.currencyExposure(
SWAPTION_REC_LONG, RATE_PROVIDER_AT_MATURITY, VOLS_AT_MATURITY);
MultiCurrencyAmount computedPay = SWAPTION_PRICER.currencyExposure(
SWAPTION_PAY_SHORT, RATE_PROVIDER_AT_MATURITY, VOLS_AT_MATURITY);
PointSensitivityBuilder pointRec =
SWAPTION_PRICER.presentValueSensitivityRatesStickyModel(SWAPTION_REC_LONG, RATE_PROVIDER_AT_MATURITY, VOLS_AT_MATURITY);
MultiCurrencyAmount expectedRec = RATE_PROVIDER.currencyExposure(pointRec.build())
.plus(SWAPTION_PRICER.presentValue(SWAPTION_REC_LONG, RATE_PROVIDER_AT_MATURITY, VOLS_AT_MATURITY));
assertEquals(computedRec.size(), 1);
assertEquals(computedRec.getAmount(USD).getAmount(), expectedRec.getAmount(USD).getAmount(), NOTIONAL * TOL);
PointSensitivityBuilder pointPay =
SWAPTION_PRICER.presentValueSensitivityRatesStickyModel(SWAPTION_PAY_SHORT, RATE_PROVIDER_AT_MATURITY, VOLS_AT_MATURITY);
MultiCurrencyAmount expectedPay = RATE_PROVIDER.currencyExposure(pointPay.build())
.plus(SWAPTION_PRICER.presentValue(SWAPTION_PAY_SHORT, RATE_PROVIDER_AT_MATURITY, VOLS_AT_MATURITY));
assertEquals(computedPay.size(), 1);
assertEquals(computedPay.getAmount(USD).getAmount(), expectedPay.getAmount(USD).getAmount(), NOTIONAL * TOL);
}
public void test_currencyExposure_afterMaturity() {
MultiCurrencyAmount computedRec = SWAPTION_PRICER.currencyExposure(
SWAPTION_REC_LONG, RATE_PROVIDER_AFTER_MATURITY, VOLS_AFTER_MATURITY);
MultiCurrencyAmount computedPay = SWAPTION_PRICER.currencyExposure(
SWAPTION_PAY_SHORT, RATE_PROVIDER_AFTER_MATURITY, VOLS_AFTER_MATURITY);
assertEquals(computedRec.size(), 1);
assertEquals(computedRec.getAmount(USD).getAmount(), 0d, NOTIONAL * TOL);
assertEquals(computedPay.size(), 1);
assertEquals(computedPay.getAmount(USD).getAmount(), 0d, NOTIONAL * TOL);
}
//-------------------------------------------------------------------------
public void test_impliedVolatility() {
double computedRec = SWAPTION_PRICER.impliedVolatility(SWAPTION_REC_LONG, RATE_PROVIDER, VOLS);
double computedPay = SWAPTION_PRICER.impliedVolatility(SWAPTION_PAY_SHORT, RATE_PROVIDER, VOLS);
double forward = SWAP_PRICER.parRate(RSWAP_REC, RATE_PROVIDER);
double expected = VOLS.volatility(MATURITY_DATE, TENOR_YEAR, RATE, forward);
assertEquals(computedRec, expected, TOL);
assertEquals(computedPay, expected, TOL);
}
public void test_impliedVolatility_atMaturity() {
double computedRec =
SWAPTION_PRICER.impliedVolatility(SWAPTION_REC_LONG, RATE_PROVIDER_AT_MATURITY, VOLS_AT_MATURITY);
double computedPay =
SWAPTION_PRICER.impliedVolatility(SWAPTION_PAY_SHORT, RATE_PROVIDER_AT_MATURITY, VOLS_AT_MATURITY);
double forward = SWAP_PRICER.parRate(RSWAP_REC, RATE_PROVIDER_AT_MATURITY);
double expected = VOLS_AT_MATURITY.volatility(MATURITY_DATE, TENOR_YEAR, RATE, forward);
assertEquals(computedRec, expected, TOL);
assertEquals(computedPay, expected, TOL);
}
public void test_impliedVolatility_afterMaturity() {
assertThrowsIllegalArg(() -> SWAPTION_PRICER.impliedVolatility(
SWAPTION_REC_LONG, RATE_PROVIDER_AFTER_MATURITY, VOLS_AFTER_MATURITY));
assertThrowsIllegalArg(() -> SWAPTION_PRICER.impliedVolatility(
SWAPTION_PAY_SHORT, RATE_PROVIDER_AFTER_MATURITY, VOLS_AFTER_MATURITY));
}
//-------------------------------------------------------------------------
public void test_presentValueDelta_parity() {
double pvbp = SWAP_PRICER.getLegPricer()
.pvbp(SWAPTION_REC_LONG.getUnderlying().getLegs(SwapLegType.FIXED).get(0), RATE_PROVIDER);
CurrencyAmount deltaRec = SWAPTION_PRICER.presentValueDelta(SWAPTION_REC_LONG, RATE_PROVIDER, VOLS);
CurrencyAmount deltaPay = SWAPTION_PRICER.presentValueDelta(SWAPTION_PAY_SHORT, RATE_PROVIDER, VOLS);
assertEquals(deltaRec.getAmount() + deltaPay.getAmount(), -pvbp, TOLERANCE_DELTA);
}
public void test_presentValueDelta_afterMaturity() {
CurrencyAmount deltaRec =
SWAPTION_PRICER.presentValueDelta(SWAPTION_REC_LONG, RATE_PROVIDER_AFTER_MATURITY, VOLS_AFTER_MATURITY);
assertEquals(deltaRec.getAmount(), 0, TOLERANCE_DELTA);
CurrencyAmount deltaPay =
SWAPTION_PRICER.presentValueDelta(SWAPTION_PAY_SHORT, RATE_PROVIDER_AFTER_MATURITY, VOLS_AFTER_MATURITY);
assertEquals(deltaPay.getAmount(), 0, TOLERANCE_DELTA);
}
public void test_presentValueDelta_atMaturity() {
double forward = SWAP_PRICER.parRate(RSWAP_REC, RATE_PROVIDER_AT_MATURITY);
double pvbp = SWAP_PRICER.getLegPricer()
.pvbp(SWAPTION_REC_LONG.getUnderlying().getLegs(SwapLegType.FIXED).get(0), RATE_PROVIDER_AT_MATURITY);
CurrencyAmount deltaRec =
SWAPTION_PRICER.presentValueDelta(SWAPTION_REC_LONG, RATE_PROVIDER_AT_MATURITY, VOLS_AT_MATURITY);
assertEquals(deltaRec.getAmount(), RATE > forward ? -pvbp : 0, TOLERANCE_DELTA);
CurrencyAmount deltaPay =
SWAPTION_PRICER.presentValueDelta(SWAPTION_PAY_SHORT, RATE_PROVIDER_AT_MATURITY, VOLS_AT_MATURITY);
assertEquals(deltaPay.getAmount(), RATE > forward ? 0 : pvbp, TOLERANCE_DELTA);
}
//-------------------------------------------------------------------------
public void test_presentValueSensitivityRatesStickyModel() {
PointSensitivityBuilder pointRec =
SWAPTION_PRICER.presentValueSensitivityRatesStickyModel(SWAPTION_REC_LONG, RATE_PROVIDER, VOLS);
CurrencyParameterSensitivities computedRec = RATE_PROVIDER.parameterSensitivity(pointRec.build());
CurrencyParameterSensitivities expectedRec =
FD_CAL.sensitivity(RATE_PROVIDER, (p) -> SWAPTION_PRICER.presentValue(SWAPTION_REC_LONG, (p), VOLS));
assertTrue(computedRec.equalWithTolerance(expectedRec, NOTIONAL * FD_EPS * 100d));
PointSensitivityBuilder pointPay =
SWAPTION_PRICER.presentValueSensitivityRatesStickyModel(SWAPTION_PAY_SHORT, RATE_PROVIDER, VOLS);
CurrencyParameterSensitivities computedPay = RATE_PROVIDER.parameterSensitivity(pointPay.build());
CurrencyParameterSensitivities expectedPay =
FD_CAL.sensitivity(RATE_PROVIDER, (p) -> SWAPTION_PRICER.presentValue(SWAPTION_PAY_SHORT, (p), VOLS));
assertTrue(computedPay.equalWithTolerance(expectedPay, NOTIONAL * FD_EPS * 100d));
}
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));
}
public void test_presentValueSensitivityRatesStickyModel_atMaturity() {
PointSensitivityBuilder pointRec =
SWAPTION_PRICER.presentValueSensitivityRatesStickyModel(SWAPTION_REC_LONG, RATE_PROVIDER_AT_MATURITY, VOLS_AT_MATURITY);
CurrencyParameterSensitivities computedRec =
RATE_PROVIDER_AT_MATURITY.parameterSensitivity(pointRec.build());
CurrencyParameterSensitivities expectedRec = FD_CAL.sensitivity(
RATE_PROVIDER_AT_MATURITY, (p) -> SWAPTION_PRICER.presentValue(SWAPTION_REC_LONG, (p), VOLS_AT_MATURITY));
assertTrue(computedRec.equalWithTolerance(expectedRec, NOTIONAL * FD_EPS * 100d));
PointSensitivities pointPay = SWAPTION_PRICER.presentValueSensitivityRatesStickyModel(SWAPTION_PAY_SHORT,
RATE_PROVIDER_AT_MATURITY, VOLS_AT_MATURITY).build();
for (PointSensitivity sensi : pointPay.getSensitivities()) {
assertEquals(Math.abs(sensi.getSensitivity()), 0d);
}
}
public void test_presentValueSensitivityRatesStickyModel_afterMaturity() {
PointSensitivities pointRec = SWAPTION_PRICER.presentValueSensitivityRatesStickyModel(
SWAPTION_REC_LONG, RATE_PROVIDER_AFTER_MATURITY, VOLS_AFTER_MATURITY).build();
for (PointSensitivity sensi : pointRec.getSensitivities()) {
assertEquals(Math.abs(sensi.getSensitivity()), 0d);
}
PointSensitivities pointPay = SWAPTION_PRICER.presentValueSensitivityRatesStickyModel(
SWAPTION_PAY_SHORT, RATE_PROVIDER_AFTER_MATURITY, VOLS_AFTER_MATURITY).build();
for (PointSensitivity sensi : pointPay.getSensitivities()) {
assertEquals(Math.abs(sensi.getSensitivity()), 0d);
}
}
public void test_presentValueSensitivity_parity() {
CurrencyParameterSensitivities pvSensiRecLong = RATE_PROVIDER.parameterSensitivity(
SWAPTION_PRICER.presentValueSensitivityRatesStickyModel(SWAPTION_REC_LONG, RATE_PROVIDER, VOLS).build());
CurrencyParameterSensitivities pvSensiRecShort = RATE_PROVIDER.parameterSensitivity(
SWAPTION_PRICER.presentValueSensitivityRatesStickyModel(SWAPTION_REC_SHORT, RATE_PROVIDER, VOLS).build());
CurrencyParameterSensitivities pvSensiPayLong = RATE_PROVIDER.parameterSensitivity(
SWAPTION_PRICER.presentValueSensitivityRatesStickyModel(SWAPTION_PAY_LONG, RATE_PROVIDER, VOLS).build());
CurrencyParameterSensitivities pvSensiPayShort = RATE_PROVIDER.parameterSensitivity(
SWAPTION_PRICER.presentValueSensitivityRatesStickyModel(SWAPTION_PAY_SHORT, RATE_PROVIDER, VOLS).build());
assertTrue(pvSensiRecLong.equalWithTolerance(pvSensiRecShort.multipliedBy(-1d), NOTIONAL * TOL));
assertTrue(pvSensiPayLong.equalWithTolerance(pvSensiPayShort.multipliedBy(-1d), NOTIONAL * TOL));
CurrencyParameterSensitivities pvSensiSwap = RATE_PROVIDER.parameterSensitivity(
SWAP_PRICER.presentValueSensitivity(RSWAP_PAY, RATE_PROVIDER).build());
assertTrue(pvSensiSwap.equalWithTolerance(pvSensiPayLong.combinedWith(pvSensiRecLong.multipliedBy(-1d)),
NOTIONAL * TOL));
assertTrue(pvSensiSwap.equalWithTolerance(pvSensiRecShort.combinedWith(pvSensiPayShort.multipliedBy(-1d)),
NOTIONAL * TOL));
}
//-------------------------------------------------------------------------
public void test_presentValueVega_parity() {
SwaptionSensitivity vegaRec = SWAPTION_PRICER
.presentValueSensitivityModelParamsVolatility(SWAPTION_REC_LONG, RATE_PROVIDER, VOLS);
SwaptionSensitivity vegaPay = SWAPTION_PRICER
.presentValueSensitivityModelParamsVolatility(SWAPTION_PAY_SHORT, RATE_PROVIDER, VOLS);
assertEquals(vegaRec.getSensitivity(), -vegaPay.getSensitivity(), TOLERANCE_DELTA);
}
public void test_presentValueVega_atMaturity() {
SwaptionSensitivity vegaRec = SWAPTION_PRICER.presentValueSensitivityModelParamsVolatility(
SWAPTION_REC_LONG, RATE_PROVIDER_AT_MATURITY, VOLS_AT_MATURITY);
assertEquals(vegaRec.getSensitivity(), 0, TOLERANCE_DELTA);
SwaptionSensitivity vegaPay = SWAPTION_PRICER.presentValueSensitivityModelParamsVolatility(
SWAPTION_PAY_SHORT, RATE_PROVIDER_AT_MATURITY, VOLS_AT_MATURITY);
assertEquals(vegaPay.getSensitivity(), 0, TOLERANCE_DELTA);
}
public void test_presentValueVega_afterMaturity() {
SwaptionSensitivity vegaRec = SWAPTION_PRICER.presentValueSensitivityModelParamsVolatility(
SWAPTION_REC_LONG, RATE_PROVIDER_AFTER_MATURITY, VOLS_AFTER_MATURITY);
assertEquals(vegaRec.getSensitivity(), 0, TOLERANCE_DELTA);
SwaptionSensitivity vegaPay = SWAPTION_PRICER.presentValueSensitivityModelParamsVolatility(
SWAPTION_PAY_SHORT, RATE_PROVIDER_AFTER_MATURITY, VOLS_AFTER_MATURITY);
assertEquals(vegaPay.getSensitivity(), 0, TOLERANCE_DELTA);
}
public void test_presentValueVega_SwaptionSensitivity() {
SwaptionSensitivity vegaRec = SWAPTION_PRICER
.presentValueSensitivityModelParamsVolatility(SWAPTION_REC_LONG, RATE_PROVIDER, VOLS);
assertEquals(VOLS.parameterSensitivity(vegaRec), CurrencyParameterSensitivities.empty());
}
//-------------------------------------------------------------------------
public void test_presentValueSensitivityModelParamsSabr() {
PointSensitivities sensiRec =
SWAPTION_PRICER.presentValueSensitivityModelParamsSabr(SWAPTION_REC_LONG, RATE_PROVIDER, VOLS).build();
PointSensitivities sensiPay =
SWAPTION_PRICER.presentValueSensitivityModelParamsSabr(SWAPTION_PAY_SHORT, RATE_PROVIDER, VOLS).build();
double forward = SWAP_PRICER.parRate(RSWAP_REC, RATE_PROVIDER);
double pvbp = SWAP_PRICER.getLegPricer().pvbp(RSWAP_REC.getLegs(SwapLegType.FIXED).get(0), RATE_PROVIDER);
double volatility = VOLS.volatility(SWAPTION_REC_LONG.getExpiry(),
TENOR_YEAR, RATE, forward);
double maturity = VOLS.relativeTime(SWAPTION_REC_LONG.getExpiry());
double[] volSensi = VOLS.getParameters()
.volatilityAdjoint(maturity, TENOR_YEAR, RATE, forward).getDerivatives().toArray();
double vegaRec = pvbp * BlackFormulaRepository.vega(forward + SwaptionSabrRateVolatilityDataSet.SHIFT,
RATE + SwaptionSabrRateVolatilityDataSet.SHIFT, maturity, volatility);
double vegaPay = -pvbp * BlackFormulaRepository.vega(forward + SwaptionSabrRateVolatilityDataSet.SHIFT,
RATE + SwaptionSabrRateVolatilityDataSet.SHIFT, maturity, volatility);
assertSensitivity(sensiRec, SabrParameterType.ALPHA, vegaRec * volSensi[2], TOL);
assertSensitivity(sensiRec, SabrParameterType.BETA, vegaRec * volSensi[3], TOL);
assertSensitivity(sensiRec, SabrParameterType.RHO, vegaRec * volSensi[4], TOL);
assertSensitivity(sensiRec, SabrParameterType.NU, vegaRec * volSensi[5], TOL);
assertSensitivity(sensiPay, SabrParameterType.ALPHA, vegaPay * volSensi[2], TOL);
assertSensitivity(sensiPay, SabrParameterType.BETA, vegaPay * volSensi[3], TOL);
assertSensitivity(sensiPay, SabrParameterType.RHO, vegaPay * volSensi[4], TOL);
assertSensitivity(sensiPay, SabrParameterType.NU, vegaPay * volSensi[5], TOL);
}
private void assertSensitivity(PointSensitivities points, SabrParameterType type, double expected, double tol) {
for (PointSensitivity point : points.getSensitivities()) {
SwaptionSabrSensitivity sens = (SwaptionSabrSensitivity) point;
assertEquals(sens.getCurrency(), USD);
assertEquals(sens.getVolatilitiesName(), VOLS.getName());
assertEquals(sens.getTenor(), (double) TENOR_YEAR);
if (sens.getSensitivityType() == type) {
assertEquals(sens.getSensitivity(), expected, NOTIONAL * tol);
return;
}
}
fail("Did not find sensitivity: " + type + " in " + points);
}
public void test_presentValueSensitivityModelParamsSabr_atMaturity() {
PointSensitivities sensiRec = SWAPTION_PRICER.presentValueSensitivityModelParamsSabr(
SWAPTION_REC_LONG, RATE_PROVIDER_AT_MATURITY, VOLS_AT_MATURITY).build();
assertSensitivity(sensiRec, SabrParameterType.ALPHA, 0, TOL);
assertSensitivity(sensiRec, SabrParameterType.BETA, 0, TOL);
assertSensitivity(sensiRec, SabrParameterType.RHO, 0, TOL);
assertSensitivity(sensiRec, SabrParameterType.NU, 0, TOL);
PointSensitivities sensiPay = SWAPTION_PRICER.presentValueSensitivityModelParamsSabr(
SWAPTION_PAY_SHORT, RATE_PROVIDER_AT_MATURITY, VOLS_AT_MATURITY).build();
assertSensitivity(sensiPay, SabrParameterType.ALPHA, 0, TOL);
assertSensitivity(sensiPay, SabrParameterType.BETA, 0, TOL);
assertSensitivity(sensiPay, SabrParameterType.RHO, 0, TOL);
assertSensitivity(sensiPay, SabrParameterType.NU, 0, TOL);
}
public void test_presentValueSensitivityModelParamsSabr_afterMaturity() {
PointSensitivities sensiRec = SWAPTION_PRICER.presentValueSensitivityModelParamsSabr(
SWAPTION_REC_LONG, RATE_PROVIDER_AFTER_MATURITY, VOLS_AFTER_MATURITY).build();
assertEquals(sensiRec.getSensitivities().size(), 0);
PointSensitivities sensiPay = SWAPTION_PRICER.presentValueSensitivityModelParamsSabr(
SWAPTION_PAY_SHORT, RATE_PROVIDER_AFTER_MATURITY, VOLS_AFTER_MATURITY).build();
assertEquals(sensiPay.getSensitivities().size(), 0);
}
public void test_presentValueSensitivityModelParamsSabr_parity() {
PointSensitivities pvSensiRecLong =
SWAPTION_PRICER.presentValueSensitivityModelParamsSabr(SWAPTION_REC_LONG, RATE_PROVIDER, VOLS).build();
PointSensitivities pvSensiRecShort =
SWAPTION_PRICER.presentValueSensitivityModelParamsSabr(SWAPTION_REC_SHORT, RATE_PROVIDER, VOLS).build();
PointSensitivities pvSensiPayLong =
SWAPTION_PRICER.presentValueSensitivityModelParamsSabr(SWAPTION_PAY_LONG, RATE_PROVIDER, VOLS).build();
PointSensitivities pvSensiPayShort =
SWAPTION_PRICER.presentValueSensitivityModelParamsSabr(SWAPTION_PAY_SHORT, RATE_PROVIDER, VOLS).build();
assertSensitivity(pvSensiRecLong, pvSensiRecShort, SabrParameterType.ALPHA, -1);
assertSensitivity(pvSensiPayLong, pvSensiPayShort, SabrParameterType.ALPHA, -1);
assertSensitivity(pvSensiRecLong, pvSensiPayLong, SabrParameterType.ALPHA, 1);
assertSensitivity(pvSensiPayShort, pvSensiPayShort, SabrParameterType.ALPHA, 1);
assertSensitivity(pvSensiRecLong, pvSensiRecShort, SabrParameterType.BETA, -1);
assertSensitivity(pvSensiPayLong, pvSensiPayShort, SabrParameterType.BETA, -1);
assertSensitivity(pvSensiRecLong, pvSensiPayLong, SabrParameterType.BETA, 1);
assertSensitivity(pvSensiPayShort, pvSensiPayShort, SabrParameterType.BETA, 1);
assertSensitivity(pvSensiRecLong, pvSensiRecShort, SabrParameterType.RHO, -1);
assertSensitivity(pvSensiPayLong, pvSensiPayShort, SabrParameterType.RHO, -1);
assertSensitivity(pvSensiRecLong, pvSensiPayLong, SabrParameterType.RHO, 1);
assertSensitivity(pvSensiPayShort, pvSensiPayShort, SabrParameterType.RHO, 1);
assertSensitivity(pvSensiRecLong, pvSensiRecShort, SabrParameterType.NU, -1);
assertSensitivity(pvSensiPayLong, pvSensiPayShort, SabrParameterType.NU, -1);
assertSensitivity(pvSensiRecLong, pvSensiPayLong, SabrParameterType.NU, 1);
assertSensitivity(pvSensiPayShort, pvSensiPayShort, SabrParameterType.NU, 1);
}
private void assertSensitivity(
PointSensitivities points1,
PointSensitivities points2,
SabrParameterType type,
int factor) {
// use ordinal() as a hack to find correct type
assertEquals(
points1.getSensitivities().get(type.ordinal()).getSensitivity(),
points2.getSensitivities().get(type.ordinal()).getSensitivity() * factor,
NOTIONAL * TOL);
}
//-------------------------------------------------------------------------
public void regressionPv() {
CurrencyAmount pvComputed = SWAPTION_PRICER.presentValue(SWAPTION_PAY_LONG, RATE_PROVIDER, VOLS_REGRESSION);
assertEquals(pvComputed.getAmount(), 3156216.489577751, REGRESSION_TOL * NOTIONAL);
}
public void regressionPvCurveSensi() {
PointSensitivityBuilder point =
SWAPTION_PRICER.presentValueSensitivityRatesStickyModel(SWAPTION_PAY_LONG, RATE_PROVIDER, VOLS_REGRESSION);
CurrencyParameterSensitivities sensiComputed = RATE_PROVIDER.parameterSensitivity(point.build());
final double[] deltaDsc = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 109037.92080563342, 637123.4570377409,
-931862.187003511, -2556192.7520530378, -4233440.216336116, -5686205.439275854, -6160338.898970505,
-3709275.494841247, 0.0};
final double[] deltaFwd = {0.0, 0.0, 0.0, 0.0, -1.0223186788452002E8, 2506923.9169937484, 4980364.73045286,
1.254633556119663E7, 1.528160539036628E8, 2.5824191204559547E8, 0.0, 0.0, 0.0, 0.0, 0.0};
CurrencyParameterSensitivities sensiExpected = CurrencyParameterSensitivities.of(
SwaptionSabrRateVolatilityDataSet.CURVE_DSC_USD.createParameterSensitivity(USD, DoubleArray.copyOf(deltaDsc)),
SwaptionSabrRateVolatilityDataSet.CURVE_FWD_USD.createParameterSensitivity(USD, DoubleArray.copyOf(deltaFwd)));
assertTrue(sensiComputed.equalWithTolerance(sensiExpected, NOTIONAL * REGRESSION_TOL));
}
public void regressionPvSurfaceSensi() {
PointSensitivities pointComputed =
SWAPTION_PRICER.presentValueSensitivityModelParamsSabr(SWAPTION_PAY_LONG, RATE_PROVIDER, VOLS_REGRESSION).build();
assertSensitivity(pointComputed, SabrParameterType.ALPHA, 6.5786313367554754E7, REGRESSION_TOL);
assertSensitivity(pointComputed, SabrParameterType.BETA, -1.2044275797229866E7, REGRESSION_TOL);
assertSensitivity(pointComputed, SabrParameterType.RHO, 266223.51118849067, REGRESSION_TOL);
assertSensitivity(pointComputed, SabrParameterType.NU, 400285.5505271345, REGRESSION_TOL);
CurrencyParameterSensitivities sensiComputed =
VOLS_REGRESSION.parameterSensitivity(pointComputed);
double[][] alphaExp = new double[][] {
{0.0, 1.0, 0.0}, {0.5, 1.0, 0.0}, {1.0, 1.0, 0.0}, {2.0, 1.0, 0.0}, {5.0, 1.0, 0.0}, {10.0, 1.0, 0.0},
{0.0, 5.0, 0.0}, {0.5, 5.0, 0.0}, {1.0, 5.0, 6204.475194599179}, {2.0, 5.0, 3.94631212984123E7},
{5.0, 5.0, 0.0}, {10.0, 5.0, 0.0}, {0.0, 10.0, 0.0}, {0.5, 10.0, 0.0}, {1.0, 10.0, 4136.961894403858},
{2.0, 10.0, 2.631285063205345E7}, {5.0, 10.0, 0.0}, {10.0, 10.0, 0.0},};
double[][] betaExp = new double[][] {
{0.0, 1.0, -0.0}, {0.5, 1.0, -0.0}, {1.0, 1.0, -0.0}, {2.0, 1.0, -0.0}, {5.0, 1.0, -0.0},
{10.0, 1.0, -0.0}, {0.0, 5.0, -0.0}, {0.5, 5.0, -0.0}, {1.0, 5.0, -1135.926404680998},
{2.0, 5.0, -7224978.759366533}, {5.0, 5.0, -0.0}, {10.0, 5.0, -0.0}, {0.0, 10.0, -0.0}, {0.5, 10.0, -0.0},
{1.0, 10.0, -757.402375482629}, {2.0, 10.0, -4817403.70908317}, {5.0, 10.0, -0.0}, {10.0, 10.0, -0.0}};
double[][] rhoExp = new double[][] {
{0.0, 1.0, 0.0}, {0.5, 1.0, 0.0}, {1.0, 1.0, 0.0}, {2.0, 1.0, 0.0}, {5.0, 1.0, 0.0}, {10.0, 1.0, 0.0},
{0.0, 5.0, 0.0}, {0.5, 5.0, 0.0}, {1.0, 5.0, 25.10821912392996}, {2.0, 5.0, 159699.03429338703},
{5.0, 5.0, 0.0}, {10.0, 5.0, 0.0}, {0.0, 10.0, 0.0}, {0.5, 10.0, 0.0}, {1.0, 10.0, 16.741423326578513},
{2.0, 10.0, 106482.62725265314}, {5.0, 10.0, 0.0}, {10.0, 10.0, 0.0}};
double[][] nuExp = new double[][] {
{0.0, 1.0, 0.0}, {0.5, 1.0, 0.0}, {1.0, 1.0, 0.0}, {2.0, 1.0, 0.0}, {5.0, 1.0, 0.0}, {10.0, 1.0, 0.0},
{0.0, 5.0, 0.0}, {0.5, 5.0, 0.0}, {1.0, 5.0, 37.751952372314484}, {2.0, 5.0, 240118.59649585965},
{5.0, 5.0, 0.0}, {10.0, 5.0, 0.0}, {0.0, 10.0, 0.0}, {0.5, 10.0, 0.0}, {1.0, 10.0, 25.171893432592533},
{2.0, 10.0, 160104.03018547}, {5.0, 10.0, 0.0}, {10.0, 10.0, 0.0}};
double[][][] exps = new double[][][] {alphaExp, betaExp, rhoExp, nuExp};
SurfaceMetadata[] metadata = new SurfaceMetadata[] {SwaptionSabrRateVolatilityDataSet.META_ALPHA,
SwaptionSabrRateVolatilityDataSet.META_BETA_USD, SwaptionSabrRateVolatilityDataSet.META_RHO,
SwaptionSabrRateVolatilityDataSet.META_NU};
// x-y-value order does not match sorted order in surface, thus sort it
CurrencyParameterSensitivities sensiExpected = CurrencyParameterSensitivities.empty();
for (int i = 0; i < exps.length; ++i) {
int size = exps[i].length;
Map<DoublesPair, Double> sensiMap = new TreeMap<>();
for (int j = 0; j < size; ++j) {
sensiMap.put(DoublesPair.of(exps[i][j][0], exps[i][j][1]), exps[i][j][2]);
}
List<ParameterMetadata> paramMetadata = new ArrayList<>(size);
List<Double> sensi = new ArrayList<>();
for (Entry<DoublesPair, Double> entry : sensiMap.entrySet()) {
paramMetadata.add(SwaptionSurfaceExpiryTenorParameterMetadata.of(
entry.getKey().getFirst(), entry.getKey().getSecond()));
sensi.add(entry.getValue());
}
SurfaceMetadata surfaceMetadata = metadata[i].withParameterMetadata(paramMetadata);
sensiExpected = sensiExpected.combinedWith(
CurrencyParameterSensitivity.of(
surfaceMetadata.getSurfaceName(),
surfaceMetadata.getParameterMetadata().get(),
USD,
DoubleArray.copyOf(sensi)));
}
testSurfaceParameterSensitivities(sensiComputed, sensiExpected, REGRESSION_TOL * NOTIONAL);
}
//-------------------------------------------------------------------------
private void testSurfaceParameterSensitivities(
CurrencyParameterSensitivities computed,
CurrencyParameterSensitivities expected,
double tol) {
List<CurrencyParameterSensitivity> listComputed = new ArrayList<>(computed.getSensitivities());
List<CurrencyParameterSensitivity> listExpected = new ArrayList<>(expected.getSensitivities());
for (CurrencyParameterSensitivity sensExpected : listExpected) {
int index = Math.abs(Collections.binarySearch(listComputed, sensExpected,
CurrencyParameterSensitivity::compareKey));
CurrencyParameterSensitivity sensComputed = listComputed.get(index);
int nSens = sensExpected.getParameterCount();
assertEquals(sensComputed.getParameterCount(), nSens);
for (int i = 0; i < nSens; ++i) {
assertEquals(sensComputed.getSensitivity().get(i), sensExpected.getSensitivity().get(i), tol);
}
listComputed.remove(index);
}
}
}