/**
* 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.date.BusinessDayConventions.MODIFIED_FOLLOWING;
import static com.opengamma.strata.basics.date.DayCounts.THIRTY_U_360;
import static com.opengamma.strata.basics.index.IborIndices.EUR_EURIBOR_6M;
import static com.opengamma.strata.basics.schedule.Frequency.P6M;
import static com.opengamma.strata.collect.TestHelper.assertThrowsIllegalArg;
import static com.opengamma.strata.collect.TestHelper.dateUtc;
import static com.opengamma.strata.product.common.LongShort.LONG;
import static com.opengamma.strata.product.common.LongShort.SHORT;
import static com.opengamma.strata.product.common.PayReceive.PAY;
import static com.opengamma.strata.product.common.PayReceive.RECEIVE;
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.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.BusinessDayAdjustment;
import com.opengamma.strata.basics.date.DaysAdjustment;
import com.opengamma.strata.basics.date.HolidayCalendarId;
import com.opengamma.strata.basics.date.HolidayCalendarIds;
import com.opengamma.strata.basics.schedule.PeriodicSchedule;
import com.opengamma.strata.basics.schedule.RollConventions;
import com.opengamma.strata.basics.schedule.StubConvention;
import com.opengamma.strata.basics.value.ValueSchedule;
import com.opengamma.strata.collect.DoubleArrayMath;
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.LongShort;
import com.opengamma.strata.product.swap.FixedRateCalculation;
import com.opengamma.strata.product.swap.IborRateCalculation;
import com.opengamma.strata.product.swap.NotionalSchedule;
import com.opengamma.strata.product.swap.PaymentSchedule;
import com.opengamma.strata.product.swap.RateCalculationSwapLeg;
import com.opengamma.strata.product.swap.ResolvedSwap;
import com.opengamma.strata.product.swap.ResolvedSwapLeg;
import com.opengamma.strata.product.swap.Swap;
import com.opengamma.strata.product.swap.SwapLeg;
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;
/**
* Test {@link SabrSwaptionCashParYieldProductPricer}.
*/
@Test
public class SabrSwaptionCashParYieldProductPricerTest {
private static final ReferenceData REF_DATA = ReferenceData.standard();
private static final ZonedDateTime VAL_DATE_TIME = dateUtc(2008, 8, 18);
private static final ZonedDateTime MATURITY = dateUtc(2014, 3, 18);
private static final HolidayCalendarId CALENDAR = HolidayCalendarIds.SAT_SUN;
private static final BusinessDayAdjustment BDA_MF = BusinessDayAdjustment.of(MODIFIED_FOLLOWING, CALENDAR);
private static final LocalDate SETTLE =
BDA_MF.adjust(CALENDAR.resolve(REF_DATA).shift(MATURITY.toLocalDate(), 2), REF_DATA);
private static final double NOTIONAL = 100000000; //100m
private static final int TENOR_YEAR = 5;
private static final LocalDate END = SETTLE.plusYears(TENOR_YEAR);
private static final double RATE = 0.0175;
private static final PeriodicSchedule PERIOD_FIXED = PeriodicSchedule.builder()
.startDate(SETTLE)
.endDate(END)
.frequency(P6M)
.businessDayAdjustment(BDA_MF)
.stubConvention(StubConvention.SHORT_FINAL)
.rollConvention(RollConventions.EOM)
.build();
private static final PaymentSchedule PAYMENT_FIXED = PaymentSchedule.builder()
.paymentFrequency(P6M)
.paymentDateOffset(DaysAdjustment.NONE)
.build();
private static final FixedRateCalculation RATE_FIXED = FixedRateCalculation.builder()
.dayCount(THIRTY_U_360)
.rate(ValueSchedule.of(RATE))
.build();
private static final PeriodicSchedule PERIOD_IBOR = PeriodicSchedule.builder()
.startDate(SETTLE)
.endDate(END)
.frequency(P6M)
.businessDayAdjustment(BDA_MF)
.stubConvention(StubConvention.SHORT_FINAL)
.rollConvention(RollConventions.EOM)
.build();
private static final PaymentSchedule PAYMENT_IBOR = PaymentSchedule.builder()
.paymentFrequency(P6M)
.paymentDateOffset(DaysAdjustment.NONE)
.build();
private static final IborRateCalculation RATE_IBOR = IborRateCalculation.builder()
.index(EUR_EURIBOR_6M)
.fixingDateOffset(DaysAdjustment.ofBusinessDays(-2, CALENDAR, BDA_MF))
.build();
private static final SwapLeg FIXED_LEG_REC = RateCalculationSwapLeg.builder()
.payReceive(RECEIVE)
.accrualSchedule(PERIOD_FIXED)
.paymentSchedule(PAYMENT_FIXED)
.notionalSchedule(NotionalSchedule.of(EUR, NOTIONAL))
.calculation(RATE_FIXED)
.build();
private static final SwapLeg FIXED_LEG_PAY = RateCalculationSwapLeg.builder()
.payReceive(PAY)
.accrualSchedule(PERIOD_FIXED)
.paymentSchedule(PAYMENT_FIXED)
.notionalSchedule(NotionalSchedule.of(EUR, NOTIONAL))
.calculation(RATE_FIXED)
.build();
private static final SwapLeg IBOR_LEG_REC = RateCalculationSwapLeg.builder()
.payReceive(RECEIVE)
.accrualSchedule(PERIOD_IBOR)
.paymentSchedule(PAYMENT_IBOR)
.notionalSchedule(NotionalSchedule.of(EUR, NOTIONAL))
.calculation(RATE_IBOR)
.build();
private static final SwapLeg IBOR_LEG_PAY = RateCalculationSwapLeg.builder()
.payReceive(PAY)
.accrualSchedule(PERIOD_IBOR)
.paymentSchedule(PAYMENT_IBOR)
.notionalSchedule(NotionalSchedule.of(EUR, NOTIONAL))
.calculation(RATE_IBOR)
.build();
private static final Swap SWAP_REC = Swap.of(FIXED_LEG_REC, IBOR_LEG_PAY);
private static final ResolvedSwap RSWAP_REC = SWAP_REC.resolve(REF_DATA);
private static final Swap SWAP_PAY = Swap.of(FIXED_LEG_PAY, IBOR_LEG_REC);
private static final ResolvedSwapLeg RFIXED_LEG_REC = FIXED_LEG_REC.resolve(REF_DATA);
private static final CashSwaptionSettlement PAR_YIELD =
CashSwaptionSettlement.of(SETTLE, CashSwaptionSettlementMethod.PAR_YIELD);
private static final ResolvedSwaption SWAPTION_REC_LONG = Swaption
.builder()
.expiryDate(AdjustableDate.of(MATURITY.toLocalDate(), BDA_MF))
.expiryTime(MATURITY.toLocalTime())
.expiryZone(MATURITY.getZone())
.swaptionSettlement(PAR_YIELD)
.longShort(LONG)
.underlying(SWAP_REC)
.build().
resolve(REF_DATA);
private static final ResolvedSwaption SWAPTION_REC_SHORT = Swaption
.builder()
.expiryDate(AdjustableDate.of(MATURITY.toLocalDate(), BDA_MF))
.expiryTime(MATURITY.toLocalTime())
.expiryZone(MATURITY.getZone())
.swaptionSettlement(PAR_YIELD)
.longShort(SHORT)
.underlying(SWAP_REC)
.build().
resolve(REF_DATA);
private static final ResolvedSwaption SWAPTION_PAY_LONG = Swaption
.builder()
.expiryDate(AdjustableDate.of(MATURITY.toLocalDate(), BDA_MF))
.expiryTime(MATURITY.toLocalTime())
.expiryZone(MATURITY.getZone())
.swaptionSettlement(PAR_YIELD)
.longShort(LONG)
.underlying(SWAP_PAY)
.build().
resolve(REF_DATA);
private static final ResolvedSwaption SWAPTION_PAY_SHORT = Swaption
.builder()
.expiryDate(AdjustableDate.of(MATURITY.toLocalDate(), BDA_MF))
.expiryTime(MATURITY.toLocalTime())
.expiryZone(MATURITY.getZone())
.swaptionSettlement(PAR_YIELD)
.longShort(SHORT)
.underlying(SWAP_PAY)
.build().
resolve(REF_DATA);
private static final ResolvedSwaption SWAPTION_PHYS = Swaption.builder()
.expiryDate(AdjustableDate.of(MATURITY.toLocalDate()))
.expiryTime(MATURITY.toLocalTime())
.expiryZone(MATURITY.getZone())
.longShort(LongShort.LONG)
.swaptionSettlement(PhysicalSwaptionSettlement.DEFAULT)
.underlying(SWAP_REC)
.build().
resolve(REF_DATA);
private static final SabrParametersSwaptionVolatilities VOLS_REG =
SwaptionSabrRateVolatilityDataSet.getVolatilitiesEur(VAL_DATE_TIME.toLocalDate(), false);
private static final SabrParametersSwaptionVolatilities VOLS =
SwaptionSabrRateVolatilityDataSet.getVolatilitiesEur(VAL_DATE_TIME.toLocalDate(), true);
private static final SabrParametersSwaptionVolatilities VOLS_AT_MATURITY =
SwaptionSabrRateVolatilityDataSet.getVolatilitiesEur(MATURITY.toLocalDate(), true);
private static final SabrParametersSwaptionVolatilities VOLS_AFTER_MATURITY =
SwaptionSabrRateVolatilityDataSet.getVolatilitiesEur(MATURITY.toLocalDate().plusDays(1), true);
private static final ImmutableRatesProvider RATE_PROVIDER =
SwaptionSabrRateVolatilityDataSet.getRatesProviderEur(VAL_DATE_TIME.toLocalDate());
private static final ImmutableRatesProvider RATE_PROVIDER_AT_MATURITY =
SwaptionSabrRateVolatilityDataSet.getRatesProviderEur(MATURITY.toLocalDate());
private static final ImmutableRatesProvider RATE_PROVIDER_AFTER_MATURITY =
SwaptionSabrRateVolatilityDataSet.getRatesProviderEur(MATURITY.toLocalDate().plusDays(1));
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 SabrSwaptionCashParYieldProductPricer PRICER = SabrSwaptionCashParYieldProductPricer.DEFAULT;
private static final DiscountingSwapProductPricer PRICER_SWAP = DiscountingSwapProductPricer.DEFAULT;
private static final RatesFiniteDifferenceSensitivityCalculator FD_CAL =
new RatesFiniteDifferenceSensitivityCalculator(FD_EPS);
//-------------------------------------------------------------------------
public void validate_cash_settlement() {
assertThrowsIllegalArg(() -> PRICER.presentValue(SWAPTION_PHYS, RATE_PROVIDER, VOLS));
}
//-------------------------------------------------------------------------
public void test_presentValue() {
CurrencyAmount computedRec = PRICER.presentValue(SWAPTION_REC_LONG, RATE_PROVIDER, VOLS);
CurrencyAmount computedPay = PRICER.presentValue(SWAPTION_PAY_SHORT, RATE_PROVIDER, VOLS);
double forward = PRICER_SWAP.parRate(RSWAP_REC, RATE_PROVIDER);
double annuityCash = PRICER_SWAP.getLegPricer().annuityCash(RFIXED_LEG_REC, forward);
double expiry = VOLS.relativeTime(MATURITY);
double volatility = VOLS.volatility(SWAPTION_REC_LONG.getExpiry(), TENOR_YEAR, RATE, forward);
double df = RATE_PROVIDER.discountFactor(EUR, SETTLE);
double expectedRec = df * annuityCash * BlackFormulaRepository.price(forward + SwaptionSabrRateVolatilityDataSet.SHIFT,
RATE + SwaptionSabrRateVolatilityDataSet.SHIFT, expiry, volatility, false);
double expectedPay = -df * annuityCash * BlackFormulaRepository.price(forward + SwaptionSabrRateVolatilityDataSet.SHIFT,
RATE + SwaptionSabrRateVolatilityDataSet.SHIFT, expiry, volatility, true);
assertEquals(computedRec.getCurrency(), EUR);
assertEquals(computedRec.getAmount(), expectedRec, NOTIONAL * TOL);
assertEquals(computedPay.getCurrency(), EUR);
assertEquals(computedPay.getAmount(), expectedPay, NOTIONAL * TOL);
}
public void test_presentValue_atMaturity() {
CurrencyAmount computedRec =
PRICER.presentValue(SWAPTION_REC_LONG, RATE_PROVIDER_AT_MATURITY, VOLS_AT_MATURITY);
CurrencyAmount computedPay =
PRICER.presentValue(SWAPTION_PAY_SHORT, RATE_PROVIDER_AT_MATURITY, VOLS_AT_MATURITY);
double forward = PRICER_SWAP.parRate(RSWAP_REC, RATE_PROVIDER_AT_MATURITY);
double annuityCash = PRICER_SWAP.getLegPricer().annuityCash(RFIXED_LEG_REC, forward);
double df = RATE_PROVIDER_AT_MATURITY.discountFactor(EUR, SETTLE);
assertEquals(computedRec.getAmount(), df * annuityCash * (RATE - forward), NOTIONAL * TOL);
assertEquals(computedPay.getAmount(), 0d, NOTIONAL * TOL);
}
public void test_presentValue_afterExpiry() {
CurrencyAmount computedRec =
PRICER.presentValue(SWAPTION_REC_LONG, RATE_PROVIDER_AFTER_MATURITY, VOLS_AFTER_MATURITY);
CurrencyAmount computedPay =
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 = PRICER.presentValue(SWAPTION_REC_LONG, RATE_PROVIDER, VOLS);
CurrencyAmount pvRecShort = PRICER.presentValue(SWAPTION_REC_SHORT, RATE_PROVIDER, VOLS);
CurrencyAmount pvPayLong = PRICER.presentValue(SWAPTION_PAY_LONG, RATE_PROVIDER, VOLS);
CurrencyAmount pvPayShort = PRICER.presentValue(SWAPTION_PAY_SHORT, RATE_PROVIDER, VOLS);
assertEquals(pvRecLong.getAmount(), -pvRecShort.getAmount(), NOTIONAL * TOL);
assertEquals(pvPayLong.getAmount(), -pvPayShort.getAmount(), NOTIONAL * TOL);
double forward = PRICER_SWAP.parRate(RSWAP_REC, RATE_PROVIDER);
double annuityCash = PRICER_SWAP.getLegPricer().annuityCash(RFIXED_LEG_REC, forward);
double df = RATE_PROVIDER.discountFactor(EUR, SETTLE);
double expected = df * annuityCash * (forward - RATE);
assertEquals(pvPayLong.getAmount() - pvRecLong.getAmount(), expected, NOTIONAL * TOL);
assertEquals(pvPayShort.getAmount() - pvRecShort.getAmount(), -expected, NOTIONAL * TOL);
}
public void test_presentValue_parity_atMaturity() {
CurrencyAmount pvRecLong =
PRICER.presentValue(SWAPTION_REC_LONG, RATE_PROVIDER_AT_MATURITY, VOLS_AT_MATURITY);
CurrencyAmount pvRecShort =
PRICER.presentValue(SWAPTION_REC_SHORT, RATE_PROVIDER_AT_MATURITY, VOLS_AT_MATURITY);
CurrencyAmount pvPayLong =
PRICER.presentValue(SWAPTION_PAY_LONG, RATE_PROVIDER_AT_MATURITY, VOLS_AT_MATURITY);
CurrencyAmount pvPayShort =
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 forward = PRICER_SWAP.parRate(RSWAP_REC, RATE_PROVIDER_AT_MATURITY);
double annuityCash = PRICER_SWAP.getLegPricer().annuityCash(RFIXED_LEG_REC, forward);
double df = RATE_PROVIDER_AT_MATURITY.discountFactor(EUR, SETTLE);
double expected = df * annuityCash * (forward - RATE);
assertEquals(pvPayLong.getAmount() - pvRecLong.getAmount(), expected, NOTIONAL * TOL);
assertEquals(pvPayShort.getAmount() - pvRecShort.getAmount(), -expected, NOTIONAL * TOL);
}
//-------------------------------------------------------------------------
public void test_currencyExposure() {
MultiCurrencyAmount computedRec = PRICER.currencyExposure(SWAPTION_REC_LONG, RATE_PROVIDER, VOLS);
MultiCurrencyAmount computedPay = PRICER.currencyExposure(SWAPTION_PAY_SHORT, RATE_PROVIDER, VOLS);
PointSensitivityBuilder pointRec =
PRICER.presentValueSensitivityRatesStickyModel(SWAPTION_REC_LONG, RATE_PROVIDER, VOLS);
MultiCurrencyAmount expectedRec = RATE_PROVIDER.currencyExposure(pointRec.build())
.plus(PRICER.presentValue(SWAPTION_REC_LONG, RATE_PROVIDER, VOLS));
assertEquals(computedRec.size(), 1);
assertEquals(computedRec.getAmount(EUR).getAmount(), expectedRec.getAmount(EUR).getAmount(), NOTIONAL * TOL);
PointSensitivityBuilder pointPay =
PRICER.presentValueSensitivityRatesStickyModel(SWAPTION_PAY_SHORT, RATE_PROVIDER, VOLS);
MultiCurrencyAmount expectedPay = RATE_PROVIDER.currencyExposure(pointPay.build())
.plus(PRICER.presentValue(SWAPTION_PAY_SHORT, RATE_PROVIDER, VOLS));
assertEquals(computedPay.size(), 1);
assertEquals(computedPay.getAmount(EUR).getAmount(), expectedPay.getAmount(EUR).getAmount(), NOTIONAL * TOL);
}
public void test_currencyExposure_atMaturity() {
MultiCurrencyAmount computedRec = PRICER.currencyExposure(
SWAPTION_REC_LONG, RATE_PROVIDER_AT_MATURITY, VOLS_AT_MATURITY);
MultiCurrencyAmount computedPay = PRICER.currencyExposure(
SWAPTION_PAY_SHORT, RATE_PROVIDER_AT_MATURITY, VOLS_AT_MATURITY);
PointSensitivityBuilder pointRec =
PRICER.presentValueSensitivityRatesStickyModel(SWAPTION_REC_LONG, RATE_PROVIDER_AT_MATURITY, VOLS_AT_MATURITY);
MultiCurrencyAmount expectedRec = RATE_PROVIDER.currencyExposure(pointRec.build())
.plus(PRICER.presentValue(SWAPTION_REC_LONG, RATE_PROVIDER_AT_MATURITY, VOLS_AT_MATURITY));
assertEquals(computedRec.size(), 1);
assertEquals(computedRec.getAmount(EUR).getAmount(), expectedRec.getAmount(EUR).getAmount(), NOTIONAL * TOL);
PointSensitivityBuilder pointPay =
PRICER.presentValueSensitivityRatesStickyModel(SWAPTION_PAY_SHORT, RATE_PROVIDER_AT_MATURITY, VOLS_AT_MATURITY);
MultiCurrencyAmount expectedPay = RATE_PROVIDER.currencyExposure(pointPay.build())
.plus(PRICER.presentValue(SWAPTION_PAY_SHORT, RATE_PROVIDER_AT_MATURITY, VOLS_AT_MATURITY));
assertEquals(computedPay.size(), 1);
assertEquals(computedPay.getAmount(EUR).getAmount(), expectedPay.getAmount(EUR).getAmount(), NOTIONAL * TOL);
}
public void test_currencyExposure_afterMaturity() {
MultiCurrencyAmount computedRec = PRICER.currencyExposure(
SWAPTION_REC_LONG, RATE_PROVIDER_AFTER_MATURITY, VOLS_AFTER_MATURITY);
MultiCurrencyAmount computedPay = PRICER.currencyExposure(
SWAPTION_PAY_SHORT, RATE_PROVIDER_AFTER_MATURITY, VOLS_AFTER_MATURITY);
assertEquals(computedRec.size(), 1);
assertEquals(computedRec.getAmount(EUR).getAmount(), 0d, NOTIONAL * TOL);
assertEquals(computedPay.size(), 1);
assertEquals(computedPay.getAmount(EUR).getAmount(), 0d, NOTIONAL * TOL);
}
//-------------------------------------------------------------------------
public void test_impliedVolatility() {
double computedRec = PRICER.impliedVolatility(SWAPTION_REC_LONG, RATE_PROVIDER, VOLS);
double computedPay = PRICER.impliedVolatility(SWAPTION_PAY_SHORT, RATE_PROVIDER, VOLS);
double forward = PRICER_SWAP.parRate(RSWAP_REC, RATE_PROVIDER);
double expected = VOLS.volatility(MATURITY, TENOR_YEAR, RATE, forward);
assertEquals(computedRec, expected, TOL);
assertEquals(computedPay, expected, TOL);
}
public void test_impliedVolatility_atMaturity() {
double computedRec =
PRICER.impliedVolatility(SWAPTION_REC_LONG, RATE_PROVIDER_AT_MATURITY, VOLS_AT_MATURITY);
double computedPay =
PRICER.impliedVolatility(SWAPTION_PAY_SHORT, RATE_PROVIDER_AT_MATURITY, VOLS_AT_MATURITY);
double forward = PRICER_SWAP.parRate(RSWAP_REC, RATE_PROVIDER_AT_MATURITY);
double expected = VOLS_AT_MATURITY.volatility(MATURITY, TENOR_YEAR, RATE, forward);
assertEquals(computedRec, expected, TOL);
assertEquals(computedPay, expected, TOL);
}
public void test_impliedVolatility_afterMaturity() {
assertThrowsIllegalArg(() -> PRICER.impliedVolatility(
SWAPTION_REC_LONG, RATE_PROVIDER_AFTER_MATURITY, VOLS_AFTER_MATURITY));
assertThrowsIllegalArg(() -> PRICER.impliedVolatility(
SWAPTION_PAY_SHORT, RATE_PROVIDER_AFTER_MATURITY, VOLS_AFTER_MATURITY));
}
//-------------------------------------------------------------------------
public void test_presentValueDelta_parity() {
double forward = PRICER_SWAP.parRate(RSWAP_REC, RATE_PROVIDER);
ResolvedSwapLeg fixedLeg = SWAPTION_REC_LONG.getUnderlying().getLegs(SwapLegType.FIXED).get(0);
double annuityCash = PRICER_SWAP.getLegPricer().annuityCash(fixedLeg, forward);
CashSwaptionSettlement cashSettlement = (CashSwaptionSettlement) SWAPTION_REC_LONG.getSwaptionSettlement();
double discountSettle = RATE_PROVIDER.discountFactor(fixedLeg.getCurrency(), cashSettlement.getSettlementDate());
double pvbpCash = Math.abs(annuityCash * discountSettle);
CurrencyAmount deltaRec = PRICER.presentValueDelta(SWAPTION_REC_LONG, RATE_PROVIDER, VOLS);
CurrencyAmount deltaPay = PRICER.presentValueDelta(SWAPTION_PAY_SHORT, RATE_PROVIDER, VOLS);
assertEquals(deltaRec.getAmount() + deltaPay.getAmount(), -pvbpCash, TOLERANCE_DELTA);
}
public void test_presentValueDelta_afterMaturity() {
CurrencyAmount deltaRec =
PRICER.presentValueDelta(SWAPTION_REC_LONG, RATE_PROVIDER_AFTER_MATURITY, VOLS_AFTER_MATURITY);
assertEquals(deltaRec.getAmount(), 0, TOLERANCE_DELTA);
CurrencyAmount deltaPay =
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 = PRICER_SWAP.parRate(RSWAP_REC, RATE_PROVIDER_AT_MATURITY);
ResolvedSwapLeg fixedLeg = SWAPTION_REC_LONG.getUnderlying().getLegs(SwapLegType.FIXED).get(0);
double annuityCash = PRICER_SWAP.getLegPricer().annuityCash(fixedLeg, forward);
CashSwaptionSettlement cashSettlement = (CashSwaptionSettlement) SWAPTION_REC_LONG.getSwaptionSettlement();
double discountSettle = RATE_PROVIDER_AT_MATURITY.discountFactor(fixedLeg.getCurrency(), cashSettlement.getSettlementDate());
double pvbpCash = Math.abs(annuityCash * discountSettle);
CurrencyAmount deltaRec =
PRICER.presentValueDelta(SWAPTION_REC_LONG, RATE_PROVIDER_AT_MATURITY, VOLS_AT_MATURITY);
assertEquals(deltaRec.getAmount(), RATE > forward ? -pvbpCash : 0, TOLERANCE_DELTA);
CurrencyAmount deltaPay =
PRICER.presentValueDelta(SWAPTION_PAY_SHORT, RATE_PROVIDER_AT_MATURITY, VOLS_AT_MATURITY);
assertEquals(deltaPay.getAmount(), RATE > forward ? 0 : pvbpCash, TOLERANCE_DELTA);
}
//-------------------------------------------------------------------------
public void test_presentValueSensitivityRatesStickyModel() {
PointSensitivityBuilder pointRec =
PRICER.presentValueSensitivityRatesStickyModel(SWAPTION_REC_LONG, RATE_PROVIDER, VOLS);
CurrencyParameterSensitivities computedRec = RATE_PROVIDER.parameterSensitivity(pointRec.build());
CurrencyParameterSensitivities expectedRec =
FD_CAL.sensitivity(RATE_PROVIDER, (p) -> PRICER.presentValue(SWAPTION_REC_LONG, (p), VOLS));
assertTrue(computedRec.equalWithTolerance(expectedRec, NOTIONAL * FD_EPS * 200d));
PointSensitivityBuilder pointPay =
PRICER.presentValueSensitivityRatesStickyModel(SWAPTION_PAY_SHORT, RATE_PROVIDER, VOLS);
CurrencyParameterSensitivities computedPay = RATE_PROVIDER.parameterSensitivity(pointPay.build());
CurrencyParameterSensitivities expectedPay =
FD_CAL.sensitivity(RATE_PROVIDER, (p) -> PRICER.presentValue(SWAPTION_PAY_SHORT, (p), VOLS));
assertTrue(computedPay.equalWithTolerance(expectedPay, NOTIONAL * FD_EPS * 200d));
}
public void test_presentValueSensitivityRatesStickyStrike() {
SwaptionVolatilities volSabr = SwaptionSabrRateVolatilityDataSet.getVolatilitiesEur(VAL_DATE_TIME.toLocalDate(), false);
double impliedVol = 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 =
PRICER.presentValueSensitivityRatesStickyStrike(SWAPTION_REC_LONG, RATE_PROVIDER, volSabr);
CurrencyParameterSensitivities computedRec = RATE_PROVIDER.parameterSensitivity(pointRec.build());
CurrencyParameterSensitivities expectedRec =
FD_CAL.sensitivity(RATE_PROVIDER, (p) -> PRICER.presentValue(SWAPTION_REC_LONG, (p), volCst));
assertTrue(computedRec.equalWithTolerance(expectedRec, NOTIONAL * FD_EPS * 300d));
PointSensitivityBuilder pointPay =
PRICER.presentValueSensitivityRatesStickyStrike(SWAPTION_PAY_SHORT, RATE_PROVIDER, volSabr);
CurrencyParameterSensitivities computedPay = RATE_PROVIDER.parameterSensitivity(pointPay.build());
CurrencyParameterSensitivities expectedPay =
FD_CAL.sensitivity(RATE_PROVIDER, (p) -> PRICER.presentValue(SWAPTION_PAY_SHORT, (p), volCst));
assertTrue(computedPay.equalWithTolerance(expectedPay, NOTIONAL * FD_EPS * 300d));
}
public void test_presentValueSensitivityRatesStickyModel_atMaturity() {
PointSensitivityBuilder pointRec =
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) -> PRICER.presentValue(SWAPTION_REC_LONG, (p), VOLS_AT_MATURITY));
assertTrue(computedRec.equalWithTolerance(expectedRec, NOTIONAL * FD_EPS * 100d));
PointSensitivities pointPay = 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 = 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 = 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_presentValueSensitivityRatesStickyModel_parity() {
CurrencyParameterSensitivities pvSensiRecLong = RATE_PROVIDER.parameterSensitivity(
PRICER.presentValueSensitivityRatesStickyModel(SWAPTION_REC_LONG, RATE_PROVIDER, VOLS).build());
CurrencyParameterSensitivities pvSensiRecShort = RATE_PROVIDER.parameterSensitivity(
PRICER.presentValueSensitivityRatesStickyModel(SWAPTION_REC_SHORT, RATE_PROVIDER, VOLS).build());
CurrencyParameterSensitivities pvSensiPayLong = RATE_PROVIDER.parameterSensitivity(
PRICER.presentValueSensitivityRatesStickyModel(SWAPTION_PAY_LONG, RATE_PROVIDER, VOLS).build());
CurrencyParameterSensitivities pvSensiPayShort = RATE_PROVIDER.parameterSensitivity(
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));
double forward = PRICER_SWAP.parRate(RSWAP_REC, RATE_PROVIDER);
PointSensitivityBuilder forwardSensi = PRICER_SWAP.parRateSensitivity(RSWAP_REC, RATE_PROVIDER);
double annuityCash = PRICER_SWAP.getLegPricer().annuityCash(RSWAP_REC.getLegs(SwapLegType.FIXED).get(0), forward);
double annuityCashDeriv = PRICER_SWAP.getLegPricer()
.annuityCashDerivative(RSWAP_REC.getLegs(SwapLegType.FIXED).get(0), forward).getDerivative(0);
double discount = RATE_PROVIDER.discountFactor(EUR, SETTLE);
PointSensitivityBuilder discountSensi = RATE_PROVIDER.discountFactors(EUR).zeroRatePointSensitivity(SETTLE);
PointSensitivities expecedPoint = discountSensi.multipliedBy(annuityCash * (forward - RATE)).combinedWith(
forwardSensi.multipliedBy(discount * annuityCash + discount * annuityCashDeriv * (forward - RATE))).build();
CurrencyParameterSensitivities expected = RATE_PROVIDER.parameterSensitivity(expecedPoint);
assertTrue(expected.equalWithTolerance(pvSensiPayLong.combinedWith(pvSensiRecLong.multipliedBy(-1d)),
NOTIONAL * TOL));
assertTrue(expected.equalWithTolerance(pvSensiRecShort.combinedWith(pvSensiPayShort.multipliedBy(-1d)),
NOTIONAL * TOL));
}
//-------------------------------------------------------------------------
public void test_presentValueVega_parity() {
SwaptionSensitivity vegaRec = PRICER
.presentValueSensitivityModelParamsVolatility(SWAPTION_REC_LONG, RATE_PROVIDER, VOLS);
SwaptionSensitivity vegaPay = PRICER
.presentValueSensitivityModelParamsVolatility(SWAPTION_PAY_SHORT, RATE_PROVIDER, VOLS);
assertEquals(vegaRec.getSensitivity(), -vegaPay.getSensitivity(), TOLERANCE_DELTA);
}
public void test_presentValueVega_atMaturity() {
SwaptionSensitivity vegaRec = PRICER.presentValueSensitivityModelParamsVolatility(
SWAPTION_REC_LONG, RATE_PROVIDER_AT_MATURITY, VOLS_AT_MATURITY);
assertEquals(vegaRec.getSensitivity(), 0, TOLERANCE_DELTA);
SwaptionSensitivity vegaPay = 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 = PRICER.presentValueSensitivityModelParamsVolatility(
SWAPTION_REC_LONG, RATE_PROVIDER_AFTER_MATURITY, VOLS_AFTER_MATURITY);
assertEquals(vegaRec.getSensitivity(), 0, TOLERANCE_DELTA);
SwaptionSensitivity vegaPay = 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 = PRICER
.presentValueSensitivityModelParamsVolatility(SWAPTION_REC_LONG, RATE_PROVIDER, VOLS);
assertEquals(VOLS.parameterSensitivity(vegaRec), CurrencyParameterSensitivities.empty());
}
//-------------------------------------------------------------------------
public void test_presentValueSensitivityModelParamsSabr() {
PointSensitivities sensiRec =
PRICER.presentValueSensitivityModelParamsSabr(SWAPTION_REC_LONG, RATE_PROVIDER, VOLS).build();
PointSensitivities sensiPay =
PRICER.presentValueSensitivityModelParamsSabr(SWAPTION_PAY_SHORT, RATE_PROVIDER, VOLS).build();
double forward = PRICER_SWAP.parRate(RSWAP_REC, RATE_PROVIDER);
double annuityCash = PRICER_SWAP.getLegPricer().annuityCash(RFIXED_LEG_REC, forward);
double expiry = VOLS.relativeTime(MATURITY);
double volatility = VOLS.volatility(SWAPTION_REC_LONG.getExpiry(), TENOR_YEAR, RATE, forward);
double df = RATE_PROVIDER.discountFactor(EUR, SETTLE);
double[] volSensi =
VOLS.getParameters().volatilityAdjoint(expiry, TENOR_YEAR, RATE, forward).getDerivatives().toArray();
double vegaRec = df * annuityCash * BlackFormulaRepository.vega(forward + SwaptionSabrRateVolatilityDataSet.SHIFT,
RATE + SwaptionSabrRateVolatilityDataSet.SHIFT, expiry, volatility);
double vegaPay = -df * annuityCash * BlackFormulaRepository.vega(forward + SwaptionSabrRateVolatilityDataSet.SHIFT,
RATE + SwaptionSabrRateVolatilityDataSet.SHIFT, expiry, volatility);
assertSensitivity(sensiRec, SabrParameterType.ALPHA, vegaRec * volSensi[2]);
assertSensitivity(sensiRec, SabrParameterType.BETA, vegaRec * volSensi[3]);
assertSensitivity(sensiRec, SabrParameterType.RHO, vegaRec * volSensi[4]);
assertSensitivity(sensiRec, SabrParameterType.NU, vegaRec * volSensi[5]);
assertSensitivity(sensiPay, SabrParameterType.ALPHA, vegaPay * volSensi[2]);
assertSensitivity(sensiPay, SabrParameterType.BETA, vegaPay * volSensi[3]);
assertSensitivity(sensiPay, SabrParameterType.RHO, vegaPay * volSensi[4]);
assertSensitivity(sensiPay, SabrParameterType.NU, vegaPay * volSensi[5]);
}
private void assertSensitivity(PointSensitivities points, SabrParameterType type, double expected) {
for (PointSensitivity point : points.getSensitivities()) {
SwaptionSabrSensitivity sens = (SwaptionSabrSensitivity) point;
assertEquals(sens.getCurrency(), EUR);
assertEquals(sens.getVolatilitiesName(), VOLS.getName());
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 = PRICER.presentValueSensitivityModelParamsSabr(
SWAPTION_REC_LONG, RATE_PROVIDER_AT_MATURITY, VOLS_AT_MATURITY).build();
assertSensitivity(sensiRec, SabrParameterType.ALPHA, 0);
assertSensitivity(sensiRec, SabrParameterType.BETA, 0);
assertSensitivity(sensiRec, SabrParameterType.RHO, 0);
assertSensitivity(sensiRec, SabrParameterType.NU, 0);
PointSensitivities sensiPay = PRICER.presentValueSensitivityModelParamsSabr(
SWAPTION_PAY_SHORT, RATE_PROVIDER_AT_MATURITY, VOLS_AT_MATURITY).build();
assertSensitivity(sensiPay, SabrParameterType.ALPHA, 0);
assertSensitivity(sensiPay, SabrParameterType.BETA, 0);
assertSensitivity(sensiPay, SabrParameterType.RHO, 0);
assertSensitivity(sensiPay, SabrParameterType.NU, 0);
}
public void test_presentValueSensitivityModelParamsSabr_afterMaturity() {
PointSensitivities sensiRec = PRICER.presentValueSensitivityModelParamsSabr(
SWAPTION_REC_LONG, RATE_PROVIDER_AFTER_MATURITY, VOLS_AFTER_MATURITY).build();
assertEquals(sensiRec.getSensitivities().size(), 0);
PointSensitivities sensiPay = 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 =
PRICER.presentValueSensitivityModelParamsSabr(SWAPTION_REC_LONG, RATE_PROVIDER, VOLS).build();
PointSensitivities pvSensiRecShort =
PRICER.presentValueSensitivityModelParamsSabr(SWAPTION_REC_SHORT, RATE_PROVIDER, VOLS).build();
PointSensitivities pvSensiPayLong =
PRICER.presentValueSensitivityModelParamsSabr(SWAPTION_PAY_LONG, RATE_PROVIDER, VOLS).build();
PointSensitivities pvSensiPayShort =
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 regressionPresentValue() {
CurrencyAmount pvLongPay = PRICER.presentValue(SWAPTION_PAY_LONG, RATE_PROVIDER, VOLS_REG);
CurrencyAmount pvShortPay = PRICER.presentValue(SWAPTION_PAY_SHORT, RATE_PROVIDER, VOLS_REG);
CurrencyAmount pvLongRec = PRICER.presentValue(SWAPTION_REC_LONG, RATE_PROVIDER, VOLS_REG);
CurrencyAmount pvShortRec = PRICER.presentValue(SWAPTION_REC_SHORT, RATE_PROVIDER, VOLS_REG);
assertEquals(pvLongPay.getAmount(), 2419978.690066857, NOTIONAL * TOL);
assertEquals(pvShortPay.getAmount(), -2419978.690066857, NOTIONAL * TOL);
assertEquals(pvLongRec.getAmount(), 3498144.2628540806, NOTIONAL * TOL);
assertEquals(pvShortRec.getAmount(), -3498144.2628540806, NOTIONAL * TOL);
}
public void regressionCurveSensitivity() {
double[] sensiDscExp = new double[] {0.0, 0.0, 0.0, 0.0, -1.1942174487944763E7, -1565567.6976298545};
double[] sensiFwdExp = new double[] {0.0, 0.0, 0.0, 0.0, -2.3978768078237808E8, 4.8392987803482056E8};
PointSensitivityBuilder point = PRICER.presentValueSensitivityRatesStickyModel(SWAPTION_PAY_LONG, RATE_PROVIDER, VOLS_REG);
CurrencyParameterSensitivities sensi = RATE_PROVIDER.parameterSensitivity(point.build());
double[] sensiDscCmp = sensi.getSensitivity(SwaptionSabrRateVolatilityDataSet.META_DSC_EUR.getCurveName(), EUR)
.getSensitivity().toArray();
double[] sensiFwdCmp = sensi.getSensitivity(SwaptionSabrRateVolatilityDataSet.META_FWD_EUR.getCurveName(), EUR)
.getSensitivity().toArray();
assertTrue(DoubleArrayMath.fuzzyEquals(sensiDscCmp, sensiDscExp, TOL * NOTIONAL));
assertTrue(DoubleArrayMath.fuzzyEquals(sensiFwdCmp, sensiFwdExp, TOL * NOTIONAL));
}
public void regressionSurfaceSensitivity() {
PointSensitivities pointComputed =
PRICER.presentValueSensitivityModelParamsSabr(SWAPTION_PAY_LONG, RATE_PROVIDER, VOLS_REG).build();
assertSensitivity(pointComputed, SabrParameterType.ALPHA, 4.862767907309804E7);
assertSensitivity(pointComputed, SabrParameterType.BETA, -1.1095143998998241E7);
assertSensitivity(pointComputed, SabrParameterType.RHO, 575158.6667143379);
assertSensitivity(pointComputed, SabrParameterType.NU, 790627.3506603877);
CurrencyParameterSensitivities sensiComputed =
VOLS_REG.parameterSensitivity(pointComputed);
double[][] alphaExp = new double[][] {
{0.0, 0.0, 0.0}, {0.5, 0.0, 0.0}, {1.0, 0.0, 0.0}, {2.0, 0.0, 0.0}, {5.0, 0.0, 0.0}, {10.0, 0.0, 0.0},
{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, 2.3882653164816026E7},
{10.0, 1.0, 3132724.0980162215}, {0.0, 10.0, 0.0}, {0.5, 10.0, 0.0}, {1.0, 10.0, 0.0}, {2.0, 10.0, 0.0},
{5.0, 10.0, 1.910612253185282E7}, {10.0, 10.0, 2506179.2784129772}, {0.0, 100.0, 0.0}, {0.5, 100.0, 0.0},
{1.0, 100.0, 0.0}, {2.0, 100.0, 0.0}, {5.0, 100.0, 0.0}, {10.0, 100.0, 0.0}};
double[][] betaExp = new double[][] {
{0.0, 0.0, -0.0}, {0.5, 0.0, -0.0}, {1.0, 0.0, -0.0}, {2.0, 0.0, -0.0}, {5.0, 0.0, -0.0},
{10.0, 0.0, -0.0}, {100.0, 0.0, -0.0}, {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, -5449190.275839399}, {10.0, 1.0, -714778.6124929579}, {100.0, 1.0, -0.0},
{0.0, 10.0, -0.0}, {0.5, 10.0, -0.0}, {1.0, 10.0, -0.0}, {2.0, 10.0, -0.0}, {5.0, 10.0, -4359352.220671519},
{10.0, 10.0, -571822.8899943662}, {100.0, 10.0, -0.0}, {0.0, 100.0, -0.0}, {0.5, 100.0, -0.0},
{1.0, 100.0, -0.0}, {2.0, 100.0, -0.0}, {5.0, 100.0, -0.0}, {10.0, 100.0, -0.0}, {100.0, 100.0, -0.0}};
double[][] rhoExp = new double[][] {
{0.0, 0.0, 0.0}, {0.5, 0.0, 0.0}, {1.0, 0.0, 0.0}, {2.0, 0.0, 0.0}, {5.0, 0.0, 0.0}, {10.0, 0.0, 0.0},
{100.0, 0.0, 0.0}, {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, 282479.3453791586}, {10.0, 1.0, 37053.24723991797}, {100.0, 1.0, 0.0}, {0.0, 10.0, 0.0},
{1.0, 10.0, 0.0}, {2.0, 10.0, 0.0}, {0.5, 10.0, 0.0}, {5.0, 10.0, 225983.4763033269},
{10.0, 10.0, 29642.597791934375}, {100.0, 10.0, 0.0}, {0.0, 100.0, 0.0}, {0.5, 100.0, 0.0},
{1.0, 100.0, 0.0}, {2.0, 100.0, 0.0}, {5.0, 100.0, 0.0}, {10.0, 100.0, 0.0}, {100.0, 100.0, 0.0}};
double[][] nuExp = new double[][] {
{0.0, 0.0, 0.0}, {0.5, 0.0, 0.0}, {1.0, 0.0, 0.0}, {2.0, 0.0, 0.0}, {5.0, 0.0, 0.0}, {10.0, 0.0, 0.0},
{100.0, 0.0, 0.0}, {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, 388303.1055225815}, {10.0, 1.0, 50934.31151096723}, {100.0, 1.0, 0.0}, {0.0, 10.0, 0.0},
{0.5, 10.0, 0.0}, {1.0, 10.0, 0.0}, {2.0, 10.0, 0.0}, {5.0, 10.0, 310642.48441806517},
{10.0, 10.0, 40747.44920877378}, {100.0, 10.0, 0.0}, {0.0, 100.0, 0.0}, {0.5, 100.0, 0.0},
{1.0, 100.0, 0.0}, {2.0, 100.0, 0.0}, {5.0, 100.0, 0.0}, {10.0, 100.0, 0.0}, {100.0, 100.0, 0.0}};
double[][][] exps = new double[][][] {alphaExp, betaExp, rhoExp, nuExp};
SurfaceMetadata[] metadata = new SurfaceMetadata[] {SwaptionSabrRateVolatilityDataSet.META_ALPHA,
SwaptionSabrRateVolatilityDataSet.META_BETA_EUR, 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(),
EUR,
DoubleArray.copyOf(sensi)));
}
testSurfaceParameterSensitivities(sensiComputed, sensiExpected, 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);
}
}
}