/**
* Copyright (C) 2011 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.analytics.financial.provider.description.inflation;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeSet;
import org.apache.commons.lang.ObjectUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.opengamma.OpenGammaRuntimeException;
import com.opengamma.analytics.financial.forex.method.FXMatrix;
import com.opengamma.analytics.financial.instrument.index.IborIndex;
import com.opengamma.analytics.financial.instrument.index.IndexON;
import com.opengamma.analytics.financial.instrument.index.IndexPrice;
import com.opengamma.analytics.financial.legalentity.LegalEntity;
import com.opengamma.analytics.financial.legalentity.LegalEntityFilter;
import com.opengamma.analytics.financial.model.interestrate.curve.PriceIndexCurve;
import com.opengamma.analytics.financial.model.interestrate.curve.YieldAndDiscountCurve;
import com.opengamma.analytics.financial.provider.description.interestrate.IssuerProviderDiscount;
import com.opengamma.analytics.financial.provider.description.interestrate.MulticurveProviderDiscount;
import com.opengamma.analytics.financial.provider.sensitivity.multicurve.ForwardSensitivity;
import com.opengamma.util.ArgumentChecker;
import com.opengamma.util.money.Currency;
import com.opengamma.util.tuple.DoublesPair;
import com.opengamma.util.tuple.Pair;
/**
* Class describing a "market" with discounting, forward, price index and credit curves.
* The forward rate are computed as the ratio of discount factors stored in YieldAndDiscountCurve.
*/
public class InflationIssuerProviderDiscount implements InflationIssuerProviderInterface {
private static final Logger s_logger = LoggerFactory.getLogger(InflationIssuerProviderDiscount.class);
/** The inflation provider. */
private final InflationProviderDiscount _inflationProvider;
/** The issuer provider. */
private final IssuerProviderDiscount _issuerProvider;
/**
* A map with issuer discounting curves.
*/
private final Map<Pair<Object, LegalEntityFilter<LegalEntity>>, YieldAndDiscountCurve> _issuerCurves;
/**
* The set of names of all curves used in the inflation provider.
*/
private Set<String> _inflationNames;
/**
* The set of all curves names. If contains the names of the inflation provider curves names and the issuer curves names.
*/
private final Set<String> _allNames = new TreeSet<>();
/**
* The map between the curves names and the curves themselves.
*/
//TODO these aren't the best names
private final Map<String, YieldAndDiscountCurve> _issuerCurvesNames = new LinkedHashMap<>();
/**
* Constructor with empty maps for discounting, forward and price index.
*/
public InflationIssuerProviderDiscount() {
_inflationProvider = new InflationProviderDiscount();
_issuerCurves = new LinkedHashMap<>();
_issuerProvider = new IssuerProviderDiscount(this.getMulticurveProvider(), _issuerCurves);
setAllCurves();
}
/**
* Constructor with empty maps for discounting, forward and price index.
* @param fxMatrix The FXMatrix.
*/
public InflationIssuerProviderDiscount(final FXMatrix fxMatrix) {
_inflationProvider = new InflationProviderDiscount(fxMatrix);
_issuerCurves = new LinkedHashMap<>();
_issuerProvider = new IssuerProviderDiscount(this.getMulticurveProvider(), _issuerCurves);
setAllCurves();
}
/**
* Constructor from an existing market. The given market maps are used for the new market (the same maps are used, not copied).
* @param discountingCurves A map with one (discounting) curve by currency.
* @param forwardIborCurves A map with one (forward) curve by Ibor index.
* @param forwardONCurves A map with one (forward) curve by ON index.
* @param priceIndexCurves A map with one price curve by price index.
* @param issuerCurves A map with issuer discounting curves.
* @param fxMatrix The FXMatrix.
*/
public InflationIssuerProviderDiscount(final Map<Currency, YieldAndDiscountCurve> discountingCurves, final Map<IborIndex, YieldAndDiscountCurve> forwardIborCurves,
final Map<IndexON, YieldAndDiscountCurve> forwardONCurves, final Map<IndexPrice, PriceIndexCurve> priceIndexCurves,
final Map<Pair<Object, LegalEntityFilter<LegalEntity>>, YieldAndDiscountCurve> issuerCurves, final FXMatrix fxMatrix) {
_inflationProvider = new InflationProviderDiscount(discountingCurves, forwardIborCurves, forwardONCurves, priceIndexCurves, fxMatrix);
_issuerCurves = issuerCurves;
_issuerProvider = new IssuerProviderDiscount(this.getMulticurveProvider(), _issuerCurves);
setAllCurves();
}
/**
* Constructor from exiting multicurveProvider and inflation map. The given provider and map are used for the new provider (the same maps are used, not copied).
* @param inflation The inflation provider.
* @param issuerCurves A map with issuer discounting curves.
*/
public InflationIssuerProviderDiscount(final InflationProviderDiscount inflation, final Map<Pair<Object, LegalEntityFilter<LegalEntity>>, YieldAndDiscountCurve> issuerCurves) {
_inflationProvider = inflation;
_issuerCurves = issuerCurves;
_issuerProvider = new IssuerProviderDiscount(this.getMulticurveProvider(), _issuerCurves);
setAllCurves();
}
/**
* Constructor from exiting multicurveProvider and inflation map. The given provider and map are used for the new provider (the same maps are used, not copied).
* @param inflation The inflation provider.
* @param issuerProvider A map with issuer discounting curves.
*/
public InflationIssuerProviderDiscount(final InflationProviderDiscount inflation, final IssuerProviderDiscount issuerProvider) {
_inflationProvider = inflation;
_issuerCurves = issuerProvider.getIssuerCurves();
_issuerProvider = new IssuerProviderDiscount(this.getMulticurveProvider(), _issuerCurves);
setAllCurves();
}
/**
* Constructor from exiting issuerProvider. The given provider and map are used for the new provider (the same maps are used, not copied).
* @param issuerProvider A map with issuer discounting curves.
*/
public InflationIssuerProviderDiscount(final IssuerProviderDiscount issuerProvider) {
_inflationProvider = new InflationProviderDiscount();
_inflationProvider.setAll(new InflationProviderDiscount(issuerProvider.getMulticurveProvider()));
_issuerCurves = issuerProvider.getIssuerCurves();
_issuerProvider = new IssuerProviderDiscount(this.getMulticurveProvider(), _issuerCurves);
setAllCurves();
}
@Override
public InflationIssuerProviderDiscount copy() {
final InflationProviderDiscount inflationProvider = _inflationProvider.copy();
final LinkedHashMap<Pair<Object, LegalEntityFilter<LegalEntity>>, YieldAndDiscountCurve> issuerCurves = new LinkedHashMap<>(_issuerCurves);
return new InflationIssuerProviderDiscount(inflationProvider, issuerCurves);
}
/**
* Sets all curves.
*/
protected void setAllCurves() {
_inflationNames = _inflationProvider.getAllCurveNames();
_allNames.addAll(_inflationNames);
_allNames.addAll(_inflationProvider.getMulticurveProvider().getAllCurveNames());
for (final Map.Entry<Pair<Object, LegalEntityFilter<LegalEntity>>, YieldAndDiscountCurve> entry : _issuerCurves.entrySet()) {
if (entry.getValue() == null) {
throw new OpenGammaRuntimeException("Curve with key " + entry.getValue() + " was null");
}
_allNames.add(entry.getValue().getName());
_issuerCurvesNames.put(entry.getValue().getName(), entry.getValue());
}
}
/**
* Sets the price index curve for a price index.
* @param issuerCcy The issuer/currency pair.
* @param curve The curve.
*/
public void setCurve(final Pair<Object, LegalEntityFilter<LegalEntity>> issuerCcy, final YieldAndDiscountCurve curve) {
ArgumentChecker.notNull(issuerCcy, "Name-currency");
ArgumentChecker.notNull(curve, "curve");
if (_issuerCurves.containsKey(issuerCcy)) {
throw new IllegalArgumentException("Issuer/currency curve already set: " + issuerCcy.toString());
}
_issuerCurves.put(issuerCcy, curve);
setAllCurves();
}
@Override
public double getDiscountFactor(final Pair<Object, LegalEntityFilter<LegalEntity>> issuerCcy, final Double time) {
return _issuerCurves.get(issuerCcy).getDiscountFactor(time);
}
@Override
public double getDiscountFactor(final LegalEntity issuer, final Double time) {
for (final Map.Entry<Pair<Object, LegalEntityFilter<LegalEntity>>, YieldAndDiscountCurve> entry : _issuerCurves.entrySet()) {
if (entry.getKey().getFirst().equals(entry.getKey().getSecond().getFilteredData(issuer))) {
return entry.getValue().getDiscountFactor(time);
}
}
s_logger.error("Could not find issuer discounting curve for {}. There are {} curve available", issuer, _issuerCurves.size());
for (final Map.Entry<Pair<Object, LegalEntityFilter<LegalEntity>>, YieldAndDiscountCurve> entry : _issuerCurves.entrySet()) {
s_logger.error("matching key = {}, filter {} matches = {}", entry.getKey().getFirst(), issuer, entry.getKey().getSecond().getFilteredData(issuer));
}
throw new IllegalArgumentException("Issuer discounting curve not found for " + issuer);
}
@Override
public Set<Pair<Object, LegalEntityFilter<LegalEntity>>> getIssuers() {
return _issuerCurves.keySet();
}
@Override
public MulticurveProviderDiscount getMulticurveProvider() {
return _inflationProvider.getMulticurveProvider();
}
@Override
public InflationProviderDiscount getInflationProvider() {
return _inflationProvider;
}
@Override
public IssuerProviderDiscount getIssuerProvider() {
return new IssuerProviderDiscount(this.getMulticurveProvider(), _issuerCurves);
}
/**
* Gets the curve for an identifier / filter pair.
* @param issuer The issuer
* @return The curve, null if not found
*/
public YieldAndDiscountCurve getCurve(final Pair<Object, LegalEntityFilter<LegalEntity>> issuer) {
return _issuerCurves.get(issuer);
}
/**
* Gets the curve for an issuer.
* @param issuer The issuer
* @return The curve, null if not found
*/
public YieldAndDiscountCurve getCurve(final LegalEntity issuer) {
for (final Map.Entry<Pair<Object, LegalEntityFilter<LegalEntity>>, YieldAndDiscountCurve> entry : _issuerCurves.entrySet()) {
if (entry.getKey().getFirst().equals(entry.getKey().getSecond().getFilteredData(issuer))) {
return entry.getValue();
}
}
throw new IllegalArgumentException("Could not get curve for " + issuer);
}
/**
* Gets the curve(with a name) for an issuer .
* @param name The name
* @return The curve, null if not found
*/
public YieldAndDiscountCurve getCurve(final String name) {
for (final Entry<String, YieldAndDiscountCurve> entry : _issuerCurvesNames.entrySet()) {
if (entry.getKey().equals(name)) {
return entry.getValue();
}
}
throw new IllegalArgumentException("Could not get curve for " + name);
}
@Override
public Integer getNumberOfParameters(final String name) {
final PriceIndexCurve inflationCurve = _inflationProvider.getCurve(name);
final YieldAndDiscountCurve curve = _inflationProvider.getMulticurveProvider().getCurve(name);
final YieldAndDiscountCurve issuerCurve = _issuerCurvesNames.get(name);
if (inflationCurve != null) {
return inflationCurve.getNumberOfParameters();
} else if (curve != null) {
return curve.getNumberOfParameters();
} else if (issuerCurve != null) {
return issuerCurve.getNumberOfParameters();
}
throw new UnsupportedOperationException("Cannot return the number of parameter for a null curve");
}
/**
* Return the number of intrinsic parameters for the definition of the curve.
* Which is the total number of parameters minus the parameters of the curves in curvesNames (If they are in curves).
* @param name the name of the curve.
* @param curvesNames The list of curves names.
* @return The number of parameters.
*/
public Integer getNumberOfIntrinsicParameters(final String name, final Set<String> curvesNames) {
final YieldAndDiscountCurve issuerCurve = _issuerCurvesNames.get(name);
if (issuerCurve != null) {
return issuerCurve.getNumberOfIntrinsicParameters(curvesNames);
}
return _inflationProvider.getNumberOfIntrinsicParameters(name, curvesNames);
}
@Override
public List<String> getUnderlyingCurvesNames(final String name) {
final PriceIndexCurve inflationCurve = _inflationProvider.getCurve(name);
final YieldAndDiscountCurve curve = _inflationProvider.getMulticurveProvider().getCurve(name);
final YieldAndDiscountCurve issuerCurve = _issuerCurvesNames.get(name);
if (inflationCurve != null) {
return inflationCurve.getUnderlyingCurvesNames();
} else if (curve != null) {
return curve.getUnderlyingCurvesNames();
} else if (issuerCurve != null) {
return issuerCurve.getUnderlyingCurvesNames();
}
throw new UnsupportedOperationException("Cannot return the number of parameter for a null curve");
}
// ===== Methods related to InflationProvider =====
@Override
public double getPriceIndex(final IndexPrice index, final Double time) {
return _inflationProvider.getPriceIndex(index, time);
}
@Override
public String getName(final IndexPrice index) {
return _inflationProvider.getName(index);
}
/**
* Gets the price index curve associated to a given price index in the market.
* @param index The Price index.
* @return The curve.
*/
public PriceIndexCurve getCurve(final IndexPrice index) {
return _inflationProvider.getCurve(index);
}
@Override
public Set<IndexPrice> getPriceIndexes() {
return _inflationProvider.getPriceIndexes();
}
/**
* Sets the price index curve for a price index.
* @param index The price index.
* @param curve The curve.
*/
public void setCurve(final IndexPrice index, final PriceIndexCurve curve) {
_inflationProvider.setCurve(index, curve);
setAllCurves();
}
/**
* Replaces the discounting curve for a price index.
* @param index The price index.
* @param curve The price curve for the index.
* @throws IllegalArgumentException if curve name NOT already present
*/
public void replaceCurve(final IndexPrice index, final PriceIndexCurve curve) {
_inflationProvider.replaceCurve(index, curve);
}
// ===== Methods related to MulticurveProvider =====
@Override
public double getDiscountFactor(final Currency ccy, final Double time) {
return _inflationProvider.getDiscountFactor(ccy, time);
}
@Override
public String getName(final Currency ccy) {
return _inflationProvider.getName(ccy);
}
@Override
public Set<Currency> getCurrencies() {
return _inflationProvider.getCurrencies();
}
@Override
public double getForwardRate(final IborIndex index, final double startTime, final double endTime, final double accrualFactor) {
return _inflationProvider.getForwardRate(index, startTime, endTime, accrualFactor);
}
@Override
public String getName(final IborIndex index) {
return _inflationProvider.getName(index);
}
@Override
public Set<IborIndex> getIndexesIbor() {
return _inflationProvider.getIndexesIbor();
}
@Override
public double getForwardRate(final IndexON index, final double startTime, final double endTime, final double accrualFactor) {
return _inflationProvider.getForwardRate(index, startTime, endTime, accrualFactor);
}
@Override
public String getName(final IndexON index) {
return _inflationProvider.getName(index);
}
@Override
public Set<IndexON> getIndexesON() {
return _inflationProvider.getIndexesON();
}
/**
* Gets the discounting curve associated in a given currency in the market.
* @param ccy The currency.
* @return The curve.
*/
public YieldAndDiscountCurve getCurve(final Currency ccy) {
return _inflationProvider.getCurve(ccy);
}
/**
* Gets the forward curve associated to a given Ibor index in the market.
* @param index The Ibor index.
* @return The curve.
*/
public YieldAndDiscountCurve getCurve(final IborIndex index) {
return _inflationProvider.getCurve(index);
}
/**
* Gets the forward curve associated to a given ON index in the market.
* @param index The ON index.
* @return The curve.
*/
public YieldAndDiscountCurve getCurve(final IndexON index) {
return _inflationProvider.getCurve(index);
}
/**
* Sets the discounting curve for a given currency.
* @param ccy The currency.
* @param curve The yield curve used for discounting.
*/
public void setCurve(final Currency ccy, final YieldAndDiscountCurve curve) {
_inflationProvider.setCurve(ccy, curve);
setAllCurves();
}
/**
* Sets the curve associated to an Ibor index.
* @param index The index.
* @param curve The curve.
*/
public void setCurve(final IborIndex index, final YieldAndDiscountCurve curve) {
_inflationProvider.setCurve(index, curve);
setAllCurves();
}
/**
* Sets the curve associated to an ON index.
* @param index The index.
* @param curve The curve.
*/
public void setCurve(final IndexON index, final YieldAndDiscountCurve curve) {
_inflationProvider.setCurve(index, curve);
setAllCurves();
}
/**
* Replaces the discounting curve for a given currency.
* @param ccy The currency.
* @param curve The yield curve used for discounting.
* @throws IllegalArgumentException if curve name NOT already present
*/
public void replaceCurve(final Currency ccy, final YieldAndDiscountCurve curve) {
_inflationProvider.replaceCurve(ccy, curve);
}
/**
* Replaces the forward curve for a given index.
* @param index The index.
* @param curve The yield curve used for forward.
* @throws IllegalArgumentException if curve name NOT already present
*/
public void replaceCurve(final IborIndex index, final YieldAndDiscountCurve curve) {
_inflationProvider.replaceCurve(index, curve);
}
@Override
public double getFxRate(final Currency ccy1, final Currency ccy2) {
return _inflationProvider.getFxRate(ccy1, ccy2);
}
/**
* Gets the underlying FXMatrix containing the exchange rates.
* @return The matrix.
*/
@Override
public FXMatrix getFxRates() {
return _inflationProvider.getFxRates();
}
// ===== Methods related to All =====
@Override
public Set<String> getAllNames() {
return getAllCurveNames();
}
@Override
public Set<String> getAllCurveNames() {
final Set<String> names = new TreeSet<>();
names.addAll(_inflationProvider.getAllNames());
final Set<Pair<Object, LegalEntityFilter<LegalEntity>>> issuerSet = _issuerCurves.keySet();
for (final Pair<Object, LegalEntityFilter<LegalEntity>> issuer : issuerSet) {
names.add(_issuerCurves.get(issuer).getName());
}
return names;
}
/**
* Set all the curves contains in another bundle. If a currency or index is already present in the map, the associated curve is changed.
* @param other The other bundle.
*/
// * TODO: REVIEW: Should we check that the curve are already present?
public void setAll(final InflationIssuerProviderDiscount other) {
ArgumentChecker.notNull(other, "Inflation provider");
_inflationProvider.setAll(other.getInflationProvider());
_issuerCurves.putAll(other._issuerCurves);
}
// ===== Convenience methods =====
/**
* Replaces an issuer curve.
* @param ic The key of the curve to replace
* @param replacement The replacement curve
* @return A new provider with the curve replaced.
*/
public InflationIssuerProviderDiscount withIssuerCurve(final Pair<Object, LegalEntityFilter<LegalEntity>> ic, final YieldAndDiscountCurve replacement) {
final Map<Pair<Object, LegalEntityFilter<LegalEntity>>, YieldAndDiscountCurve> newIssuerCurves = new LinkedHashMap<>(_issuerCurves);
newIssuerCurves.put(ic, replacement);
return new InflationIssuerProviderDiscount(_inflationProvider, newIssuerCurves);
}
@Override
public InflationProviderInterface withDiscountFactor(final Currency ccy, final Pair<Object, LegalEntityFilter<LegalEntity>> replacement) {
return _inflationProvider.withDiscountFactor(ccy, _issuerCurves.get(replacement));
}
@Override
public InflationProviderInterface withDiscountFactor(final Currency ccy, final LegalEntity replacement) {
for (final Map.Entry<Pair<Object, LegalEntityFilter<LegalEntity>>, YieldAndDiscountCurve> entry : _issuerCurves.entrySet()) {
if (entry.getKey().getFirst().equals(entry.getKey().getSecond().getFilteredData(replacement))) {
return _inflationProvider.withDiscountFactor(ccy, entry.getValue());
}
}
throw new IllegalArgumentException("Issuer discounting curve not found: " + replacement);
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + _inflationProvider.hashCode();
result = prime * result + _issuerCurves.hashCode();
return result;
}
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof InflationIssuerProviderDiscount)) {
return false;
}
final InflationIssuerProviderDiscount other = (InflationIssuerProviderDiscount) obj;
if (!ObjectUtils.equals(_inflationProvider, other._inflationProvider)) {
return false;
}
if (!ObjectUtils.equals(_issuerCurves, other._issuerCurves)) {
return false;
}
return true;
}
@Override
public double[] parameterSensitivity(final String name, final List<DoublesPair> pointSensitivity) {
if (_inflationProvider.getMulticurveProvider().getAllNames().contains(name)) {
return _inflationProvider.parameterSensitivity(name, pointSensitivity);
}
final YieldAndDiscountCurve curve = _issuerCurvesNames.get(name);
if (curve == null) {
throw new IllegalArgumentException("Could not get curve called " + name);
}
final int nbParameters = curve.getNumberOfParameters();
final double[] result = new double[nbParameters];
if (pointSensitivity != null && !pointSensitivity.isEmpty()) {
for (final DoublesPair timeAndS : pointSensitivity) {
final double[] sensi1Point = curve.getInterestRateParameterSensitivity(timeAndS.getFirst());
for (int loopparam = 0; loopparam < nbParameters; loopparam++) {
result[loopparam] += timeAndS.getSecond() * sensi1Point[loopparam];
}
}
}
return result;
}
@Override
public double[] parameterForwardSensitivity(final String name, final List<ForwardSensitivity> pointSensitivity) {
return _inflationProvider.parameterForwardSensitivity(name, pointSensitivity);
}
@Override
public double[] parameterInflationSensitivity(final String name, final List<DoublesPair> pointSensitivity) {
final YieldAndDiscountCurve curve = _issuerCurvesNames.get(name);
if (curve == null) {
return _inflationProvider.parameterInflationSensitivity(name, pointSensitivity);
}
final int nbParameters = curve.getNumberOfParameters();
final double[] result = new double[nbParameters];
if (pointSensitivity != null && pointSensitivity.size() > 0) {
for (final DoublesPair timeAndS : pointSensitivity) {
final double[] sensi1Point = curve.getInterestRateParameterSensitivity(timeAndS.getFirst());
for (int loopparam = 0; loopparam < nbParameters; loopparam++) {
result[loopparam] += timeAndS.getSecond() * sensi1Point[loopparam];
}
}
}
return result;
}
}