Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Gamma calculation with combined curve #1680

Merged
merged 1 commit into from May 8, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -13,18 +13,17 @@
import java.util.function.Function;
import java.util.stream.IntStream;

import com.google.common.collect.ImmutableList;
import com.google.common.primitives.Doubles;
import com.opengamma.strata.basics.currency.Currency;
import com.opengamma.strata.basics.index.Index;
import com.opengamma.strata.basics.index.PriceIndex;
import com.opengamma.strata.basics.index.RateIndex;
import com.opengamma.strata.collect.ArgChecker;
import com.opengamma.strata.collect.array.DoubleArray;
import com.opengamma.strata.collect.array.DoubleMatrix;
import com.opengamma.strata.collect.tuple.Pair;
import com.opengamma.strata.data.MarketDataName;
import com.opengamma.strata.market.curve.Curve;
import com.opengamma.strata.market.curve.NodalCurve;
import com.opengamma.strata.market.curve.ParallelShiftedCurve;
import com.opengamma.strata.market.param.CrossGammaParameterSensitivities;
import com.opengamma.strata.market.param.CrossGammaParameterSensitivity;
Expand Down Expand Up @@ -124,10 +123,24 @@ public CrossGammaParameterSensitivities calculateCrossGammaIntraCurve(
Currency currency = entry.getKey();
Curve curve = entry.getValue();
if (baseDelta.findSensitivity(curve.getName(), currency).isPresent()) {
NodalCurve nodalCurve = getNodalCurve(curve);
CrossGammaParameterSensitivity gammaSingle = computeGammaForCurve(
nodalCurve, currency, c -> immProv.toBuilder().discountCurve(currency, c).build(), sensitivitiesFn);
curve, currency, c -> immProv.toBuilder().discountCurve(currency, c).build(), sensitivitiesFn);
result = result.combinedWith(gammaSingle);
} else if (curve.split().size() > 1) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this just be a foreach loop of the split curves? Won't that handle the non-combined case?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The underlying curves should be checked only when a sensitivity object is not found, because CurrencyParameterSensitivity is not necessarily split.

