/** * Copyright (C) 2015 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.strata.pricer; import static com.opengamma.strata.basics.date.DayCounts.ACT_365F; import static com.opengamma.strata.pricer.CompoundedRateType.CONTINUOUS; import static com.opengamma.strata.pricer.CompoundedRateType.PERIODIC; import static org.testng.Assert.assertEquals; import java.time.LocalDate; import org.testng.annotations.Test; import com.opengamma.strata.basics.currency.Currency; import com.opengamma.strata.basics.currency.CurrencyAmount; import com.opengamma.strata.basics.currency.MultiCurrencyAmount; import com.opengamma.strata.basics.currency.Payment; import com.opengamma.strata.market.amount.CashFlow; import com.opengamma.strata.market.amount.CashFlows; import com.opengamma.strata.market.curve.ConstantCurve; import com.opengamma.strata.market.curve.Curves; 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.pricer.fx.RatesProviderFxDataSets; import com.opengamma.strata.pricer.rate.SimpleRatesProvider; /** * Test {@link DiscountingPaymentPricer}. */ @Test public class DiscountingPaymentPricerTest { private static final DiscountingPaymentPricer PRICER = DiscountingPaymentPricer.DEFAULT; private static final double DF = 0.96d; private static final Currency USD = Currency.USD; private static final LocalDate VAL_DATE_2014_01_22 = RatesProviderFxDataSets.VAL_DATE_2014_01_22; private static final LocalDate PAYMENT_DATE = VAL_DATE_2014_01_22.plusWeeks(8); private static final LocalDate PAYMENT_DATE_PAST = VAL_DATE_2014_01_22.minusDays(1); private static final double NOTIONAL_USD = 100_000_000; private static final Payment PAYMENT = Payment.of(CurrencyAmount.of(USD, NOTIONAL_USD), PAYMENT_DATE); private static final Payment PAYMENT_PAST = Payment.of(CurrencyAmount.of(USD, NOTIONAL_USD), PAYMENT_DATE_PAST); private static final ConstantCurve CURVE = ConstantCurve.of(Curves.discountFactors("Test", ACT_365F), DF); private static final SimpleDiscountFactors DISCOUNT_FACTORS = SimpleDiscountFactors.of(USD, VAL_DATE_2014_01_22, CURVE); private static final BaseProvider PROVIDER = new SimpleRatesProvider(VAL_DATE_2014_01_22, DISCOUNT_FACTORS); private static final double Z_SPREAD = 0.02; private static final int PERIOD_PER_YEAR = 4; private static final double TOL = 1.0e-12; private static final double EPS = 1.0e-6; //------------------------------------------------------------------------- public void test_presentValue_provider() { CurrencyAmount computed = PRICER.presentValue(PAYMENT, PROVIDER); double expected = NOTIONAL_USD * DF; assertEquals(computed.getAmount(), expected, NOTIONAL_USD * TOL); } public void test_presentValue_provider_ended() { CurrencyAmount computed = PRICER.presentValue(PAYMENT_PAST, PROVIDER); assertEquals(computed, CurrencyAmount.zero(USD)); } //------------------------------------------------------------------------- public void test_presentValue_df() { CurrencyAmount computed = PRICER.presentValue(PAYMENT, DISCOUNT_FACTORS); double expected = NOTIONAL_USD * DF; assertEquals(computed.getAmount(), expected, NOTIONAL_USD * TOL); } public void test_presentValue_df_ended() { CurrencyAmount computed = PRICER.presentValue(PAYMENT_PAST, DISCOUNT_FACTORS); assertEquals(computed, CurrencyAmount.zero(USD)); } //------------------------------------------------------------------------- public void test_presentValueAmount_provider() { double computed = PRICER.presentValueAmount(PAYMENT, PROVIDER); double expected = NOTIONAL_USD * DF; assertEquals(computed, expected, NOTIONAL_USD * TOL); } public void test_presentValueAmount_provider_ended() { double computed = PRICER.presentValueAmount(PAYMENT_PAST, PROVIDER); assertEquals(computed, 0d, 0d); } //------------------------------------------------------------------------- public void test_presentValueWithSpread_df_spread_continuous() { CurrencyAmount computed = PRICER .presentValueWithSpread(PAYMENT, DISCOUNT_FACTORS, Z_SPREAD, CONTINUOUS, 0); double relativeYearFraction = ACT_365F.relativeYearFraction(VAL_DATE_2014_01_22, PAYMENT_DATE); double expected = NOTIONAL_USD * DF * Math.exp(-Z_SPREAD * relativeYearFraction); assertEquals(computed.getAmount(), expected, NOTIONAL_USD * TOL); } public void test_presentValueWithSpread_df_spread_periodic() { CurrencyAmount computed = PRICER.presentValueWithSpread( PAYMENT, DISCOUNT_FACTORS, Z_SPREAD, PERIODIC, PERIOD_PER_YEAR); double relativeYearFraction = ACT_365F.relativeYearFraction(VAL_DATE_2014_01_22, PAYMENT_DATE); double rate = (Math.pow(DF, -1d / PERIOD_PER_YEAR / relativeYearFraction) - 1d) * PERIOD_PER_YEAR; double expected = NOTIONAL_USD * discountFactorFromPeriodicallyCompoundedRate(rate + Z_SPREAD, PERIOD_PER_YEAR, relativeYearFraction); assertEquals(computed.getAmount(), expected, NOTIONAL_USD * TOL); } public void test_presentValueWithSpread_df_ended_spread() { CurrencyAmount computed = PRICER.presentValueWithSpread(PAYMENT_PAST, DISCOUNT_FACTORS, Z_SPREAD, PERIODIC, 3); assertEquals(computed, CurrencyAmount.zero(USD)); } private double discountFactorFromPeriodicallyCompoundedRate(double rate, double periodPerYear, double time) { return Math.pow(1d + rate / periodPerYear, -periodPerYear * time); } //------------------------------------------------------------------------- public void test_explainPresentValue_provider() { CurrencyAmount fvExpected = PRICER.forecastValue(PAYMENT, PROVIDER); CurrencyAmount pvExpected = PRICER.presentValue(PAYMENT, PROVIDER); ExplainMap explain = PRICER.explainPresentValue(PAYMENT, PROVIDER); Currency currency = PAYMENT.getCurrency(); assertEquals(explain.get(ExplainKey.ENTRY_TYPE).get(), "Payment"); assertEquals(explain.get(ExplainKey.PAYMENT_DATE).get(), PAYMENT.getDate()); assertEquals(explain.get(ExplainKey.PAYMENT_CURRENCY).get(), currency); assertEquals(explain.get(ExplainKey.DISCOUNT_FACTOR).get(), DF, TOL); assertEquals(explain.get(ExplainKey.FORECAST_VALUE).get().getCurrency(), currency); assertEquals(explain.get(ExplainKey.FORECAST_VALUE).get().getAmount(), fvExpected.getAmount(), TOL); assertEquals(explain.get(ExplainKey.PRESENT_VALUE).get().getCurrency(), currency); assertEquals(explain.get(ExplainKey.PRESENT_VALUE).get().getAmount(), pvExpected.getAmount(), TOL); } public void test_explainPresentValue_provider_ended() { ExplainMap explain = PRICER.explainPresentValue(PAYMENT_PAST, PROVIDER); Currency currency = PAYMENT_PAST.getCurrency(); assertEquals(explain.get(ExplainKey.ENTRY_TYPE).get(), "Payment"); assertEquals(explain.get(ExplainKey.PAYMENT_DATE).get(), PAYMENT_PAST.getDate()); assertEquals(explain.get(ExplainKey.PAYMENT_CURRENCY).get(), currency); assertEquals(explain.get(ExplainKey.FORECAST_VALUE).get().getCurrency(), currency); assertEquals(explain.get(ExplainKey.FORECAST_VALUE).get().getAmount(), 0, TOL); assertEquals(explain.get(ExplainKey.PRESENT_VALUE).get().getCurrency(), currency); assertEquals(explain.get(ExplainKey.PRESENT_VALUE).get().getAmount(), 0, TOL); } //------------------------------------------------------------------------- public void test_presentValueSensitivity_provider() { PointSensitivities point = PRICER.presentValueSensitivity(PAYMENT, PROVIDER).build(); double relativeYearFraction = ACT_365F.relativeYearFraction(VAL_DATE_2014_01_22, PAYMENT_DATE); double expected = -DF * relativeYearFraction * NOTIONAL_USD; ZeroRateSensitivity actual = (ZeroRateSensitivity) point.getSensitivities().get(0); assertEquals(actual.getCurrency(), USD); assertEquals(actual.getCurveCurrency(), USD); assertEquals(actual.getYearFraction(), relativeYearFraction); assertEquals(actual.getSensitivity(), expected, NOTIONAL_USD * TOL); } public void test_presentValueSensitivity_provider_ended() { PointSensitivities computed = PRICER.presentValueSensitivity(PAYMENT_PAST, PROVIDER).build(); assertEquals(computed, PointSensitivities.empty()); } //------------------------------------------------------------------------- public void test_presentValueSensitivity_df() { PointSensitivities point = PRICER.presentValueSensitivity(PAYMENT, DISCOUNT_FACTORS).build(); double relativeYearFraction = ACT_365F.relativeYearFraction(VAL_DATE_2014_01_22, PAYMENT_DATE); double expected = -DF * relativeYearFraction * NOTIONAL_USD; ZeroRateSensitivity actual = (ZeroRateSensitivity) point.getSensitivities().get(0); assertEquals(actual.getCurrency(), USD); assertEquals(actual.getCurveCurrency(), USD); assertEquals(actual.getYearFraction(), relativeYearFraction); assertEquals(actual.getSensitivity(), expected, NOTIONAL_USD * TOL); } public void test_presentValueSensitivity_df_ended() { PointSensitivities computed = PRICER.presentValueSensitivity(PAYMENT_PAST, DISCOUNT_FACTORS).build(); assertEquals(computed, PointSensitivities.empty()); } //------------------------------------------------------------------------- public void test_presentValueSensitivityWithSpread_df_spread_continuous() { PointSensitivities point = PRICER.presentValueSensitivityWithSpread( PAYMENT, DISCOUNT_FACTORS, Z_SPREAD, CONTINUOUS, 0).build(); double relativeYearFraction = ACT_365F.relativeYearFraction(VAL_DATE_2014_01_22, PAYMENT_DATE); double expected = -DF * relativeYearFraction * NOTIONAL_USD * Math.exp(-Z_SPREAD * relativeYearFraction); ZeroRateSensitivity actual = (ZeroRateSensitivity) point.getSensitivities().get(0); assertEquals(actual.getCurrency(), USD); assertEquals(actual.getCurveCurrency(), USD); assertEquals(actual.getYearFraction(), relativeYearFraction); assertEquals(actual.getSensitivity(), expected, NOTIONAL_USD * TOL); } public void test_presentValueSensitivityWithSpread_df_spread_periodic() { PointSensitivities point = PRICER.presentValueSensitivityWithSpread( PAYMENT, DISCOUNT_FACTORS, Z_SPREAD, PERIODIC, PERIOD_PER_YEAR).build(); double relativeYearFraction = ACT_365F.relativeYearFraction(VAL_DATE_2014_01_22, PAYMENT_DATE); double discountFactorUp = DF * Math.exp(-EPS * relativeYearFraction); double discountFactorDw = DF * Math.exp(EPS * relativeYearFraction); double rateUp = (Math.pow(discountFactorUp, -1d / PERIOD_PER_YEAR / relativeYearFraction) - 1d) * PERIOD_PER_YEAR; double rateDw = (Math.pow(discountFactorDw, -1d / PERIOD_PER_YEAR / relativeYearFraction) - 1d) * PERIOD_PER_YEAR; double expected = 0.5 * NOTIONAL_USD / EPS * ( discountFactorFromPeriodicallyCompoundedRate(rateUp + Z_SPREAD, PERIOD_PER_YEAR, relativeYearFraction) - discountFactorFromPeriodicallyCompoundedRate(rateDw + Z_SPREAD, PERIOD_PER_YEAR, relativeYearFraction)); ZeroRateSensitivity actual = (ZeroRateSensitivity) point.getSensitivities().get(0); assertEquals(actual.getCurrency(), USD); assertEquals(actual.getCurveCurrency(), USD); assertEquals(actual.getYearFraction(), relativeYearFraction); assertEquals(actual.getSensitivity(), expected, NOTIONAL_USD * EPS); } public void test_presentValueSensitivityWithSpread_df_spread_ended() { PointSensitivities computed = PRICER.presentValueSensitivityWithSpread(PAYMENT_PAST, DISCOUNT_FACTORS, Z_SPREAD, PERIODIC, 3).build(); assertEquals(computed, PointSensitivities.empty()); } //------------------------------------------------------------------------- public void test_forecastValue_provider() { assertEquals(PRICER.forecastValue(PAYMENT, PROVIDER).getAmount(), NOTIONAL_USD, 0d); assertEquals(PRICER.forecastValueAmount(PAYMENT, PROVIDER), NOTIONAL_USD, 0d); } public void test_forecastValue_provider_ended() { assertEquals(PRICER.forecastValue(PAYMENT_PAST, PROVIDER).getAmount(), 0d, 0d); assertEquals(PRICER.forecastValueAmount(PAYMENT_PAST, PROVIDER), 0d, 0d); } //------------------------------------------------------------------------- public void test_cashFlow_provider() { CashFlow expected = CashFlow.ofForecastValue(PAYMENT_DATE, USD, NOTIONAL_USD, DF); assertEquals(PRICER.cashFlows(PAYMENT, PROVIDER), CashFlows.of(expected)); } public void test_cashFlow_provider_ended() { assertEquals(PRICER.cashFlows(PAYMENT_PAST, PROVIDER), CashFlows.NONE); } //------------------------------------------------------------------------- public void test_currencyExposure() { assertEquals( PRICER.currencyExposure(PAYMENT, PROVIDER), MultiCurrencyAmount.of(PRICER.presentValue(PAYMENT, PROVIDER))); } public void test_currentCash_onDate() { SimpleRatesProvider prov = new SimpleRatesProvider(PAYMENT.getDate(), DISCOUNT_FACTORS); assertEquals(PRICER.currentCash(PAYMENT, prov), PAYMENT.getValue()); } public void test_currentCash_past() { assertEquals(PRICER.currentCash(PAYMENT_PAST, PROVIDER), CurrencyAmount.zero(USD)); } }