/** * Copyright (C) 2015 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.strata.pricer.bond; import static com.opengamma.strata.basics.currency.Currency.GBP; import static com.opengamma.strata.basics.currency.Currency.USD; import static com.opengamma.strata.basics.date.DayCounts.ACT_365F; import static com.opengamma.strata.collect.TestHelper.assertThrowsIllegalArg; import static com.opengamma.strata.collect.TestHelper.coverBeanEquals; import static com.opengamma.strata.collect.TestHelper.coverImmutableBean; import static com.opengamma.strata.collect.TestHelper.date; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; import java.time.LocalDate; import java.util.Optional; import org.testng.annotations.Test; import com.google.common.collect.ImmutableMap; import com.opengamma.strata.basics.StandardId; import com.opengamma.strata.basics.currency.Currency; import com.opengamma.strata.collect.array.DoubleArray; import com.opengamma.strata.collect.tuple.Pair; import com.opengamma.strata.market.curve.CurveMetadata; import com.opengamma.strata.market.curve.CurveName; import com.opengamma.strata.market.curve.Curves; import com.opengamma.strata.market.curve.InterpolatedNodalCurve; import com.opengamma.strata.market.curve.interpolator.CurveInterpolator; import com.opengamma.strata.market.curve.interpolator.CurveInterpolators; import com.opengamma.strata.market.param.CurrencyParameterSensitivities; import com.opengamma.strata.market.sensitivity.PointSensitivities; import com.opengamma.strata.pricer.DiscountFactors; import com.opengamma.strata.pricer.ZeroRateDiscountFactors; import com.opengamma.strata.pricer.ZeroRateSensitivity; import com.opengamma.strata.product.SecurityId; /** * Test {@link ImmutableLegalEntityDiscountingProvider}. */ @Test public class ImmutableLegalEntityDiscountingProviderTest { private static final LocalDate DATE = date(2015, 6, 4); private static final CurveInterpolator INTERPOLATOR = CurveInterpolators.LINEAR; private static final CurveName NAME_REPO = CurveName.of("TestRepoCurve"); private static final CurveMetadata METADATA_REPO = Curves.zeroRates(NAME_REPO, ACT_365F); private static final InterpolatedNodalCurve CURVE_REPO = InterpolatedNodalCurve.of(METADATA_REPO, DoubleArray.of(0, 10), DoubleArray.of(1, 2), INTERPOLATOR); private static final ZeroRateDiscountFactors DSC_FACTORS_REPO = ZeroRateDiscountFactors.of(GBP, DATE, CURVE_REPO); private static final RepoGroup GROUP_REPO_SECURITY = RepoGroup.of("ISSUER1 BND 5Y"); private static final RepoGroup GROUP_REPO_ISSUER = RepoGroup.of("ISSUER1"); private static final SecurityId ID_SECURITY = SecurityId.of("OG-Ticker", "Bond-5Y"); private static final CurveName NAME_ISSUER = CurveName.of("TestIssuerCurve"); private static final CurveMetadata METADATA_ISSUER = Curves.zeroRates(NAME_ISSUER, ACT_365F); private static final InterpolatedNodalCurve CURVE_ISSUER = InterpolatedNodalCurve.of(METADATA_ISSUER, DoubleArray.of(0, 15), DoubleArray.of(1, 2.5), INTERPOLATOR); private static final ZeroRateDiscountFactors DSC_FACTORS_ISSUER = ZeroRateDiscountFactors.of(GBP, DATE, CURVE_ISSUER); private static final LegalEntityGroup GROUP_ISSUER = LegalEntityGroup.of("ISSUER1"); private static final StandardId ID_ISSUER = StandardId.of("OG-Ticker", "Issuer-1"); //------------------------------------------------------------------------- public void test_builder() { ImmutableLegalEntityDiscountingProvider test = ImmutableLegalEntityDiscountingProvider.builder() .issuerCurves(ImmutableMap.<Pair<LegalEntityGroup, Currency>, DiscountFactors>of( Pair.<LegalEntityGroup, Currency>of(GROUP_ISSUER, GBP), DSC_FACTORS_ISSUER)) .issuerCurveGroups(ImmutableMap.<StandardId, LegalEntityGroup>of(ID_ISSUER, GROUP_ISSUER)) .repoCurves(ImmutableMap.<Pair<RepoGroup, Currency>, DiscountFactors>of( Pair.<RepoGroup, Currency>of(GROUP_REPO_SECURITY, GBP), DSC_FACTORS_REPO)) .repoCurveGroups(ImmutableMap.<StandardId, RepoGroup>of(ID_SECURITY.getStandardId(), GROUP_REPO_SECURITY)) .valuationDate(DATE) .build(); assertEquals( test.issuerCurveDiscountFactors(ID_ISSUER, GBP), IssuerCurveDiscountFactors.of(DSC_FACTORS_ISSUER, GROUP_ISSUER)); assertEquals(test.repoCurveDiscountFactors(ID_SECURITY, ID_ISSUER, GBP), RepoCurveDiscountFactors.of(DSC_FACTORS_REPO, GROUP_REPO_SECURITY)); assertEquals(test.getValuationDate(), DATE); } public void test_builder_noValuationDate() { ImmutableLegalEntityDiscountingProvider test = ImmutableLegalEntityDiscountingProvider.builder() .issuerCurves(ImmutableMap.<Pair<LegalEntityGroup, Currency>, DiscountFactors>of( Pair.<LegalEntityGroup, Currency>of(GROUP_ISSUER, GBP), DSC_FACTORS_ISSUER)) .issuerCurveGroups(ImmutableMap.<StandardId, LegalEntityGroup>of(ID_ISSUER, GROUP_ISSUER)) .repoCurves(ImmutableMap.<Pair<RepoGroup, Currency>, DiscountFactors>of( Pair.<RepoGroup, Currency>of(GROUP_REPO_ISSUER, GBP), DSC_FACTORS_REPO)) .repoCurveGroups(ImmutableMap.<StandardId, RepoGroup>of(ID_ISSUER, GROUP_REPO_ISSUER)) .build(); assertEquals( test.issuerCurveDiscountFactors(ID_ISSUER, GBP), IssuerCurveDiscountFactors.of(DSC_FACTORS_ISSUER, GROUP_ISSUER)); assertEquals(test.repoCurveDiscountFactors(ID_SECURITY, ID_ISSUER, GBP), RepoCurveDiscountFactors.of(DSC_FACTORS_REPO, GROUP_REPO_ISSUER)); assertEquals(test.getValuationDate(), DATE); } public void test_builder_noRepoRate() { ImmutableLegalEntityDiscountingProvider test = ImmutableLegalEntityDiscountingProvider.builder() .issuerCurveGroups(ImmutableMap.of(ID_ISSUER, GROUP_ISSUER)) .issuerCurves(ImmutableMap.of(Pair.of(GROUP_ISSUER, GBP), DSC_FACTORS_ISSUER)) .build(); assertEquals( test.issuerCurveDiscountFactors(ID_ISSUER, GBP), IssuerCurveDiscountFactors.of(DSC_FACTORS_ISSUER, GROUP_ISSUER)); assertEquals(test.getValuationDate(), DATE); } public void test_builder_fail() { // no relevant map for repo curve assertThrowsIllegalArg(() -> ImmutableLegalEntityDiscountingProvider.builder() .issuerCurves(ImmutableMap.<Pair<LegalEntityGroup, Currency>, DiscountFactors>of( Pair.<LegalEntityGroup, Currency>of(GROUP_ISSUER, GBP), DSC_FACTORS_ISSUER)) .issuerCurveGroups(ImmutableMap.<StandardId, LegalEntityGroup>of(ID_ISSUER, GROUP_ISSUER)) .repoCurves(ImmutableMap.<Pair<RepoGroup, Currency>, DiscountFactors>of( Pair.<RepoGroup, Currency>of(GROUP_REPO_ISSUER, GBP), DSC_FACTORS_REPO)) .repoCurveGroups(ImmutableMap.<StandardId, RepoGroup>of(ID_ISSUER, RepoGroup.of("ISSUER2 BND 5Y"))) .build()); // no relevant map for issuer curve assertThrowsIllegalArg(() -> ImmutableLegalEntityDiscountingProvider.builder() .issuerCurves(ImmutableMap.<Pair<LegalEntityGroup, Currency>, DiscountFactors>of( Pair.<LegalEntityGroup, Currency>of(GROUP_ISSUER, GBP), DSC_FACTORS_ISSUER)) .issuerCurveGroups(ImmutableMap.<StandardId, LegalEntityGroup>of(ID_ISSUER, LegalEntityGroup.of("ISSUER2"))) .repoCurves(ImmutableMap.<Pair<RepoGroup, Currency>, DiscountFactors>of( Pair.<RepoGroup, Currency>of(GROUP_REPO_ISSUER, GBP), DSC_FACTORS_REPO)) .repoCurveGroups(ImmutableMap.<StandardId, RepoGroup>of(ID_ISSUER, GROUP_REPO_ISSUER)) .build()); // issuer curve and valuation date are missing assertThrowsIllegalArg(() -> ImmutableLegalEntityDiscountingProvider.builder() .issuerCurveGroups(ImmutableMap.<StandardId, LegalEntityGroup>of(ID_ISSUER, GROUP_ISSUER)) .repoCurves(ImmutableMap.<Pair<RepoGroup, Currency>, DiscountFactors>of( Pair.<RepoGroup, Currency>of(GROUP_REPO_SECURITY, GBP), DSC_FACTORS_REPO)) .repoCurveGroups(ImmutableMap.<StandardId, RepoGroup>of(ID_SECURITY.getStandardId(), GROUP_REPO_SECURITY)) .build()); // issuer curve date is different from valuation date DiscountFactors dscFactorIssuer = ZeroRateDiscountFactors.of(GBP, date(2015, 6, 14), CURVE_ISSUER); assertThrowsIllegalArg(() -> ImmutableLegalEntityDiscountingProvider.builder() .issuerCurves(ImmutableMap.<Pair<LegalEntityGroup, Currency>, DiscountFactors>of( Pair.<LegalEntityGroup, Currency>of(GROUP_ISSUER, GBP), dscFactorIssuer)) .issuerCurveGroups(ImmutableMap.<StandardId, LegalEntityGroup>of(ID_ISSUER, GROUP_ISSUER)) .repoCurves(ImmutableMap.<Pair<RepoGroup, Currency>, DiscountFactors>of( Pair.<RepoGroup, Currency>of(GROUP_REPO_SECURITY, GBP), DSC_FACTORS_REPO)) .repoCurveGroups(ImmutableMap.<StandardId, RepoGroup>of(ID_SECURITY.getStandardId(), GROUP_REPO_SECURITY)) .valuationDate(DATE) .build()); // repo curve rate is different from valuation date DiscountFactors dscFactorRepo = ZeroRateDiscountFactors.of(GBP, date(2015, 6, 14), CURVE_REPO); assertThrowsIllegalArg(() -> ImmutableLegalEntityDiscountingProvider.builder() .issuerCurves(ImmutableMap.<Pair<LegalEntityGroup, Currency>, DiscountFactors>of( Pair.<LegalEntityGroup, Currency>of(GROUP_ISSUER, GBP), DSC_FACTORS_ISSUER)) .issuerCurveGroups(ImmutableMap.<StandardId, LegalEntityGroup>of(ID_ISSUER, GROUP_ISSUER)) .repoCurves(ImmutableMap.<Pair<RepoGroup, Currency>, DiscountFactors>of( Pair.<RepoGroup, Currency>of(GROUP_REPO_SECURITY, GBP), dscFactorRepo)) .repoCurveGroups(ImmutableMap.<StandardId, RepoGroup>of(ID_SECURITY.getStandardId(), GROUP_REPO_SECURITY)) .valuationDate(DATE) .build()); } //------------------------------------------------------------------------- public void test_discountFactor_notFound() { StandardId issuerId = StandardId.of("OG-Ticker", "Issuer-2"); LegalEntityGroup issuerGroup = LegalEntityGroup.of("ISSUER2"); RepoGroup repoGroup = RepoGroup.of("ISSUER2 BND 5Y"); SecurityId securityId = SecurityId.of("OG-Ticker", "Issuer-2-bond-5Y"); ImmutableLegalEntityDiscountingProvider test = ImmutableLegalEntityDiscountingProvider.builder() .issuerCurves(ImmutableMap.<Pair<LegalEntityGroup, Currency>, DiscountFactors>of( Pair.<LegalEntityGroup, Currency>of(GROUP_ISSUER, GBP), DSC_FACTORS_ISSUER)) .issuerCurveGroups(ImmutableMap.<StandardId, LegalEntityGroup>of(ID_ISSUER, GROUP_ISSUER, issuerId, issuerGroup)) .repoCurves(ImmutableMap.<Pair<RepoGroup, Currency>, DiscountFactors>of( Pair.<RepoGroup, Currency>of(GROUP_REPO_SECURITY, GBP), DSC_FACTORS_REPO)) .repoCurveGroups(ImmutableMap.<StandardId, RepoGroup>of(ID_SECURITY.getStandardId(), GROUP_REPO_SECURITY, issuerId, repoGroup)) .valuationDate(DATE) .build(); assertThrowsIllegalArg(() -> test.issuerCurveDiscountFactors(ID_ISSUER, USD)); assertThrowsIllegalArg(() -> test.issuerCurveDiscountFactors(StandardId.of("OG-Ticker", "foo"), GBP)); assertThrowsIllegalArg(() -> test.issuerCurveDiscountFactors(issuerId, GBP)); assertThrowsIllegalArg(() -> test.repoCurveDiscountFactors(ID_SECURITY, ID_ISSUER, USD)); assertThrowsIllegalArg(() -> test.repoCurveDiscountFactors( SecurityId.of("OG-Ticker", "foo-bond"), StandardId.of("OG-Ticker", "foo"), GBP)); assertThrowsIllegalArg(() -> test.repoCurveDiscountFactors(securityId, issuerId, GBP)); } public void test_curveParameterSensitivity() { ImmutableLegalEntityDiscountingProvider test = ImmutableLegalEntityDiscountingProvider.builder() .issuerCurves(ImmutableMap.<Pair<LegalEntityGroup, Currency>, DiscountFactors>of( Pair.<LegalEntityGroup, Currency>of(GROUP_ISSUER, GBP), DSC_FACTORS_ISSUER)) .issuerCurveGroups(ImmutableMap.<StandardId, LegalEntityGroup>of(ID_ISSUER, GROUP_ISSUER)) .repoCurves(ImmutableMap.<Pair<RepoGroup, Currency>, DiscountFactors>of( Pair.<RepoGroup, Currency>of(GROUP_REPO_ISSUER, GBP), DSC_FACTORS_REPO)) .repoCurveGroups(ImmutableMap.<StandardId, RepoGroup>of(ID_ISSUER, GROUP_REPO_ISSUER)) .valuationDate(DATE) .build(); LocalDate refDate = date(2018, 11, 24); IssuerCurveZeroRateSensitivity sensi1 = test.issuerCurveDiscountFactors(ID_ISSUER, GBP) .zeroRatePointSensitivity(refDate, GBP); RepoCurveZeroRateSensitivity sensi2 = test.repoCurveDiscountFactors(ID_SECURITY, ID_ISSUER, GBP) .zeroRatePointSensitivity(refDate, GBP); PointSensitivities sensi = PointSensitivities.of(sensi1, sensi2); CurrencyParameterSensitivities computed = test.parameterSensitivity(sensi); CurrencyParameterSensitivities expected = DSC_FACTORS_ISSUER.parameterSensitivity(sensi1.createZeroRateSensitivity()).combinedWith( DSC_FACTORS_REPO.parameterSensitivity(sensi2.createZeroRateSensitivity())); assertTrue(computed.equalWithTolerance(expected, 1.0e-12)); } public void test_curveParameterSensitivity_noSensi() { ImmutableLegalEntityDiscountingProvider test = ImmutableLegalEntityDiscountingProvider.builder() .issuerCurves(ImmutableMap.<Pair<LegalEntityGroup, Currency>, DiscountFactors>of( Pair.<LegalEntityGroup, Currency>of(GROUP_ISSUER, GBP), DSC_FACTORS_ISSUER)) .issuerCurveGroups(ImmutableMap.<StandardId, LegalEntityGroup>of(ID_ISSUER, GROUP_ISSUER)) .repoCurves(ImmutableMap.<Pair<RepoGroup, Currency>, DiscountFactors>of( Pair.<RepoGroup, Currency>of(GROUP_REPO_ISSUER, GBP), DSC_FACTORS_REPO)) .repoCurveGroups(ImmutableMap.<StandardId, RepoGroup>of(ID_ISSUER, GROUP_REPO_ISSUER)) .valuationDate(DATE) .build(); ZeroRateSensitivity sensi = ZeroRateSensitivity.of(USD, DSC_FACTORS_ISSUER.relativeYearFraction(date(2018, 11, 24)), 25d); CurrencyParameterSensitivities computed = test.parameterSensitivity(sensi.build()); assertEquals(computed, CurrencyParameterSensitivities.empty()); } public void test_findData() { ImmutableLegalEntityDiscountingProvider test = ImmutableLegalEntityDiscountingProvider.builder() .issuerCurves(ImmutableMap.<Pair<LegalEntityGroup, Currency>, DiscountFactors>of( Pair.<LegalEntityGroup, Currency>of(GROUP_ISSUER, GBP), DSC_FACTORS_ISSUER)) .issuerCurveGroups(ImmutableMap.<StandardId, LegalEntityGroup>of(ID_ISSUER, GROUP_ISSUER)) .repoCurves(ImmutableMap.<Pair<RepoGroup, Currency>, DiscountFactors>of( Pair.<RepoGroup, Currency>of(GROUP_REPO_ISSUER, GBP), DSC_FACTORS_REPO)) .repoCurveGroups(ImmutableMap.<StandardId, RepoGroup>of(ID_ISSUER, GROUP_REPO_ISSUER)) .valuationDate(DATE) .build(); assertEquals(test.findData(DSC_FACTORS_ISSUER.getCurve().getName()), Optional.of(DSC_FACTORS_ISSUER.getCurve())); assertEquals(test.findData(DSC_FACTORS_REPO.getCurve().getName()), Optional.of(DSC_FACTORS_REPO.getCurve())); assertEquals(test.findData(CurveName.of("Rubbish")), Optional.empty()); } //------------------------------------------------------------------------- public void coverage() { ImmutableLegalEntityDiscountingProvider test1 = ImmutableLegalEntityDiscountingProvider.builder() .issuerCurves(ImmutableMap.<Pair<LegalEntityGroup, Currency>, DiscountFactors>of( Pair.<LegalEntityGroup, Currency>of(GROUP_ISSUER, GBP), DSC_FACTORS_ISSUER)) .issuerCurveGroups(ImmutableMap.<StandardId, LegalEntityGroup>of(ID_ISSUER, GROUP_ISSUER)) .repoCurves(ImmutableMap.<Pair<RepoGroup, Currency>, DiscountFactors>of( Pair.<RepoGroup, Currency>of(GROUP_REPO_ISSUER, GBP), DSC_FACTORS_REPO)) .repoCurveGroups(ImmutableMap.<StandardId, RepoGroup>of(ID_ISSUER, GROUP_REPO_ISSUER)) .build(); coverImmutableBean(test1); LocalDate val = date(2015, 6, 14); DiscountFactors dscFactorIssuer = ZeroRateDiscountFactors.of(GBP, val, CURVE_ISSUER); DiscountFactors dscFactorRepo = ZeroRateDiscountFactors.of(GBP, val, CURVE_REPO); ImmutableLegalEntityDiscountingProvider test2 = ImmutableLegalEntityDiscountingProvider.builder() .issuerCurves(ImmutableMap.<Pair<LegalEntityGroup, Currency>, DiscountFactors>of( Pair.<LegalEntityGroup, Currency>of(GROUP_ISSUER, GBP), dscFactorIssuer)) .issuerCurveGroups(ImmutableMap.<StandardId, LegalEntityGroup>of(StandardId.of("OG-Ticker", "foo"), GROUP_ISSUER)) .repoCurves(ImmutableMap.<Pair<RepoGroup, Currency>, DiscountFactors>of( Pair.<RepoGroup, Currency>of(RepoGroup.of("ISSUER2 BND 5Y"), GBP), dscFactorRepo)) .repoCurveGroups(ImmutableMap.<StandardId, RepoGroup>of(ID_SECURITY.getStandardId(), RepoGroup.of("ISSUER2 BND 5Y"))) .build(); coverBeanEquals(test1, test2); } }