/**
* 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.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
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.ArrayListMultimap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Multimap;
import com.opengamma.OpenGammaRuntimeException;
import com.opengamma.analytics.financial.curve.interestrate.generator.GeneratorCurveYieldInterpolated;
import com.opengamma.analytics.financial.curve.interestrate.generator.GeneratorCurveYieldInterpolatedAnchorNode;
import com.opengamma.analytics.financial.curve.interestrate.generator.GeneratorYDCurve;
import com.opengamma.analytics.financial.forex.method.FXMatrix;
import com.opengamma.analytics.financial.instrument.InstrumentDefinition;
import com.opengamma.analytics.financial.instrument.index.IborIndex;
import com.opengamma.analytics.financial.instrument.index.IndexON;
import com.opengamma.analytics.financial.interestrate.InstrumentDerivative;
import com.opengamma.analytics.financial.provider.calculator.generic.LastTimeCalculator;
import com.opengamma.analytics.financial.provider.curve.MultiCurveBundle;
import com.opengamma.analytics.financial.provider.curve.SingleCurveBundle;
import com.opengamma.analytics.math.interpolation.CombinedInterpolatorExtrapolatorFactory;
import com.opengamma.analytics.math.interpolation.Interpolator1D;
import com.opengamma.analytics.util.time.TimeCalculator;
import com.opengamma.core.link.ConventionLink;
import com.opengamma.core.link.SecurityLink;
import com.opengamma.core.marketdatasnapshot.SnapshotDataBundle;
import com.opengamma.financial.analytics.curve.AbstractCurveDefinition;
import com.opengamma.financial.analytics.curve.ConverterUtils;
import com.opengamma.financial.analytics.curve.CurveConstructionConfiguration;
import com.opengamma.financial.analytics.curve.CurveGroupConfiguration;
import com.opengamma.financial.analytics.curve.CurveNodeCurrencyVisitor;
import com.opengamma.financial.analytics.curve.CurveSpecification;
import com.opengamma.financial.analytics.curve.CurveTypeConfiguration;
import com.opengamma.financial.analytics.curve.DiscountingCurveTypeConfiguration;
import com.opengamma.financial.analytics.curve.FixedDateInterpolatedCurveDefinition;
import com.opengamma.financial.analytics.curve.IborCurveTypeConfiguration;
import com.opengamma.financial.analytics.curve.InterpolatedCurveDefinition;
import com.opengamma.financial.analytics.curve.OvernightCurveTypeConfiguration;
import com.opengamma.financial.analytics.curve.credit.CurveSpecificationBuilder;
import com.opengamma.financial.analytics.ircurve.strips.CurveNodeWithIdentifier;
import com.opengamma.financial.analytics.ircurve.strips.PointsCurveNodeWithIdentifier;
import com.opengamma.financial.convention.IborIndexConvention;
import com.opengamma.financial.convention.OvernightIndexConvention;
import com.opengamma.financial.security.index.OvernightIndex;
import com.opengamma.id.ExternalIdBundle;
import com.opengamma.sesame.CurveNodeConverterFn;
import com.opengamma.sesame.CurveNodeInstrumentDefinitionFactory;
import com.opengamma.sesame.SimpleEnvironment;
import com.opengamma.sesame.marketdata.builders.MarketDataBuilder;
import com.opengamma.sesame.marketdata.scenarios.CurveInputs;
import com.opengamma.sesame.marketdata.scenarios.CyclePerturbations;
import com.opengamma.sesame.marketdata.scenarios.FilteredPerturbation;
import com.opengamma.sesame.marketdata.scenarios.MulticurveMatchDetails;
import com.opengamma.sesame.marketdata.scenarios.StandardMatchDetails;
import com.opengamma.timeseries.date.DateTimeSeries;
import com.opengamma.util.ArgumentChecker;
import com.opengamma.util.money.Currency;
import com.opengamma.util.result.Result;
import it.unimi.dsi.fastutil.doubles.DoubleArrayList;
/**
* Abstract base class for market data builders that build multicurve bundles.
*
* @param <T> the type of the multicurve bundle
*/
abstract class AbstractMulticurveMarketDataBuilder<T> implements MarketDataBuilder {
private final CurveSpecificationBuilder _curveSpecBuilder;
private final CurveNodeConverterFn _curveNodeConverter;
private final CurveNodeInstrumentDefinitionFactory _definitionFactory;
/**
* @param curveSpecBuilder for building curve specifications
* @param curveNodeConverter for converting curve node instruments to derivatives
* @param definitionFactory creates instrument definitions for curve node instruments
*/
AbstractMulticurveMarketDataBuilder(CurveSpecificationBuilder curveSpecBuilder,
CurveNodeConverterFn curveNodeConverter,
CurveNodeInstrumentDefinitionFactory definitionFactory) {
_curveSpecBuilder = ArgumentChecker.notNull(curveSpecBuilder, "curveSpecBuilder");
_curveNodeConverter = ArgumentChecker.notNull(curveNodeConverter, "curveNodeConverter");
_definitionFactory = ArgumentChecker.notNull(definitionFactory, "definitionFactory");
}
@Override
public Set<MarketDataRequirement> getSingleValueRequirements(SingleValueRequirement requirement,
ZonedDateTime valuationTime,
Set<? extends MarketDataRequirement> suppliedData) {
CurveConstructionConfiguration curveConfig = getCurveConfig(requirement);
Set<MarketDataRequirement> parentBundleRequirements = getParentBundleRequirements(requirement, curveConfig);
ImmutableSet.Builder<MarketDataRequirement> requirements = ImmutableSet.builder();
requirements.addAll(parentBundleRequirements);
// TODO this can go into a shared method
Set<CurveNodeWithIdentifier> curveNodes = getBundleNodes(curveConfig, valuationTime);
requirements.addAll(getRequirementsForCurveNodes(requirement, curveNodes));
Set<Currency> currencies = getCurrencies(curveConfig, valuationTime);
FxMatrixId fxMatrixId = FxMatrixId.of(currencies);
requirements.add(SingleValueRequirement.of(fxMatrixId, requirement.getMarketDataTime()));
return requirements.build();
}
/**
* Extracts the curve configuration from the curve bundle requirement.
* <p>
* This is necessary because there are multiple types of market data IDs for curves and they don't share an
* interface. The {@code getConfig()} methods on the ID classes are package-private and would have to be public if
* they were defined on a common interface.
*
* @param requirement the requirement for the curve bundle
* @return the configuration for building the curve bundle
*/
abstract CurveConstructionConfiguration getCurveConfig(SingleValueRequirement requirement);
/**
* Returns the requirements for all the curve bundles that the curve configuration depends on.
* <p>
* This recursively includes the bundles it depends on directly and any dependencies of the parent bundles
*
* @param requirement the requirement for the curve bundle
* @param curveConfig the curve bundle configuration
* @return the requirements for all the curve bundles that the curve configuration depends on
*/
abstract Set<MarketDataRequirement> getParentBundleRequirements(SingleValueRequirement requirement,
CurveConstructionConfiguration curveConfig);
@Override
public Set<MarketDataRequirement> getTimeSeriesRequirements(TimeSeriesRequirement requirement,
Map<MarketDataId<?>, DateTimeSeries<LocalDate, ?>> suppliedData) {
// TODO implement getTimeSeriesRequirements()
throw new UnsupportedOperationException("getTimeSeriesRequirements not implemented");
}
@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 abstract Class<? extends MarketDataId<T>> getKeyType();
/**
* Returns the nodes for all curves in a bundle.
*
* @param curveConfig configuration for a curve bundle
* @param valuationTime the valuation time for which the curve is required
* @return nodes for all curves in the bundle
*/
private Set<CurveNodeWithIdentifier> getBundleNodes(CurveConstructionConfiguration curveConfig,
ZonedDateTime valuationTime) {
ImmutableSet.Builder<CurveNodeWithIdentifier> curveNodes = ImmutableSet.builder();
for (CurveGroupConfiguration group : curveConfig.getCurveGroups()) {
for (AbstractCurveDefinition curveDefinition : group.resolveTypesForCurves().keySet()) {
curveNodes.addAll(getCurveNodes(curveDefinition, valuationTime));
}
}
return curveNodes.build();
}
/**
* Returns all the nodes in a curve.
*
* @param curveDef the curve definition
* @param valuationTime the valuation time for which the curve is required
* @return nodes for all curves in the bundle
*/
private Set<CurveNodeWithIdentifier> getCurveNodes(AbstractCurveDefinition curveDef, ZonedDateTime valuationTime) {
// the original platform code has this cast so assume it's safe
CurveSpecification curveSpec =
(CurveSpecification) _curveSpecBuilder.buildSpecification(valuationTime.toInstant(),
valuationTime.toLocalDate(),
curveDef);
return curveSpec.getNodes();
}
/**
* Returns the market data requirements for a set of curve nodes.
*
* @param curveBundleRequirement the requirement for the bundle containing the nodes
* @param curveNodes the nodes
* @return the market data requirements for the curve nodes
*/
private Set<MarketDataRequirement> getRequirementsForCurveNodes(MarketDataRequirement curveBundleRequirement,
Set<CurveNodeWithIdentifier> curveNodes) {
ImmutableSet.Builder<MarketDataRequirement> requirements = ImmutableSet.builder();
// loop through the curve nodes, create a requirement for each node's market data
for (CurveNodeWithIdentifier node : curveNodes) {
ExternalIdBundle nodeId = node.getIdentifier().toBundle();
requirements.add(SingleValueRequirement.of(RawId.of(nodeId), curveBundleRequirement.getMarketDataTime()));
if (node instanceof PointsCurveNodeWithIdentifier) {
// For these curves there are 2 tickers and we need access to both of them
PointsCurveNodeWithIdentifier pointsNode = (PointsCurveNodeWithIdentifier) node;
ExternalIdBundle underlyingId = pointsNode.getUnderlyingIdentifier().toBundle();
requirements.add(SingleValueRequirement.of(RawId.of(underlyingId), curveBundleRequirement.getMarketDataTime()));
}
}
return requirements.build();
}
/**
* Builds the intermediate results required by subclasses when building curve bundles.
*
* @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
* @return a multicurve bundle built from the configuration
*/
@SuppressWarnings("unchecked")
IntermediateResults buildIntermediateResults(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();
Multimap<String, CurveTypeConfiguration> configTypes = ArrayListMultimap.create();
// gather data about each curve
Map<String, Currency> currenciesByCurveName = new HashMap<>();
Multimap<String, IborIndex> iborIndexByCurveName = ArrayListMultimap.create();
Multimap<String, IndexON> onIndexByCurveName = ArrayListMultimap.create();
List<MultiCurveBundle<GeneratorYDCurve>> curveBundles = new ArrayList<>();
// the market data perturbations that apply to this curve bundle
Collection<FilteredPerturbation> filteredPerturbations = cyclePerturbations.getPerturbations(bundleRequirement);
// market data perturbations that perturb the data in a SnapshotDataBundle
Collection<FilteredPerturbation> dataBundlePerturbations =
MarketDataUtils.filterPerturbations(
filteredPerturbations,
CurveInputs.class,
MulticurveMatchDetails.class);
// loop over the curve groups in the bundle
for (CurveGroupConfiguration groupConfig : bundleConfig.getCurveGroups()) {
List<SingleCurveBundle<GeneratorYDCurve>> singleCurveBundles = new ArrayList<>();
// loop over the individual curves in the curve group
for (Map.Entry<AbstractCurveDefinition, List<? extends CurveTypeConfiguration>> entry :
groupConfig.resolveTypesForCurves().entrySet()) {
AbstractCurveDefinition curveDefinition = entry.getKey();
List<? extends CurveTypeConfiguration> curveConfigTypes = entry.getValue();
Set<CurveNodeWithIdentifier> curveNodes = getCurveNodes(curveDefinition, valuationTime);
SnapshotDataBundle dataBundle = createDataBundle(marketDataBundle, bundleRequirement, curveNodes);
String curveName = curveDefinition.getName();
SnapshotDataBundle perturbedData = perturbCurveData(curveNodes, dataBundle, curveName, dataBundlePerturbations);
Map<CurveNodeWithIdentifier, InstrumentDefinition> definitionMap =
createInstrumentDefinition(perturbedData, fxMatrix, valuationTime, curveNodes);
List<InstrumentDerivative> derivatives =
createInstrumentDerivatives(marketDataBundle, valuationTime, definitionMap);
configTypes.putAll(curveName, curveConfigTypes);
iborIndexByCurveName.putAll(curveName, createIborIndices(curveConfigTypes));
onIndexByCurveName.putAll(curveName, createOvernightIndices(curveConfigTypes));
Currency currency = getCurrency(curveConfigTypes);
if (currency != null) {
currenciesByCurveName.put(curveName, currency);
}
SingleCurveBundle<GeneratorYDCurve> singleCurveBundle =
createSingleCurveBundle(valuationTime, curveDefinition, curveNodes, derivatives);
singleCurveBundles.add(singleCurveBundle);
}
SingleCurveBundle[] singleBundleArray = singleCurveBundles.toArray(new SingleCurveBundle[singleCurveBundles.size()]);
curveBundles.add(new MultiCurveBundle<GeneratorYDCurve>(singleBundleArray));
}
return new IntermediateResults(currenciesByCurveName,
iborIndexByCurveName,
onIndexByCurveName,
configTypes,
curveBundles);
}
/**
* Applies perturbations to the data used to build a curve. If none of the perturbations match the curve
* then the input data is returned unchanged.
*
* @param curveNodes the curve nodes
* @param dataBundle the market data at each of the curve nodes
* @param curveName the curve name
* @param dataBundlePerturbations perturbations that apply to {@code SnapshotDataBundle}
* @return the market data for building the curve, possibly with a perturbation applied
*/
private SnapshotDataBundle perturbCurveData(Set<CurveNodeWithIdentifier> curveNodes,
SnapshotDataBundle dataBundle,
String curveName,
Collection<FilteredPerturbation> dataBundlePerturbations) {
FilteredPerturbation perturbation = perturbationForCurve(curveName, dataBundlePerturbations);
if (perturbation == null) {
return dataBundle;
}
CurveInputs curveInputs = new CurveInputs(curveNodes, dataBundle);
return ((CurveInputs) perturbation.apply(curveInputs)).getNodeData();
}
// TODO Java 8 - use Optional
@SuppressWarnings("unchecked")
@Nullable
private static FilteredPerturbation perturbationForCurve(
String curveName,
Collection<FilteredPerturbation> perturbations) {
MulticurveMatchDetails matchDetails = StandardMatchDetails.multicurve(curveName);
for (FilteredPerturbation perturbation : perturbations) {
if (perturbation.detailsMatch(matchDetails)) {
return perturbation;
}
}
return null;
}
/**
* Creates an array for parameter guesses for the curve.
* Protected to allow override in sub classes.
*
* @param curveNodes the curve nodes
* @return an array of doubles containing parameter guesses
*/
protected double[] getParameterGuessForCurves(Set<CurveNodeWithIdentifier> curveNodes) {
double[] parameterGuessForCurves = new double[curveNodes.size()];
Arrays.fill(parameterGuessForCurves, 0.02);
return parameterGuessForCurves;
}
/**
* Creates a {@code SingleCurveBundle} from a curve definition, curve generator and its instrument derivatives.
*
* @param valuationTime the valuation time for which the curve is required
* @param curveDefinition the curve definition
* @param curveNodes the curve nodes
* @param derivatives the derivatives for the curve nodes
* @return a bundle containing the curve generator and derivatives
*/
private SingleCurveBundle<GeneratorYDCurve> createSingleCurveBundle(ZonedDateTime valuationTime,
AbstractCurveDefinition curveDefinition,
Set<CurveNodeWithIdentifier> curveNodes,
List<InstrumentDerivative> derivatives) {
double[] parameterGuessForCurves = getParameterGuessForCurves(curveNodes);
GeneratorYDCurve curveGenerator = createCurveGenerator(curveDefinition, valuationTime.toLocalDate());
double[] startingPoint = curveGenerator.initialGuess(parameterGuessForCurves);
InstrumentDerivative[] derivativeArray = derivatives.toArray(new InstrumentDerivative[derivatives.size()]);
return new SingleCurveBundle<>(curveDefinition.getName(), derivativeArray, startingPoint, curveGenerator);
}
// TODO this is required by the legacy curve code but should be replaced when the curves are overhauled
/**
* Creates a {@link SnapshotDataBundle} containing the market data for a set of curve nodes.
*
* @param marketDataBundle the market data
* @return a bundle of market data for the curve nodes
*/
private SnapshotDataBundle createDataBundle(MarketDataBundle marketDataBundle,
MarketDataRequirement curveBundleRequirement,
Set<CurveNodeWithIdentifier> curveNodes) {
// TODO this implementation is dodgy - the long term goal should be to stop using SnapshotDataBundles at all
// node converters should use the market data key and the MarketDataEnvironment could be passed in
// instead of the data bundle
Set<MarketDataRequirement> nodeRequirements = getRequirementsForCurveNodes(curveBundleRequirement, curveNodes);
SnapshotDataBundle dataBundle = new SnapshotDataBundle();
for (MarketDataRequirement requirement : nodeRequirements) {
@SuppressWarnings("unchecked")
MarketDataId<Double> marketDataId = (RawId<Double>) requirement.getMarketDataId();
Double nodeData = marketDataBundle.get(marketDataId, Double.class).getValue();
ExternalIdBundle id = ((RawId<Double>) marketDataId).getId();
dataBundle.setDataPoint(id, nodeData);
}
return dataBundle;
}
/**
* Creates derivatives for the nodes on a curve.
*
* @param marketDataBundle the market data environment
* @param valuationTime the valuation time for which the curve is required
* @param defs the curve nodes to instrument definition map
* @return the derivatives for the instruments used by the curve nodes
*/
private List<InstrumentDerivative> createInstrumentDerivatives(MarketDataBundle marketDataBundle,
ZonedDateTime valuationTime,
Map<CurveNodeWithIdentifier, InstrumentDefinition> defs) {
ImmutableList.Builder<InstrumentDerivative> derivativesForCurve = ImmutableList.builder();
// TODO this is required because the definition factory and converter were originally engine functions
// they could be migrated away from using environment now they're not used in the engine
SimpleEnvironment env = new SimpleEnvironment(valuationTime, marketDataBundle);
for (Map.Entry<CurveNodeWithIdentifier, InstrumentDefinition> entry : defs.entrySet()) {
Result<InstrumentDerivative> derivativeResult =
_curveNodeConverter.getDerivative(env, entry.getKey(), entry.getValue(), valuationTime);
derivativesForCurve.add(derivativeResult.getValue());
}
return derivativesForCurve.build();
}
/**
* Creates definitions for the nodes on a curve.
*
* @param snapshot market data for the nodes TODO remove this all the way down through the analytics
* @param fxMatrix FX rates for the currencies used by the curve node instruments
* @param valuationTime the valuation time for which the curve is required
* @param nodes the curve nodes
* @return the definitions for the instruments used by the curve nodes
*/
private Map<CurveNodeWithIdentifier, InstrumentDefinition> createInstrumentDefinition(SnapshotDataBundle snapshot,
FXMatrix fxMatrix,
ZonedDateTime valuationTime,
Set<CurveNodeWithIdentifier> nodes) {
ImmutableMap.Builder<CurveNodeWithIdentifier, InstrumentDefinition> definitions = ImmutableMap.builder();
for (CurveNodeWithIdentifier node : nodes) {
InstrumentDefinition<?> instrumentDefn =
_definitionFactory.createInstrumentDefinition(node, snapshot, valuationTime, fxMatrix);
definitions.put(node, instrumentDefn);
}
return definitions.build();
}
/**
* Returns the currency for the first config type that is discounting or null if there is no discounting type.
*
* @param configTypes the curve config types
* @return the currency for the first config type that is discounting, null if none of them are
*/
@Nullable
private Currency getCurrency(List<? extends CurveTypeConfiguration> configTypes) {
for (CurveTypeConfiguration configType : configTypes) {
if (configType instanceof DiscountingCurveTypeConfiguration) {
String reference = ((DiscountingCurveTypeConfiguration) configType).getReference();
return Currency.of(reference);
}
}
return null;
}
/**
* Creates overnight indices for any of {@code configTypes} that are overnight config types.
*
* @param configTypes the curve config types
* @return overnight indices for any of the config types that are overnight
*/
private List<IndexON> createOvernightIndices(List<? extends CurveTypeConfiguration> configTypes) {
ImmutableList.Builder<IndexON> indices = ImmutableList.builder();
for (CurveTypeConfiguration configType : configTypes) {
if (configType instanceof OvernightCurveTypeConfiguration) {
OvernightCurveTypeConfiguration onType = (OvernightCurveTypeConfiguration) configType;
OvernightIndex index = SecurityLink.resolvable(onType.getConvention().toBundle(), OvernightIndex.class).resolve();
OvernightIndexConvention indexConvention =
ConventionLink.resolvable(index.getConventionId(), OvernightIndexConvention.class).resolve();
IndexON indexON = ConverterUtils.indexON(index.getName(), indexConvention);
indices.add(indexON);
}
}
return indices.build();
}
/**
* Creates IBOR indices for any of {@code configType} that are IBOR config types.
*
* @param configTypes the curve config types
* @return IBOR indices for any of the config types that are IBOR
*/
private List<IborIndex> createIborIndices(List<? extends CurveTypeConfiguration> configTypes) {
ImmutableList.Builder<IborIndex> indices = ImmutableList.builder();
for (CurveTypeConfiguration configType : configTypes) {
if (configType instanceof IborCurveTypeConfiguration) {
IborCurveTypeConfiguration iborType = (IborCurveTypeConfiguration) configType;
com.opengamma.financial.security.index.IborIndex indexSecurity =
SecurityLink.resolvable(iborType.getConvention(),
com.opengamma.financial.security.index.IborIndex.class).resolve();
IborIndexConvention indexConvention =
ConventionLink.resolvable(indexSecurity.getConventionId(), IborIndexConvention.class).resolve();
IborIndex iborIndex = ConverterUtils.indexIbor(
indexSecurity.getName(),
indexConvention,
indexSecurity.getTenor());
indices.add(iborIndex);
}
}
return indices.build();
}
/**
* Creates a curve generator for a curve definition and valuation date.
*
* @param definition the curve definition
* @param valuationDate the valuation date
* @return a generator capable of generating the curve
*/
private GeneratorYDCurve createCurveGenerator(AbstractCurveDefinition definition, LocalDate valuationDate) {
if (definition instanceof InterpolatedCurveDefinition) {
InterpolatedCurveDefinition interpolatedDefinition = (InterpolatedCurveDefinition) definition;
Interpolator1D interpolator =
CombinedInterpolatorExtrapolatorFactory.getInterpolator(interpolatedDefinition.getInterpolatorName(),
interpolatedDefinition.getLeftExtrapolatorName(),
interpolatedDefinition.getRightExtrapolatorName());
if (definition instanceof FixedDateInterpolatedCurveDefinition) {
FixedDateInterpolatedCurveDefinition fixedDateDefinition = (FixedDateInterpolatedCurveDefinition) definition;
List<LocalDate> fixedDates = fixedDateDefinition.getFixedDates();
DoubleArrayList nodePoints = new DoubleArrayList(fixedDates.size()); //TODO what about equal node points?
for (LocalDate fixedDate : fixedDates) {
nodePoints.add(TimeCalculator.getTimeBetween(valuationDate, fixedDate)); //TODO what to do if the fixed date is before the valuation date?
}
double anchor = nodePoints.get(0); //TODO should the anchor go into the definition?
return new GeneratorCurveYieldInterpolatedAnchorNode(nodePoints.toDoubleArray(), anchor, interpolator);
}
return new GeneratorCurveYieldInterpolated(LastTimeCalculator.getInstance(), interpolator);
}
throw new OpenGammaRuntimeException("Cannot handle curves of type " + definition.getClass());
}
/**
* Returns the currencies used by a curve bundle and all its ancestor curve bundles.
*
* @param curveConfig the curve bundle configuration
* @param valuationTime the valuation time of the curve
* @return the currencies used by the curve bundle and all its ancestor bundles
*/
Set<Currency> getCurrencies(CurveConstructionConfiguration curveConfig, ZonedDateTime valuationTime) {
ImmutableSet.Builder<Currency> currencies = ImmutableSet.builder();
CurveNodeCurrencyVisitor currencyVisitor = new CurveNodeCurrencyVisitor();
for (final CurveGroupConfiguration group : curveConfig.getCurveGroups()) {
Map<AbstractCurveDefinition, List<? extends CurveTypeConfiguration>> typesByCurve = group.resolveTypesForCurves();
for (AbstractCurveDefinition curveDefinition : typesByCurve.keySet()) {
Set<CurveNodeWithIdentifier> nodes = getCurveNodes(curveDefinition, valuationTime);
for (CurveNodeWithIdentifier node : nodes) {
currencies.addAll(node.getCurveNode().accept(currencyVisitor));
}
}
}
return currencies.build();
}
/**
* A set of intermediate values used for building curves.
*/
static class IntermediateResults {
private final Map<String, Currency> _currenciesByCurveName;
private final Multimap<String, IborIndex> _iborIndexByCurveName;
private final Multimap<String, IndexON> _onIndexByCurveName;
private final Multimap<String, CurveTypeConfiguration> _configTypes;
private final List<MultiCurveBundle<GeneratorYDCurve>> _curveBundles;
private IntermediateResults(Map<String, Currency> currenciesByCurveName,
Multimap<String, IborIndex> iborIndexByCurveName,
Multimap<String, IndexON> onIndexByCurveName,
Multimap<String, CurveTypeConfiguration> configTypes,
List<MultiCurveBundle<GeneratorYDCurve>> curveBundles) {
_currenciesByCurveName = currenciesByCurveName;
_iborIndexByCurveName = iborIndexByCurveName;
_onIndexByCurveName = onIndexByCurveName;
_curveBundles = curveBundles;
_configTypes = configTypes;
}
Map<String, Currency> getCurrenciesByCurveName() {
return _currenciesByCurveName;
}
Multimap<String, IborIndex> getIborIndexByCurveName() {
return _iborIndexByCurveName;
}
Multimap<String, IndexON> getOnIndexByCurveName() {
return _onIndexByCurveName;
}
Multimap<String, CurveTypeConfiguration> getConfigTypes() {
return _configTypes;
}
List<MultiCurveBundle<GeneratorYDCurve>> getCurveBundles() {
return _curveBundles;
}
}
}