/** * Copyright (C) 2012 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.integration.tool.marketdata; import static com.google.common.collect.Sets.newHashSet; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; import org.apache.commons.cli.Option; import org.apache.commons.cli.Options; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.threeten.bp.Clock; import org.threeten.bp.LocalDate; import com.opengamma.bbg.BloombergIdentifierProvider; import com.opengamma.bbg.loader.hts.BloombergHistoricalTimeSeriesLoader; import com.opengamma.component.tool.AbstractTool; import com.opengamma.core.config.ConfigSource; import com.opengamma.core.id.ExternalSchemes; import com.opengamma.financial.analytics.ircurve.ConfigDBInterpolatedYieldCurveSpecificationBuilder; import com.opengamma.financial.analytics.ircurve.FixedIncomeStripWithIdentifier; import com.opengamma.financial.analytics.ircurve.InterpolatedYieldCurveSpecification; import com.opengamma.financial.analytics.ircurve.InterpolatedYieldCurveSpecificationBuilder; import com.opengamma.financial.analytics.ircurve.YieldCurveDefinition; import com.opengamma.financial.convention.ConventionBundle; import com.opengamma.financial.convention.ConventionBundleMaster; import com.opengamma.financial.convention.DefaultConventionBundleSource; import com.opengamma.financial.convention.InMemoryConventionBundleMaster; import com.opengamma.id.ExternalId; import com.opengamma.id.VersionCorrection; import com.opengamma.integration.tool.IntegrationToolContext; import com.opengamma.master.config.ConfigDocument; import com.opengamma.master.config.ConfigMaster; import com.opengamma.master.config.ConfigSearchRequest; import com.opengamma.master.config.impl.ConfigSearchIterator; import com.opengamma.scripts.Scriptable; import com.opengamma.util.money.Currency; /** */ @Scriptable public class CurveHtsResolverTool extends AbstractTool<IntegrationToolContext> { /** Logger. */ private static Logger s_logger = LoggerFactory.getLogger(CurveHtsResolverTool.class); /** Portfolio name option flag */ private static final String CURVE_NAME_OPT = "n"; /** Write option flag */ private static final String WRITE_OPT = "w"; /** Verbose option flag */ private static final String VERBOSE_OPT = "v"; /** Time series data provider option flag */ private static final String TIME_SERIES_DATAPROVIDER_OPT = "p"; /** Time series data field option flag */ private static final String TIME_SERIES_DATAFIELD_OPT = "d"; //------------------------------------------------------------------------- /** * Main method to run the tool. * * @param args the standard tool arguments, not null */ public static void main(final String[] args) { // CSIGNORE new CurveHtsResolverTool().invokeAndTerminate(args); } //------------------------------------------------------------------------- @SuppressWarnings("unchecked") @Override protected void doRun() { Set<ExternalId> curveNodesExternalIds; Set<ExternalId> initialRateExternalIds; final ConfigSource configSource = getToolContext().getConfigSource(); final ConfigMaster configMaster = getToolContext().getConfigMaster(); // Find all matching curves final List<YieldCurveDefinition> curves = getCurveDefinitionNames(configMaster, getCommandLine().getOptionValue(CURVE_NAME_OPT)); // Get initial rate hts external ids for curves final Set<Currency> currencies = newHashSet(); for (final YieldCurveDefinition curve : curves) { currencies.add(curve.getCurrency()); } initialRateExternalIds = getInitialRateExternalIds(currencies); // Get all other required hts external ids for curves final List<LocalDate> dates = buildDates(); final Set<String> curveNames = new HashSet<>(); for (YieldCurveDefinition ycd : curves) { curveNames.add(ycd.getName() + "_" + ycd.getCurrency().getCode()); } curveNodesExternalIds = getCurveRequiredExternalIds(configSource, curveNames, dates); // Load the required time series loadHistoricalData(getCommandLine().hasOption(WRITE_OPT), getCommandLine().getOptionValues(TIME_SERIES_DATAFIELD_OPT) == null ? new String[] {"PX_LAST" } : getCommandLine() .getOptionValues(TIME_SERIES_DATAFIELD_OPT), getCommandLine().getOptionValue(TIME_SERIES_DATAPROVIDER_OPT) == null ? "CMPL" : getCommandLine().getOptionValue(TIME_SERIES_DATAPROVIDER_OPT), initialRateExternalIds, curveNodesExternalIds); } private Set<ExternalId> getInitialRateExternalIds(final Set<Currency> currencies) { final ConventionBundleMaster cbm = new InMemoryConventionBundleMaster(); final DefaultConventionBundleSource cbs = new DefaultConventionBundleSource(cbm); final Set<ExternalId> externalInitialRateId = newHashSet(); for (final Currency currency : currencies) { for (final String swapType : new String[] {"SWAP", "3M_SWAP", "6M_SWAP" }) { final String product = currency.getCode() + "_" + swapType; final ConventionBundle convention = cbs.getConventionBundle(ExternalId.of(InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME, product)); if (convention != null) { final ExternalId initialRate = convention.getSwapFloatingLegInitialRate(); final ConventionBundle realIdConvention = cbs.getConventionBundle(initialRate); if (realIdConvention != null) { externalInitialRateId.add(realIdConvention.getIdentifiers().getExternalId(ExternalSchemes.BLOOMBERG_TICKER)); } else { s_logger.error("No convention for {}", initialRate.toString()); } } else { s_logger.warn("No convention for {} product", product); } } } return externalInitialRateId; } /** * Generate quarterly dates +/- 2 years around today to cover futures from past and near future * * @return list of dates */ private List<LocalDate> buildDates() { final Clock clock = Clock.systemDefaultZone(); final List<LocalDate> dates = new ArrayList<LocalDate>(); final LocalDate twoYearsAgo = LocalDate.now(clock).minusYears(2); final LocalDate twoYearsTime = LocalDate.now(clock).plusYears(2); for (LocalDate next = twoYearsAgo; next.isBefore(twoYearsTime); next = next.plusMonths(3)) { dates.add(next); } return dates; } /** * Get all the curve definition config object names specified by glob expression. * * @param configMaster * @param nameExpr glob type expression - e.g. blah* * @return list of names of config objects matching glob expression */ private List<YieldCurveDefinition> getCurveDefinitionNames(final ConfigMaster configMaster, final String nameExpr) { final List<YieldCurveDefinition> results = new ArrayList<YieldCurveDefinition>(); final ConfigSearchRequest<YieldCurveDefinition> request = new ConfigSearchRequest<YieldCurveDefinition>(YieldCurveDefinition.class); request.setName(nameExpr); for (final ConfigDocument doc : ConfigSearchIterator.iterable(configMaster, request)) { results.add((YieldCurveDefinition) doc.getConfig().getValue()); } return results; } /** * For a given list of curve names, on a given list of dates, get the superset of all ids required by those curves. * * @param configSource * @param names * @param dates * @return list of all ids required by curves */ private Set<ExternalId> getCurveRequiredExternalIds(final ConfigSource configSource, final Collection<String> names, final List<LocalDate> dates) { final Set<ExternalId> externalIds = newHashSet(); for (final String name : names) { s_logger.info("Processing curve " + name); YieldCurveDefinition curveDefinition = configSource.getSingle(YieldCurveDefinition.class, name, VersionCorrection.LATEST); if (curveDefinition != null) { InterpolatedYieldCurveSpecificationBuilder builder = new ConfigDBInterpolatedYieldCurveSpecificationBuilder(configSource); for (LocalDate date : dates) { s_logger.info("Processing curve date " + date); try { final InterpolatedYieldCurveSpecification curveSpec = builder.buildCurve(date, curveDefinition, VersionCorrection.LATEST); for (final FixedIncomeStripWithIdentifier strip : curveSpec.getStrips()) { s_logger.info("Processing strip " + strip.getSecurity()); externalIds.add(strip.getSecurity()); } } catch (final Throwable t) { s_logger.warn("Unable to build curve " + t.getMessage()); } } } else { s_logger.warn("No curve definition with '{}' name", name); } } return externalIds; } private void loadHistoricalData(final boolean write, final String[] dataFields, final String dataProvider, final Set<ExternalId>... externalIdSets) { final BloombergHistoricalTimeSeriesLoader loader = new BloombergHistoricalTimeSeriesLoader(getToolContext().getHistoricalTimeSeriesMaster(), getToolContext() .getHistoricalTimeSeriesProvider(), new BloombergIdentifierProvider(getToolContext().getBloombergReferenceDataProvider())); for (final Set<ExternalId> externalIds : externalIdSets) { if (externalIds.size() > 0) { for (final String dataField : dataFields) { s_logger.info("Loading time series (field: " + dataField + ", provider: " + dataProvider + ") with external IDs " + externalIds); if (write) { loader.loadTimeSeries(externalIds, dataProvider, dataField, LocalDate.now().minusYears(1), null); } } } } } @Override protected Options createOptions(final boolean contextProvided) { final Options options = super.createOptions(contextProvided); final Option curveNameOption = new Option(CURVE_NAME_OPT, "name", true, "The name of the yield curve definition for which to resolve time series"); curveNameOption.setRequired(true); options.addOption(curveNameOption); final Option writeOption = new Option(WRITE_OPT, "write", false, "Actually persists the time series to the database if specified, otherwise pretty-prints without persisting"); options.addOption(writeOption); final Option verboseOption = new Option(VERBOSE_OPT, "verbose", false, "Displays progress messages on the terminal"); options.addOption(verboseOption); final Option timeSeriesDataProviderOption = new Option(TIME_SERIES_DATAPROVIDER_OPT, "provider", true, "The name of the time series data provider"); options.addOption(timeSeriesDataProviderOption); final Option timeSeriesDataFieldOption = new Option(TIME_SERIES_DATAFIELD_OPT, "field", true, "The name(s) of the time series data field(s)"); options.addOption(timeSeriesDataFieldOption); return options; } }