/**
* Copyright (C) 2014 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.sesame.marketdata;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import org.threeten.bp.LocalDate;
import org.threeten.bp.ZonedDateTime;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.LinkedListMultimap;
import com.google.common.collect.Multimap;
import com.opengamma.analytics.financial.forex.method.FXMatrix;
import com.opengamma.analytics.financial.legalentity.LegalEntity;
import com.opengamma.analytics.financial.legalentity.LegalEntityFilter;
import com.opengamma.analytics.financial.provider.calculator.issuer.ParSpreadMarketQuoteCurveSensitivityIssuerDiscountingCalculator;
import com.opengamma.analytics.financial.provider.calculator.issuer.ParSpreadMarketQuoteIssuerDiscountingCalculator;
import com.opengamma.analytics.financial.provider.curve.CurveBuildingBlockBundle;
import com.opengamma.analytics.financial.provider.curve.issuer.IssuerDiscountBuildingRepository;
import com.opengamma.analytics.financial.provider.description.interestrate.IssuerProviderDiscount;
import com.opengamma.financial.analytics.curve.CurveConstructionConfiguration;
import com.opengamma.financial.analytics.curve.CurveTypeConfiguration;
import com.opengamma.financial.analytics.curve.IssuerCurveTypeConfiguration;
import com.opengamma.financial.analytics.curve.credit.CurveSpecificationBuilder;
import com.opengamma.sesame.CurveNodeConverterFn;
import com.opengamma.sesame.CurveNodeInstrumentDefinitionFactory;
import com.opengamma.sesame.IssuerProviderBundle;
import com.opengamma.sesame.marketdata.builders.MarketDataBuilder;
import com.opengamma.sesame.marketdata.scenarios.CyclePerturbations;
import com.opengamma.timeseries.date.DateTimeSeries;
import com.opengamma.util.ArgumentChecker;
import com.opengamma.util.money.Currency;
import com.opengamma.util.result.Result;
import com.opengamma.util.tuple.Pair;
import com.opengamma.util.tuple.Pairs;
/**
* Market data builder for issuer curve bundles.
*/
public class IssuerMulticurveMarketDataBuilder
extends AbstractMulticurveMarketDataBuilder<IssuerProviderBundle>
implements MarketDataBuilder {
private static final ParSpreadMarketQuoteIssuerDiscountingCalculator DISCOUNTING_CALCULATOR =
ParSpreadMarketQuoteIssuerDiscountingCalculator.getInstance();
private static final ParSpreadMarketQuoteCurveSensitivityIssuerDiscountingCalculator CURVE_SENSITIVITY_CALCULATOR =
ParSpreadMarketQuoteCurveSensitivityIssuerDiscountingCalculator.getInstance();
private final IssuerDiscountBuildingRepository _curveBuilder;
/**
* @param curveSpecBuilder for building curve specifications
* @param curveNodeConverter for converting curve node instruments to derivatives
* @param definitionFactory creates instrument definitions for curve node instruments
* @param curveBuilder analytics object for building and calibrating the curve bundle
*/
public IssuerMulticurveMarketDataBuilder(CurveSpecificationBuilder curveSpecBuilder,
CurveNodeConverterFn curveNodeConverter,
CurveNodeInstrumentDefinitionFactory definitionFactory,
IssuerDiscountBuildingRepository curveBuilder) {
super(curveSpecBuilder, curveNodeConverter, definitionFactory);
_curveBuilder = ArgumentChecker.notNull(curveBuilder, "curveBuilder");
}
@Override
public Set<MarketDataRequirement> getTimeSeriesRequirements(
TimeSeriesRequirement requirement,
Map<MarketDataId<?>, DateTimeSeries<LocalDate, ?>> suppliedData) {
// TODO implement getTimeSeriesRequirements()
throw new UnsupportedOperationException("getTimeSeriesRequirements not implemented");
}
@Override
public Map<SingleValueRequirement, Result<?>> buildSingleValues(MarketDataBundle marketDataBundle,
ZonedDateTime valuationTime,
Set<SingleValueRequirement> requirements,
MarketDataSource marketDataSource,
CyclePerturbations cyclePerturbations) {
ImmutableMap.Builder<SingleValueRequirement, Result<?>> results = ImmutableMap.builder();
for (SingleValueRequirement requirement : requirements) {
IssuerMulticurveId marketDataId = (IssuerMulticurveId) requirement.getMarketDataId();
CurveConstructionConfiguration curveConfig = marketDataId.getConfig();
IssuerProviderBundle bundle =
buildBundle(marketDataBundle, valuationTime, curveConfig, requirement, cyclePerturbations);
results.put(requirement, Result.success(bundle));
}
return results.build();
}
@Override
public Map<TimeSeriesRequirement, Result<? extends DateTimeSeries<LocalDate, ?>>> buildTimeSeries(
MarketDataBundle marketDataBundle,
Set<TimeSeriesRequirement> requirements,
MarketDataSource marketDataSource,
CyclePerturbations cyclePerturbations) {
// TODO implement this
return Collections.emptyMap();
}
@Override
public Class<IssuerMulticurveId> getKeyType() {
return IssuerMulticurveId.class;
}
@Override
CurveConstructionConfiguration getCurveConfig(SingleValueRequirement requirement) {
IssuerMulticurveId marketDataId = (IssuerMulticurveId) requirement.getMarketDataId();
return marketDataId.getConfig();
}
@Override
Set<MarketDataRequirement> getParentBundleRequirements(SingleValueRequirement requirement,
CurveConstructionConfiguration curveConfig) {
ImmutableSet.Builder<MarketDataRequirement> parentBundleRequirements = ImmutableSet.builder();
for (String parentBundleName : curveConfig.getExogenousConfigurations()) {
IssuerMulticurveId curveBundleId = IssuerMulticurveId.of(parentBundleName);
parentBundleRequirements.add(SingleValueRequirement.of(curveBundleId, requirement.getMarketDataTime()));
}
return parentBundleRequirements.build();
}
/**
* Builds a multicurve bundle
*
* @param marketDataBundle the market data
* @param valuationTime the valuation time for which the curve bundle should be built
* @param bundleConfig the configuration for the multicurve bundle
* @param cyclePerturbations the perturbations that should be applied to the market data for this calculation cycle
* @return a multicurve bundle built from the configuration
*/
@SuppressWarnings("unchecked")
private IssuerProviderBundle buildBundle(MarketDataBundle marketDataBundle,
ZonedDateTime valuationTime,
CurveConstructionConfiguration bundleConfig,
MarketDataRequirement bundleRequirement,
CyclePerturbations cyclePerturbations) {
Set<Currency> currencies = getCurrencies(bundleConfig, valuationTime);
FxMatrixId fxMatrixKey = FxMatrixId.of(currencies);
FXMatrix fxMatrix = marketDataBundle.get(fxMatrixKey, FXMatrix.class).getValue();
IssuerProviderDiscount parentBundle = createParentBundle(marketDataBundle, bundleConfig, fxMatrix);
IntermediateResults intermediateResults = buildIntermediateResults(marketDataBundle,
valuationTime,
bundleConfig,
bundleRequirement,
cyclePerturbations);
Pair<IssuerProviderDiscount, CurveBuildingBlockBundle> calibratedCurves =
_curveBuilder.makeCurvesFromDerivatives(intermediateResults.getCurveBundles(),
parentBundle,
intermediateResults.getCurrenciesByCurveName(),
intermediateResults.getIborIndexByCurveName(),
intermediateResults.getOnIndexByCurveName(),
createIssuerMap(intermediateResults.getConfigTypes()),
DISCOUNTING_CALCULATOR,
CURVE_SENSITIVITY_CALCULATOR);
return new IssuerProviderBundle(calibratedCurves.getFirst(), calibratedCurves.getSecond());
}
/**
* Returns a map of curve names to issuer details where the curve
* configuration type is {@link IssuerCurveTypeConfiguration}.
*
* @param configTypes the configuration types of the curves, keyed by curve name
* @return a map of curve names to issuer details where the curve
* configuration type is {@link IssuerCurveTypeConfiguration}
*/
private LinkedListMultimap<String, Pair<Object, LegalEntityFilter<LegalEntity>>> createIssuerMap(
Multimap<String, CurveTypeConfiguration> configTypes) {
LinkedListMultimap<String, Pair<Object, LegalEntityFilter<LegalEntity>>> results = LinkedListMultimap.create();
for (Map.Entry<String, CurveTypeConfiguration> entry : configTypes.entries()) {
String curveName = entry.getKey();
CurveTypeConfiguration configType = entry.getValue();
if (configType instanceof IssuerCurveTypeConfiguration) {
IssuerCurveTypeConfiguration issuerType = (IssuerCurveTypeConfiguration) configType;
results.put(curveName, Pairs.<Object, LegalEntityFilter<LegalEntity>>of(issuerType.getKeys(), issuerType.getFilters()));
}
}
return results;
}
/**
* Creates the parent curve bundle for a curve bundle.
* TODO this doesn't work yet, is it supported anywhere? ProviderUtils doesn't have a method for merging them
*
* @param marketDataBundle the market data
* @param bundleConfig the curve bundle configuration
* @param fxMatrix the FX rates for the currencies used by the curve
* @return the curve bundle's parent bundle
*/
private static IssuerProviderDiscount createParentBundle(MarketDataBundle marketDataBundle,
CurveConstructionConfiguration bundleConfig,
FXMatrix fxMatrix) {
return new IssuerProviderDiscount(fxMatrix);
}
}