com.opengamma.bbg.loader.BloombergHistoricalTimeSeriesLoader.java Source code

Java tutorial

Introduction

Here is the source code for com.opengamma.bbg.loader.BloombergHistoricalTimeSeriesLoader.java

Source

/**
 * Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies
 *
 * Please see distribution for license.
 */
package com.opengamma.bbg.loader;

import static com.opengamma.bbg.BloombergConstants.BLOOMBERG_DATA_SOURCE_NAME;

import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import javax.time.calendar.LocalDate;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.base.Objects;
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
import com.opengamma.OpenGammaRuntimeException;
import com.opengamma.bbg.BloombergConstants;
import com.opengamma.bbg.util.BloombergDataUtils;
import com.opengamma.core.historicaltimeseries.HistoricalTimeSeries;
import com.opengamma.core.historicaltimeseries.HistoricalTimeSeriesSource;
import com.opengamma.core.id.ExternalSchemes;
import com.opengamma.id.ExternalId;
import com.opengamma.id.ExternalIdBundle;
import com.opengamma.id.ExternalIdBundleWithDates;
import com.opengamma.id.ExternalIdSearch;
import com.opengamma.id.ExternalIdSearchType;
import com.opengamma.id.UniqueId;
import com.opengamma.id.VersionCorrection;
import com.opengamma.master.historicaltimeseries.ExternalIdResolver;
import com.opengamma.master.historicaltimeseries.HistoricalTimeSeriesGetFilter;
import com.opengamma.master.historicaltimeseries.HistoricalTimeSeriesInfoDocument;
import com.opengamma.master.historicaltimeseries.HistoricalTimeSeriesInfoSearchRequest;
import com.opengamma.master.historicaltimeseries.HistoricalTimeSeriesInfoSearchResult;
import com.opengamma.master.historicaltimeseries.HistoricalTimeSeriesLoader;
import com.opengamma.master.historicaltimeseries.HistoricalTimeSeriesMaster;
import com.opengamma.master.historicaltimeseries.ManageableHistoricalTimeSeriesInfo;
import com.opengamma.util.ArgumentChecker;
import com.opengamma.util.OpenGammaClock;
import com.opengamma.util.monitor.OperationTimer;
import com.opengamma.util.time.DateUtils;
import com.opengamma.util.timeseries.localdate.LocalDateDoubleTimeSeries;

/**
 * Loads time-series information from Bloomberg.
 * <p>
 * This loads missing historical time-series data from Bloomberg.
 */
public class BloombergHistoricalTimeSeriesLoader implements HistoricalTimeSeriesLoader {

    /** Logger. */
    private static final Logger s_logger = LoggerFactory.getLogger(BloombergHistoricalTimeSeriesLoader.class);
    /**
     * No time-series before this date.
     */
    private static final LocalDate DEFAULT_START_DATE = LocalDate.of(1900, 1, 1);

    /**
     * The master.
     */
    private final HistoricalTimeSeriesMaster _htsMaster;
    /**
     * The provider of time-series.
     */
    private final HistoricalTimeSeriesSource _underlyingHtsProvider;
    /**
     * The resolver of identifiers.
     */
    private final ExternalIdResolver _identifierResolver;

    /**
     * Creates an instance.
     * 
     * @param htsMaster  the time-series master, not null
     * @param underlyingHtsProvider  the time-series provider for the underlying data source, not null
     * @param identifierProvider  the identifier resovler for the underlying data source, not null
     */
    public BloombergHistoricalTimeSeriesLoader(final HistoricalTimeSeriesMaster htsMaster,
            final HistoricalTimeSeriesSource underlyingHtsProvider, final ExternalIdResolver identifierProvider) {
        ArgumentChecker.notNull(htsMaster, "htsMaster");
        ArgumentChecker.notNull(underlyingHtsProvider, "underlyingHtsProvider");
        ArgumentChecker.notNull(identifierProvider, "identifierProvider");
        _htsMaster = htsMaster;
        _underlyingHtsProvider = underlyingHtsProvider;
        _identifierResolver = identifierProvider;
    }

