/**
* Copyright (C) 2012 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.analytics.financial.provider.sensitivity.multicurve;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.apache.commons.lang.ObjectUtils;
import com.opengamma.analytics.financial.forex.method.FXMatrix;
import com.opengamma.analytics.math.matrix.DoubleMatrix1D;
import com.opengamma.analytics.math.matrix.MatrixAlgebra;
import com.opengamma.analytics.math.matrix.MatrixAlgebraFactory;
import com.opengamma.util.ArgumentChecker;
import com.opengamma.util.money.Currency;
import com.opengamma.util.tuple.Pair;
import com.opengamma.util.tuple.Pairs;
/**
* Class containing the sensitivity of the present value to specific parameters or market quotes and methods for manipulating these data.
* The vector of sensitivities is stored with reference to a curve name and currency pair, with the sensitivity amounts assumed to be in the currency of the pair.
*/
public class MultipleCurrencyParameterSensitivity {
/**
* The map containing the sensitivity. The map links a pair of curve name and currency to a vector of sensitivities (sensitivities to parameters/inputs).
* The sensitivity is expressed in the currency of the pair.
*/
private final LinkedHashMap<Pair<String, Currency>, DoubleMatrix1D> _sensitivity;
/**
* Default constructor, creating an empty LinkedHashMap for the sensitivity.
*/
public MultipleCurrencyParameterSensitivity() {
_sensitivity = new LinkedHashMap<>();
}
/**
* Constructor taking a map. A new map is created.
* @param sensitivity The map with the sensitivities, not null. The map is copied.
*/
public MultipleCurrencyParameterSensitivity(final LinkedHashMap<Pair<String, Currency>, DoubleMatrix1D> sensitivity) {
ArgumentChecker.notNull(sensitivity, "sensitivity");
_sensitivity = new LinkedHashMap<>(sensitivity);
}
/**
* Static constructor from a map. A new map is created.
* @param sensitivity A map of name / currency pairs to vector of sensitivities, not null
* @return An new instance of ParameterSensitivity
*/
public static MultipleCurrencyParameterSensitivity of(final LinkedHashMap<Pair<String, Currency>, DoubleMatrix1D> sensitivity) {
ArgumentChecker.notNull(sensitivity, "sensitivity");
return new MultipleCurrencyParameterSensitivity(sensitivity);
}
/**
* Constructor from a simple sensitivity and a currency.
* @param single The Simple parameter sensitivity
* @param ccy The currency.
* @return The multiple currency sensitivity.
*/
public static MultipleCurrencyParameterSensitivity of(final SimpleParameterSensitivity single, final Currency ccy) {
final LinkedHashMap<Pair<String, Currency>, DoubleMatrix1D> sensi = new LinkedHashMap<>();
for (final String name : single.getAllNames()) {
sensi.put(Pairs.of(name, ccy), single.getSensitivity(name));
}
return MultipleCurrencyParameterSensitivity.of(sensi);
}
/**
* Create a copy of the sensitivity and add a given named sensitivity to it. If the name / currency pair is in the map, the two sensitivity matrices are added.
* Otherwise, a new entry is put into the map
* @param nameCcy The name and the currency, not null
* @param sensitivity The sensitivity to add, not null
* @return The total sensitivity.
*/
public MultipleCurrencyParameterSensitivity plus(final Pair<String, Currency> nameCcy, final DoubleMatrix1D sensitivity) {
ArgumentChecker.notNull(nameCcy, "Name/currency");
ArgumentChecker.notNull(sensitivity, "Matrix");
final MatrixAlgebra algebra = MatrixAlgebraFactory.COMMONS_ALGEBRA;
final LinkedHashMap<Pair<String, Currency>, DoubleMatrix1D> result = new LinkedHashMap<>();
result.putAll(_sensitivity);
if (result.containsKey(nameCcy)) {
result.put(nameCcy, (DoubleMatrix1D) algebra.add(result.get(nameCcy), sensitivity));
} else {
result.put(nameCcy, sensitivity);
}
return new MultipleCurrencyParameterSensitivity(result);
}
/**
* Create a copy of the sensitivity and add a given sensitivity to it.
* @param other The sensitivity to add.
* @return The total sensitivity.
*/
public MultipleCurrencyParameterSensitivity plus(final MultipleCurrencyParameterSensitivity other) {
ArgumentChecker.notNull(other, "Sensitivity to add");
final MatrixAlgebra algebra = MatrixAlgebraFactory.COMMONS_ALGEBRA;
final LinkedHashMap<Pair<String, Currency>, DoubleMatrix1D> result = new LinkedHashMap<>();
result.putAll(_sensitivity);
for (final Map.Entry<Pair<String, Currency>, DoubleMatrix1D> entry : other.getSensitivities().entrySet()) {
final Pair<String, Currency> nameCcy = entry.getKey();
if (result.containsKey(nameCcy)) {
result.put(nameCcy, (DoubleMatrix1D) algebra.add(result.get(nameCcy), entry.getValue()));
} else {
result.put(nameCcy, entry.getValue());
}
}
return new MultipleCurrencyParameterSensitivity(result);
}
/**
* Create a copy of the object with all the sensitivities multiplied by a common factor.
* @param factor The factor.
* @return The multiplied sensitivity.
*/
public MultipleCurrencyParameterSensitivity multipliedBy(final double factor) {
final MatrixAlgebra algebra = MatrixAlgebraFactory.COMMONS_ALGEBRA;
final LinkedHashMap<Pair<String, Currency>, DoubleMatrix1D> result = new LinkedHashMap<>();
for (final Pair<String, Currency> nameCcy : _sensitivity.keySet()) {
result.put(nameCcy, (DoubleMatrix1D) algebra.scale(_sensitivity.get(nameCcy), factor));
}
return new MultipleCurrencyParameterSensitivity(result);
}
/**
* Create a new parameter sensitivity with the new sensitivity with all the values in a common currency.
* @param fxMatrix The matrix with relevant exchange rates, not null
* @param ccy The currency in which the sensitivity is converted, not null
* @return The converted sensitivity.
*/
public MultipleCurrencyParameterSensitivity converted(final FXMatrix fxMatrix, final Currency ccy) {
ArgumentChecker.notNull(ccy, "Currency");
ArgumentChecker.notNull(fxMatrix, "FX Matrix");
MultipleCurrencyParameterSensitivity result = new MultipleCurrencyParameterSensitivity();
final MatrixAlgebra algebra = MatrixAlgebraFactory.COMMONS_ALGEBRA;
for (final Map.Entry<Pair<String, Currency>, DoubleMatrix1D> entry : _sensitivity.entrySet()) {
final Pair<String, Currency> nameCcy = entry.getKey();
final double fxRate = fxMatrix.getFxRate(nameCcy.getSecond(), ccy);
final Pair<String, Currency> nameCcyNew = Pairs.of(nameCcy.getFirst(), ccy);
final DoubleMatrix1D sensitivityNew = (DoubleMatrix1D) algebra.scale(entry.getValue(), fxRate);
result = result.plus(nameCcyNew, sensitivityNew);
}
return result;
}
/**
* Returns the sensitivities wrapped in an unmodifiable map
* @return The sensitivities
*/
public Map<Pair<String, Currency>, DoubleMatrix1D> getSensitivities() {
return Collections.unmodifiableMap(_sensitivity);
}
/**
* Returns the sensitivities for a particular curve name. An unmodifiable map
* of Currency -> Sensitivities will be returned. Note that this implementation
* will not be efficient if there are a large number of curves.
*
* @param name the name of the curve to get sensitivities for
* @return map of sensitivities by currency
*/
public Map<Currency, DoubleMatrix1D> getSensitivityByName(String name) {
Map<Currency, DoubleMatrix1D> matches = new HashMap<>();
for (Entry<Pair<String, Currency>, DoubleMatrix1D> entry : _sensitivity.entrySet()) {
final Pair<String, Currency> curveName = entry.getKey();
if (curveName.getFirst().equals(name)) {
matches.put(curveName.getSecond(), entry.getValue());
}
}
return Collections.unmodifiableMap(matches);
}
/**
* Returns the sensitivity for a given name/currency pair.
* @param nameCcy The name and the currency, not null
* @return The sensitivity.
*/
public DoubleMatrix1D getSensitivity(final Pair<String, Currency> nameCcy) {
ArgumentChecker.notNull(nameCcy, "Name");
return _sensitivity.get(nameCcy);
}
/**
* Returns the sensitivity for a given name.
* @param name The name.
* @param ccy The currency.
* @return The sensitivity.
*/
public DoubleMatrix1D getSensitivity(final String name, final Currency ccy) {
ArgumentChecker.notNull(name, "Name");
ArgumentChecker.notNull(ccy, "Currency");
return _sensitivity.get(Pairs.of(name, ccy));
}
/**
* Returns a map<Pair<String, Currency>, Double> with the total sensitivity with respect to each curve/currency.
* @return The map.
*/
public Map<Pair<String, Currency>, Double> totalSensitivityByCurveCurrency() {
final HashMap<Pair<String, Currency>, Double> s = new HashMap<>();
for (final Entry<Pair<String, Currency>, DoubleMatrix1D> entry : _sensitivity.entrySet()) {
double total = 0.0;
for (int loopi = 0; loopi < entry.getValue().getNumberOfElements(); loopi++) {
total += entry.getValue().getEntry(loopi);
}
s.put(entry.getKey(), total);
}
return s;
}
/**
* Returns the total sensitivity to all curves, in a given currency.
* @param fxMatrix The FX matrix will the exchange rates.
* @param ccy The currency for the conversion.
* @return The sensitivity.
*/
public double totalSensitivity(final FXMatrix fxMatrix, final Currency ccy) {
double total = 0.0;
for (final Entry<Pair<String, Currency>, DoubleMatrix1D> entry : _sensitivity.entrySet()) {
final double fx = fxMatrix.getFxRate(entry.getKey().getSecond(), ccy);
for (int loopi = 0; loopi < entry.getValue().getNumberOfElements(); loopi++) {
total += entry.getValue().getEntry(loopi) * fx;
}
}
return total;
}
/**
* Returns a set with all the curve names.
* @return The set of names.
*/
public Set<Pair<String, Currency>> getAllNamesCurrency() {
return _sensitivity.keySet();
}
@Override
public String toString() {
return _sensitivity.toString();
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + _sensitivity.hashCode();
return result;
}
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof MultipleCurrencyParameterSensitivity)) {
return false;
}
final MultipleCurrencyParameterSensitivity other = (MultipleCurrencyParameterSensitivity) obj;
if (!ObjectUtils.equals(_sensitivity, other._sensitivity)) {
return false;
}
return true;
}
}