/** * Copyright (C) 2015 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.strata.examples.marketdata; import static com.opengamma.strata.collect.TestHelper.assertThrowsIllegalArg; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertFalse; import static org.testng.Assert.assertTrue; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.net.URL; import java.net.URLClassLoader; import java.nio.file.Files; import java.nio.file.Path; import java.time.LocalDate; import java.util.Set; import java.util.jar.JarEntry; import java.util.jar.JarOutputStream; import org.testng.annotations.Test; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Sets; import com.opengamma.strata.basics.StandardId; import com.opengamma.strata.basics.currency.Currency; import com.opengamma.strata.basics.index.IborIndices; import com.opengamma.strata.basics.index.OvernightIndices; import com.opengamma.strata.collect.Messages; import com.opengamma.strata.data.FieldName; import com.opengamma.strata.data.FxRateId; import com.opengamma.strata.data.ImmutableMarketData; import com.opengamma.strata.data.MarketDataId; import com.opengamma.strata.data.ObservableId; import com.opengamma.strata.examples.marketdata.credit.markit.MarkitRedCode; import com.opengamma.strata.market.curve.CurveGroupName; import com.opengamma.strata.market.curve.CurveId; import com.opengamma.strata.market.curve.CurveName; import com.opengamma.strata.market.observable.IndexQuoteId; import com.opengamma.strata.market.observable.QuoteId; import com.opengamma.strata.pricer.credit.IsdaIndexCreditCurveInputsId; import com.opengamma.strata.pricer.credit.IsdaIndexRecoveryRateId; import com.opengamma.strata.pricer.credit.IsdaSingleNameCreditCurveInputsId; import com.opengamma.strata.pricer.credit.IsdaSingleNameRecoveryRateId; import com.opengamma.strata.pricer.credit.IsdaYieldCurveInputsId; import com.opengamma.strata.product.credit.IndexReferenceInformation; import com.opengamma.strata.product.credit.RestructuringClause; import com.opengamma.strata.product.credit.SeniorityLevel; import com.opengamma.strata.product.credit.SingleNameReferenceInformation; /** * Test {@link ExampleMarketDataBuilder}, {@link DirectoryMarketDataBuilder} and {@link JarMarketDataBuilder}. */ @Test public class ExampleMarketDataBuilderTest { private static final String EXAMPLE_MARKET_DATA_CLASSPATH_ROOT = "example-marketdata"; private static final String EXAMPLE_MARKET_DATA_DIRECTORY_ROOT = "src/main/resources/example-marketdata"; private static final String TEST_SPACES_DIRECTORY_ROOT = "src/test/resources/test-marketdata with spaces"; private static final String TEST_SPACES_CLASSPATH_ROOT = "test-marketdata with spaces"; private static final CurveGroupName DEFAULT_CURVE_GROUP = CurveGroupName.of("Default"); private static final LocalDate MARKET_DATA_DATE = LocalDate.of(2014, 1, 22); private static final Set<ObservableId> TIME_SERIES = ImmutableSet.of( IndexQuoteId.of(IborIndices.USD_LIBOR_3M), IndexQuoteId.of(IborIndices.USD_LIBOR_6M), IndexQuoteId.of(OvernightIndices.USD_FED_FUND), IndexQuoteId.of(IborIndices.GBP_LIBOR_3M)); private static final Set<MarketDataId<?>> VALUES = ImmutableSet.of( CurveId.of(DEFAULT_CURVE_GROUP, CurveName.of("USD-Disc")), CurveId.of(DEFAULT_CURVE_GROUP, CurveName.of("GBP-Disc")), CurveId.of(DEFAULT_CURVE_GROUP, CurveName.of("USD-3ML")), CurveId.of(DEFAULT_CURVE_GROUP, CurveName.of("USD-6ML")), CurveId.of(DEFAULT_CURVE_GROUP, CurveName.of("GBP-3ML")), FxRateId.of(Currency.USD, Currency.GBP), QuoteId.of(StandardId.of("OG-Future", "Eurex-FGBL-Mar14")), QuoteId.of(StandardId.of("OG-Future", "Eurex-FGBL-Mar14"), FieldName.SETTLEMENT_PRICE), QuoteId.of(StandardId.of("OG-FutOpt", "Eurex-OGBL-Mar14-C150")), QuoteId.of(StandardId.of("OG-FutOpt", "Eurex-OGBL-Mar14-C150"), FieldName.SETTLEMENT_PRICE), QuoteId.of(StandardId.of("OG-Future", "CME-ED-Mar14")), QuoteId.of(StandardId.of("OG-Future", "CME-ED-Mar14"), FieldName.SETTLEMENT_PRICE), QuoteId.of(StandardId.of("OG-Future", "Ibor-USD-LIBOR-3M-Mar15")), QuoteId.of(StandardId.of("OG-Future", "Ibor-USD-LIBOR-3M-Mar15"), FieldName.SETTLEMENT_PRICE), QuoteId.of(StandardId.of("OG-Future", "Ibor-USD-LIBOR-3M-Jun15")), QuoteId.of(StandardId.of("OG-Future", "Ibor-USD-LIBOR-3M-Jun15"), FieldName.SETTLEMENT_PRICE), QuoteId.of(StandardId.of("OG-Future", "CME-F1U-Mar15")), QuoteId.of(StandardId.of("OG-Future", "CME-F1U-Mar15"), FieldName.SETTLEMENT_PRICE), QuoteId.of(StandardId.of("OG-Future", "CME-F1U-Jun15")), QuoteId.of(StandardId.of("OG-Future", "CME-F1U-Jun15"), FieldName.SETTLEMENT_PRICE), IsdaYieldCurveInputsId.of(Currency.USD), IsdaSingleNameCreditCurveInputsId.of( SingleNameReferenceInformation.of( MarkitRedCode.id("COMP10"), SeniorityLevel.SENIOR_UNSECURED_FOREIGN, Currency.USD, RestructuringClause.NO_RESTRUCTURING_2014)), IsdaSingleNameCreditCurveInputsId.of( SingleNameReferenceInformation.of( MarkitRedCode.id("COMP02"), SeniorityLevel.SENIOR_UNSECURED_FOREIGN, Currency.USD, RestructuringClause.NO_RESTRUCTURING_2014)), IsdaSingleNameCreditCurveInputsId.of( SingleNameReferenceInformation.of( MarkitRedCode.id("COMP01"), SeniorityLevel.SENIOR_UNSECURED_FOREIGN, Currency.USD, RestructuringClause.NO_RESTRUCTURING_2014)), IsdaSingleNameCreditCurveInputsId.of( SingleNameReferenceInformation.of( MarkitRedCode.id("COMP11"), SeniorityLevel.SENIOR_UNSECURED_FOREIGN, Currency.EUR, RestructuringClause.MOD_MOD_RESTRUCTURING_2014)), IsdaSingleNameCreditCurveInputsId.of( SingleNameReferenceInformation.of( MarkitRedCode.id("COMP11"), SeniorityLevel.SUBORDINATE_LOWER_TIER_2, Currency.EUR, RestructuringClause.MOD_MOD_RESTRUCTURING_2014)), IsdaIndexCreditCurveInputsId.of( IndexReferenceInformation.of( MarkitRedCode.id("INDEX0001"), 22, 4)), IsdaSingleNameRecoveryRateId.of( SingleNameReferenceInformation.of( MarkitRedCode.id("COMP10"), SeniorityLevel.SENIOR_UNSECURED_FOREIGN, Currency.USD, RestructuringClause.NO_RESTRUCTURING_2014)), IsdaSingleNameRecoveryRateId.of( SingleNameReferenceInformation.of( MarkitRedCode.id("COMP02"), SeniorityLevel.SENIOR_UNSECURED_FOREIGN, Currency.USD, RestructuringClause.NO_RESTRUCTURING_2014)), IsdaSingleNameRecoveryRateId.of( SingleNameReferenceInformation.of( MarkitRedCode.id("COMP01"), SeniorityLevel.SENIOR_UNSECURED_FOREIGN, Currency.USD, RestructuringClause.NO_RESTRUCTURING_2014)), IsdaSingleNameRecoveryRateId.of( SingleNameReferenceInformation.of( MarkitRedCode.id("COMP11"), SeniorityLevel.SENIOR_UNSECURED_FOREIGN, Currency.EUR, RestructuringClause.MOD_MOD_RESTRUCTURING_2014)), IsdaSingleNameRecoveryRateId.of( SingleNameReferenceInformation.of( MarkitRedCode.id("COMP11"), SeniorityLevel.SUBORDINATE_LOWER_TIER_2, Currency.EUR, RestructuringClause.MOD_MOD_RESTRUCTURING_2014)), IsdaIndexRecoveryRateId.of( IndexReferenceInformation.of( MarkitRedCode.id("INDEX0001"), 22, 4))); public void test_directory() { Path rootPath = new File(EXAMPLE_MARKET_DATA_DIRECTORY_ROOT).toPath(); DirectoryMarketDataBuilder builder = new DirectoryMarketDataBuilder(rootPath); assertBuilder(builder); } public void test_classpath_jar() throws Exception { // Create a JAR file containing the example market data File tempFile = File.createTempFile(ExampleMarketDataBuilderTest.class.getSimpleName(), ".jar"); try (FileOutputStream tempFileOut = new FileOutputStream(tempFile)) { try (JarOutputStream zipFileOut = new JarOutputStream(tempFileOut)) { File diskRoot = new File(EXAMPLE_MARKET_DATA_DIRECTORY_ROOT); appendToJar(diskRoot, "zip-data", diskRoot, zipFileOut); } } // Obtain a classloader which can see this JAR ClassLoader originalContextClassLoader = Thread.currentThread().getContextClassLoader(); try (URLClassLoader classLoader = URLClassLoader.newInstance(new URL[] {tempFile.toURI().toURL()})) { // Test automatically finding the resource inside the JAR Thread.currentThread().setContextClassLoader(classLoader); assertBuilder(ExampleMarketDataBuilder.ofResource("zip-data", classLoader)); } finally { Thread.currentThread().setContextClassLoader(originalContextClassLoader); try { Files.deleteIfExists(tempFile.toPath()); } catch (IOException ex) { // ignore } } } public void test_ofPath() { Path rootPath = new File(EXAMPLE_MARKET_DATA_DIRECTORY_ROOT).toPath(); ExampleMarketDataBuilder builder = ExampleMarketDataBuilder.ofPath(rootPath); assertBuilder(builder); } public void test_ofPath_with_spaces() { Path rootPath = new File(TEST_SPACES_DIRECTORY_ROOT).toPath(); ExampleMarketDataBuilder builder = ExampleMarketDataBuilder.ofPath(rootPath); ImmutableMarketData snapshot = builder.buildSnapshot(LocalDate.of(2015, 1, 1)); assertEquals(snapshot.getTimeSeries().size(), 1); } public void test_ofResource_directory() { ExampleMarketDataBuilder builder = ExampleMarketDataBuilder.ofResource(EXAMPLE_MARKET_DATA_CLASSPATH_ROOT); assertBuilder(builder); } public void test_ofResource_directory_extraSlashes() { ExampleMarketDataBuilder builder = ExampleMarketDataBuilder.ofResource("/" + EXAMPLE_MARKET_DATA_CLASSPATH_ROOT + "/"); assertBuilder(builder); } public void test_ofResource_directory_notFound() { assertThrowsIllegalArg(() -> ExampleMarketDataBuilder.ofResource("bad-dir")); } public void test_ofResource_directory_with_spaces() { ExampleMarketDataBuilder builder = ExampleMarketDataBuilder.ofResource(TEST_SPACES_CLASSPATH_ROOT); ImmutableMarketData snapshot = builder.buildSnapshot(MARKET_DATA_DATE); assertEquals(snapshot.getTimeSeries().size(), 1); } //------------------------------------------------------------------------- private void assertBuilder(ExampleMarketDataBuilder builder) { ImmutableMarketData snapshot = builder.buildSnapshot(MARKET_DATA_DATE); assertEquals(MARKET_DATA_DATE, snapshot.getValuationDate()); for (ObservableId id : TIME_SERIES) { assertFalse(snapshot.getTimeSeries(id).isEmpty(), "Time-series not found: " + id); } assertEquals(snapshot.getTimeSeries().size(), TIME_SERIES.size(), Messages.format("Snapshot contained unexpected time-series: {}", Sets.difference(snapshot.getTimeSeries().keySet(), TIME_SERIES))); for (MarketDataId<?> id : VALUES) { assertTrue(snapshot.containsValue(id), "Id not found: " + id); } assertEquals(snapshot.getValues().size(), VALUES.size(), Messages.format("Snapshot contained unexpected market data: {}", Sets.difference(snapshot.getValues().keySet(), VALUES))); } //------------------------------------------------------------------------- // build jar file // jar files use forward-slash on all operating systems // directories always have a trailing forward-slash // there must be no slash at the root private void appendToJar(File sourceRootDir, String destRootPath, File currentFile, JarOutputStream jarOutput) throws IOException { if (currentFile.isDirectory()) { String entryName = getEntryName(sourceRootDir, destRootPath, currentFile) + '/'; jarOutput.putNextEntry(new JarEntry(entryName)); jarOutput.closeEntry(); for (File content : currentFile.listFiles()) { appendToJar(sourceRootDir, destRootPath, content, jarOutput); } } else { String entryName = getEntryName(sourceRootDir, destRootPath, currentFile); jarOutput.putNextEntry(new JarEntry(entryName)); try (FileInputStream fileIn = new FileInputStream(currentFile)) { byte[] b = new byte[1024]; int len; while ((len = fileIn.read(b)) != -1) { jarOutput.write(b, 0, len); } } jarOutput.closeEntry(); } } private String getEntryName(File sourceRootDir, String destRootPath, File currentFile) { String relativePath = currentFile.getAbsolutePath().substring(sourceRootDir.getAbsolutePath().length()); return destRootPath + relativePath.replace('\\', '/'); } }