/**
* Copyright (C) 2016 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.strata.pricer.cms;
import static com.opengamma.strata.basics.currency.Currency.EUR;
import static com.opengamma.strata.basics.date.DayCounts.ACT_360;
import static com.opengamma.strata.basics.date.HolidayCalendarIds.EUTA;
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 java.time.LocalDate;
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.BusinessDayAdjustment;
import com.opengamma.strata.basics.date.BusinessDayConventions;
import com.opengamma.strata.basics.date.DaysAdjustment;
import com.opengamma.strata.basics.schedule.Frequency;
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.timeseries.LocalDateDoubleTimeSeries;
import com.opengamma.strata.market.explain.ExplainKey;
import com.opengamma.strata.market.explain.ExplainMap;
import com.opengamma.strata.market.sensitivity.PointSensitivities;
import com.opengamma.strata.market.sensitivity.PointSensitivityBuilder;
import com.opengamma.strata.pricer.rate.ImmutableRatesProvider;
import com.opengamma.strata.pricer.swap.DiscountingSwapLegPricer;
import com.opengamma.strata.pricer.swaption.SabrParametersSwaptionVolatilities;
import com.opengamma.strata.pricer.swaption.SwaptionSabrRateVolatilityDataSet;
import com.opengamma.strata.product.cms.CmsLeg;
import com.opengamma.strata.product.cms.ResolvedCms;
import com.opengamma.strata.product.cms.ResolvedCmsLeg;
import com.opengamma.strata.product.swap.FixedRateCalculation;
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.ResolvedSwapLeg;
import com.opengamma.strata.product.swap.SwapIndex;
import com.opengamma.strata.product.swap.SwapIndices;
/**
* Test {@link SabrExtrapolationReplicationCmsProductPricer}.
*/
@Test
public class SabrExtrapolationReplicationCmsProductPricerTest {
private static final ReferenceData REF_DATA = ReferenceData.standard();
// CMS products
private static final SwapIndex INDEX = SwapIndices.EUR_EURIBOR_1100_5Y;
private static final LocalDate START = LocalDate.of(2015, 10, 21);
private static final LocalDate END = LocalDate.of(2020, 10, 21);
private static final Frequency FREQUENCY = Frequency.P12M;
private static final BusinessDayAdjustment BUSS_ADJ_EUR =
BusinessDayAdjustment.of(BusinessDayConventions.FOLLOWING, EUTA);
private static final PeriodicSchedule SCHEDULE_EUR =
PeriodicSchedule.of(START, END, FREQUENCY, BUSS_ADJ_EUR, StubConvention.NONE, RollConventions.NONE);
private static final double NOTIONAL_VALUE = 1.0e6;
private static final ValueSchedule NOTIONAL = ValueSchedule.of(NOTIONAL_VALUE);
private static final ValueSchedule CAP = ValueSchedule.of(0.0145);
private static final ResolvedCmsLeg CMS_LEG = CmsLeg.builder()
.index(INDEX)
.notional(NOTIONAL)
.payReceive(RECEIVE)
.paymentSchedule(SCHEDULE_EUR)
.capSchedule(CAP)
.build()
.resolve(REF_DATA);
private static final ResolvedSwapLeg PAY_LEG = RateCalculationSwapLeg.builder()
.payReceive(PAY)
.accrualSchedule(SCHEDULE_EUR)
.calculation(
FixedRateCalculation.of(0.0035, ACT_360))
.paymentSchedule(
PaymentSchedule.builder().paymentFrequency(FREQUENCY).paymentDateOffset(DaysAdjustment.NONE).build())
.notionalSchedule(
NotionalSchedule.of(CurrencyAmount.of(EUR, NOTIONAL_VALUE)))
.build()
.resolve(REF_DATA);
private static final ResolvedCms CMS_TWO_LEGS = ResolvedCms.of(CMS_LEG, PAY_LEG);
private static final ResolvedCms CMS_ONE_LEG = ResolvedCms.of(CMS_LEG);
// providers
private static final LocalDate VALUATION = LocalDate.of(2015, 8, 18);
private static final ImmutableRatesProvider RATES_PROVIDER =
SwaptionSabrRateVolatilityDataSet.getRatesProviderEur(VALUATION);
private static final SabrParametersSwaptionVolatilities VOLATILITIES =
SwaptionSabrRateVolatilityDataSet.getVolatilitiesEur(VALUATION, true);
// providers - valuation on payment date
private static final LocalDate FIXING = LocalDate.of(2016, 10, 19); // fixing for the second period.
private static final double OBS_INDEX = 0.013;
private static final LocalDateDoubleTimeSeries TIME_SERIES = LocalDateDoubleTimeSeries.of(FIXING, OBS_INDEX);
private static final LocalDate PAYMENT = LocalDate.of(2017, 10, 23); // payment date of the second payment
private static final ImmutableRatesProvider RATES_PROVIDER_ON_PAY =
SwaptionSabrRateVolatilityDataSet.getRatesProviderEur(PAYMENT, TIME_SERIES);
private static final SabrParametersSwaptionVolatilities VOLATILITIES_ON_PAY =
SwaptionSabrRateVolatilityDataSet.getVolatilitiesEur(PAYMENT, true);
// pricers
private static final double CUT_OFF_STRIKE = 0.10;
private static final double MU = 2.50;
private static final SabrExtrapolationReplicationCmsPeriodPricer PERIOD_PRICER =
SabrExtrapolationReplicationCmsPeriodPricer.of(CUT_OFF_STRIKE, MU);
private static final SabrExtrapolationReplicationCmsLegPricer CMS_LEG_PRICER =
new SabrExtrapolationReplicationCmsLegPricer(PERIOD_PRICER);
private static final DiscountingSwapLegPricer SWAP_LEG_PRICER = DiscountingSwapLegPricer.DEFAULT;
private static final SabrExtrapolationReplicationCmsProductPricer PRODUCT_PRICER =
new SabrExtrapolationReplicationCmsProductPricer(CMS_LEG_PRICER, SWAP_LEG_PRICER);
private static final double TOL = 1.0e-13;
public void test_presentValue() {
MultiCurrencyAmount pv1 = PRODUCT_PRICER.presentValue(CMS_ONE_LEG, RATES_PROVIDER, VOLATILITIES);
MultiCurrencyAmount pv2 = PRODUCT_PRICER.presentValue(CMS_TWO_LEGS, RATES_PROVIDER, VOLATILITIES);
CurrencyAmount pvCms = CMS_LEG_PRICER.presentValue(CMS_LEG, RATES_PROVIDER, VOLATILITIES);
CurrencyAmount pvPay = SWAP_LEG_PRICER.presentValue(PAY_LEG, RATES_PROVIDER);
assertEquals(pv1, MultiCurrencyAmount.of(pvCms));
assertEquals(pv2, MultiCurrencyAmount.of(pvCms).plus(pvPay));
}
public void test_presentValueSensitivity() {
PointSensitivityBuilder pt1 = PRODUCT_PRICER.presentValueSensitivityRates(CMS_ONE_LEG, RATES_PROVIDER, VOLATILITIES);
PointSensitivityBuilder pt2 = PRODUCT_PRICER.presentValueSensitivityRates(CMS_TWO_LEGS, RATES_PROVIDER, VOLATILITIES);
PointSensitivityBuilder ptCms =
CMS_LEG_PRICER.presentValueSensitivityRates(CMS_LEG, RATES_PROVIDER, VOLATILITIES);
PointSensitivityBuilder ptPay = SWAP_LEG_PRICER.presentValueSensitivity(PAY_LEG, RATES_PROVIDER);
assertEquals(pt1, ptCms);
assertEquals(pt2, ptCms.combinedWith(ptPay));
}
public void test_presentValueSensitivitySabrParameter() {
PointSensitivities pt1 =
PRODUCT_PRICER.presentValueSensitivityModelParamsSabr(CMS_ONE_LEG, RATES_PROVIDER, VOLATILITIES).build();
PointSensitivities pt2 =
PRODUCT_PRICER.presentValueSensitivityModelParamsSabr(CMS_TWO_LEGS, RATES_PROVIDER, VOLATILITIES).build();
PointSensitivities ptCms =
CMS_LEG_PRICER.presentValueSensitivityModelParamsSabr(CMS_LEG, RATES_PROVIDER, VOLATILITIES).build();
assertEquals(pt1, ptCms);
assertEquals(pt2, ptCms);
}
public void test_presentValueSensitivityStrike() {
double sensi1 = PRODUCT_PRICER.presentValueSensitivityStrike(CMS_ONE_LEG, RATES_PROVIDER, VOLATILITIES);
double sensi2 = PRODUCT_PRICER.presentValueSensitivityStrike(CMS_TWO_LEGS, RATES_PROVIDER, VOLATILITIES);
double sensiCms = CMS_LEG_PRICER.presentValueSensitivityStrike(CMS_LEG, RATES_PROVIDER, VOLATILITIES);
assertEquals(sensi1, sensiCms);
assertEquals(sensi2, sensiCms);
}
public void test_currencyExposure() {
MultiCurrencyAmount computed1 = PRODUCT_PRICER.currencyExposure(CMS_ONE_LEG, RATES_PROVIDER, VOLATILITIES);
MultiCurrencyAmount computed2 = PRODUCT_PRICER.currencyExposure(CMS_TWO_LEGS, RATES_PROVIDER, VOLATILITIES);
MultiCurrencyAmount pv1 = PRODUCT_PRICER.presentValue(CMS_ONE_LEG, RATES_PROVIDER, VOLATILITIES);
PointSensitivityBuilder pt1 = PRODUCT_PRICER.presentValueSensitivityRates(CMS_ONE_LEG, RATES_PROVIDER, VOLATILITIES);
MultiCurrencyAmount expected1 = RATES_PROVIDER.currencyExposure(pt1.build()).plus(pv1);
MultiCurrencyAmount pv2 = PRODUCT_PRICER.presentValue(CMS_TWO_LEGS, RATES_PROVIDER, VOLATILITIES);
PointSensitivityBuilder pt2 = PRODUCT_PRICER.presentValueSensitivityRates(CMS_TWO_LEGS, RATES_PROVIDER, VOLATILITIES);
MultiCurrencyAmount expected2 = RATES_PROVIDER.currencyExposure(pt2.build()).plus(pv2);
assertEquals(computed1.getAmount(EUR).getAmount(), expected1.getAmount(EUR).getAmount(), NOTIONAL_VALUE * TOL);
assertEquals(computed2.getAmount(EUR).getAmount(), expected2.getAmount(EUR).getAmount(), NOTIONAL_VALUE * TOL);
}
public void test_currentCash() {
MultiCurrencyAmount cc1 = PRODUCT_PRICER.currentCash(CMS_ONE_LEG, RATES_PROVIDER, VOLATILITIES);
MultiCurrencyAmount cc2 = PRODUCT_PRICER.currentCash(CMS_TWO_LEGS, RATES_PROVIDER, VOLATILITIES);
assertEquals(cc1, MultiCurrencyAmount.of(CurrencyAmount.zero(EUR)));
assertEquals(cc2, MultiCurrencyAmount.of(CurrencyAmount.zero(EUR)));
}
public void test_currentCash_onPay() {
MultiCurrencyAmount cc1 = PRODUCT_PRICER.currentCash(CMS_ONE_LEG, RATES_PROVIDER_ON_PAY, VOLATILITIES_ON_PAY);
MultiCurrencyAmount cc2 = PRODUCT_PRICER.currentCash(CMS_TWO_LEGS, RATES_PROVIDER_ON_PAY, VOLATILITIES_ON_PAY);
CurrencyAmount ccCms = CMS_LEG_PRICER.currentCash(CMS_LEG, RATES_PROVIDER_ON_PAY, VOLATILITIES_ON_PAY);
CurrencyAmount ccPay = SWAP_LEG_PRICER.currentCash(PAY_LEG, RATES_PROVIDER_ON_PAY);
assertEquals(cc1, MultiCurrencyAmount.of(ccCms));
assertEquals(cc2, MultiCurrencyAmount.of(ccCms).plus(ccPay));
}
public void test_pvExplain() {
ExplainMap explain1 = PRODUCT_PRICER.explainPresentValue(CMS_ONE_LEG, RATES_PROVIDER, VOLATILITIES);
assertEquals(explain1.get(ExplainKey.ENTRY_TYPE).get(), "CmsSwap");
assertEquals(explain1.get(ExplainKey.LEGS).get().size(), 1);
ExplainMap explain2 = PRODUCT_PRICER.explainPresentValue(CMS_TWO_LEGS, RATES_PROVIDER, VOLATILITIES);
assertEquals(explain2.get(ExplainKey.ENTRY_TYPE).get(), "CmsSwap");
assertEquals(explain2.get(ExplainKey.LEGS).get().size(), 2);
ExplainMap explainCms = CMS_LEG_PRICER.explainPresentValue(CMS_LEG, RATES_PROVIDER, VOLATILITIES);
ExplainMap explainOther = SWAP_LEG_PRICER.explainPresentValue(CMS_TWO_LEGS.getPayLeg().get(), RATES_PROVIDER);
assertEquals(explain2.get(ExplainKey.LEGS).get().get(0), explainCms);
assertEquals(explain2.get(ExplainKey.LEGS).get().get(1), explainOther);
}
}