ImmutableList<Curve> curves = curve.split();
int nCurves = curves.size();
for (int i = 0; i < nCurves; ++i) {
int currentIndex = i;
Curve underlyingCurve = curves.get(currentIndex);
if (baseDelta.findSensitivity(underlyingCurve.getName(), currency).isPresent()) {
CrossGammaParameterSensitivity gammaSingle = computeGammaForCurve(
underlyingCurve,
currency,
c -> immProv.toBuilder().discountCurve(currency, curve.withUnderlyingCurve(currentIndex, c)).build(),
sensitivitiesFn);
result = result.combinedWith(gammaSingle);
}
}
}
}
// forward curve
Expand All @@ -137,10 +150,24 @@ public CrossGammaParameterSensitivities calculateCrossGammaIntraCurve(
Currency currency = getCurrency(index);
Curve curve = entry.getValue();
if (baseDelta.findSensitivity(curve.getName(), currency).isPresent()) {
NodalCurve nodalCurve = getNodalCurve(curve);
CrossGammaParameterSensitivity gammaSingle = computeGammaForCurve(
nodalCurve, currency, c -> immProv.toBuilder().indexCurve(index, c).build(), sensitivitiesFn);
curve, currency, c -> immProv.toBuilder().indexCurve(index, c).build(), sensitivitiesFn);
result = result.combinedWith(gammaSingle);
} else if (curve.split().size() > 1) {
ImmutableList<Curve> curves = curve.split();
int nCurves = curves.size();
for (int i = 0; i < nCurves; ++i) {
int currentIndex = i;
Curve underlyingCurve = curves.get(currentIndex);
if (baseDelta.findSensitivity(underlyingCurve.getName(), currency).isPresent()) {
CrossGammaParameterSensitivity gammaSingle = computeGammaForCurve(
underlyingCurve,
currency,
c -> immProv.toBuilder().indexCurve(index, curve.withUnderlyingCurve(currentIndex, c)).build(),
sensitivitiesFn);
result = result.combinedWith(gammaSingle);
}
}
}
}
}
Expand Down Expand Up @@ -175,10 +202,24 @@ public CrossGammaParameterSensitivities calculateCrossGammaCrossCurve(
Currency currency = entry.getKey();
Curve curve = entry.getValue();
if (baseDelta.findSensitivity(curve.getName(), currency).isPresent()) {
NodalCurve nodalCurve = getNodalCurve(curve);
CrossGammaParameterSensitivity gammaSingle = computeGammaForCurve(
baseDeltaSingle, nodalCurve, c -> immProv.toBuilder().discountCurve(currency, c).build(), sensitivitiesFn);
baseDeltaSingle, curve, c -> immProv.toBuilder().discountCurve(currency, c).build(), sensitivitiesFn);
resultInner = resultInner.combinedWith(gammaSingle);
} else if (curve.split().size() > 1) {
ImmutableList<Curve> curves = curve.split();
int nCurves = curves.size();
for (int i = 0; i < nCurves; ++i) {
int currentIndex = i;
Curve underlyingCurve = curves.get(currentIndex);
if (baseDelta.findSensitivity(underlyingCurve.getName(), currency).isPresent()) {
CrossGammaParameterSensitivity gammaSingle = computeGammaForCurve(
baseDeltaSingle,
underlyingCurve,
c -> immProv.toBuilder().discountCurve(currency, curve.withUnderlyingCurve(currentIndex, c)).build(),
sensitivitiesFn);
resultInner = resultInner.combinedWith(gammaSingle);
}
}
}
}
// forward curve
Expand All @@ -188,10 +229,24 @@ public CrossGammaParameterSensitivities calculateCrossGammaCrossCurve(
Currency currency = getCurrency(index);
Curve curve = entry.getValue();
if (baseDelta.findSensitivity(curve.getName(), currency).isPresent()) {
NodalCurve nodalCurve = getNodalCurve(curve);
CrossGammaParameterSensitivity gammaSingle = computeGammaForCurve(
baseDeltaSingle, nodalCurve, c -> immProv.toBuilder().indexCurve(index, c).build(), sensitivitiesFn);
baseDeltaSingle, curve, c -> immProv.toBuilder().indexCurve(index, c).build(), sensitivitiesFn);
resultInner = resultInner.combinedWith(gammaSingle);
} else if (curve.split().size() > 1) {
ImmutableList<Curve> curves = curve.split();
int nCurves = curves.size();
for (int i = 0; i < nCurves; ++i) {
int currentIndex = i;
Curve underlyingCurve = curves.get(currentIndex);
if (baseDelta.findSensitivity(underlyingCurve.getName(), currency).isPresent()) {
CrossGammaParameterSensitivity gammaSingle = computeGammaForCurve(
baseDeltaSingle,
underlyingCurve,
c -> immProv.toBuilder().indexCurve(index, curve.withUnderlyingCurve(currentIndex, c)).build(),
sensitivitiesFn);
resultInner = resultInner.combinedWith(gammaSingle);
}
}
}
}
}
Expand All @@ -201,11 +256,6 @@ public CrossGammaParameterSensitivities calculateCrossGammaCrossCurve(
}

//-------------------------------------------------------------------------
private NodalCurve getNodalCurve(Curve curve) {
ArgChecker.isTrue(curve instanceof NodalCurve, "underlying curve must be NodalCurve");
return (NodalCurve) curve;
}

