/**
* Copyright (C) 2013 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.analytics.tutorial.analysis.swap;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Arrays;
import org.testng.annotations.Test;
import org.threeten.bp.Period;
import org.threeten.bp.ZonedDateTime;
import com.opengamma.analytics.financial.datasets.CalendarTarget;
import com.opengamma.analytics.financial.instrument.index.GeneratorSwapFixedIbor;
import com.opengamma.analytics.financial.instrument.index.GeneratorSwapFixedIborMaster;
import com.opengamma.analytics.financial.instrument.index.IborIndex;
import com.opengamma.analytics.financial.instrument.index.IndexIborMaster;
import com.opengamma.analytics.financial.instrument.swap.SwapFixedIborDefinition;
import com.opengamma.analytics.financial.interestrate.payments.derivative.Coupon;
import com.opengamma.analytics.financial.interestrate.swap.derivative.SwapFixedCoupon;
import com.opengamma.analytics.financial.model.interestrate.curve.YieldAndDiscountCurve;
import com.opengamma.analytics.financial.model.interestrate.curve.YieldCurve;
import com.opengamma.analytics.financial.provider.calculator.discounting.CrossGammaSingleCurveCalculator;
import com.opengamma.analytics.financial.provider.calculator.discounting.PresentValueCurveSensitivityDiscountingCalculator;
import com.opengamma.analytics.financial.provider.calculator.discounting.PresentValueDiscountingCalculator;
import com.opengamma.analytics.financial.provider.curve.CurveBuildingBlockBundle;
import com.opengamma.analytics.financial.provider.description.MulticurveProviderDiscountDataSets;
import com.opengamma.analytics.financial.provider.description.interestrate.MulticurveProviderDiscount;
import com.opengamma.analytics.financial.provider.description.interestrate.ParameterProviderInterface;
import com.opengamma.analytics.financial.provider.sensitivity.multicurve.MultipleCurrencyParameterSensitivity;
import com.opengamma.analytics.financial.provider.sensitivity.parameter.ParameterSensitivityParameterCalculator;
import com.opengamma.analytics.financial.schedule.ScheduleCalculator;
import com.opengamma.analytics.math.curve.InterpolatedDoublesCurve;
import com.opengamma.analytics.math.matrix.DoubleMatrix1D;
import com.opengamma.analytics.math.matrix.DoubleMatrix2D;
import com.opengamma.analytics.math.matrix.OGMatrixAlgebra;
import com.opengamma.analytics.tutorial.datasets.AnalysisMarketDataEURJun13Sets;
import com.opengamma.financial.convention.calendar.ExceptionCalendar;
import com.opengamma.financial.convention.calendar.MondayToFridayCalendar;
import com.opengamma.util.ArgumentChecker;
import com.opengamma.util.money.Currency;
import com.opengamma.util.time.DateUtils;
import com.opengamma.util.tuple.Pair;
/**
* Analysis of cross-gamma to zero-coupon and market rates.
*/
public class SwapGammaSingleCurveProfitAnalysis {
private static final ExceptionCalendar TARGET = new CalendarTarget("TARGET");
private static final ExceptionCalendar LON = new MondayToFridayCalendar("LON");
private static final ZonedDateTime REFERENCE_DATE = DateUtils.getUTCDate(2013, 6, 13);
private static final ZonedDateTime SPOT_DATE = ScheduleCalculator.getAdjustedDate(REFERENCE_DATE, 2, TARGET);
private static final ZonedDateTime SPOT_DATE_GBP = ScheduleCalculator.getAdjustedDate(REFERENCE_DATE, 0, LON);
private static final GeneratorSwapFixedIborMaster MASTER_SWAP_FIXED_IBOR = GeneratorSwapFixedIborMaster.getInstance();
private static final GeneratorSwapFixedIbor EUR1YEURIBOR3M = MASTER_SWAP_FIXED_IBOR.getGenerator("EUR1YEURIBOR3M", TARGET);
private static final GeneratorSwapFixedIbor GBP6MLIBOR6M = MASTER_SWAP_FIXED_IBOR.getGenerator("GBP6MLIBOR6M", TARGET);
private static final IndexIborMaster MASTER_IBOR_INDEX = IndexIborMaster.getInstance();
private static final IborIndex EURIBOR3M = MASTER_IBOR_INDEX.getIndex("EURIBOR3M");
private static final Currency EUR = EURIBOR3M.getCurrency();
private static final IborIndex GBPLIBOR6M = MASTER_IBOR_INDEX.getIndex("GBPLIBOR6M");
private static final Period TENOR_START = Period.ofMonths(150);
private static final Period TENOR_SWAP = Period.ofYears(5);
private static final boolean IS_PAYER = true;
private static final double NOTIONAL = 1.0E6; // 1m
private static final ZonedDateTime START_DATE = ScheduleCalculator.getAdjustedDate(SPOT_DATE, TENOR_START, EURIBOR3M, TARGET);
private static final ZonedDateTime START_DATE_GBP = ScheduleCalculator.getAdjustedDate(SPOT_DATE_GBP, TENOR_START, GBPLIBOR6M, TARGET);
private static final SwapFixedIborDefinition SWAP_EUR_DEFINITION = SwapFixedIborDefinition.from(START_DATE, TENOR_SWAP, EUR1YEURIBOR3M, NOTIONAL, 0.02, IS_PAYER);
private static final SwapFixedCoupon<Coupon> SWAP_EUR = SWAP_EUR_DEFINITION.toDerivative(REFERENCE_DATE);
private static final SwapFixedIborDefinition SWAP_GBP_DEFINITION = SwapFixedIborDefinition.from(START_DATE_GBP, TENOR_SWAP, GBP6MLIBOR6M, NOTIONAL, 0.02, IS_PAYER);
private static final SwapFixedCoupon<Coupon> SWAP_GBP = SWAP_GBP_DEFINITION.toDerivative(REFERENCE_DATE);
private static final PresentValueDiscountingCalculator PVDC = PresentValueDiscountingCalculator.getInstance();
private static final PresentValueCurveSensitivityDiscountingCalculator PVCSDC = PresentValueCurveSensitivityDiscountingCalculator.getInstance();
private static final ParameterSensitivityParameterCalculator<ParameterProviderInterface> PSC = new ParameterSensitivityParameterCalculator<>(PVCSDC);
private static final Pair<MulticurveProviderDiscount, CurveBuildingBlockBundle> MULTICURVE_PAIR_0 = AnalysisMarketDataEURJun13Sets.getMulticurveEUR();
private static final Pair<MulticurveProviderDiscount, CurveBuildingBlockBundle> SINGLECURVE_PAIR_0 = AnalysisMarketDataEURJun13Sets.getSingleCurveEUR();
private static final MulticurveProviderDiscount SINGLECURVE_GBP = MulticurveProviderDiscountDataSets.createSinglecurveGbp();
private static final String[] CURVE_NAME = new String[2];
static {
CURVE_NAME[0] = MULTICURVE_PAIR_0.getFirst().getName(EUR);
CURVE_NAME[1] = MULTICURVE_PAIR_0.getFirst().getName(EURIBOR3M);
}
private static final double BP1 = 1.0E-4;
private static final double SHIFT = 1 * BP1;
private static final OGMatrixAlgebra ALGEBRA = new OGMatrixAlgebra();
private static final CrossGammaSingleCurveCalculator GC = new CrossGammaSingleCurveCalculator(BP1, PVCSDC);
private static final int NB_NODE_EUR = AnalysisMarketDataEURJun13Sets.getCurveEURNumberNodeForward();
private static final DoubleMatrix2D GAMMA_EUR = GC.calculateCrossGamma(SWAP_EUR, SINGLECURVE_PAIR_0.getFirst());
private static final double[] GAMMA_SUM_EUR = new double[GAMMA_EUR.getNumberOfColumns()];
static {
for (int loopcol = 0; loopcol < GAMMA_EUR.getNumberOfColumns(); loopcol++) {
for (int looprow = 0; looprow < GAMMA_EUR.getNumberOfRows(); looprow++) {
GAMMA_SUM_EUR[loopcol] += GAMMA_EUR.getEntry(looprow, loopcol);
}
}
}
private static final DoubleMatrix2D GAMMA_GBP = GC.calculateCrossGamma(SWAP_GBP, SINGLECURVE_GBP);
private static final double[] GAMMA_SUM_GBP = new double[GAMMA_GBP.getNumberOfColumns()];
private static final double GAMMA_TOT_GBP;
static {
double gammaTot = 0;
for (int loopcol = 0; loopcol < GAMMA_GBP.getNumberOfColumns(); loopcol++) {
for (int looprow = 0; looprow < GAMMA_GBP.getNumberOfRows(); looprow++) {
GAMMA_SUM_GBP[loopcol] += GAMMA_GBP.getEntry(looprow, loopcol);
}
gammaTot += GAMMA_SUM_GBP[loopcol];
}
GAMMA_TOT_GBP = gammaTot;
}
private static final int NB_NODE_GBP = GAMMA_GBP.getNumberOfColumns();
@Test(enabled = false)
public void crossGammaZeroSingleExport() {
try {
final FileWriter writer = new FileWriter("swap-x-gamma-single.csv");
for (int loopnodei = 0; loopnodei < NB_NODE_EUR; loopnodei++) {
String line = "";
for (int loopnode2 = 0; loopnode2 < NB_NODE_EUR; loopnode2++) {
line = line + "," + GAMMA_EUR.getEntry(loopnodei, loopnode2);
}
writer.append(line + "0 \n");
}
writer.flush();
writer.close();
} catch (final IOException e) {
e.printStackTrace();
}
}
@SuppressWarnings("unused")
@Test(enabled = false)
public void crossGammaDiagonalComp() {
double[] marketMvtArray = new double[NB_NODE_EUR];
Arrays.fill(marketMvtArray, 0.0010);
marketMvtArray[5] = -0.0020;
marketMvtArray[7] = -0.0020;
marketMvtArray[9] = -0.0020;
marketMvtArray[11] = -0.0020;
DoubleMatrix2D marketMvt = new DoubleMatrix2D(new double[][] {marketMvtArray });
double plTotal = (Double) ALGEBRA.multiply(ALGEBRA.multiply(marketMvt, GAMMA_EUR), ALGEBRA.getTranspose(marketMvt)).getEntry(0, 0);
double plDiag = 0;
for (int loopdiag = 0; loopdiag < NB_NODE_EUR; loopdiag++) {
plDiag += GAMMA_EUR.getEntry(loopdiag, loopdiag) * marketMvtArray[loopdiag] * marketMvtArray[loopdiag];
}
double plCol = 0;
for (int loopcol = 0; loopcol < NB_NODE_EUR; loopcol++) {
plCol += GAMMA_SUM_EUR[loopcol] * marketMvtArray[loopcol] * marketMvtArray[loopcol];
}
}
@SuppressWarnings("unused")
@Test(enabled = false)
public void crossGammaDiagonalCompGBP() {
double[] marketMvtArray = new double[NB_NODE_GBP];
Arrays.fill(marketMvtArray, 0.0001); // 1bp
DoubleMatrix2D marketMvt = new DoubleMatrix2D(new double[][] {marketMvtArray });
double plTotal = (Double) ALGEBRA.multiply(ALGEBRA.multiply(marketMvt, GAMMA_GBP), ALGEBRA.getTranspose(marketMvt)).getEntry(0, 0);
double plDiag = 0;
for (int loopdiag = 0; loopdiag < NB_NODE_GBP; loopdiag++) {
plDiag += GAMMA_GBP.getEntry(loopdiag, loopdiag) * marketMvtArray[loopdiag] * marketMvtArray[loopdiag];
}
int t = 0;
}
/**
* Uses historical data to estimate the difference between diagonal Gamma, sum of column gamma,
* parallel gamma and full cross-gamma.
* The result file is exported in the root directory of OG-Analytics.
* @throws IOException
*/
@Test(enabled = false)
public void crossGammaDiagonalCompGbpHts() throws IOException {
final String sheetFilePath = "src/test/resources/analysis/historical_time_series/curve-changes-gbp-10y.csv";
double[][] shift = GammaAnalysisUtils.parseShifts(sheetFilePath, BP1);
int nbScenarios = shift.length;
double[] plGammaTotal = new double[nbScenarios];
double[] plGammaDiag = new double[nbScenarios];
double[] plGammaCol = new double[nbScenarios];
double[] plGammaPar = new double[nbScenarios];
for (int loopsc = 0; loopsc < nbScenarios; loopsc++) {
DoubleMatrix2D marketMvt = new DoubleMatrix2D(new double[][] {shift[loopsc] });
plGammaTotal[loopsc] = (Double) ALGEBRA.multiply(ALGEBRA.multiply(marketMvt, GAMMA_GBP), ALGEBRA.getTranspose(marketMvt)).getEntry(0, 0) * 0.5;
for (int loopdiag = 0; loopdiag < NB_NODE_GBP; loopdiag++) {
plGammaDiag[loopsc] += GAMMA_GBP.getEntry(loopdiag, loopdiag) * shift[loopsc][loopdiag] * shift[loopsc][loopdiag] * 0.5;
}
for (int loopcol = 0; loopcol < NB_NODE_GBP; loopcol++) {
plGammaCol[loopsc] += GAMMA_SUM_GBP[loopcol] * shift[loopsc][loopcol] * shift[loopsc][loopcol] * 0.5;
}
double shiftAverage = 0;
for (int loopcol = 0; loopcol < NB_NODE_GBP; loopcol++) {
shiftAverage += shift[loopsc][loopcol];
}
shiftAverage /= NB_NODE_GBP;
plGammaPar[loopsc] = GAMMA_TOT_GBP * shiftAverage * shiftAverage * 0.5;
}
String fileName = "swap-x-gamma-pl-" + TENOR_START.toString() + "x" + TENOR_SWAP.toString() + ".csv";
try {
final FileWriter writer = new FileWriter(fileName);
for (int loopsc = 0; loopsc < nbScenarios; loopsc++) {
String line = plGammaTotal[loopsc] + "," + plGammaDiag[loopsc] + "," + plGammaCol[loopsc] + "," + plGammaPar[loopsc] + " \n";
writer.append(line);
}
writer.flush();
writer.close();
} catch (final IOException e) {
e.printStackTrace();
}
}
@Test(enabled = false)
public void crossGammaPerformance() {
long startTime, endTime;
final int nbTest = 5000;
final int nbTest2 = 1000;
startTime = System.currentTimeMillis();
for (int looptest = 0; looptest < nbTest; looptest++) {
SWAP_GBP.accept(PVDC, SINGLECURVE_GBP);
}
endTime = System.currentTimeMillis();
System.out.println("PresentValue: " + nbTest + " cross-gamma (" + NB_NODE_GBP + " nodes): " + (endTime - startTime) + " ms");
// Performance note: Present value: 11-Jul-2014: On Mac Pro 3.2 GHz Quad-Core Intel Xeon: 40 ms for 5000 swaps.
startTime = System.currentTimeMillis();
for (int looptest = 0; looptest < nbTest; looptest++) {
SWAP_GBP.accept(PVCSDC, SINGLECURVE_GBP);
}
endTime = System.currentTimeMillis();
System.out.println("PresentValueCurveSensitivity: " + nbTest + " cross-gamma (" + NB_NODE_GBP + " nodes): " + (endTime - startTime) + " ms");
// Performance note: Curve sensitivity: 11-Jul-2014: On Mac Pro 3.2 GHz Quad-Core Intel Xeon: 105 ms for 5000 swaps.
startTime = System.currentTimeMillis();
for (int looptest = 0; looptest < nbTest; looptest++) {
GC.calculateCrossGamma(SWAP_GBP, SINGLECURVE_GBP);
}
endTime = System.currentTimeMillis();
System.out.println("CrossGammaSingleCurveCalculator: " + nbTest + " cross-gamma (" + NB_NODE_GBP + " nodes): " + (endTime - startTime) + " ms");
// Performance note: Cross-gamma: 11-Jul-2014: On Mac Pro 3.2 GHz Quad-Core Intel Xeon: 5400 ms for 5000 swaps.
startTime = System.currentTimeMillis();
for (int looptest = 0; looptest < nbTest2; looptest++) {
String name = SINGLECURVE_GBP.getAllNames().iterator().next();
Currency ccy = SINGLECURVE_GBP.getCurrencyForName(name).get(0);
YieldAndDiscountCurve curve = SINGLECURVE_GBP.getCurve(name);
ArgumentChecker.isTrue(curve instanceof YieldCurve, "curve should be YieldCurve");
YieldCurve yieldCurve = (YieldCurve) curve;
ArgumentChecker.isTrue(yieldCurve.getCurve() instanceof InterpolatedDoublesCurve, "Yield curve should be based on InterpolatedDoublesCurve");
InterpolatedDoublesCurve interpolatedCurve = (InterpolatedDoublesCurve) yieldCurve.getCurve();
double[] y = interpolatedCurve.getYDataAsPrimitive();
double[] x = interpolatedCurve.getXDataAsPrimitive();
double[][] gammaExpected = new double[NB_NODE_GBP][NB_NODE_GBP];
for (int i = 0; i < NB_NODE_GBP; i++) {
for (int j = i; j < NB_NODE_GBP; j++) {
double[][] pv = new double[2][2];
for (int pmi = 0; pmi < 2; pmi++) {
for (int pmj = 0; pmj < 2; pmj++) {
final double[] yieldBumpedPP = y.clone();
yieldBumpedPP[i] += ((pmi == 0) ? SHIFT : -SHIFT);
yieldBumpedPP[j] += ((pmj == 0) ? SHIFT : -SHIFT);
final YieldAndDiscountCurve curveBumped = new YieldCurve(name,
new InterpolatedDoublesCurve(x, yieldBumpedPP, interpolatedCurve.getInterpolator(), true));
MulticurveProviderDiscount providerBumped = new MulticurveProviderDiscount();
for (Currency loopccy : SINGLECURVE_GBP.getCurrencies()) {
providerBumped.setCurve(loopccy, curveBumped);
}
for (IborIndex loopibor : SINGLECURVE_GBP.getIndexesIbor()) {
providerBumped.setCurve(loopibor, curveBumped);
}
pv[pmi][pmj] = SWAP_GBP.accept(PVDC, providerBumped).getAmount(ccy);
}
}
gammaExpected[i][j] = (pv[0][0] - pv[1][0] - pv[0][1] + pv[1][1]) / (2 * SHIFT * 2 * SHIFT);
gammaExpected[j][i] = gammaExpected[i][j];
}
}
}
endTime = System.currentTimeMillis();
System.out.println("CrossGamma - bump and recompute: " + nbTest2 + " cross-gamma (" + NB_NODE_GBP + " nodes): " + (endTime - startTime) + " ms");
// Performance note: Cross-gamma: 11-Jul-2014: On Mac Pro 3.2 GHz Quad-Core Intel Xeon: 13100 ms for 1000 swaps.
}
@Test(enabled = false)
public void crossGammaZeroMulti() {
MulticurveProviderDiscount multicurve = MULTICURVE_PAIR_0.getFirst();
MultipleCurrencyParameterSensitivity ps0 = PSC.calculateSensitivity(SWAP_EUR, multicurve);
DoubleMatrix1D[] ps0Mat = new DoubleMatrix1D[2];
for (int i = 0; i < 2; i++) {
ps0Mat[i] = ps0.getSensitivity(CURVE_NAME[i], EUR);
}
DoubleMatrix1D[][][] psShift = new DoubleMatrix1D[2][2][];
DoubleMatrix1D[][][] gamma = new DoubleMatrix1D[2][2][]; // Curve shifted, curve impacted
int[] nbNode = new int[2];
nbNode[0] = AnalysisMarketDataEURJun13Sets.getCurveEURNumberNodeDiscounting();
nbNode[1] = AnalysisMarketDataEURJun13Sets.getCurveEURNumberNodeForward();
MultipleCurrencyParameterSensitivity[] psShiftDsc = new MultipleCurrencyParameterSensitivity[nbNode[0]];
for (int i = 0; i < 2; i++) {
psShift[0][i] = new DoubleMatrix1D[nbNode[0]];
gamma[0][i] = new DoubleMatrix1D[nbNode[0]];
}
for (int loopdsc = 0; loopdsc < nbNode[0]; loopdsc++) {
MulticurveProviderDiscount multicurveShift = AnalysisMarketDataEURJun13Sets.getMulticurvesEURShiftParameterPoint(SHIFT, loopdsc, true);
psShiftDsc[loopdsc] = PSC.calculateSensitivity(SWAP_EUR, multicurveShift);
for (int i = 0; i < 2; i++) {
psShift[0][i][loopdsc] = psShiftDsc[loopdsc].getSensitivity(CURVE_NAME[i], EUR);
gamma[0][i][loopdsc] = (DoubleMatrix1D) ALGEBRA.add(psShift[0][i][loopdsc], ALGEBRA.scale(ps0Mat[i], -1.0));
}
}
for (int i = 0; i < 2; i++) {
psShift[1][i] = new DoubleMatrix1D[nbNode[1]];
gamma[1][i] = new DoubleMatrix1D[nbNode[1]];
}
MultipleCurrencyParameterSensitivity[] psShiftFwd = new MultipleCurrencyParameterSensitivity[nbNode[1]];
for (int loopfwd = 0; loopfwd < nbNode[1]; loopfwd++) {
MulticurveProviderDiscount multicurveShift = AnalysisMarketDataEURJun13Sets.getMulticurvesEURShiftParameterPoint(SHIFT, loopfwd, false);
psShiftFwd[loopfwd] = PSC.calculateSensitivity(SWAP_EUR, multicurveShift);
for (int i = 0; i < 2; i++) {
psShift[1][i][loopfwd] = psShiftFwd[loopfwd].getSensitivity(CURVE_NAME[i], EUR);
gamma[1][i][loopfwd] = (DoubleMatrix1D) ALGEBRA.add(psShift[1][i][loopfwd], ALGEBRA.scale(ps0Mat[i], -1.0));
}
}
try {
final FileWriter writer = new FileWriter("swap-x-gamma-multicurve.csv");
for (int i = 0; i < 2; i++) {
for (int loopnodei = 0; loopnodei < nbNode[i]; loopnodei++) {
String line = "";
for (int j = 0; j < 2; j++) {
for (int loopnode2 = 0; loopnode2 < nbNode[j]; loopnode2++) {
line = line + "," + gamma[i][j][loopnodei].getEntry(loopnode2);
}
}
writer.append(line + "0 \n");
}
}
writer.flush();
writer.close();
} catch (final IOException e) {
e.printStackTrace();
}
@SuppressWarnings("unused")
int t = 0;
}
}