/**
* Copyright (C) 2016 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.strata.measure.rate;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import com.google.common.collect.ImmutableSet;
import com.opengamma.strata.basics.currency.Currency;
import com.opengamma.strata.basics.currency.FxRateProvider;
import com.opengamma.strata.basics.index.Index;
import com.opengamma.strata.calc.CalculationRules;
import com.opengamma.strata.calc.runner.CalculationParameter;
import com.opengamma.strata.calc.runner.CalculationParameters;
import com.opengamma.strata.calc.runner.FunctionRequirements;
import com.opengamma.strata.collect.MapStream;
import com.opengamma.strata.data.MarketData;
import com.opengamma.strata.data.MarketDataId;
import com.opengamma.strata.data.ObservableSource;
import com.opengamma.strata.data.scenario.ScenarioMarketData;
import com.opengamma.strata.market.curve.CurveGroup;
import com.opengamma.strata.market.curve.CurveGroupDefinition;
import com.opengamma.strata.market.curve.CurveGroupEntry;
import com.opengamma.strata.market.curve.CurveGroupName;
import com.opengamma.strata.market.curve.CurveId;
import com.opengamma.strata.market.curve.CurveName;
import com.opengamma.strata.pricer.rate.RatesProvider;
/**
* The lookup that provides access to rates in market data.
* <p>
* The rates market lookup provides access to discount curves and forward curves.
* This includes Ibor index rates, Overnight index rates, Price index rates,
* FX rates and discounting.
* <p>
* The lookup implements {@link CalculationParameter} and is used by passing it
* as an argument to {@link CalculationRules}. It provides the link between the
* data that the function needs and the data that is available in {@link ScenarioMarketData}.
* <p>
* Implementations of this interface must be immutable.
*/
public interface RatesMarketDataLookup extends CalculationParameter {
/**
* Obtains an instance based on a map of discount and forward curve identifiers.
* <p>
* The discount and forward curves refer to the curve identifier.
* The curves themselves are provided in {@link ScenarioMarketData}
* using {@link CurveId} as the identifier.
*
* @param discountCurveIds the discount curve identifiers, keyed by currency
* @param forwardCurveIds the forward curves identifiers, keyed by index
* @return the rates lookup containing the specified curves
*/
public static RatesMarketDataLookup of(
Map<Currency, CurveId> discountCurveIds,
Map<Index, CurveId> forwardCurveIds) {
return DefaultRatesMarketDataLookup.of(
discountCurveIds, forwardCurveIds, ObservableSource.NONE, FxRateLookup.ofRates());
}
/**
* Obtains an instance based on a map of discount and forward curve identifiers,
* specifying the source of FX rates.
* <p>
* The discount and forward curves refer to the curve identifier.
* The curves themselves are provided in {@link ScenarioMarketData}
* using {@link CurveId} as the identifier.
* The source of market data is rarely needed, as most applications use only one
* underlying data source.
*
* @param discountCurveIds the discount curve identifiers, keyed by currency
* @param forwardCurveIds the forward curves identifiers, keyed by index
* @param obsSource the source of market data for quotes and other observable market data
* @param fxLookup the lookup used to obtain FX rates
* @return the rates lookup containing the specified curves
*/
public static RatesMarketDataLookup of(
Map<Currency, CurveId> discountCurveIds,
Map<Index, CurveId> forwardCurveIds,
ObservableSource obsSource,
FxRateLookup fxLookup) {
return DefaultRatesMarketDataLookup.of(discountCurveIds, forwardCurveIds, obsSource, fxLookup);
}
/**
* Obtains an instance based on a group of discount and forward curves.
* <p>
* The discount and forward curves refer to the curve name.
* The curves themselves are provided in {@link ScenarioMarketData}
* using {@link CurveId} as the identifier.
*
* @param groupName the curve group name
* @param discountCurves the discount curves, keyed by currency
* @param forwardCurves the forward curves, keyed by index
* @return the rates lookup containing the specified curves
*/
public static RatesMarketDataLookup of(
CurveGroupName groupName,
Map<Currency, CurveName> discountCurves,
Map<? extends Index, CurveName> forwardCurves) {
Map<Currency, CurveId> discountCurveIds = MapStream.of(discountCurves)
.mapValues(c -> CurveId.of(groupName, c))
.toMap();
Map<? extends Index, CurveId> forwardCurveIds = MapStream.of(forwardCurves)
.mapValues(c -> CurveId.of(groupName, c))
.toMap();
return DefaultRatesMarketDataLookup.of(discountCurveIds, forwardCurveIds, ObservableSource.NONE, FxRateLookup.ofRates());
}
/**
* Obtains an instance based on a curve group.
* <p>
* The discount curves and forward curves from the group are extracted and used to build the lookup.
*
* @param curveGroup the curve group to base the lookup on
* @return the rates lookup based on the specified group
*/
public static RatesMarketDataLookup of(CurveGroup curveGroup) {
CurveGroupName groupName = curveGroup.getName();
Map<Currency, CurveId> discountCurves = MapStream.of(curveGroup.getDiscountCurves())
.mapValues(c -> CurveId.of(groupName, c.getName()))
.toMap();
Map<Index, CurveId> forwardCurves = MapStream.of(curveGroup.getForwardCurves())
.mapValues(c -> CurveId.of(groupName, c.getName()))
.toMap();
return DefaultRatesMarketDataLookup.of(discountCurves, forwardCurves, ObservableSource.NONE, FxRateLookup.ofRates());
}
/**
* Obtains an instance based on a curve group definition.
* <p>
* The discount curves and forward curves from the group are extracted and used to build the lookup.
*
* @param curveGroupDefinition the curve group to base the lookup on
* @return the rates lookup based on the specified group
*/
public static RatesMarketDataLookup of(CurveGroupDefinition curveGroupDefinition) {
CurveGroupName groupName = curveGroupDefinition.getName();
Map<Currency, CurveId> discountCurves = new HashMap<>();
Map<Index, CurveId> forwardCurves = new HashMap<>();
for (CurveGroupEntry entry : curveGroupDefinition.getEntries()) {
CurveId curveId = CurveId.of(groupName, entry.getCurveName());
entry.getDiscountCurrencies().forEach(ccy -> discountCurves.put(ccy, curveId));
entry.getIndices().forEach(idx -> forwardCurves.put(idx, curveId));
}
return DefaultRatesMarketDataLookup.of(discountCurves, forwardCurves, ObservableSource.NONE, FxRateLookup.ofRates());
}
/**
* Obtains an instance based on a curve group definition.
* <p>
* The discount curves and forward curves from the group are extracted and used to build the lookup.
*
* @param curveGroupDefinition the curve group to base the lookup on
* @param observableSource the source of market data for quotes and other observable market data
* @param fxLookup the lookup used to obtain FX rates
* @return the rates lookup based on the specified group
*/
public static RatesMarketDataLookup of(CurveGroupDefinition curveGroupDefinition,
ObservableSource observableSource,
FxRateLookup fxLookup) {
CurveGroupName groupName = curveGroupDefinition.getName();
Map<Currency, CurveId> discountCurves = new HashMap<>();
Map<Index, CurveId> forwardCurves = new HashMap<>();
for (CurveGroupEntry entry : curveGroupDefinition.getEntries()) {
CurveId curveId = CurveId.of(groupName, entry.getCurveName());
entry.getDiscountCurrencies().forEach(ccy -> discountCurves.put(ccy, curveId));
entry.getIndices().forEach(idx -> forwardCurves.put(idx, curveId));
}
return DefaultRatesMarketDataLookup.of(discountCurves, forwardCurves, observableSource, fxLookup);
}
//-------------------------------------------------------------------------
/**
* Gets the type that the lookup will be queried by.
* <p>
* This returns {@code RatesMarketLookup.class}.
* When querying parameters using {@link CalculationParameters#findParameter(Class)},
* {@code RatesMarketLookup.class} must be passed in to find the instance.
*
* @return the type of the parameter implementation
*/
@Override
default Class<? extends CalculationParameter> queryType() {
return RatesMarketDataLookup.class;
}
//-------------------------------------------------------------------------
/**
* Gets the set of currencies that discount factors are provided for.
*
* @return the set of discount curve currencies
*/
public abstract ImmutableSet<Currency> getDiscountCurrencies();
/**
* Gets the identifiers used to obtain the discount factors for the specified currency.
* <p>
* In most cases, the identifier will refer to a curve.
* If the currency is not found, an exception is thrown.
*
* @param currency the currency for which identifiers are required
* @return the set of market data identifiers
* @throws IllegalArgumentException if the currency is not found
*/
public abstract ImmutableSet<MarketDataId<?>> getDiscountMarketDataIds(Currency currency);
/**
* Gets the set of indices that forward rates are provided for.
*
* @return the set of forward curve indices
*/
public abstract ImmutableSet<Index> getForwardIndices();
/**
* Gets the identifiers used to obtain the forward rates for the specified index.
* <p>
* In most cases, the identifier will refer to a curve.
* If the index is not found, an exception is thrown.
*
* @param index the index for which identifiers are required
* @return the set of market data identifiers
* @throws IllegalArgumentException if the index is not found
*/
public abstract ImmutableSet<MarketDataId<?>> getForwardMarketDataIds(Index index);
//-------------------------------------------------------------------------
/**
* Creates market data requirements for the specified currencies.
* <p>
* This is used when discount factors are required, but forward curves are not.
*
* @param currencies the currencies, for which discount factors will be needed
* @return the requirements
* @throws IllegalArgumentException if unable to create requirements
*/
public default FunctionRequirements requirements(Set<Currency> currencies) {
return requirements(currencies, ImmutableSet.of());
}
/**
* Creates market data requirements for the specified currency and indices.
*
* @param currency the currency, for which discount factors are needed
* @param indices the indices, for which forward curves and time-series will be needed
* @return the requirements
* @throws IllegalArgumentException if unable to create requirements
*/
public default FunctionRequirements requirements(Currency currency, Index... indices) {
return requirements(ImmutableSet.of(currency), ImmutableSet.copyOf(indices));
}
/**
* Creates market data requirements for the specified currencies and indices.
*
* @param currencies the currencies, for which discount factors will be needed
* @param indices the indices, for which forward curves and time-series will be needed
* @return the requirements
* @throws IllegalArgumentException if unable to create requirements
*/
public abstract FunctionRequirements requirements(Set<Currency> currencies, Set<? extends Index> indices);
//-------------------------------------------------------------------------
/**
* Obtains a filtered view of the complete set of market data.
* <p>
* This method returns an instance that binds the lookup to the market data.
* The input is {@link ScenarioMarketData}, which contains market data for all scenarios.
*
* @param marketData the complete set of market data for all scenarios
* @return the filtered market data
*/
public default RatesScenarioMarketData marketDataView(ScenarioMarketData marketData) {
return DefaultRatesScenarioMarketData.of(this, marketData);
}
/**
* Obtains a filtered view of the complete set of market data.
* <p>
* This method returns an instance that binds the lookup to the market data.
* The input is {@link MarketData}, which contains market data for one scenario.
*
* @param marketData the complete set of market data for one scenario
* @return the filtered market data
*/
public default RatesMarketData marketDataView(MarketData marketData) {
return DefaultRatesMarketData.of(this, marketData);
}
//-------------------------------------------------------------------------
/**
* Obtains a rates provider based on the specified market data.
* <p>
* This provides a {@link RatesProvider} suitable for pricing a rates product.
* Although this method can be used directly, it is typically invoked indirectly
* via {@link RatesMarketData}:
* <pre>
* // bind the baseData to this lookup
* RatesMarketData view = lookup.marketView(baseData);
*
* // pass around RatesMarketData within the function to use in pricing
* RatesProvider provider = view.ratesProvider();
* </pre>
*
* @param marketData the complete set of market data for one scenario
* @return the rates provider
*/
public abstract RatesProvider ratesProvider(MarketData marketData);
/**
* Obtains an FX rate provider based on the specified market data.
* <p>
* This provides an {@link FxRateProvider} suitable for obtaining FX rates.
* Although this method can be used directly, it is typically invoked indirectly
* via {@link RatesMarketData}:
* <pre>
* // bind the baseData to this lookup
* RatesMarketData view = lookup.marketView(baseData);
*
* // pass around RatesMarketData within the function to use in pricing
* RatesProvider provider = view.fxRateProvider();
* </pre>
*
* @param marketData the complete set of market data for one scenario
* @return the FX rate provider
*/
public abstract FxRateProvider fxRateProvider(MarketData marketData);
}