/**
* Copyright (C) 2014 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.sesame.marketdata.builders;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import javax.annotation.Nullable;
import org.threeten.bp.LocalDate;
import org.threeten.bp.ZonedDateTime;
import com.google.common.collect.ImmutableMap;
import com.opengamma.core.historicaltimeseries.HistoricalTimeSeries;
import com.opengamma.core.historicaltimeseries.HistoricalTimeSeriesSource;
import com.opengamma.id.ExternalIdBundle;
import com.opengamma.sesame.marketdata.FieldName;
import com.opengamma.sesame.marketdata.MarketDataBundle;
import com.opengamma.sesame.marketdata.MarketDataId;
import com.opengamma.sesame.marketdata.MarketDataRequest;
import com.opengamma.sesame.marketdata.MarketDataRequirement;
import com.opengamma.sesame.marketdata.MarketDataSource;
import com.opengamma.sesame.marketdata.MarketDataTime;
import com.opengamma.sesame.marketdata.RawId;
import com.opengamma.sesame.marketdata.SingleValueRequirement;
import com.opengamma.sesame.marketdata.TimeSeriesRequirement;
import com.opengamma.sesame.marketdata.scenarios.CyclePerturbations;
import com.opengamma.timeseries.date.DateTimeSeries;
import com.opengamma.util.ArgumentChecker;
import com.opengamma.util.result.FailureStatus;
import com.opengamma.util.result.Result;
import com.opengamma.util.time.LocalDateRange;
/**
* Market data builder for market data values provided by an external data source.
* <p>
* Default values are taken from a {@link MarketDataSource}, time series and values for a specific date
* are loaded from a historical time series source.
*/
public class RawMarketDataBuilder implements MarketDataBuilder {
private final HistoricalTimeSeriesSource _timeSeriesSource;
private final String _dataSource;
private final String _dataProvider;
/**
* @param timeSeriesSource source of historical time series data
* @param dataSource the data source name used when querying the time series source
* @param dataProvider the data provider name used when querying the time series source, possibly null
*/
public RawMarketDataBuilder(HistoricalTimeSeriesSource timeSeriesSource,
String dataSource,
@Nullable String dataProvider) {
_timeSeriesSource = ArgumentChecker.notNull(timeSeriesSource, "timeSeriesSource");
_dataSource = ArgumentChecker.notEmpty(dataSource, "dataSource");
_dataProvider = dataProvider;
}
@Override
public Set<MarketDataRequirement> getSingleValueRequirements(SingleValueRequirement requirement,
ZonedDateTime valuationTime,
Set<? extends MarketDataRequirement> suppliedData) {
return Collections.emptySet();
}
@Override
public Set<MarketDataRequirement> getTimeSeriesRequirements(
TimeSeriesRequirement requirement,
Map<MarketDataId<?>, DateTimeSeries<LocalDate, ?>> suppliedData) {
return Collections.emptySet();
}
@Override
public Map<SingleValueRequirement, Result<?>> buildSingleValues(MarketDataBundle marketDataBundle,
ZonedDateTime valuationTime,
Set<SingleValueRequirement> marketDataRequirements,
MarketDataSource marketDataSource,
CyclePerturbations cyclePerturbations) {
// map of request->requirement so we can build the results
Map<MarketDataRequest, SingleValueRequirement> requirementMap = new HashMap<>();
ImmutableMap.Builder<SingleValueRequirement, Result<?>> results = ImmutableMap.builder();
for (SingleValueRequirement requirement : marketDataRequirements) {
// builders are keyed by type in the engine and requirements are dispatched to builders based on their key type
// so this cast will always succeed
RawId<?> marketDataId = (RawId<?>) requirement.getMarketDataId();
MarketDataTime time = requirement.getMarketDataTime();
switch (time.getType()) {
case VALUATION_TIME:
// use the market data source
FieldName fieldName = marketDataId.getFieldName();
ExternalIdBundle id = marketDataId.getId();
MarketDataRequest request = MarketDataRequest.of(id, fieldName);
requirementMap.put(request, requirement);
break;
case DATE:
// use the HTS source
// for now we only support LocalDate
LocalDate date = time.getDate();
// TODO get the value from the time series source
HistoricalTimeSeries timeSeries =
_timeSeriesSource.getHistoricalTimeSeries(marketDataId.getId(), _dataSource, _dataProvider,
marketDataId.toString(), date, true, date, true);
if (timeSeries != null && !timeSeries.getTimeSeries().isEmpty()) {
Double value = timeSeries.getTimeSeries().getValue(date);
if (value != null) {
results.put(requirement, Result.success(value));
}
}
break;
default:
// TODO failure - can't handle exact times yet
break;
}
}
Map<MarketDataRequest, Result<?>> data = marketDataSource.get(requirementMap.keySet());
for (Map.Entry<MarketDataRequest, Result<?>> entry : data.entrySet()) {
MarketDataRequest request = entry.getKey();
SingleValueRequirement requirement = requirementMap.get(request);
results.put(requirement, entry.getValue());
}
return results.build();
}
@Override
public Map<TimeSeriesRequirement, Result<? extends DateTimeSeries<LocalDate, ?>>> buildTimeSeries(
MarketDataBundle marketDataBundle,
Set<TimeSeriesRequirement> requirements,
MarketDataSource marketDataSource,
CyclePerturbations cyclePerturbations) {
Map<TimeSeriesRequirement, Result<? extends DateTimeSeries<LocalDate, ?>>> results = new HashMap<>();
for (TimeSeriesRequirement requirement : requirements) {
RawId<?> marketDataId = (RawId<?>) requirement.getMarketDataId();
LocalDateRange dateRange = requirement.getMarketDataTime().getDateRange();
HistoricalTimeSeries timeSeries =
_timeSeriesSource.getHistoricalTimeSeries(marketDataId.getId(), _dataSource, _dataProvider,
marketDataId.getFieldName().getName(),
dateRange.getStartDateInclusive(), true,
dateRange.getEndDateInclusive(), true);
if (timeSeries == null || timeSeries.getTimeSeries().isEmpty()) {
Result<DateTimeSeries<LocalDate, ?>> result = Result.failure(FailureStatus.MISSING_DATA,
"No time series data available for {}/{}",
marketDataId.getId(), dateRange);
results.put(requirement, result);
} else {
Result<DateTimeSeries<LocalDate, ?>> result =
Result.<DateTimeSeries<LocalDate, ?>>success(timeSeries.getTimeSeries());
results.put(requirement, result);
}
}
return results;
}
@SuppressWarnings("unchecked")
@Override
public Class getKeyType() {
return RawId.class;
}
}