/**
* Copyright (C) 2014 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.analytics.financial.interestrate.capletstripping;
import static org.testng.AssertJUnit.assertEquals;
import static org.testng.AssertJUnit.assertFalse;
import static org.testng.AssertJUnit.assertTrue;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.testng.annotations.Test;
import com.opengamma.analytics.financial.interestrate.payments.derivative.CapFloorIbor;
import com.opengamma.analytics.math.matrix.ColtMatrixAlgebra;
import com.opengamma.analytics.math.matrix.DoubleMatrix1D;
import com.opengamma.analytics.math.matrix.DoubleMatrix2D;
import com.opengamma.analytics.math.matrix.MatrixAlgebra;
import com.opengamma.analytics.math.statistics.leastsquare.LeastSquareResults;
import com.opengamma.analytics.math.surface.NodalObjectsSurface;
import com.opengamma.util.test.TestGroup;
/**
*
*/
@Test(groups = TestGroup.UNIT)
public class CapletStrippingDirectGlobalWithPenaltyTest extends CapletStrippingSetup {
/**
* Use all of the market data
*/
@Test(enabled = false)
public void MarketDataTestWithATM() {
final double[] capStrikes = getStrikes();
final int nStrikes = capStrikes.length;
final int nCapEndTimes = getCapEndTimes().length;
final List<CapFloor> atmCaps = getATMCaps();
final List<CapFloor>[] caps = new List[nStrikes + nCapEndTimes];
final double[][] capVols = new double[nStrikes + nCapEndTimes][];
final int[] atmPos = new int[nCapEndTimes];
int k = 0;
for (int i = 0; i < nStrikes; ++i) {
while (k < nCapEndTimes && capStrikes[i] > atmCaps.get(k).getStrike()) {
caps[i + k] = new ArrayList<>(1);
capVols[i + k] = new double[1];
caps[i + k].add(atmCaps.get(k));
capVols[i + k][0] = getAtmVols()[k];
atmPos[k] = i + k;
++k;
}
caps[i + k] = getCaps(i);
capVols[i + k] = getCapVols(i);
if (i == nStrikes - 1 && k != nCapEndTimes) {
while (k < nCapEndTimes) {
caps[i + k] = new ArrayList<>(1);
capVols[i + k] = new double[1];
caps[i + k].add(atmCaps.get(k));
capVols[i + k][0] = getAtmVols()[k];
atmPos[k] = i + k;
++k;
}
}
}
final double[] allCapStrikes = new double[nStrikes + nCapEndTimes];
for (int i = 0; i < nStrikes + nCapEndTimes; ++i) {
allCapStrikes[i] = caps[i].get(0).getStrike();
}
final int sample = nStrikes + nCapEndTimes - 1;
final int nCapsSample = caps[sample].size();
final CapFloorIbor[] payments = caps[sample].get(nCapsSample - 1).getPayments();
final int nPayments = payments.length;
final double[] fixingTimes = new double[nPayments];
final double[] PaymentTimes = new double[nPayments];
for (int i = 0; i < nPayments; ++i) {
fixingTimes[i] = payments[i].getFixingTime();
PaymentTimes[i] = payments[i].getPaymentTime();
}
final CapletVolatilityNodalSurfaceProvider provider = new CapletVolatilityNodalSurfaceProvider(allCapStrikes, fixingTimes);
final CapletStrippingDirectGlobalWithPenalty cpst = new CapletStrippingDirectGlobalWithPenalty(caps, getYieldCurves(), provider);
LeastSquareResults res = cpst.solveForVol(capVols);
int l = 0;
System.out.print("\t");
for (int j = 0; j < nPayments; ++j) {
System.out.print(PaymentTimes[j] + "\t");
}
System.out.print("\n");
for (int i = 0; i < nStrikes + nCapEndTimes; ++i) {
if (l < nCapEndTimes && i == atmPos[l]) { // skipping atm strikes
++l;
} else {
System.out.print(allCapStrikes[i] + "\t");
// final int nCaps = caps[i].size();
// final CapFloor lastCap = caps[i].get(nCaps - 1);
// final int nLongPayments = lastCap.getNumberOfPayments();
// for (int j = 0; j < nLongPayments; ++j) {
for (int j = 0; j < nPayments; ++j) {
System.out.print(res.getFitParameters().getData()[i * nPayments + j] + "\t");
}
System.out.print("\n");
}
}
System.out.println(res.getChiSq());
DoubleMatrix1D resVec = res.getFitParameters();
double[][] resMatrix = new double[nStrikes + nCapEndTimes][nPayments];
for (int i = 0; i < nStrikes + nCapEndTimes; ++i) {
for (int j = 0; j < nPayments; ++j) {
resMatrix[i][j] = resVec.getEntry(i * nPayments + j);
}
}
for (int i = 0; i < nStrikes + nCapEndTimes; ++i) {
final int nCaps = caps[i].size();
for (int j = 0; j < nCaps; ++j) {
CapFloor cf = caps[i].get(j);
CapFloorPricer pr = new CapFloorPricer(cf, getYieldCurves());
final int nP = pr.getNumberCaplets();
final double[] vols = Arrays.copyOf(resMatrix[i], nP);
System.out.println(capVols[i][j] + "\t" + pr.impliedVol(vols));
}
}
}
/**
* Exclude ATM caps, that is, grid is almost homogeneous
*/
@Test(enabled = false)
public void MarketDataTestExcATM() {
final double[] capStrikes = getStrikes();
final int nStrikes = capStrikes.length;
final List<CapFloor>[] caps = new List[nStrikes];
final double[][] capVols = new double[nStrikes][];
int k = 0;
for (int i = 0; i < nStrikes; ++i) {
caps[i] = getCaps(i);
capVols[i] = getCapVols(i);
}
final int sample = 5;
final int nCapsSample = caps[sample].size();
final CapFloorIbor[] payments = caps[sample].get(nCapsSample - 1).getPayments();
final int nPayments = payments.length;
final double[] fixingTimes = new double[nPayments];
for (int i = 0; i < nPayments; ++i) {
fixingTimes[i] = payments[i].getFixingTime();
}
final CapletVolatilityNodalSurfaceProvider provider = new CapletVolatilityNodalSurfaceProvider(capStrikes, fixingTimes);
final CapletStrippingDirectGlobalWithPenalty cpst = new CapletStrippingDirectGlobalWithPenalty(caps, getYieldCurves(), provider);
LeastSquareResults res = cpst.solveForVol(capVols);
System.out.print("\t");
for (int j = 0; j < nPayments; ++j) {
System.out.print(fixingTimes[j] + "\t");
}
System.out.print("\n");
for (int i = 0; i < nStrikes; ++i) {
System.out.print(capStrikes[i] + "\t");
for (int j = 0; j < nPayments; ++j) {
System.out.print(res.getFitParameters().getData()[i * nPayments + j] + "\t");
}
System.out.print("\n");
}
System.out.println(res.getChiSq());
DoubleMatrix1D resVec = res.getFitParameters();
double[][] resMatrix = new double[nStrikes][nPayments];
for (int i = 0; i < nStrikes; ++i) {
for (int j = 0; j < nPayments; ++j) {
resMatrix[i][j] = resVec.getEntry(i * nPayments + j);
}
}
// double chiSq = 0.;
for (int i = 0; i < nStrikes; ++i) {
final int nCaps = caps[i].size();
for (int j = 0; j < nCaps; ++j) {
CapFloor cf = caps[i].get(j);
CapFloorPricer pr = new CapFloorPricer(cf, getYieldCurves());
final int nP = pr.getNumberCaplets();
final double[] vols = Arrays.copyOf(resMatrix[i], nP);
System.out.println(capVols[i][j] + "\t" + pr.impliedVol(vols));
}
}
}
/**
* Tests below are unit tests for {@link CapletStrippingDirectGlobalWithPenalty} and {@link CapletVolatilityNodalSurfaceProvider}
*/
/**
*
*/
@Test
public void NodalProvidorOutputTest() {
final double epsLocal = 1.e-12;
double[] strikes = new double[] {2.0, 3.5, 4.5 };
double[] times = new double[] {0.5, 2.2, 3.4, 5.1 };
CapletVolatilityNodalSurfaceProvider provider = new CapletVolatilityNodalSurfaceProvider(strikes, times);
int nStrikes = strikes.length;
int nTimes = times.length;
int expNumber = nStrikes * nTimes;
Integer[] expStrikeIntegerNodes = new Integer[] {0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2 };
Integer[] expTimeIntegerNodes = new Integer[] {0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3 };
assertEquals(expNumber, provider.getNumberOfNodes());
assertArray(expStrikeIntegerNodes, provider.getStrikeIntegerNodes());
assertArray(expTimeIntegerNodes, provider.getTimeIntegerNodes());
assertArray(strikes, provider.getStrikes(), epsLocal);
assertArray(times, provider.getFixingTimes(), epsLocal);
double[] data = new double[expNumber];
Double[] Data = new Double[expNumber];
for (int i = 0; i < expNumber; ++i) {
data[i] = i;
Data[i] = (double) i;
}
NodalObjectsSurface<Integer, Integer, Double> expSurface = new NodalObjectsSurface<>(expStrikeIntegerNodes, expTimeIntegerNodes, Data);
NodalObjectsSurface<Integer, Integer, Double> surface = provider.evaluate(new DoubleMatrix1D(data));
assertArray(expSurface.getXData(), surface.getXData());
assertArray(expSurface.getYData(), surface.getYData());
assertArray(expSurface.getZData(), surface.getZData(), epsLocal);
double lambdaK = 1.5;
double lambdaT = 1.8;
DoubleMatrix2D matrix = provider.getPenaltyMatrix(lambdaK, lambdaT);
double[] dk = new double[] {strikes[1] - strikes[0], strikes[2] - strikes[1] };
double[] dt = new double[] {times[1] - times[0], times[2] - times[1], times[3] - times[2] };
final DoubleMatrix1D sampleVec1D = new DoubleMatrix1D(data);
final MatrixAlgebra alg = new ColtMatrixAlgebra();
double penalty = alg.getInnerProduct(sampleVec1D, alg.multiply(matrix, sampleVec1D));
double expPenalty = 4.0 * Math.pow(lambdaK * (4.0 / dk[1] - 4.0 / dk[0]) / dk[0], 2.0) + 3.0 * Math.pow(lambdaT * (1.0 / dt[1] - 1.0 / dt[0]) / dt[0], 2.0) + 3.0 *
Math.pow(lambdaT * (1.0 / dt[2] - 1.0 / dt[1]) / dt[1], 2.0);
assertEquals(expPenalty, penalty, epsLocal);
}
/**
*
*/
@Test
public void NodalProvidorHashCodeEqualsTest() {
double[] strikes1 = new double[] {2.0, 3.5, 4.5 };
double[] times1 = new double[] {0.5, 2.2, 3.4, 5.1 };
CapletVolatilityNodalSurfaceProvider provider1 = new CapletVolatilityNodalSurfaceProvider(strikes1, times1);
double[] strikes2 = new double[] {2.1, 3.5, 4.5 };
double[] times2 = new double[] {0.5, 2.2, 3.4, 5.2 };
CapletVolatilityNodalSurfaceProvider provider2 = new CapletVolatilityNodalSurfaceProvider(strikes1, times2);
CapletVolatilityNodalSurfaceProvider provider3 = new CapletVolatilityNodalSurfaceProvider(strikes2, times1);
CapletVolatilityNodalSurfaceProvider provider4 = new CapletVolatilityNodalSurfaceProvider(strikes1, times1);
double[] strikes3 = new double[] {2.1, 3.5, 4.5, 5.2 };
double[] times3 = new double[] {0.5, 2.2, 3.4, 5.2, 10.0 };
CapletVolatilityNodalSurfaceProvider provider5 = new CapletVolatilityNodalSurfaceProvider(strikes3, times1);
CapletVolatilityNodalSurfaceProvider provider6 = new CapletVolatilityNodalSurfaceProvider(strikes1, times3);
assertTrue(provider1.equals(provider1));
assertTrue(provider1.equals(provider4));
assertEquals(provider1.hashCode(), provider4.hashCode());
assertFalse(provider1.equals(provider2));
assertFalse(provider1.equals(provider3));
assertFalse(provider1.equals(null));
assertFalse(provider1.equals(new double[] {}));
assertFalse(provider1.hashCode() == provider5.hashCode());
assertFalse(provider1.hashCode() == provider6.hashCode());
assertFalse(provider1.equals(provider5));
assertFalse(provider1.equals(provider6));
}
@SuppressWarnings("unused")
@Test
public void CapletStrippingDirectGlobalWithPenaltyAllTest() {
/*
* Preparing data
*/
final double[] capStrikes = getStrikes();
final int nStrikes = capStrikes.length;
final int nCapEndTimes = getCapEndTimes().length;
final List<CapFloor> atmCaps = getATMCaps();
final List<CapFloor>[] caps = new List[nStrikes + nCapEndTimes];
final double[][] capVols = new double[nStrikes + nCapEndTimes][];
final int[] atmPos = new int[nCapEndTimes];
int k = 0;
for (int i = 0; i < nStrikes; ++i) {
while (k < nCapEndTimes && capStrikes[i] > atmCaps.get(k).getStrike()) {
caps[i + k] = new ArrayList<>(1);
capVols[i + k] = new double[1];
caps[i + k].add(atmCaps.get(k));
capVols[i + k][0] = getAtmVols()[k];
atmPos[k] = i + k;
++k;
}
caps[i + k] = getCaps(i);
capVols[i + k] = getCapVols(i);
if (i == nStrikes - 1 && k != nCapEndTimes) {
while (k < nCapEndTimes) {
caps[i + k] = new ArrayList<>(1);
capVols[i + k] = new double[1];
caps[i + k].add(atmCaps.get(k));
capVols[i + k][0] = getAtmVols()[k];
atmPos[k] = i + k;
++k;
}
}
}
final double[] allCapStrikes = new double[nStrikes + nCapEndTimes];
for (int i = 0; i < nStrikes + nCapEndTimes; ++i) {
allCapStrikes[i] = caps[i].get(0).getStrike();
}
final int sample = nStrikes + nCapEndTimes - 1;
final int nCapsSample = caps[sample].size();
final CapFloorIbor[] payments = caps[sample].get(nCapsSample - 1).getPayments();
final int nPayments = payments.length;
final double[] fixingTimes = new double[nPayments];
final double[] PaymentTimes = new double[nPayments];
for (int i = 0; i < nPayments; ++i) {
fixingTimes[i] = payments[i].getFixingTime();
PaymentTimes[i] = payments[i].getPaymentTime();
}
/*
* Use subset of full data
*/
int nStrikesUse = 5;
double[] strikesUse = new double[nStrikesUse];
List<CapFloor>[] capsUse = new List[nStrikesUse];
double[][] capVolsUse = new double[nStrikesUse][];
double[][] capVolsErrorUse = new double[nStrikesUse][];
double[][] guessUse = new double[nStrikesUse][nPayments];
for (int i = 0; i < nStrikesUse; ++i) {
strikesUse[i] = allCapStrikes[i];
capsUse[i] = caps[i];
capVolsUse[i] = capVols[i];
for (int j = 0; j < nPayments; ++j) {
guessUse[i][j] = 0.4;
}
capVolsErrorUse[i] = new double[capsUse[i].size()];
for (int j = 0; j < capsUse[i].size(); ++j) {
capVolsErrorUse[i][j] = 0.0001;
}
}
/*
* Solve
*/
final CapletVolatilityNodalSurfaceProvider provider = new CapletVolatilityNodalSurfaceProvider(strikesUse, fixingTimes);
final CapletStrippingDirectGlobalWithPenalty cpst = new CapletStrippingDirectGlobalWithPenalty(capsUse, getYieldCurves(), provider);
LeastSquareResults res = cpst.solveForVol(capVolsUse);
LeastSquareResults res1 = cpst.solveForVol(capVolsUse, capVolsErrorUse, guessUse);
DoubleMatrix1D resVec = res.getFitParameters();
DoubleMatrix1D resVec1 = res1.getFitParameters();
double[][] resMatrix = new double[nStrikesUse][nPayments];
double[][] resMatrix1 = new double[nStrikesUse][nPayments];
for (int i = 0; i < nStrikesUse; ++i) {
for (int j = 0; j < nPayments; ++j) {
resMatrix[i][j] = resVec.getEntry(i * nPayments + j);
resMatrix1[i][j] = resVec1.getEntry(i * nPayments + j);
}
}
for (int i = 0; i < nStrikesUse; ++i) {
final int nCaps = capsUse[i].size();
for (int j = 0; j < nCaps; ++j) {
CapFloor cf = capsUse[i].get(j);
CapFloorPricer pr = new CapFloorPricer(cf, getYieldCurves());
final int nP = pr.getNumberCaplets();
final double[] vols = Arrays.copyOf(resMatrix[i], nP);
assertEquals(capVolsUse[i][j], pr.impliedVol(vols), 1.e-2);
final double[] vols1 = Arrays.copyOf(resMatrix1[i], nP);
assertEquals(capVolsUse[i][j], pr.impliedVol(vols1), 1.e-2);
}
}
/**
* hashCode and equals
*/
final CapletStrippingDirectGlobalWithPenalty cpst1 = new CapletStrippingDirectGlobalWithPenalty(capsUse, getYieldCurves(), provider);
assertTrue(cpst.equals(cpst));
assertFalse(cpst.hashCode() == cpst1.hashCode());
assertFalse(cpst.equals(cpst1));
/**
* Exception expected
*/
try {
new CapletStrippingDirectGlobalWithPenalty(capsUse, getYieldCurves(), provider, 1.0, -1.0);
} catch (final Exception e) {
assertEquals("lambdaTime should be non-negative", e.getMessage());
}
try {
new CapletStrippingDirectGlobalWithPenalty(capsUse, getYieldCurves(), provider, -1.0, 1.0);
} catch (final Exception e) {
assertEquals("lambdaStrike should be non-negative", e.getMessage());
}
try {
cpst.solveForVol(capVols);
} catch (final Exception e) {
assertEquals("number of elements in input is different form expected vector length", e.getMessage());
}
try {
cpst.solveForVol(new double[][] {capVols[0] });
} catch (final Exception e) {
assertEquals("number of elements in input is different form expected vector length", e.getMessage());
}
}
private void assertArray(final Integer[] x, final Integer[] y) {
int n = x.length;
for (int i = 0; i < n; ++i) {
assertEquals(x[i], y[i]);
}
}
private void assertArray(final double[] x, final double[] y, final double eps) {
int n = x.length;
for (int i = 0; i < n; ++i) {
assertEquals(x[i], y[i], eps);
}
}
private void assertArray(final Double[] x, final Double[] y, final double eps) {
int n = x.length;
for (int i = 0; i < n; ++i) {
assertEquals(x[i], y[i], eps);
}
}
}