/** * Copyright (C) 2014 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.analytics.financial.equity.trs; import static org.testng.AssertJUnit.assertEquals; import static org.testng.AssertJUnit.assertTrue; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.testng.annotations.Test; import org.threeten.bp.ZonedDateTime; import com.google.common.collect.Sets; import com.opengamma.analytics.financial.datasets.CalendarGBP; import com.opengamma.analytics.financial.datasets.CalendarUSD; import com.opengamma.analytics.financial.equity.Equity; import com.opengamma.analytics.financial.equity.EquityDefinition; import com.opengamma.analytics.financial.equity.EquityTrsDataBundle; import com.opengamma.analytics.financial.equity.trs.definition.EquityTotalReturnSwap; import com.opengamma.analytics.financial.equity.trs.definition.EquityTotalReturnSwapDefinition; import com.opengamma.analytics.financial.equity.trs.method.EquityTotalReturnSwapDiscountingMethod; import com.opengamma.analytics.financial.instrument.annuity.AnnuityDefinition; import com.opengamma.analytics.financial.instrument.annuity.AnnuityDefinitionBuilder; import com.opengamma.analytics.financial.instrument.index.IborIndex; import com.opengamma.analytics.financial.instrument.index.IndexIborMaster; import com.opengamma.analytics.financial.instrument.index.IndexON; import com.opengamma.analytics.financial.instrument.index.IndexONMaster; import com.opengamma.analytics.financial.instrument.payment.CouponIborSpreadDefinition; import com.opengamma.analytics.financial.instrument.payment.CouponONSpreadDefinition; import com.opengamma.analytics.financial.instrument.payment.PaymentDefinition; import com.opengamma.analytics.financial.interestrate.annuity.derivative.Annuity; import com.opengamma.analytics.financial.interestrate.payments.derivative.Payment; import com.opengamma.analytics.financial.legalentity.CreditRating; import com.opengamma.analytics.financial.legalentity.LegalEntity; import com.opengamma.analytics.financial.legalentity.Region; import com.opengamma.analytics.financial.legalentity.Sector; import com.opengamma.analytics.financial.provider.calculator.discounting.PresentValueCurveSensitivityDiscountingCalculator; import com.opengamma.analytics.financial.provider.calculator.discounting.PresentValueDiscountingCalculator; import com.opengamma.analytics.financial.provider.calculator.equity.PresentValueCurveSensitivityEquityDiscountingCalculator; import com.opengamma.analytics.financial.provider.calculator.equity.PresentValueEquityDiscountingCalculator; import com.opengamma.analytics.financial.provider.description.MulticurveProviderDiscountDataSets; import com.opengamma.analytics.financial.provider.description.interestrate.MulticurveProviderDiscount; import com.opengamma.analytics.financial.provider.sensitivity.multicurve.MulticurveSensitivity; import com.opengamma.analytics.financial.provider.sensitivity.multicurve.MultipleCurrencyMulticurveSensitivity; import com.opengamma.analytics.financial.util.AssertSensitivityObjects; import com.opengamma.analytics.util.time.TimeCalculator; import com.opengamma.financial.convention.StubType; import com.opengamma.financial.convention.calendar.Calendar; import com.opengamma.timeseries.precise.zdt.ImmutableZonedDateTimeDoubleTimeSeries; import com.opengamma.timeseries.precise.zdt.ZonedDateTimeDoubleTimeSeries; import com.opengamma.util.i18n.Country; import com.opengamma.util.money.Currency; import com.opengamma.util.money.CurrencyAmount; import com.opengamma.util.money.MultipleCurrencyAmount; import com.opengamma.util.time.DateUtils; import com.opengamma.util.tuple.DoublesPair; /** * Test related to the equity total return swap pricing methodology by discounting of funding leg the cash-flows. */ public class EquityTotalReturnSwapDiscountingMethodTest { private static final ZonedDateTime EFFECTIVE_DATE_1 = DateUtils.getUTCDate(2012, 2, 9); private static final ZonedDateTime EFFECTIVE_DATE_2 = DateUtils.getUTCDate(2012, 3, 9); private static final ZonedDateTime TERMINATION_DATE_1 = DateUtils.getUTCDate(2012, 5, 9); private static final ZonedDateTime TERMINATION_DATE_2 = DateUtils.getUTCDate(2012, 12, 9); private static final ZonedDateTime REFERENCE_DATE_1 = DateUtils.getUTCDate(2012, 2, 2); // Before effective date. private static final ZonedDateTime REFERENCE_DATE_2 = DateUtils.getUTCDate(2012, 2, 16); // After effective date 1. private static final ZonedDateTime REFERENCE_DATE_3 = DateUtils.getUTCDate(2012, 3, 16); // After effective date 2. private static final double EFFECTIVE_TIME_1_1 = TimeCalculator.getTimeBetween(REFERENCE_DATE_1, EFFECTIVE_DATE_1); private static final double EFFECTIVE_TIME_2_1 = TimeCalculator.getTimeBetween(REFERENCE_DATE_2, EFFECTIVE_DATE_1); private static final double TERMINATION_TIME_1_1 = TimeCalculator.getTimeBetween(REFERENCE_DATE_1, TERMINATION_DATE_1); private static final double TERMINATION_TIME_2_1 = TimeCalculator.getTimeBetween(REFERENCE_DATE_2, TERMINATION_DATE_1); private static final ZonedDateTime[] FIXING_DATES_USDLIBOR = new ZonedDateTime[] {DateUtils.getUTCDate(2012, 2, 7), DateUtils.getUTCDate(2012, 2, 8), DateUtils.getUTCDate(2012, 2, 9), DateUtils.getUTCDate(2012, 3, 7) }; private static final double[] FIXING_RATES_USDLIBOR = new double[] {0.0040, 0.0041, 0.0042, 0.0043 }; private static final ZonedDateTimeDoubleTimeSeries FIXING_TS_USDLIBOR = ImmutableZonedDateTimeDoubleTimeSeries.ofUTC(FIXING_DATES_USDLIBOR, FIXING_RATES_USDLIBOR); private static final ZonedDateTime[] FIXING_DATES_GBPSONIA = new ZonedDateTime[] {DateUtils.getUTCDate(2012, 2, 7), DateUtils.getUTCDate(2012, 2, 8), DateUtils.getUTCDate(2012, 2, 9), DateUtils.getUTCDate(2012, 2, 12), DateUtils.getUTCDate(2012, 2, 13), DateUtils.getUTCDate(2012, 2, 14), DateUtils.getUTCDate(2012, 2, 15), DateUtils.getUTCDate(2012, 2, 16) }; private static final double[] FIXING_RATES_GBPSONIA = new double[] {0.0010, 0.0011, 0.0012, 0.0013, 0.0010, 0.0011, 0.0012, 0.0013 }; private static final ZonedDateTimeDoubleTimeSeries FIXING_TS_GBPSONIA = ImmutableZonedDateTimeDoubleTimeSeries.ofUTC(FIXING_DATES_GBPSONIA, FIXING_RATES_GBPSONIA); private static final Currency GBP = Currency.GBP; private static final Calendar LON = new CalendarGBP("LON"); // Equity private static final double NB_SHARES = 1000000; private static final String OG_NAME = "OpenGamma Ltd"; private static final String OG_TICKER = "OG"; private static final LegalEntity OG_LEGAL_ENTITY = new LegalEntity(OG_TICKER, OG_NAME, Sets.newHashSet(CreditRating.of("AAA", "ABC", true)), Sector.of("Technology"), Region.of("UK", Country.GB, Currency.GBP)); private static final EquityDefinition EQUITY_DEFINITION_REC = new EquityDefinition(OG_LEGAL_ENTITY, GBP, NB_SHARES); private static final Equity EQUITY_REC = new Equity(OG_LEGAL_ENTITY, GBP, NB_SHARES); private static final Equity EQUITY_PAY = new Equity(OG_LEGAL_ENTITY, GBP, -NB_SHARES); private static final double DIVIDEND_RATIO = 1.0; private static final double NOTIONAL_TRS_GBP = 123456000; // Funding: unique ON with spread coupon in GBP: receive TRS equity, pay funding private static final IndexON GBPSONIA = IndexONMaster.getInstance().getIndex("SONIA"); private static final double SPREAD_GBP = 0.0010; private static final CouponONSpreadDefinition FUNDING_ON_CPN_REC_DEFINITION = new CouponONSpreadDefinition(GBP, TERMINATION_DATE_1, EFFECTIVE_DATE_1, TERMINATION_DATE_1, GBPSONIA.getDayCount().getDayCountFraction(EFFECTIVE_DATE_1, TERMINATION_DATE_1), NOTIONAL_TRS_GBP, GBPSONIA, EFFECTIVE_DATE_1, TERMINATION_DATE_1, LON, SPREAD_GBP); private static final AnnuityDefinition<? extends PaymentDefinition> FUNDING_LEG_ON_REC_DEFINITION = new AnnuityDefinition<>(new PaymentDefinition[] {FUNDING_ON_CPN_REC_DEFINITION }, LON); private static final Annuity<? extends Payment> FUNDING_LEG_ON_REC_1 = FUNDING_LEG_ON_REC_DEFINITION.toDerivative(REFERENCE_DATE_1, FIXING_TS_GBPSONIA); private static final Annuity<? extends Payment> FUNDING_LEG_ON_REC_2 = FUNDING_LEG_ON_REC_DEFINITION.toDerivative(REFERENCE_DATE_2, FIXING_TS_GBPSONIA); private static final EquityTotalReturnSwap TRS_PAY_ON_REC_1 = new EquityTotalReturnSwap(EFFECTIVE_TIME_1_1, TERMINATION_TIME_1_1, FUNDING_LEG_ON_REC_1, EQUITY_PAY, -NOTIONAL_TRS_GBP, GBP, DIVIDEND_RATIO); private static final EquityTotalReturnSwap TRS_PAY_ON_REC_2 = new EquityTotalReturnSwap(EFFECTIVE_TIME_2_1, TERMINATION_TIME_2_1, FUNDING_LEG_ON_REC_2, EQUITY_PAY, -NOTIONAL_TRS_GBP, GBP, DIVIDEND_RATIO); // Funding: unique ON coupon in GBP: pay TRS bond, receive funding private static final CouponONSpreadDefinition FUNDING_ON_CPN_PAY_DEFINITION = new CouponONSpreadDefinition(GBP, TERMINATION_DATE_1, EFFECTIVE_DATE_1, TERMINATION_DATE_1, GBPSONIA.getDayCount().getDayCountFraction(EFFECTIVE_DATE_1, TERMINATION_DATE_1), -NOTIONAL_TRS_GBP, GBPSONIA, EFFECTIVE_DATE_1, TERMINATION_DATE_1, LON, SPREAD_GBP); private static final AnnuityDefinition<? extends PaymentDefinition> FUNDING_LEG_ON_PAY_DEFINITION = new AnnuityDefinition<>(new PaymentDefinition[] {FUNDING_ON_CPN_PAY_DEFINITION }, LON); private static final Annuity<? extends Payment> FUNDING_LEG_ON_PAY_1 = FUNDING_LEG_ON_PAY_DEFINITION.toDerivative(REFERENCE_DATE_1, FIXING_TS_GBPSONIA); private static final EquityTotalReturnSwap TRS_REC_ON_PAY_1 = new EquityTotalReturnSwap(EFFECTIVE_TIME_1_1, TERMINATION_TIME_1_1, FUNDING_LEG_ON_PAY_1, EQUITY_REC, NOTIONAL_TRS_GBP, GBP, DIVIDEND_RATIO); // Funding: multiple USD Libor coupons private static final double NOTIONAL_TRS_USD = 199000000; private static final Calendar NYC = new CalendarUSD("NYC"); private static final double SPREAD = 0.0010; private static final IborIndex USDLIBOR3M = IndexIborMaster.getInstance().getIndex("USDLIBOR3M"); private static final Currency USD = USDLIBOR3M.getCurrency(); private static final AnnuityDefinition<CouponIborSpreadDefinition> FUNDING_LEG_IBOR_PAY_DEFINITION = AnnuityDefinitionBuilder.couponIborSpread(EFFECTIVE_DATE_2, TERMINATION_DATE_2, USDLIBOR3M.getTenor(), NOTIONAL_TRS_USD, SPREAD, USDLIBOR3M, true, USDLIBOR3M.getDayCount(), USDLIBOR3M.getBusinessDayConvention(), true, NYC, StubType.SHORT_START, 0); private static final Annuity<? extends Payment> FUNDING_LEG_IBOR_PAY_1 = FUNDING_LEG_IBOR_PAY_DEFINITION.toDerivative(REFERENCE_DATE_1, FIXING_TS_USDLIBOR); private static final Annuity<? extends Payment> FUNDING_LEG_IBOR_PAY_2 = FUNDING_LEG_IBOR_PAY_DEFINITION.toDerivative(REFERENCE_DATE_3, FIXING_TS_USDLIBOR); private static final EquityTotalReturnSwapDefinition TRS_REC_IBOR_PAY_DEFINITION = new EquityTotalReturnSwapDefinition(EFFECTIVE_DATE_2, TERMINATION_DATE_2, FUNDING_LEG_IBOR_PAY_DEFINITION, EQUITY_DEFINITION_REC, NOTIONAL_TRS_USD, USD, DIVIDEND_RATIO); private static final EquityTotalReturnSwap TRS_REC_IBOR_PAY_1 = TRS_REC_IBOR_PAY_DEFINITION.toDerivative(REFERENCE_DATE_1, FIXING_TS_USDLIBOR); private static final EquityTotalReturnSwap TRS_REC_IBOR_PAY_2 = TRS_REC_IBOR_PAY_DEFINITION.toDerivative(REFERENCE_DATE_3, FIXING_TS_USDLIBOR); private static final EquityTotalReturnSwapDiscountingMethod METHOD_TRS_EQT = EquityTotalReturnSwapDiscountingMethod.getInstance(); private static final PresentValueDiscountingCalculator PVDC = PresentValueDiscountingCalculator.getInstance(); private static final PresentValueEquityDiscountingCalculator PVEDC = PresentValueEquityDiscountingCalculator.getInstance(); private static final PresentValueCurveSensitivityDiscountingCalculator PVCSDC = PresentValueCurveSensitivityDiscountingCalculator.getInstance(); private static final PresentValueCurveSensitivityEquityDiscountingCalculator PVCSEDC = PresentValueCurveSensitivityEquityDiscountingCalculator.getInstance(); private static final MulticurveProviderDiscount MULTICURVE = MulticurveProviderDiscountDataSets.createMulticurveGbpUsd(); private static final double EQUITY_PRICE = 123.4; private static final EquityTrsDataBundle EQUITY_MULTICURVE = new EquityTrsDataBundle(EQUITY_PRICE, MULTICURVE); private static final double TOLERANCE_PV = 1.0E-2; private static final double TOLERANCE_PV_DELTA = 1.0E+2; @Test(expectedExceptions = IllegalArgumentException.class) public void dividednRatio() { EquityTotalReturnSwap wrongRatio = new EquityTotalReturnSwap(EFFECTIVE_TIME_1_1, TERMINATION_TIME_1_1, FUNDING_LEG_ON_REC_1, EQUITY_PAY, -NOTIONAL_TRS_GBP, GBP, 0.5); METHOD_TRS_EQT.presentValue(wrongRatio, EQUITY_MULTICURVE); } @Test /** Test present value and currency exposure for an example where the funding and equity are in the same currency. * The TRS is paid or received. There is only one ON coupon in the funding. The valuation date is before the TRS effective date */ public void presentValueONSameCurrencyBeforeEffective() { MultipleCurrencyAmount pvComputedPay = METHOD_TRS_EQT.presentValue(TRS_PAY_ON_REC_1, EQUITY_MULTICURVE); assertEquals("EquityTotalReturnSwapDiscountingMethod: present value", 1, pvComputedPay.size()); // Equity and funding in same currency assertTrue("EquityTotalReturnSwapDiscountingMethod: present value", pvComputedPay.getAmount(GBP) != 0.0); MultipleCurrencyAmount pvEquity = MultipleCurrencyAmount.of(GBP, -NB_SHARES * EQUITY_PRICE); MultipleCurrencyAmount pvPreviousFixing = MultipleCurrencyAmount.of(GBP, NOTIONAL_TRS_GBP * MULTICURVE.getDiscountFactor(GBP, TRS_PAY_ON_REC_1.getFundingLeg().getNthPayment(0).getPaymentTime())); MultipleCurrencyAmount pvFunding = FUNDING_LEG_ON_REC_1.accept(PVDC, MULTICURVE); MultipleCurrencyAmount pvExpected = pvEquity.plus(pvPreviousFixing).plus(pvFunding); assertEquals("BondTRSDiscountingMethod: present value", pvExpected.getAmount(GBP), pvComputedPay.getAmount(GBP), TOLERANCE_PV); MultipleCurrencyAmount pvComputedRec = METHOD_TRS_EQT.presentValue(TRS_REC_ON_PAY_1, EQUITY_MULTICURVE); assertEquals("BondTRSDiscountingMethod: present value", -pvComputedPay.getAmount(GBP), pvComputedRec.getAmount(GBP), TOLERANCE_PV); MultipleCurrencyAmount pvAssetLeg = METHOD_TRS_EQT.presentValueAssetLeg(TRS_PAY_ON_REC_1, EQUITY_MULTICURVE); MultipleCurrencyAmount pvFundingLeg = METHOD_TRS_EQT.presentValueFundingLeg(TRS_PAY_ON_REC_1, EQUITY_MULTICURVE); assertEquals("BondTRSDiscountingMethod: present value", pvExpected.getAmount(GBP), pvFundingLeg.plus(pvAssetLeg).getAmount(GBP), TOLERANCE_PV); // Currency exposure MultipleCurrencyAmount ceComputedPay = METHOD_TRS_EQT.currencyExposure(TRS_PAY_ON_REC_1, EQUITY_MULTICURVE); MultipleCurrencyAmount ceComputedRec = METHOD_TRS_EQT.currencyExposure(TRS_REC_ON_PAY_1, EQUITY_MULTICURVE); assertEquals("BondTRSDiscountingMethod: currency exposure", pvComputedRec.getAmount(GBP), ceComputedRec.getAmount(GBP), TOLERANCE_PV); assertEquals("BondTRSDiscountingMethod: currency exposure", pvComputedPay.getAmount(GBP), ceComputedPay.getAmount(GBP), TOLERANCE_PV); // Method vs Calculator MultipleCurrencyAmount pvCalculatorPay = TRS_PAY_ON_REC_1.accept(PVEDC, EQUITY_MULTICURVE); assertEquals("BondTRSDiscountingMethod: present value", pvCalculatorPay.getAmount(GBP), pvComputedPay.getAmount(GBP), TOLERANCE_PV); // Asset exposure MultipleCurrencyAmount ae = METHOD_TRS_EQT.assetExposure(TRS_PAY_ON_REC_1, EQUITY_MULTICURVE); assertEquals("BondTRSDiscountingMethod: asset exposure", pvEquity.getAmount(GBP), ae.getAmount(GBP), TOLERANCE_PV); } @Test /** Test present value and currency exposure for an example where the funding and equity are in the same currency. * The TRS is paid or received. The valuation date is after the TRS effective date */ public void presentValueONSameCurrencyAfterEffective() { MultipleCurrencyAmount pvComputed = METHOD_TRS_EQT.presentValue(TRS_PAY_ON_REC_2, EQUITY_MULTICURVE); assertEquals("BondTRSDiscountingMethod: present value", 1, pvComputed.size()); // Bond and funding in same currency assertTrue("BondTRSDiscountingMethod: present value", pvComputed.getAmount(GBP) != 0.0); MultipleCurrencyAmount pvEquity = MultipleCurrencyAmount.of(GBP, -NB_SHARES * EQUITY_PRICE); MultipleCurrencyAmount pvPreviousFixing = MultipleCurrencyAmount.of(GBP, NOTIONAL_TRS_GBP * MULTICURVE.getDiscountFactor(GBP, TRS_PAY_ON_REC_2.getFundingLeg().getNthPayment(0).getPaymentTime())); MultipleCurrencyAmount pvFunding = FUNDING_LEG_ON_REC_2.accept(PVDC, MULTICURVE); MultipleCurrencyAmount pvExpected = pvEquity.plus(pvPreviousFixing).plus(pvFunding); assertEquals("BondTRSDiscountingMethod: present value", pvExpected.getAmount(GBP), pvComputed.getAmount(GBP), TOLERANCE_PV); // Equity and funding in same currency // Currency exposure MultipleCurrencyAmount ceComputedRec = METHOD_TRS_EQT.currencyExposure(TRS_PAY_ON_REC_2, EQUITY_MULTICURVE); assertEquals("BondTRSDiscountingMethod: currency exposure", pvComputed.getAmount(GBP), ceComputedRec.getAmount(GBP), TOLERANCE_PV); // Asset exposure MultipleCurrencyAmount ae = METHOD_TRS_EQT.assetExposure(TRS_PAY_ON_REC_2, EQUITY_MULTICURVE); assertEquals("BondTRSDiscountingMethod: asset exposure", pvEquity.getAmount(GBP), ae.getAmount(GBP), TOLERANCE_PV); } @Test /** Test present value and currency exposure for an example where the funding and equity are in different currencies. * The TRS is paid. There are 3 Libor coupons in the funding. The valuation date is before the TRS effective date */ public void presentValueIborDiffCurrencyBeforeEffective() { MultipleCurrencyAmount pvComputedRec = METHOD_TRS_EQT.presentValue(TRS_REC_IBOR_PAY_1, EQUITY_MULTICURVE); assertEquals("BondTRSDiscountingMethod: present value", 1, pvComputedRec.size()); // Converted in funding: USD assertTrue("BondTRSDiscountingMethod: present value", pvComputedRec.getAmount(USD) != 0.0); MultipleCurrencyAmount pvEquityGbp = MultipleCurrencyAmount.of(GBP, NB_SHARES * EQUITY_PRICE); CurrencyAmount pvEquityUsd = MULTICURVE.getFxRates().convert(pvEquityGbp, USD); MultipleCurrencyAmount pvPreviousFixing = MultipleCurrencyAmount.of(USD, -NOTIONAL_TRS_USD * MULTICURVE.getDiscountFactor(USD, TRS_REC_IBOR_PAY_1.getFundingLeg().getNthPayment(0).getPaymentTime())); MultipleCurrencyAmount pvFunding = FUNDING_LEG_IBOR_PAY_1.getNthPayment(0).accept(PVDC, MULTICURVE); MultipleCurrencyAmount pvExpected = pvPreviousFixing.plus(pvFunding).plus(pvEquityUsd); assertEquals("BondTRSDiscountingMethod: present value", pvExpected.getAmount(USD), pvComputedRec.getAmount(USD), TOLERANCE_PV); MultipleCurrencyAmount pvAssetLeg = METHOD_TRS_EQT.presentValueAssetLeg(TRS_REC_IBOR_PAY_1, EQUITY_MULTICURVE); MultipleCurrencyAmount pvFundingLeg = METHOD_TRS_EQT.presentValueFundingLeg(TRS_REC_IBOR_PAY_1, EQUITY_MULTICURVE); assertEquals("BondTRSDiscountingMethod: present value", pvExpected.getAmount(USD), pvFundingLeg.plus(pvAssetLeg).getAmount(USD), TOLERANCE_PV); // Currency exposure MultipleCurrencyAmount ceComputedRec = METHOD_TRS_EQT.currencyExposure(TRS_REC_IBOR_PAY_1, EQUITY_MULTICURVE); assertEquals("BondTRSDiscountingMethod: currency exposure", 2, ceComputedRec.size()); // GBP equity and USD funding (and notional currency) assertEquals("BondTRSDiscountingMethod: currency exposure", MULTICURVE.getFxRates().convert(ceComputedRec, GBP).getAmount(), MULTICURVE.getFxRates().convert(pvComputedRec, GBP).getAmount(), TOLERANCE_PV); // CE and PV total should be the same; only conversion is different assertEquals("BondTRSDiscountingMethod: currency exposure", pvEquityGbp.getAmount(GBP), ceComputedRec.getAmount(GBP), TOLERANCE_PV); // Method vs Calculator MultipleCurrencyAmount pvCalculatorRec = TRS_REC_IBOR_PAY_1.accept(PVEDC, EQUITY_MULTICURVE); assertEquals("BondTRSDiscountingMethod: present value", pvCalculatorRec.getAmount(USD), pvComputedRec.getAmount(USD), TOLERANCE_PV); // Asset exposure MultipleCurrencyAmount ae = METHOD_TRS_EQT.assetExposure(TRS_REC_IBOR_PAY_1, EQUITY_MULTICURVE); assertEquals("BondTRSDiscountingMethod: asset exposure", pvEquityGbp.getAmount(GBP), ae.getAmount(GBP), TOLERANCE_PV); } @Test /** Test present value and currency exposure for an example where the funding and equity are in different currencies. * The TRS is paid. There are 3 Libor coupons in the funding. The valuation date is after the TRS effective date, in the first funding period. */ public void presentValueIborDiffCurrencyAfterEffective() { MultipleCurrencyAmount pvComputedRec = METHOD_TRS_EQT.presentValue(TRS_REC_IBOR_PAY_2, EQUITY_MULTICURVE); assertEquals("BondTRSDiscountingMethod: present value", 1, pvComputedRec.size()); // Converted in funding: USD assertTrue("BondTRSDiscountingMethod: present value", pvComputedRec.getAmount(USD) != 0.0); MultipleCurrencyAmount pvEquityGbp = MultipleCurrencyAmount.of(GBP, NB_SHARES * EQUITY_PRICE); CurrencyAmount pvEquityUsd = MULTICURVE.getFxRates().convert(pvEquityGbp, USD); MultipleCurrencyAmount pvPreviousFixing = MultipleCurrencyAmount.of(USD, -NOTIONAL_TRS_USD * MULTICURVE.getDiscountFactor(USD, TRS_REC_IBOR_PAY_2.getFundingLeg().getNthPayment(0).getPaymentTime())); MultipleCurrencyAmount pvFunding0 = FUNDING_LEG_IBOR_PAY_2.getNthPayment(0).accept(PVDC, MULTICURVE); MultipleCurrencyAmount pvExpected = pvPreviousFixing.plus(pvFunding0).plus(pvEquityUsd); assertEquals("BondTRSDiscountingMethod: present value", pvExpected.getAmount(USD), pvComputedRec.getAmount(USD), TOLERANCE_PV); MultipleCurrencyAmount pvAssetLeg = METHOD_TRS_EQT.presentValueAssetLeg(TRS_REC_IBOR_PAY_2, EQUITY_MULTICURVE); MultipleCurrencyAmount pvFundingLeg = METHOD_TRS_EQT.presentValueFundingLeg(TRS_REC_IBOR_PAY_2, EQUITY_MULTICURVE); assertEquals("BondTRSDiscountingMethod: present value", pvExpected.getAmount(USD), pvFundingLeg.plus(pvAssetLeg).getAmount(USD), TOLERANCE_PV); // Currency exposure MultipleCurrencyAmount ceComputedRec = METHOD_TRS_EQT.currencyExposure(TRS_REC_IBOR_PAY_2, EQUITY_MULTICURVE); assertEquals("BondTRSDiscountingMethod: currency exposure", 2, ceComputedRec.size()); // GBP equity and USD funding (and notional currency) assertEquals("BondTRSDiscountingMethod: currency exposure", MULTICURVE.getFxRates().convert(ceComputedRec, GBP).getAmount(), MULTICURVE.getFxRates().convert(pvComputedRec, GBP).getAmount(), TOLERANCE_PV); // CE and PV total should be the same; only conversion is different assertEquals("BondTRSDiscountingMethod: currency exposure", pvEquityGbp.getAmount(GBP), ceComputedRec.getAmount(GBP), TOLERANCE_PV); // Asset exposure MultipleCurrencyAmount ae = METHOD_TRS_EQT.assetExposure(TRS_REC_IBOR_PAY_2, EQUITY_MULTICURVE); assertEquals("BondTRSDiscountingMethod: asset exposure", pvEquityGbp.getAmount(GBP), ae.getAmount(GBP), TOLERANCE_PV); } @Test /** Test present value curve sensitivity for an example where the funding and equity are in different currencies. * The TRS is paid. There are 3 Libor coupons in the funding. The valuation date is after the TRS effective date, in the first funding period. */ public void presentValueCurveSensitivityIborDiffCurrencyAfterEffective() { MultipleCurrencyMulticurveSensitivity pvcsComputedRec = METHOD_TRS_EQT.presentValueCurveSensitivity(TRS_REC_IBOR_PAY_2, EQUITY_MULTICURVE).cleaned(); double amount = -NOTIONAL_TRS_USD * MULTICURVE.getDiscountFactor(USD, TRS_REC_IBOR_PAY_2.getFundingLeg().getNthPayment(0).getPaymentTime()); double time = TRS_REC_IBOR_PAY_2.getFundingLeg().getNthPayment(0).getPaymentTime(); final Map<String, List<DoublesPair>> mapDsc = new HashMap<>(); final DoublesPair s = DoublesPair.of(time, -time * amount); final List<DoublesPair> list = new ArrayList<>(); list.add(s); mapDsc.put(MULTICURVE.getName(USD), list); MultipleCurrencyMulticurveSensitivity pvcsPreviousFixing = new MultipleCurrencyMulticurveSensitivity(); pvcsPreviousFixing = pvcsPreviousFixing.plus(USD, MulticurveSensitivity.ofYieldDiscounting(mapDsc)); MultipleCurrencyMulticurveSensitivity pvcsFunding0 = FUNDING_LEG_IBOR_PAY_2.getNthPayment(0).accept(PVCSDC, MULTICURVE); MultipleCurrencyMulticurveSensitivity pvcsExpected = pvcsPreviousFixing.plus(pvcsFunding0).cleaned(); AssertSensitivityObjects.assertEquals("", pvcsExpected, pvcsComputedRec, TOLERANCE_PV_DELTA); } @Test public void presentValueCurveSensitivityMethodVsCalculator() { MultipleCurrencyMulticurveSensitivity pvcsComputedRec = METHOD_TRS_EQT.presentValueCurveSensitivity(TRS_REC_IBOR_PAY_2, EQUITY_MULTICURVE).cleaned(); MultipleCurrencyMulticurveSensitivity pvcsCalculator = TRS_REC_IBOR_PAY_2.accept(PVCSEDC, EQUITY_MULTICURVE).cleaned(); AssertSensitivityObjects.assertEquals("", pvcsComputedRec, pvcsCalculator, TOLERANCE_PV_DELTA); } }