    //-------------------------------------------------------------------------
    @Override
    public Map<ExternalId, UniqueId> addTimeSeries(Set<ExternalId> externalIds, String dataProvider,
            String dataField, LocalDate startDate, LocalDate endDate) {
        ArgumentChecker.notEmpty(externalIds, "externalIds");
        ArgumentChecker.notNull(dataField, "dataField");
        dataProvider = BloombergDataUtils.resolveDataProvider(dataProvider);
        if (startDate == null) {
            startDate = DEFAULT_START_DATE;
        }
        if (endDate == null) {
            endDate = DateUtils.previousWeekDay();
        }

        // finds the time-series that need loading
        Map<ExternalId, UniqueId> result = new HashMap<ExternalId, UniqueId>();
        Set<ExternalId> missingTimeseries = findTimeSeries(externalIds, dataProvider, dataField, result);

        // batch in groups of 100 to avoid out-of-memory issues
        for (List<ExternalId> partition : Iterables.partition(missingTimeseries, 100)) {
            Set<ExternalId> subSet = Sets.newHashSet(partition);
            fetchTimeSeries(subSet, dataField, dataProvider, startDate, endDate, result);
        }
        return result;
    }

    /**
     * Finds those time-series that are not in the master.
     * 
     * @param externalIds  the identifiers to lookup, not null
     * @param dataProvider  the data provider, not null
     * @param dataField  the data field, not null
     * @param result  the result map of identifiers, updated if already in database, not null
     * @return the missing identifiers, not null
     */
    protected Set<ExternalId> findTimeSeries(Set<ExternalId> externalIds, String dataProvider, String dataField,
            Map<ExternalId, UniqueId> result) {

        HistoricalTimeSeriesInfoSearchRequest searchRequest = new HistoricalTimeSeriesInfoSearchRequest();
        searchRequest.addExternalIds(externalIds);
        searchRequest.setDataField(dataField);
        searchRequest.setDataProvider(dataProvider);
        searchRequest.setDataSource(BLOOMBERG_DATA_SOURCE_NAME);
        HistoricalTimeSeriesInfoSearchResult searchResult = _htsMaster.search(searchRequest);

        Set<ExternalId> missing = new HashSet<ExternalId>(externalIds);
        for (HistoricalTimeSeriesInfoDocument doc : searchResult.getDocuments()) {
            Set<ExternalId> intersection = Sets
                    .intersection(doc.getInfo().getExternalIdBundle().toBundle().getExternalIds(), externalIds)
                    .immutableCopy();
            if (intersection.size() == 1) {
                ExternalId identifier = intersection.iterator().next();
                missing.remove(identifier);
                result.put(identifier, doc.getUniqueId());
            } else {
                throw new OpenGammaRuntimeException(
                        "Unable to match single identifier: " + doc.getInfo().getExternalIdBundle());
            }
        }
        return missing;
    }