private Currency getCurrency(Index index) {
if (index instanceof RateIndex) {
return ((RateIndex) index).getCurrency();
Expand All @@ -215,53 +265,55 @@ private Currency getCurrency(Index index) {
throw new IllegalArgumentException("unsupported index");
}

// compute the second order sensitivity to nodalCurve
// compute the second order sensitivity to Curve
CrossGammaParameterSensitivity computeGammaForCurve(
NodalCurve nodalCurve,
Curve curve,
Currency sensitivityCurrency,
Function<Curve, ImmutableRatesProvider> ratesProviderFn,
Function<ImmutableRatesProvider, CurrencyParameterSensitivities> sensitivitiesFn) {

Function<DoubleArray, DoubleArray> function = new Function<DoubleArray, DoubleArray>() {
@Override
public DoubleArray apply(DoubleArray t) {
NodalCurve newCurve = nodalCurve.withYValues(t);
Curve newCurve = replaceParameters(curve, t);
ImmutableRatesProvider newRates = ratesProviderFn.apply(newCurve);
CurrencyParameterSensitivities sensiMulti = sensitivitiesFn.apply(newRates);
return sensiMulti.getSensitivity(newCurve.getName(), sensitivityCurrency).getSensitivity();
}
};
DoubleMatrix sensi = fd.differentiate(function).apply(nodalCurve.getYValues());
List<ParameterMetadata> metadata = IntStream.range(0, nodalCurve.getParameterCount())
.mapToObj(i -> nodalCurve.getParameterMetadata(i))
int nParams = curve.getParameterCount();
DoubleMatrix sensi = fd.differentiate(function).apply(DoubleArray.of(nParams, n -> curve.getParameter(n)));
List<ParameterMetadata> metadata = IntStream.range(0, nParams)
.mapToObj(i -> curve.getParameterMetadata(i))
.collect(toImmutableList());
return CrossGammaParameterSensitivity.of(nodalCurve.getName(), metadata, sensitivityCurrency, sensi);
return CrossGammaParameterSensitivity.of(curve.getName(), metadata, sensitivityCurrency, sensi);
}

// computes the sensitivity of baseDeltaSingle to nodalCurve
// computes the sensitivity of baseDeltaSingle to Curve
CrossGammaParameterSensitivity computeGammaForCurve(
CurrencyParameterSensitivity baseDeltaSingle,
NodalCurve nodalCurve,
Curve curve,
Function<Curve, ImmutableRatesProvider> ratesProviderFn,
Function<ImmutableRatesProvider, CurrencyParameterSensitivities> sensitivitiesFn) {

Function<DoubleArray, DoubleArray> function = new Function<DoubleArray, DoubleArray>() {
@Override
public DoubleArray apply(DoubleArray t) {
NodalCurve newCurve = nodalCurve.withYValues(t);
Curve newCurve = replaceParameters(curve, t);
ImmutableRatesProvider newRates = ratesProviderFn.apply(newCurve);
CurrencyParameterSensitivities sensiMulti = sensitivitiesFn.apply(newRates);
return sensiMulti.getSensitivity(baseDeltaSingle.getMarketDataName(), baseDeltaSingle.getCurrency()).getSensitivity();
}
};
DoubleMatrix sensi = fd.differentiate(function).apply(nodalCurve.getYValues());
List<ParameterMetadata> metadata = IntStream.range(0, nodalCurve.getParameterCount())
.mapToObj(i -> nodalCurve.getParameterMetadata(i))
int nParams = curve.getParameterCount();
DoubleMatrix sensi = fd.differentiate(function).apply(DoubleArray.of(nParams, n -> curve.getParameter(n)));
List<ParameterMetadata> metadata = IntStream.range(0, nParams)
.mapToObj(i -> curve.getParameterMetadata(i))
.collect(toImmutableList());
return CrossGammaParameterSensitivity.of(
baseDeltaSingle.getMarketDataName(),
baseDeltaSingle.getParameterMetadata(),
nodalCurve.getName(),
curve.getName(),
metadata,
baseDeltaSingle.getCurrency(),
sensi);
Expand Down Expand Up @@ -315,6 +367,11 @@ public CurrencyParameterSensitivity calculateSemiParallelGamma(
return curve.createParameterSensitivity(curveCurrency, gamma);
}

//-------------------------------------------------------------------------
private Curve replaceParameters(Curve curve, DoubleArray newParameters) {
return curve.withPerturbation((i, v, m) -> newParameters.get(i));
}

//-------------------------------------------------------------------------
/**
* Inner class to compute the delta for a given parallel shift of the curve.
Expand Down
Expand Up @@ -25,6 +25,7 @@
import com.opengamma.strata.basics.currency.FxMatrix;
import com.opengamma.strata.collect.array.DoubleArray;
import com.opengamma.strata.collect.timeseries.LocalDateDoubleTimeSeries;
import com.opengamma.strata.market.curve.CombinedCurve;
import com.opengamma.strata.market.curve.Curve;
import com.opengamma.strata.market.curve.CurveMetadata;
import com.opengamma.strata.market.curve.CurveName;
Expand Down Expand Up @@ -199,6 +200,16 @@ public static final ImmutableRatesProvider multiUsd(LocalDate valDate) {
.timeSeries(US_CPI_U, PRICE_INDEX_TS)
.build();

public static final ImmutableRatesProvider MULTI_CPI_USD_COMBINED = ImmutableRatesProvider.builder(VAL_DATE_2014_01_22)
.fxRateProvider(FX_MATRIX_USD)
.discountCurve(USD, CombinedCurve.of(USD_L3, USD_DSC))
.overnightIndexCurve(USD_FED_FUND, CombinedCurve.of(USD_L3, USD_DSC))
.iborIndexCurve(USD_LIBOR_3M, USD_L3)
.iborIndexCurve(USD_LIBOR_6M, CombinedCurve.of(USD_L3, USD_L6))
.priceIndexCurve(US_CPI_U, US_CPI_U_CURVE)
.timeSeries(US_CPI_U, PRICE_INDEX_TS)
.build();

//-------------------------------------------------------------------------
// ===== GBP =====

Expand Down