/**
* Copyright (C) 2014 - 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.HashMap;
import java.util.List;
import java.util.Set;
import org.apache.commons.lang.ArrayUtils;
import org.testng.annotations.Test;
import org.threeten.bp.Period;
import org.threeten.bp.ZonedDateTime;
import com.opengamma.analytics.financial.instrument.index.GeneratorAttributeIR;
import com.opengamma.analytics.financial.instrument.index.GeneratorSwapFixedIbor;
import com.opengamma.analytics.financial.instrument.index.GeneratorSwapFixedIborMaster;
import com.opengamma.analytics.financial.instrument.index.GeneratorSwapIborIbor;
import com.opengamma.analytics.financial.instrument.index.GeneratorSwapIborIborMaster;
import com.opengamma.analytics.financial.instrument.index.IborIndex;
import com.opengamma.analytics.financial.instrument.index.IndexIborMaster;
import com.opengamma.analytics.financial.instrument.index.IndexON;
import com.opengamma.analytics.financial.instrument.swap.SwapFixedIborDefinition;
import com.opengamma.analytics.financial.instrument.swap.SwapIborIborDefinition;
import com.opengamma.analytics.financial.interestrate.payments.derivative.Coupon;
import com.opengamma.analytics.financial.interestrate.swap.derivative.Swap;
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.CrossGammaMultiCurveCalculator;
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.interestrate.MulticurveProviderDiscount;
import com.opengamma.analytics.financial.provider.description.interestrate.ParameterProviderInterface;
import com.opengamma.analytics.financial.provider.sensitivity.multicurve.MultipleCurrencyMulticurveSensitivity;
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.AnalysisMarketDataJPYSets;
import com.opengamma.financial.convention.calendar.ExceptionCalendar;
import com.opengamma.financial.convention.calendar.MondayToFridayCalendar;
import com.opengamma.util.money.Currency;
import com.opengamma.util.money.MultipleCurrencyAmount;
import com.opengamma.util.time.DateUtils;
import com.opengamma.util.tuple.Pair;
/**
* Analysis of cross-gamma to zero-coupon rate - Multi-curve settings.
*/
public class SwapGammaMultiCurveProfitJPYAnalysis {
private static final ExceptionCalendar TYO = new MondayToFridayCalendar("TYO");
private static final ZonedDateTime CALIBRATION_DATE = DateUtils.getUTCDate(2014, 8, 2);
private static final ZonedDateTime SPOT_DATE = ScheduleCalculator.getAdjustedDate(CALIBRATION_DATE, 2, TYO);
private static final GeneratorSwapFixedIborMaster MASTER_IRS = GeneratorSwapFixedIborMaster.getInstance();
private static final GeneratorSwapIborIborMaster MASTER_BS = GeneratorSwapIborIborMaster.getInstance();
private static final GeneratorSwapFixedIbor JPY6MLIBOR6M = MASTER_IRS.getGenerator("JPY6MLIBOR6M", TYO);
private static final GeneratorSwapIborIbor JPYLIBOR3MLIBOR6M = MASTER_BS.getGenerator("JPYLIBOR3MLIBOR6M", TYO);
private static final IndexIborMaster MASTER_IBOR_INDEX = IndexIborMaster.getInstance();
private static final IborIndex JPYLIBOR6M = MASTER_IBOR_INDEX.getIndex("JPYLIBOR6M");
private static final Currency JPY = JPYLIBOR6M.getCurrency();
private static final Period TENOR_START = Period.ofMonths(30);
private static final Period TENOR_SWAP = Period.ofYears(15);
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, JPYLIBOR6M, TYO);
private static final SwapFixedIborDefinition IRS_JPY_DEFINITION = SwapFixedIborDefinition.from(START_DATE, TENOR_SWAP, JPY6MLIBOR6M, NOTIONAL, 0.02, IS_PAYER);
private static final SwapFixedCoupon<Coupon> IRS_JPY = IRS_JPY_DEFINITION.toDerivative(CALIBRATION_DATE);
private static final double SPREAD_BS = 0.0005;
private static final SwapIborIborDefinition BS_JPY_DEFINITION =
JPYLIBOR3MLIBOR6M.generateInstrument(CALIBRATION_DATE, SPREAD_BS, NOTIONAL, new GeneratorAttributeIR(TENOR_START, TENOR_SWAP));
private static final Swap<?, ?> BS_JPY = BS_JPY_DEFINITION.toDerivative(CALIBRATION_DATE);
private static final double BP1 = 1.0E-4;
private static final PresentValueDiscountingCalculator PVDC = PresentValueDiscountingCalculator.getInstance();
private static final PresentValueCurveSensitivityDiscountingCalculator PVCSDC = PresentValueCurveSensitivityDiscountingCalculator.getInstance();
private static final CrossGammaMultiCurveCalculator CGMCC = new CrossGammaMultiCurveCalculator(BP1, PVCSDC);
private static final ParameterSensitivityParameterCalculator<ParameterProviderInterface> PSC = new ParameterSensitivityParameterCalculator<>(PVCSDC);
private static final Pair<MulticurveProviderDiscount, CurveBuildingBlockBundle> MULTICURVE_PAIR_0 =
AnalysisMarketDataJPYSets.getMulticurveJPY();
private static final MulticurveProviderDiscount MULTICURVE = MULTICURVE_PAIR_0.getFirst();
private static final String[] CURVE_NAME = new String[2];
static {
CURVE_NAME[0] = MULTICURVE_PAIR_0.getFirst().getName(JPY);
CURVE_NAME[1] = MULTICURVE_PAIR_0.getFirst().getName(JPYLIBOR6M);
}
private static final OGMatrixAlgebra ALGEBRA = new OGMatrixAlgebra();
private static final DoubleMatrix2D GAMMA_CROSS = CGMCC.calculateCrossGammaCrossCurve(IRS_JPY, MULTICURVE);
private static final double[] GAMMA_SUM_COL = new double[GAMMA_CROSS.getNumberOfColumns()];
static {
for (int loopcol = 0; loopcol < GAMMA_CROSS.getNumberOfColumns(); loopcol++) {
for (int looprow = 0; looprow < GAMMA_CROSS.getNumberOfRows(); looprow++) {
GAMMA_SUM_COL[loopcol] += GAMMA_CROSS.getEntry(looprow, loopcol);
}
}
}
private static final int NB_NODE = GAMMA_CROSS.getNumberOfColumns();
private static final HashMap<String, DoubleMatrix2D> GAMMA_INTRA = CGMCC.calculateCrossGammaIntraCurve(IRS_JPY, MULTICURVE);
private static final Set<String> CURVE_NAME_SET = GAMMA_INTRA.keySet();
private static final String[] CURVE_NAME_ARRAY = CURVE_NAME_SET.toArray(new String[0]);
private static final int[] NB_NODE_JPY = new int[3];
static {
int loopcurve = 0;
for (String curve : CURVE_NAME_SET) {
NB_NODE_JPY[loopcurve] = GAMMA_INTRA.get(curve).getNumberOfColumns();
loopcurve++;
}
}
private static final MultipleCurrencyParameterSensitivity DELTA = PSC.calculateSensitivity(IRS_JPY, MULTICURVE);
@Test(enabled = false)
public void crossGammaMulticurveIntraCurve() {
HashMap<String, DoubleMatrix2D> crossGammaIntraIrs = CGMCC.calculateCrossGammaIntraCurve(IRS_JPY, MULTICURVE);
HashMap<String, DoubleMatrix2D> crossGammaIntraBs = CGMCC.calculateCrossGammaIntraCurve(BS_JPY, MULTICURVE);
for (String name : crossGammaIntraIrs.keySet()) {
exportMatrix(crossGammaIntraIrs.get(name).getData(), "cross-gamma-jpy-irs-" + name + ".csv");
}
for (String name : crossGammaIntraBs.keySet()) {
exportMatrix(crossGammaIntraBs.get(name).getData(), "cross-gamma-jpy-bs-" + name + ".csv");
}
}
private void exportMatrix(double[][] matrix, String fileName) {
try {
final FileWriter writer = new FileWriter(fileName);
for (int loop1 = 0; loop1 < matrix.length; loop1++) {
String line = "";
for (int loop2 = 0; loop2 < matrix[loop1].length; loop2++) {
line = line + "," + matrix[loop1][loop2];
}
writer.append(line + "0 \n");
}
writer.flush();
writer.close();
} catch (final IOException e) {
e.printStackTrace();
}
}
/**
* Uses historical data to estimate the difference between intra-curve cross-gamma and full cross-gamma.
* The result file is exported in the root directory of OG-Analytics.
* @throws IOException
*/
@Test(enabled = false)
public void crossGammaCompJpyHts() throws IOException {
long startTime, endTime;
startTime = System.currentTimeMillis();
final String sheetFilePath = "src/test/resources/analysis/historical_time_series/curve-changes-jpy-multicurve.csv";
int nbCurves = CURVE_NAME_SET.size();
int nbPoints = 0;
double[][] x = new double[nbCurves][];
double[][] y = new double[nbCurves][];
for (int loopcurve = 0; loopcurve < nbCurves; loopcurve++) {
YieldAndDiscountCurve curve = MULTICURVE.getCurve(CURVE_NAME_ARRAY[loopcurve]);
InterpolatedDoublesCurve interpolatedCurve = (InterpolatedDoublesCurve) ((YieldCurve) curve).getCurve();
x[loopcurve] = interpolatedCurve.getXDataAsPrimitive();
y[loopcurve] = interpolatedCurve.getYDataAsPrimitive();
nbPoints += x[loopcurve].length;
}
double[][] shiftRelative = GammaAnalysisUtils.parseShifts(sheetFilePath, 1.0);
int nbScenarios = shiftRelative.length;
double[][] shiftAbsolute = new double[nbScenarios][nbPoints];
for (int loopsc = 0; loopsc < nbScenarios; loopsc++) {
int loopnode1 = 0;
for (int loopcurve = 0; loopcurve < nbCurves; loopcurve++) {
for (int loopnode2 = 0; loopnode2 < x[loopcurve].length; loopnode2++) {
shiftAbsolute[loopsc][loopnode1] = y[loopcurve][loopnode2] * shiftRelative[loopsc][loopnode1];
loopnode1++;
}
}
}
double[] plFullR = new double[nbScenarios];
double[] plDelta = new double[nbScenarios];
double[] plGammaCross = new double[nbScenarios];
double[] plGammaIntra = new double[nbScenarios];
double[] plGammaCol = new double[nbScenarios];
double pv0 = IRS_JPY.accept(PVDC, MULTICURVE).getAmount(JPY);
for (int loopsc = 0; loopsc < nbScenarios; loopsc++) {
double[][] marketMvtIntra = new double[nbCurves][];
int start = 0;
for (int loopcurve = 0; loopcurve < nbCurves; loopcurve++) {
marketMvtIntra[loopcurve] = ArrayUtils.subarray(shiftAbsolute[loopsc], start, start + NB_NODE_JPY[loopcurve]);
start += NB_NODE_JPY[loopcurve];
}
// Full reval
MulticurveProviderDiscount multicurveScenario = shiftedProvider(MULTICURVE, CURVE_NAME_ARRAY, x, y, marketMvtIntra);
double pv = IRS_JPY.accept(PVDC, multicurveScenario).getAmount(JPY);
plFullR[loopsc] = pv - pv0;
// Delta
for (int loopcurve = 0; loopcurve < nbCurves; loopcurve++) {
DoubleMatrix1D sensi = DELTA.getSensitivity(CURVE_NAME_ARRAY[loopcurve], JPY);
double[] deltaCurve;
if (sensi == null) { // no sensitivity
deltaCurve = new double[marketMvtIntra[loopcurve].length];
} else {
deltaCurve = DELTA.getSensitivity(CURVE_NAME_ARRAY[loopcurve], JPY).getData();
}
for (int i = 0; i < deltaCurve.length; i++) {
plDelta[loopsc] += deltaCurve[i] * marketMvtIntra[loopcurve][i];
}
}
// Intra curve cross-gamma
int loopcurve = 0;
start = 0;
for (String curve : CURVE_NAME_SET) {
DoubleMatrix2D marketMvtIntraMat = new DoubleMatrix2D(new double[][] {marketMvtIntra[loopcurve] });
start += NB_NODE_JPY[loopcurve];
loopcurve++;
plGammaIntra[loopsc] += (Double) ALGEBRA.multiply(ALGEBRA.multiply(marketMvtIntraMat, GAMMA_INTRA.get(curve)), ALGEBRA.getTranspose(marketMvtIntraMat)).getEntry(0, 0) * 0.5;
}
// Full curve cross-gamma
DoubleMatrix2D marketMvtMat = new DoubleMatrix2D(new double[][] {shiftAbsolute[loopsc] });
plGammaCross[loopsc] = (Double) ALGEBRA.multiply(ALGEBRA.multiply(marketMvtMat, GAMMA_CROSS),
ALGEBRA.getTranspose(marketMvtMat)).getEntry(0, 0) * 0.5;
// Sum of column
for (int loopcol = 0; loopcol < NB_NODE; loopcol++) {
plGammaCol[loopsc] += GAMMA_SUM_COL[loopcol] * shiftAbsolute[loopsc][loopcol] * shiftAbsolute[loopsc][loopcol] * 0.5;
}
}
String fileName = "swap-multicurve-delta-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 = plFullR[loopsc] + "," + plDelta[loopsc] + "," + plGammaCross[loopsc] + "," + plGammaIntra[loopsc] + "," + plGammaCol[loopsc] + " \n";
writer.append(line);
}
writer.flush();
writer.close();
} catch (final IOException e) {
e.printStackTrace();
}
endTime = System.currentTimeMillis();
System.out.println("SwapGammaMultiCurveProfitJPYAnalysis - p/L - " + (endTime - startTime) + " ms");
}
private MulticurveProviderDiscount shiftedProvider(MulticurveProviderDiscount multicurve, String[] curveNames,
double[][] x, double[][] y, double[][] shifts) {
MulticurveProviderDiscount multicurveBumped = new MulticurveProviderDiscount();
multicurveBumped.setForexMatrix(multicurve.getFxRates());
for (int loopcurve = 0; loopcurve < curveNames.length; loopcurve++) {
List<Currency> nameCcys = multicurve.getCurrencyForName(curveNames[loopcurve]);
List<IborIndex> nameIbors = multicurve.getIborIndexForName(curveNames[loopcurve]);
List<IndexON> nameOns = multicurve.getOvernightIndexForName(curveNames[loopcurve]);
double[] yShift = new double[y[loopcurve].length];
for (int i = 0; i < y[loopcurve].length; i++) {
yShift[i] = y[loopcurve][i] + shifts[loopcurve][i];
}
YieldCurve curve = (YieldCurve) multicurve.getCurve(curveNames[loopcurve]);
InterpolatedDoublesCurve interpolatedCurve = (InterpolatedDoublesCurve) curve.getCurve();
final YieldAndDiscountCurve curveBumped = new YieldCurve(curveNames[loopcurve],
new InterpolatedDoublesCurve(x[loopcurve], yShift, interpolatedCurve.getInterpolator(), true));
for (Currency loopccy : multicurve.getCurrencies()) {
if (nameCcys.contains(loopccy)) {
multicurveBumped.setCurve(loopccy, curveBumped);
}
}
for (IborIndex loopibor : multicurve.getIndexesIbor()) {
if (nameIbors.contains(loopibor)) {
multicurveBumped.setCurve(loopibor, curveBumped);
}
}
for (IndexON loopon : multicurve.getIndexesON()) {
if (nameOns.contains(loopon)) {
multicurveBumped.setCurve(loopon, curveBumped);
}
}
loopcurve++;
}
return multicurveBumped;
}
@SuppressWarnings("unused")
@Test(enabled = false)
public void performanceGamma() {
long startTime, endTime;
final int nbTest = 1000;
startTime = System.currentTimeMillis();
for (int looptest = 0; looptest < nbTest; looptest++) {
MultipleCurrencyAmount pv = IRS_JPY.accept(PVDC, MULTICURVE);
}
endTime = System.currentTimeMillis();
System.out.println("CrossGammaMultiCurveCalculator - " + nbTest + " pv - 3 curves: " + (endTime - startTime) + " ms");
// Performance note: PVD: 04-Aug-2014: On Mac Book Pro 2.6 GHz Intel Core i7: 20 ms for 1000 sets.
startTime = System.currentTimeMillis();
for (int looptest = 0; looptest < nbTest; looptest++) {
MultipleCurrencyMulticurveSensitivity pvcs = IRS_JPY.accept(PVCSDC, MULTICURVE);
}
endTime = System.currentTimeMillis();
System.out.println("CrossGammaMultiCurveCalculator - " + nbTest + " pvcs - 3 curves: " + (endTime - startTime) + " ms");
// Performance note: PVCSD: 04-Aug-2014: On Mac Book Pro 2.6 GHz Intel Core i7: 30 ms for 1000 sets.
startTime = System.currentTimeMillis();
for (int looptest = 0; looptest < nbTest; looptest++) {
HashMap<String, DoubleMatrix2D> crossGammaIntra = CGMCC.calculateCrossGammaIntraCurve(IRS_JPY, MULTICURVE);
}
endTime = System.currentTimeMillis();
System.out.println("CrossGammaMultiCurveCalculator - " + nbTest + " intro-curve x-gamma - 3 curves: " + (endTime - startTime) + " ms");
// Performance note: Cross-gamma intra-curve 2 curves: 04-Aug-2014: On Mac Book Pro 2.6 GHz Intel Core i7: 2000 ms for 1000 sets.
}
@SuppressWarnings("unused")
@Test(enabled = false)
public void performanceCalibration() {
long startTime, endTime;
final int nbTest = 100;
double[] dscQuotes = new double[] {0.0001,
0.0006, 0.0006, 0.0006, 0.0005, 0.0006, 0.0007, 0.0007, 0.0006, 0.0007, 0.0006,
0.0006, 0.0006, 0.0010, 0.0010, 0.0014, 0.0021, 0.0027, 0.0034, 0.0041, 0.0057,
0.0083, 0.0115, 0.0131, 0.0141, 0.0154 };
double[] fwd6Quotes = new double[] {0.0017786,
0.0029, 0.0029, 0.0029,
0.0018, 0.0017, 0.0018, 0.0021, 0.0025, 0.0025, 0.0031, 0.0040, 0.0048, 0.0057,
0.0065, 0.0084, 0.0111, 0.0143, 0.0160, 0.0170, 0.0183 };
double[] fwd3Quotes = new double[] {0.0013,
0.0020, 0.0020, 0.0020, 0.0019, 0.0019, 0.0019,
0.0005, 0.0005, 0.0005, 0.0005, 0.0006, 0.0007, 0.0008, 0.0009, 0.0009, 0.0010,
0.0011, 0.0012, 0.0013, 0.0013, 0.0013, 0.0013, 0.0014 };
startTime = System.currentTimeMillis();
for (int looptest = 0; looptest < nbTest; looptest++) {
Pair<MulticurveProviderDiscount, CurveBuildingBlockBundle> multicurve3Pair =
AnalysisMarketDataJPYSets.getMulticurveJPYOisL6L3(CALIBRATION_DATE, dscQuotes, fwd6Quotes, fwd3Quotes);
}
endTime = System.currentTimeMillis();
System.out.println("SwapGammaMultiCurveProfitJPYAnalysis - calibration - " + nbTest + " 3 curves - 3 units calibrations: " + (endTime - startTime) + " ms");
// Performance note: 3 Curve calibration linear: 04-Aug-2014: On Mac Book Pro 2.6 GHz Intel Core i7: 3900 ms for 100 sets.
// Performance note: 3 Curve calibration linear: 05-Aug-2014: On Mac Pro 3.2 GHz Quad-Core Intel Xeon: 5500 ms for 100 sets.
// Performance note: 3 Curve calibration log-ncs on df: 05-Aug-2014: On Mac Pro 3.2 GHz Quad-Core Intel Xeon: 8600 ms for 100 sets.
startTime = System.currentTimeMillis();
for (int looptest = 0; looptest < nbTest; looptest++) {
Pair<MulticurveProviderDiscount, CurveBuildingBlockBundle> multicurve2Pair =
AnalysisMarketDataJPYSets.getMulticurveJPYOisL6(CALIBRATION_DATE, dscQuotes, fwd6Quotes);
}
endTime = System.currentTimeMillis();
System.out.println("SwapGammaMultiCurveProfitJPYAnalysis - calibration - " + nbTest + " 2 curves - 2 units calibrations: " + (endTime - startTime) + " ms");
// Performance note: 2 Curve calibration: 04-Aug-2014: On Mac Book Pro 2.6 GHz Intel Core i7: 1900 ms for 100 sets. // 2900 // 3000
startTime = System.currentTimeMillis();
for (int looptest = 0; looptest < nbTest; looptest++) {
Pair<MulticurveProviderDiscount, CurveBuildingBlockBundle> multicurve3Pair =
AnalysisMarketDataJPYSets.getMulticurveJPYOisL6L3OneUnit(CALIBRATION_DATE, dscQuotes, fwd6Quotes, fwd3Quotes);
}
endTime = System.currentTimeMillis();
System.out.println("SwapGammaMultiCurveProfitJPYAnalysis - calibration - " + nbTest + " 3 curves - 1 unit calibrations: " + (endTime - startTime) + " ms");
// Performance note: 3 Curve calibration: 04-Aug-2014: On Mac Book Pro 2.6 GHz Intel Core i7: 6000 ms for 100 sets. // 9000 // 9100
startTime = System.currentTimeMillis();
for (int looptest = 0; looptest < nbTest; looptest++) {
Pair<MulticurveProviderDiscount, CurveBuildingBlockBundle> multicurve3Pair =
AnalysisMarketDataJPYSets.getMulticurveJPYOisL6OneUnit(CALIBRATION_DATE, dscQuotes, fwd6Quotes);
}
endTime = System.currentTimeMillis();
System.out.println("SwapGammaMultiCurveProfitJPYAnalysis - calibration - " + nbTest + " 2 curves - 1 unit calibrations: " + (endTime - startTime) + " ms");
// Performance note: 3 Curve calibration: 04-Aug-2014: On Mac Book Pro 2.6 GHz Intel Core i7: xxx ms for 100 sets. // 3500 // 3700
}
}