    /**
     * Fetches the time-series from Bloomberg and stores them in the master.
     * 
     * @param identifiers  the identifiers to fetch, not null
     * @param dataField  the data field, not null
     * @param dataProvider  the data provider, not null
     * @param startDate  the start date to load, not null
     * @param endDate  the end date to load, not null
     * @param result  the result map of identifiers, updated if already in database, not null
     */
    protected void fetchTimeSeries(final Set<ExternalId> identifiers, final String dataField,
            final String dataProvider, final LocalDate startDate, final LocalDate endDate,
            final Map<ExternalId, UniqueId> result) {

        Map<ExternalIdBundleWithDates, ExternalId> withDates2ExternalId = new HashMap<ExternalIdBundleWithDates, ExternalId>();
        Map<ExternalIdBundle, ExternalIdBundleWithDates> bundle2WithDates = new HashMap<ExternalIdBundle, ExternalIdBundleWithDates>();

        // lookup full set of identifiers
        Map<ExternalId, ExternalIdBundleWithDates> externalId2WithDates = _identifierResolver
                .getExternalIds(identifiers);

        // reverse map and normalize identifiers
        for (Entry<ExternalId, ExternalIdBundleWithDates> entry : externalId2WithDates.entrySet()) {
            ExternalId requestIdentifier = entry.getKey();
            ExternalIdBundleWithDates bundle = entry.getValue();
            bundle = BloombergDataUtils.addTwoDigitYearCode(bundle);
            bundle2WithDates.put(bundle.toBundle(), bundle);
            withDates2ExternalId.put(bundle, requestIdentifier);
        }

        // fetch time-series and store to master
        if (bundle2WithDates.size() > 0) {
            int identifiersSize = bundle2WithDates.keySet().size();
            System.out.printf("Loading %d ts  dataField: %s dataProvider: %s startDate: %s endDate: %s\n",
                    identifiersSize, dataField, dataProvider, startDate, endDate);
            OperationTimer timer = new OperationTimer(s_logger,
                    " loading " + identifiersSize + " timeseries from Bloomberg");
            Map<ExternalIdBundle, HistoricalTimeSeries> tsMap = loadTimeSeries(bundle2WithDates.keySet(), dataField,
                    dataProvider, startDate, endDate);
            timer.finished();

            timer = new OperationTimer(s_logger, " storing " + identifiersSize + " timeseries from Bloomberg");
            storeTimeSeries(tsMap, dataField, dataProvider, withDates2ExternalId, bundle2WithDates, result);
            timer.finished();
        }
    }

    /**
     * Loads time-series from the underlying source.
     * 
     * @param externalIds  the external identifies to load, not null
     * @param dataField  the data field, not null
     * @param dataProvider  the data provider, not null
     * @param startDate  the start date to load, not null
     * @param endDate  the end date to load, not null
     * @return the map of results, not null
     */
    protected Map<ExternalIdBundle, HistoricalTimeSeries> loadTimeSeries(Set<ExternalIdBundle> externalIds,
            String dataField, String dataProvider, LocalDate startDate, LocalDate endDate) {
        s_logger.debug("Loading time series {} ({}-{}) {}: {}",
                new Object[] { dataField, startDate, endDate, dataProvider, externalIds });
        return _underlyingHtsProvider.getHistoricalTimeSeries(externalIds,
                BloombergConstants.BLOOMBERG_DATA_SOURCE_NAME, dataProvider, dataField, startDate, true, endDate,
                true);
    }

    /**
     * Stores the time-series in the master.
     * 
     * @param tsMap  the map of time-series, not null
     * @param dataField  the data field, not null
     * @param dataProvider  the data provider, not null
     * @param bundleToIdentifier  the lookup map, not null
     * @param identifiersToBundleWithDates  the lookup map, not null
     * @param result  the result map of identifiers, updated if already in database, not null
     */
    protected void storeTimeSeries(Map<ExternalIdBundle, HistoricalTimeSeries> tsMap, String dataField,
            String dataProvider, Map<ExternalIdBundleWithDates, ExternalId> bundleToIdentifier,
            Map<ExternalIdBundle, ExternalIdBundleWithDates> identifiersToBundleWithDates,
            Map<ExternalId, UniqueId> result) {
        // Add timeseries to data store
        for (Entry<ExternalIdBundle, HistoricalTimeSeries> entry : tsMap.entrySet()) {
            ExternalIdBundle identifers = entry.getKey();
            LocalDateDoubleTimeSeries timeSeries = entry.getValue().getTimeSeries();
            if (timeSeries != null && !timeSeries.isEmpty()) {
                ManageableHistoricalTimeSeriesInfo info = new ManageableHistoricalTimeSeriesInfo();
                ExternalIdBundleWithDates bundleWithDates = identifiersToBundleWithDates.get(identifers);
                info.setExternalIdBundle(bundleWithDates);
                info.setDataField(dataField);
                info.setDataSource(BLOOMBERG_DATA_SOURCE_NAME);
                ExternalIdBundle bundle = bundleWithDates.toBundle(LocalDate.now(OpenGammaClock.getInstance()));
                String idStr = Objects.firstNonNull(bundle.getValue(ExternalSchemes.BLOOMBERG_TICKER),
                        Objects.firstNonNull(bundle.getExternalId(ExternalSchemes.BLOOMBERG_BUID),
                                bundle.getExternalIds().iterator().next()))
                        .toString();
                info.setName(dataField + " " + idStr);
                info.setDataProvider(dataProvider);
                String derivedObservationTime = BloombergDataUtils.resolveObservationTime(dataProvider);
                info.setObservationTime(derivedObservationTime);

                // get time-series creating if necessary
                HistoricalTimeSeriesInfoSearchRequest request = new HistoricalTimeSeriesInfoSearchRequest();
                request.setDataField(info.getDataField());
                request.setDataSource(info.getDataSource());
                request.setDataProvider(info.getDataProvider());
                request.setObservationTime(info.getObservationTime());
                request.setExternalIdSearch(
                        new ExternalIdSearch(info.getExternalIdBundle().toBundle(), ExternalIdSearchType.EXACT));
                HistoricalTimeSeriesInfoSearchResult searchResult = _htsMaster.search(request);
                if (searchResult.getDocuments().size() == 0) {
                    // add new
                    HistoricalTimeSeriesInfoDocument doc = _htsMaster
                            .add(new HistoricalTimeSeriesInfoDocument(info));
                    UniqueId uniqueId = _htsMaster.updateTimeSeriesDataPoints(doc.getInfo().getTimeSeriesObjectId(),
                            timeSeries);
                    result.put(bundleToIdentifier.get(bundleWithDates), uniqueId);
                } else {
                    // update existing
                    HistoricalTimeSeriesInfoDocument doc = searchResult.getDocuments().get(0);
                    HistoricalTimeSeries existingSeries = _htsMaster.getTimeSeries(
                            doc.getInfo().getTimeSeriesObjectId(), VersionCorrection.LATEST,
                            HistoricalTimeSeriesGetFilter.ofLatestPoint());
                    if (existingSeries.getTimeSeries().size() > 0) {
                        LocalDate latestTime = existingSeries.getTimeSeries().getLatestTime();
                        timeSeries = timeSeries.subSeries(latestTime, false, timeSeries.getLatestTime(), true);
                    }
                    UniqueId uniqueId = existingSeries.getUniqueId();
                    if (timeSeries.size() > 0) {
                        uniqueId = _htsMaster.updateTimeSeriesDataPoints(doc.getInfo().getTimeSeriesObjectId(),
                                timeSeries);
                    }
                    result.put(bundleToIdentifier.get(bundleWithDates), uniqueId);
                }

            } else {
                s_logger.warn("Empty historical data returned for {}", identifers);
            }
        }
    }

    //-------------------------------------------------------------------------
    @Override
    public boolean updateTimeSeries(final UniqueId uniqueId) {
        ArgumentChecker.notNull(uniqueId, "uniqueId");

        HistoricalTimeSeriesInfoDocument doc = _htsMaster.get(uniqueId);
        ManageableHistoricalTimeSeriesInfo info = doc.getInfo();
        ExternalIdBundle externalIdBundle = info.getExternalIdBundle().toBundle();
        String dataSource = info.getDataSource();
        String dataProvider = info.getDataProvider();
        String dataField = info.getDataField();
        HistoricalTimeSeries series = _underlyingHtsProvider.getHistoricalTimeSeries(externalIdBundle, dataSource,
                dataProvider, dataField);
        if (series == null) {
            return false;
        }
        _htsMaster.correctTimeSeriesDataPoints(doc.getInfo().getTimeSeriesObjectId(), series.getTimeSeries());
        return true;
    }

}