/**
* Copyright (C) 2013 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.strata.pricer.impl.credit.isda;
import static org.testng.AssertJUnit.assertEquals;
import static org.testng.AssertJUnit.assertNotSame;
import static org.testng.AssertJUnit.assertTrue;
import java.util.Arrays;
import org.joda.beans.BeanBuilder;
import org.testng.annotations.Test;
import com.opengamma.strata.collect.array.DoubleArray;
import com.opengamma.strata.market.curve.DefaultCurveMetadata;
import com.opengamma.strata.market.param.UnitParameterSensitivity;
/**
* Test {@link IsdaCompliantCurve}.
*/
@Test
public class IsdaCompliantCurveTest {
private static final double EPS = 1e-5;
/**
* no shift
*/
public void noShiftTest() {
double[] t = new double[] {0.03, 0.1, 0.2, 0.5, 0.7, 1.0, 2.0, 3.0, 3.4};
double[] r = new double[] {1.0, 0.8, 0.7, 1.2, 1.2, 1.3, 1.2, 1.0, 0.9};
double offset = 0.0;
IsdaCompliantCurve baseCurve = new IsdaCompliantCurve(t, r);
IsdaCompliantCurve offsetCurve = new IsdaCompliantCurve(t, r, offset);
assertEquals(9, offsetCurve.getNumberOfKnots());
double rtOffset = offset * r[0];
for (int i = 0; i < 100; i++) {
double time = 3.5 * i / 100.0 + offset;
double rt1 = baseCurve.getRT(time + offset) - rtOffset;
double rt2 = offsetCurve.getRT(time);
assertEquals(rt1, rt2);
}
}
/**
* Shift less than first knot
*/
public void baseShiftTest() {
double[] t = new double[] {0.03, 0.1, 0.2, 0.5, 0.7, 1.0, 2.0, 3.0, 3.4};
double[] r = new double[] {1.0, 0.8, 0.7, 1.2, 1.2, 1.3, 1.2, 1.0, 0.9};
double offset = 0.01;
IsdaCompliantCurve baseCurve = new IsdaCompliantCurve(t, r);
IsdaCompliantCurve offsetCurve = new IsdaCompliantCurve(t, r, offset);
assertEquals(9, offsetCurve.getNumberOfKnots());
double rtOffset = offset * r[0];
for (int i = 0; i < 100; i++) {
double time = 3.5 * i / 100.0 + offset;
double rt1 = baseCurve.getRT(time + offset) - rtOffset;
double rt2 = offsetCurve.getRT(time);
assertEquals(rt1, rt2, 1e-15);
}
}
/**
* shift between two knots
*/
public void baseShiftTest2() {
double[] t = new double[] {0.03, 0.1, 0.2, 0.5, 0.7, 1.0, 2.0, 3.0, 3.4};
double[] r = new double[] {1.0, 0.8, 0.7, 1.2, 1.2, 1.3, 1.2, 1.0, 0.9};
double offset = 0.3;
IsdaCompliantCurve baseCurve = new IsdaCompliantCurve(t, r);
IsdaCompliantCurve offsetCurve = new IsdaCompliantCurve(t, r, offset);
assertEquals(6, offsetCurve.getNumberOfKnots());
double rtOffset = baseCurve.getRT(offset);
for (int i = 0; i < 100; i++) {
double time = 4.0 * i / 100.;
double rt1 = baseCurve.getRT(time + offset) - rtOffset;
double rt2 = offsetCurve.getRT(time);
assertEquals(rt1, rt2, 1e-15);
}
}
/**
* shift to just before last knot and extrapolate at long way out
*/
public void baseShiftTest3() {
double[] t = new double[] {0.03, 0.1, 0.2, 0.5, 0.7, 1.0, 2.0, 3.0, 3.4};
double[] r = new double[] {1.0, 0.8, 0.7, 1.2, 1.2, 1.3, 1.2, 1.0, 0.9};
double offset = 3.3;
IsdaCompliantCurve baseCurve = new IsdaCompliantCurve(t, r);
IsdaCompliantCurve offsetCurve = new IsdaCompliantCurve(t, r, offset);
assertEquals(1, offsetCurve.getNumberOfKnots());
double rtOffset = baseCurve.getRT(offset);
for (int i = 0; i < 100; i++) {
double time = 5.0 * i / 100.;
double rt1 = baseCurve.getRT(time + offset) - rtOffset;
double rt2 = offsetCurve.getRT(time);
assertEquals(rt1, rt2, 1e-14);
}
}
/**
* shift exactly to one of the knots
*/
public void baseShiftTest4() {
double[] t = new double[] {0.03, 0.1, 0.2, 0.5, 0.7, 1.0, 2.0, 3.0, 3.4};
double[] r = new double[] {1.0, 0.8, 0.7, 0.5, 1.2, 1.3, 1.2, 1.0, 0.9};
double offset = 0.5;
IsdaCompliantCurve baseCurve = new IsdaCompliantCurve(t, r);
IsdaCompliantCurve offsetCurve = new IsdaCompliantCurve(t, r, offset);
assertEquals(5, offsetCurve.getNumberOfKnots());
double rtOffset = baseCurve.getRT(offset);
for (int i = 0; i < 100; i++) {
double time = 4.0 * i / 100.;
double rt1 = baseCurve.getRT(time + offset) - rtOffset;
double rt2 = offsetCurve.getRT(time);
assertEquals(rt1, rt2, 1e-14);
}
}
/**
* shift to last knot
*/
public void baseShiftTest5() {
double[] t = new double[] {0.03, 0.1, 0.2, 0.5, 0.7, 1.0, 2.0, 3.0, 3.4};
double[] r = new double[] {0.4, 0.8, 0.7, 1.2, 1.2, 1.3, 1.2, 1.0, 0.5};
double offset = 3.4;
IsdaCompliantCurve baseCurve = new IsdaCompliantCurve(t, r);
IsdaCompliantCurve offsetCurve = new IsdaCompliantCurve(t, r, offset);
assertEquals(1, offsetCurve.getNumberOfKnots());
double rtOffset = baseCurve.getRT(offset);
for (int i = 0; i < 100; i++) {
double time = 4.0 * i / 100.;
double rt1 = baseCurve.getRT(time + offset) - rtOffset;
double rt2 = offsetCurve.getRT(time);
assertEquals(rt1, rt2, 1e-14);
}
}
/**
* shift past last knot
*/
public void baseShiftTest6() {
double[] t = new double[] {0.03, 0.1, 0.2, 0.5, 0.7, 1.0, 2.0, 3.0, 3.4};
double[] r = new double[] {1.0, 0.8, 0.7, 1.2, 1.2, 1.3, 1.2, 1.0, 0.9};
double offset = 3.5;
IsdaCompliantCurve baseCurve = new IsdaCompliantCurve(t, r);
IsdaCompliantCurve offsetCurve = new IsdaCompliantCurve(t, r, offset);
assertEquals(1, offsetCurve.getNumberOfKnots());
double rtOffset = baseCurve.getRT(offset);
for (int i = 0; i < 100; i++) {
double time = 4.0 * i / 100.;
double rt1 = baseCurve.getRT(time + offset) - rtOffset;
double rt2 = offsetCurve.getRT(time);
assertEquals(rt1, rt2, 1e-14);
}
}
/**
* shift to first knot
*/
public void baseShiftTest7() {
double[] t = new double[] {0.03, 0.1, 0.2, 0.5, 0.7, 1.0, 2.0, 3.0, 3.4};
double[] r = new double[] {0.4, 0.8, 0.7, 1.2, 1.2, 1.3, 1.2, 1.0, 0.5};
double offset = 0.03;
IsdaCompliantCurve baseCurve = new IsdaCompliantCurve(t, r);
IsdaCompliantCurve offsetCurve = new IsdaCompliantCurve(t, r, offset);
assertEquals(8, offsetCurve.getNumberOfKnots());
double rtOffset = baseCurve.getRT(offset);
for (int i = 0; i < 100; i++) {
double time = 4.0 * i / 100.;
double rt1 = baseCurve.getRT(time + offset) - rtOffset;
double rt2 = offsetCurve.getRT(time);
assertEquals(rt1, rt2, 1e-15);
}
}
public void getRTTest() {
double[] t = new double[] {0.1, 0.2, 0.5, 0.7, 1.0, 2.0, 3.0, 3.4, 10.0};
double[] r = new double[] {1.0, 0.8, 0.7, 1.2, 1.2, 1.3, 1.2, 1.0, 0.9};
int n = t.length;
double[] rt = new double[n];
for (int i = 0; i < n; i++) {
rt[i] = r[i] * t[i];
}
IsdaCompliantCurve curve = new IsdaCompliantCurve(t, r);
double rTCalculatedi = 0.0;
double ti = 0.0;
int iterationMax = 1000000;
for (int i = 0; i < iterationMax; i++) {
ti = ti + i / iterationMax * 100;
if (ti <= t[0]) {
rTCalculatedi = ti * r[0];
}
else if (ti >= t[t.length - 1]) {
rTCalculatedi = ti * r[t.length - 1];
} else {
int indexpointi = Arrays.binarySearch(t, ti);
if (indexpointi >= 0) {
rTCalculatedi = t[indexpointi] * r[indexpointi];
} else {
indexpointi = -(1 + indexpointi);
if (indexpointi == 0) {
rTCalculatedi = ti * r[0];
} else if (indexpointi == n) {
rTCalculatedi = ti * r[n - 1];
} else {
double t1 = t[indexpointi - 1];
double t2 = t[indexpointi];
double dt = t2 - t1;
rTCalculatedi =
((t2 - ti) * r[indexpointi - 1] * t[indexpointi - 1] + (ti - t1) * r[indexpointi] * t[indexpointi]) / dt;
}
}
}
double rTexpectedi = curve.getRT(ti);
assertEquals("Time: " + ti, rTexpectedi, rTCalculatedi, 1e-10);
}
}
public void rtandSenseTest() {
double[] t = new double[] {0.1, 0.2, 0.5, 0.7, 1.0, 2.0, 3.0, 3.4, 10.0};
double[] r = new double[] {1.0, 0.8, 0.7, 1.2, 1.2, 1.3, 1.2, 1.0, 0.9};
int n = t.length;
IsdaCompliantCurve curve = new IsdaCompliantCurve(t, r);
for (int i = 0; i < 100; i++) {
double tt = i * 12.0 / 100;
double rt1 = curve.getRT(tt);
double[] fdSense = fdRTSense(curve, tt);
for (int jj = 0; jj < n; jj++) {
double[] rtandSense = curve.getRTandSensitivity(tt, jj);
assertEquals("rt " + tt, rt1, rtandSense[0], 1e-14);
assertEquals("sense " + tt + "\t" + jj, fdSense[jj], rtandSense[1], 1e-9);
}
}
}
public void getNodeSensitivity() {
double[] t = new double[] {0.1, 0.2, 0.5, 0.7, 1.0, 2.0, 3.0, 3.4, 10.0};
double[] r = new double[] {1.0, 0.8, 0.7, 1.2, 1.2, 1.3, 1.2, 1.0, 0.9};
int n = t.length;
double[] rt = new double[n];
for (int i = 0; i < n; i++) {
rt[i] = r[i] * t[i];
}
IsdaCompliantCurve curve = new IsdaCompliantCurve(t, r);
double[] rTCalculatedi = new double[n];
double ti = 0.0;
int iterationMax = 1000000;
for (int i = 0; i < iterationMax; i++) {
ti = ti + i / iterationMax * 100;
if (ti <= t[0]) {
rTCalculatedi[0] = 1.0;
}
else if (ti >= t[t.length - 1]) {
rTCalculatedi[t.length - 1] = 1.0;
} else {
int indexpointi = Arrays.binarySearch(t, ti);
if (indexpointi >= 0) {
rTCalculatedi[indexpointi] = 1.0;
} else {
indexpointi = -(1 + indexpointi);
if (indexpointi == 0) {
rTCalculatedi[0] = 1.0;
} else if (indexpointi == n) {
rTCalculatedi[n - 1] = 1.0;
} else {
double t1 = t[indexpointi - 1];
double t2 = t[indexpointi];
double dt = t2 - t1;
rTCalculatedi[indexpointi - 1] = t1 * (t2 - ti) / dt / ti;
rTCalculatedi[indexpointi] = t2 * (ti - t1) / dt / ti;
}
}
}
for (int j = 0; j < n; j++) {
DoubleArray rTexpectedi = curve.getNodeSensitivity(ti);
assertEquals("Time: " + ti, rTexpectedi.get(j), rTCalculatedi[j], 1e-10);
}
}
}
public void getNodeSensitivityvsFiniteDifferenceTest() {
double[] t = new double[] {0.1, 0.2, 0.5, 0.7, 1.0, 2.0, 3.0, 3.4, 10.0};
double[] r = new double[] {1.0, 0.8, 0.7, 1.2, 1.2, 1.3, 1.2, 1.0, 0.9};
int n = t.length;
IsdaCompliantCurve curve = new IsdaCompliantCurve(t, r);
double ti = 0.001;
int iterationMax = 10000;
for (int i = 1; i < iterationMax; i++) {
ti = ti + i / iterationMax * 100;
DoubleArray sensi = curve.getNodeSensitivity(ti);
for (int j = 0; j < n; j++) {
r[j] = r[j] + 10e-6;
curve = new IsdaCompliantCurve(t, r);
double sensii = curve.getRT(ti) / ti;
r[j] = r[j] - 2 * 10e-6;
curve = new IsdaCompliantCurve(t, r);
sensii = sensii - curve.getRT(ti) / ti;
sensii = sensii / (2 * 10e-6);
r[j] = r[j] + 10e-6;
curve = new IsdaCompliantCurve(t, r);
assertEquals("node: " + j, sensi.get(j), sensii, 1e-5);
}
}
}
public void getSingleNodeSensitivityvsNodesensitivityTest() {
double[] t = new double[] {0.1, 0.2, 0.5, 0.7, 1.0, 2.0, 3.0, 3.4, 10.0};
double[] r = new double[] {1.0, 0.8, 0.7, 1.2, 1.2, 1.3, 1.2, 1.0, 0.9};
IsdaCompliantCurve curve = new IsdaCompliantCurve(t, r);
double ti = 0.001;
int iterationMax = 1000000;
double sensitivityExpectedi = 0.0;
double sensitivityCalculatedi = 0.0;
for (int i = 0; i < iterationMax; i++) {
ti = ti + i / iterationMax * 100;
for (int j = 0; j < t.length; j++) {
sensitivityExpectedi = curve.getSingleNodeSensitivity(ti, j);
sensitivityCalculatedi = curve.getNodeSensitivity(ti).get(j);
assertEquals("Time: " + ti, sensitivityExpectedi, sensitivityCalculatedi, EPS);
}
}
}
public void getSingleNodeSensitivityvsSingleNodeDiscountFactorsensitivityTest() {
double[] t = new double[] {0.1, 0.2, 0.5, 0.7, 1.0, 2.0, 3.0, 3.4, 10.0};
double[] r = new double[] {1.0, 0.8, 0.7, 1.2, 1.2, 1.3, 1.2, 1.0, 0.9};
IsdaCompliantCurve curve = new IsdaCompliantCurve(t, r);
double ti = 0.001;
int iterationMax = 10000;
double sensitivityExpectedi = 0.0;
double sensitivityCalculatedi = 0.0;
for (int i = 0; i < iterationMax; i++) {
ti = ti + i / iterationMax * 100;
for (int j = 0; j < t.length; j++) {
sensitivityExpectedi = curve.getSingleNodeSensitivity(ti, j);
sensitivityExpectedi = -ti * sensitivityExpectedi * Math.exp(-curve.getRT(ti));
sensitivityCalculatedi = curve.getSingleNodeDiscountFactorSensitivity(ti, j);
assertEquals("Time: " + ti, sensitivityExpectedi, sensitivityCalculatedi, EPS);
}
}
}
public void withRatesTest() {
double[] t = new double[] {0.1, 0.2, 0.5, 0.7, 1.0, 2.0, 3.0, 3.4, 10.0};
double[] r1 = new double[] {1.0, 0.8, 0.7, 1.2, 1.2, 1.3, 1.2, 1.0, 0.9};
double[] r2 = new double[] {1.0, 0.8, 0.7, 1.2, 1.2, 1.3, 1.2, 1.0, 0.9};
IsdaCompliantCurve curve = new IsdaCompliantCurve(t, r1);
curve.withRates(r2);
for (int i = 0; i < t.length; i++) {
assertEquals("Node: " + i, curve.getZeroRate(t[i]), r2[i], EPS);
assertEquals("Node: " + i, curve.getRT(t[i]), r2[i] * t[i], EPS);
assertEquals("Node: " + i, curve.getDiscountFactor(t[i]), Math.exp(-r2[i] * t[i]), EPS);
}
}
public void withRateTest() {
double[] t = new double[] {0.1, 0.2, 0.5, 0.7, 1.0, 2.0, 3.0, 3.4, 10.0};
double[] r1 = new double[] {1.0, 0.8, 0.7, 1.2, 1.2, 1.3, 1.2, 1.0, 0.9};
double[] r2 = new double[] {1.0, 0.8, 0.7, 1.2, 1.2, 3.0, 1.2, 1.0, 0.9};
IsdaCompliantCurve curve = new IsdaCompliantCurve(t, r1);
IsdaCompliantCurve newcurve = curve.withRate(3.0, 5);
for (int i = 0; i < t.length; i++) {
assertEquals("Node: " + i, newcurve.getZeroRate(t[i]), r2[i], EPS);
assertEquals("Node: " + i, newcurve.getRT(t[i]), r2[i] * t[i], EPS);
assertEquals("Node: " + i, newcurve.getDiscountFactor(t[i]), Math.exp(-r2[i] * t[i]), EPS);
}
}
public void withDiscountFactorTest() {
double[] t = new double[] {0.1, 0.2, 0.5, 0.7, 1.0, 2.0, 3.0, 3.4, 10.0};
double[] r1 = new double[] {1.0, 0.8, 0.7, 1.2, 1.2, 1.3, 1.2, 1.0, 0.9};
double[] r2 = new double[] {1.0, 0.8, 0.7, 1.2, 1.2, -Math.log(0.6) / t[5], 1.2, 1.0, 0.9};
IsdaCompliantCurve curve = new IsdaCompliantCurve(t, r1);
IsdaCompliantCurve newcurve = curve.withDiscountFactor(.6, 5);
for (int i = 0; i < t.length; i++) {
assertEquals("Node: " + i, newcurve.getZeroRate(t[i]), r2[i], EPS);
assertEquals("Node: " + i, newcurve.getRT(t[i]), r2[i] * t[i], EPS);
assertEquals("Node: " + i, newcurve.getDiscountFactor(t[i]), Math.exp(-r2[i] * t[i]), EPS);
}
}
public void getZeroRateTest() {
double[] t = new double[] {0.1, 0.2, 0.5, 0.7, 1.0, 2.0, 3.0, 3.4, 10.0};
double[] r = new double[] {1.0, 0.8, 0.7, 1.2, 1.2, 1.3, 1.2, 1.0, 0.9};
IsdaCompliantCurve curve = new IsdaCompliantCurve(t, r);
double ti = 0.001;
int iterationMax = 1000000;
for (int i = 0; i < iterationMax; i++) {
ti = ti + i / iterationMax * 100;
assertEquals("Time: " + ti, curve.getZeroRate(ti), curve.getRT(ti) / ti, EPS);
}
}
public void getNumberOfKnotsTest() {
double[] t = new double[] {0.1, 0.2, 0.5, 0.7, 1.0, 2.0, 3.0, 3.4, 10.0};
double[] r = new double[] {1.0, 0.8, 0.7, 1.2, 1.2, 1.3, 1.2, 1.0, 0.9};
IsdaCompliantCurve curve = new IsdaCompliantCurve(t, r);
assertEquals("length", curve.getNumberOfKnots(), t.length, EPS);
}
public void offsetTest() {
double[] timesFromBase = new double[] {0.1, 0.2, 0.5, 0.7, 1.0, 2.0, 3.0, 3.4, 10.0};
double[] r = new double[] {0.04, 0.08, 0.07, 0.12, 0.12, 0.13, 0.12, 0.1, 0.09};
double offset = -0.04;
IsdaCompliantCurve c1 = new IsdaCompliantCurve(timesFromBase, r);
IsdaCompliantCurve c2 = new IsdaCompliantCurve(timesFromBase, r, offset);
double rtb = offset * r[0];
double pb = Math.exp(-rtb);
int steps = 1001;
for (int i = 0; i < steps; i++) {
double time = (12.0 * i) / (steps - 1) - offset;
double p1 = c1.getDiscountFactor(time + offset) / pb;
double p2 = c2.getDiscountFactor(time);
double rt1 = c1.getRT(time + offset) - rtb;
double rt2 = c2.getRT(time);
assertEquals("discount " + time, p1, p2, 1e-15);
assertEquals("rt " + time, rt1, rt2, 1e-15);
if (time > 0.0) {
double r1 = rt1 / time;
double r2 = c2.getZeroRate(time);
assertEquals("r " + time, r1, r2, 1e-15);
}
}
}
public void forwardRateTest() {
double[] t = new double[] {0.1, 0.2, 0.5, 0.7, 1.0, 2.0, 3.0, 7.0, 10.0};
double[] r = new double[] {0.04, 0.08, 0.07, 0.12, 0.12, 0.13, 0.12, 0.1, 0.09};
IsdaCompliantCurve c1 = new IsdaCompliantCurve(t, r);
double eps = 1e-5;
for (int i = 1; i < 241; i++) {
double time = eps + i * 0.05;
double f = c1.getForwardRate(time);
double rtUp = c1.getRT(time + eps);
double rtDown = c1.getRT(time - eps);
double fd = (rtUp - rtDown) / 2 / eps;
assertEquals(fd, f, 1e-10);
}
}
public void senseTest() {
double[] t = new double[] {0.1, 0.2, 0.5, 0.7, 1.0, 2.0, 3.0, 3.4, 10.0};
double[] r = new double[] {1.0, 0.8, 0.7, 1.2, 1.2, 1.3, 1.2, 1.0, 0.9};
IsdaCompliantCurve curve = new IsdaCompliantCurve(t, r);
int n = curve.getNumberOfKnots();
int nExamples = 200;
for (int jj = 0; jj < nExamples; jj++) {
double time = jj * 11.0 / (nExamples - 1);
double[] fd = fdSense(curve, time);
DoubleArray anal = curve.getNodeSensitivity(time);
for (int i = 0; i < n; i++) {
double anal2 = curve.getSingleNodeSensitivity(time, i);
assertEquals("test1 - Time: " + time, fd[i], anal.get(i), 1e-10);
assertEquals("test2 - Time: " + time, anal.get(i), anal2, 0.0);
}
}
// check nodes
for (int jj = 0; jj < n; jj++) {
DoubleArray anal = curve.getNodeSensitivity(t[jj]);
for (int i = 0; i < n; i++) {
double anal2 = curve.getSingleNodeSensitivity(t[jj], i);
double expected = i == jj ? 1.0 : 0.0;
assertEquals(expected, anal.get(i), 0.0);
assertEquals(expected, anal2, 0.0);
}
}
}
public void discountFactorSenseTest() {
double[] t = new double[] {0.1, 0.2, 0.5, 0.7, 1.0, 2.0, 3.0, 3.4, 10.0};
double[] r = new double[] {1.0, 0.8, 0.7, 1.2, 1.2, 1.3, 1.2, 1.0, 0.9};
IsdaCompliantCurve curve = new IsdaCompliantCurve(t, r);
int n = curve.getNumberOfKnots();
int nExamples = 200;
for (int jj = 0; jj < nExamples; jj++) {
double time = jj * 11.0 / (nExamples - 1);
double[] fd = fdDiscountFactorSense(curve, time);
for (int i = 0; i < n; i++) {
double anal = curve.getSingleNodeDiscountFactorSensitivity(time, i);
assertEquals("Time: " + time, fd[i], anal, 1e-10);
}
}
}
private double[] fdRTSense(IsdaCompliantCurve curve, double t) {
int n = curve.getNumberOfKnots();
double[] res = new double[n];
for (int i = 0; i < n; i++) {
double r = curve.getZeroRateAtIndex(i);
IsdaCompliantCurve curveUp = curve.withRate(r + EPS, i);
IsdaCompliantCurve curveDown = curve.withRate(r - EPS, i);
double up = curveUp.getRT(t);
double down = curveDown.getRT(t);
res[i] = (up - down) / 2 / EPS;
}
return res;
}
private double[] fdSense(IsdaCompliantCurve curve, double t) {
int n = curve.getNumberOfKnots();
double[] res = new double[n];
for (int i = 0; i < n; i++) {
double r = curve.getZeroRateAtIndex(i);
IsdaCompliantCurve curveUp = curve.withRate(r + EPS, i);
IsdaCompliantCurve curveDown = curve.withRate(r - EPS, i);
double up = curveUp.getZeroRate(t);
double down = curveDown.getZeroRate(t);
res[i] = (up - down) / 2 / EPS;
}
return res;
}
private double[] fdDiscountFactorSense(IsdaCompliantCurve curve, double t) {
int n = curve.getNumberOfKnots();
double[] res = new double[n];
for (int i = 0; i < n; i++) {
double r = curve.getZeroRateAtIndex(i);
IsdaCompliantCurve curveUp = curve.withRate(r + EPS, i);
IsdaCompliantCurve curveDown = curve.withRate(r - EPS, i);
double up = curveUp.getDiscountFactor(t);
double down = curveDown.getDiscountFactor(t);
res[i] = (up - down) / 2 / EPS;
}
return res;
}
/**
*
*/
public void buildTest() {
double tol = 1.e-13;
double[] time = new double[] {0.1, 0.3, 0.5, 1., 3.};
double[] forward = new double[] {0.06, 0.1, 0.05, 0.08, 0.11};
int num = time.length;
double[] r = new double[num];
double[] rt = new double[num];
IsdaCompliantCurve cv1 = IsdaCompliantCurve.makeFromForwardRates(time, forward);
assertEquals(num, cv1.getParameterCount());
double[] clonedTime = cv1.getKnotTimes();
assertNotSame(time, clonedTime);
rt[0] = forward[0] * time[0];
r[0] = forward[0];
double[] xData = cv1.getXValues().toArray();
double[] yData = cv1.getYValues().toArray();
for (int i = 1; i < num; ++i) {
rt[i] = rt[i - 1] + forward[i] * (time[i] - time[i - 1]);
r[i] = rt[i] / time[i];
assertEquals(r[i], cv1.getZeroRate(time[i]), EPS);
assertEquals(Math.exp(-rt[i]), cv1.getDiscountFactor(time[i]), EPS);
assertEquals(time[i], clonedTime[i]);
}
IsdaCompliantCurve cv1Clone = cv1.clone();
assertEquals(cv1.toString(), cv1Clone.toString());
double offset = 0.34;
IsdaCompliantCurve cv1Offset = cv1.withOffset(offset);
assertEquals(cv1.getDiscountFactor(0.75) / cv1.getDiscountFactor(offset), cv1Offset.getDiscountFactor(0.75 - offset), 1.e-14);
assertEquals(cv1.getDiscountFactor(1.) / cv1.getDiscountFactor(offset), cv1Offset.getDiscountFactor(1. - offset), 1.e-14);
assertEquals(cv1.getDiscountFactor(4.) / cv1.getDiscountFactor(offset), cv1Offset.getDiscountFactor(4. - offset), 1.e-14);
IsdaCompliantCurve cv2 = IsdaCompliantCurve.makeFromRT(time, rt);
IsdaCompliantCurve cv3 = new IsdaCompliantCurve(time, r);
assertEquals(cv1, cv2);
for (int i = 0; i < num; ++i) {
assertEquals(r[i], cv1.getZeroRate(time[i]), EPS);
assertEquals(Math.exp(-rt[i]), cv1.getDiscountFactor(time[i]), EPS);
assertEquals(time[i], xData[i]);
assertEquals(r[i], yData[i], EPS);
assertEquals(cv1.getTimeAtIndex(i), cv3.getTimeAtIndex(i), tol);
assertEquals(cv1.getRTAtIndex(i), cv3.getRTAtIndex(i), tol);
}
double[] T = new double[] {-0.3, -0.1, -0.};
double[] RT = new double[] {0.06, 0.1, 0.};
IsdaCompliantCurve cv11 = IsdaCompliantCurve.makeFromRT(T, RT);
double[] sen = cv11.getRTandSensitivity(0., 0);
assertEquals(cv11.getRT(0.), sen[0], tol);
assertEquals(0., sen[1], tol);
assertEquals(cv11.getForwardRate(0. - tol), cv11.getForwardRate(0.));
assertEquals(cv11.getForwardRate(T[1]), cv11.getForwardRate(T[1]));
UnitParameterSensitivity rtSense = cv1.yValueParameterSensitivity(0.33);
for (int i = 0; i < num; ++i) {
assertEquals(cv1.getSingleNodeSensitivity(0.33, i), rtSense.getSensitivity().get(i));
}
double[] refs = new double[] {0.04, 0.74, 2.};
double eps = 1.e-6;
double[] dydx = new double[] {cv1.firstDerivative(refs[0]), cv1.firstDerivative(refs[1]), cv1.firstDerivative(refs[2])};
for (int i = 0; i < refs.length; ++i) {
double res = 0.5 * (cv1.yValue(refs[i] * (1. + eps)) - cv1.yValue(refs[i] * (1. - eps))) / refs[i] / eps;
assertEquals(res, dydx[i], Math.abs(dydx[i] * eps));
}
/*
* Meta
*/
IsdaCompliantCurve.Meta meta = cv1.metaBean();
BeanBuilder<?> builder = meta.builder();
builder.set(meta.metaPropertyGet("metadata"), DefaultCurveMetadata.of("IsdaCompliantCurve"));
builder.set(meta.metaPropertyGet("t"), time);
builder.set(meta.metaPropertyGet("rt"), rt);
IsdaCompliantCurve builtCurve = (IsdaCompliantCurve) builder.build();
assertEquals(cv1, builtCurve);
assertEquals(meta.t(), meta.metaPropertyGet("t"));
assertEquals(meta.rt(), meta.metaPropertyGet("rt"));
IsdaCompliantCurve.Meta meta1 = IsdaCompliantCurve.meta();
assertEquals(meta, meta1);
/*
* hashCode and equals
*/
IsdaCompliantCurve cv4 = IsdaCompliantCurve.makeFromRT(new double[] {0.1, 0.2, 0.5, 1., 3.}, rt);
IsdaCompliantCurve cv5 = IsdaCompliantCurve.makeFromRT(new double[] {0.1, 0.3, 0.5, 1., 3.}, rt);
rt[1] *= 1.05;
IsdaCompliantCurve cv6 = IsdaCompliantCurve.makeFromRT(new double[] {0.1, 0.3, 0.5, 1., 3.}, rt);
assertTrue(cv1.equals(cv1));
assertTrue(!(cv5.equals(IsdaCompliantYieldCurve.makeFromRT(time, rt))));
assertTrue(cv1.hashCode() != cv6.hashCode());
assertTrue(!(cv1.equals(cv6)));
assertTrue(cv1.equals(cv5));
assertTrue(cv1.hashCode() == cv5.hashCode());
assertTrue(cv4.hashCode() != cv5.hashCode());
assertTrue(!(cv4.equals(cv5)));
/*
* Error returned
*/
try {
double[] shotTime = Arrays.copyOf(time, num - 1);
IsdaCompliantCurve.makeFromForwardRates(shotTime, forward);
throw new RuntimeException();
} catch (Exception e) {
assertTrue(e instanceof IllegalArgumentException);
}
try {
double[] shotTime = Arrays.copyOf(time, num - 1);
IsdaCompliantCurve.makeFromRT(shotTime, rt);
throw new RuntimeException();
} catch (Exception e) {
assertTrue(e instanceof IllegalArgumentException);
}
try {
double[] shotTime = Arrays.copyOf(time, num - 1);
new IsdaCompliantCurve(shotTime, rt);
throw new RuntimeException();
} catch (Exception e) {
assertTrue(e instanceof IllegalArgumentException);
}
try {
double[] negativeTime = Arrays.copyOf(time, num);
negativeTime[0] *= -1.;
new IsdaCompliantCurve(negativeTime, rt);
throw new RuntimeException();
} catch (Exception e) {
assertTrue(e instanceof IllegalArgumentException);
}
try {
double[] notSortTime = Arrays.copyOf(time, num);
notSortTime[2] *= 10.;
new IsdaCompliantCurve(notSortTime, rt);
throw new RuntimeException();
} catch (Exception e) {
assertTrue(e instanceof IllegalArgumentException);
}
try {
cv1.getZeroRate(-2.);
throw new RuntimeException();
} catch (Exception e) {
assertTrue(e instanceof IllegalArgumentException);
}
try {
cv1.getRTandSensitivity(-2., 1);
throw new RuntimeException();
} catch (Exception e) {
assertTrue(e instanceof IllegalArgumentException);
}
try {
cv1.getRTandSensitivity(2., -1);
throw new RuntimeException();
} catch (Exception e) {
assertTrue(e instanceof IllegalArgumentException);
}
try {
cv1.getRTandSensitivity(2., num + 2);
throw new RuntimeException();
} catch (Exception e) {
assertTrue(e instanceof IllegalArgumentException);
}
try {
cv1.getSingleNodeSensitivity(-2., 1);
throw new RuntimeException();
} catch (Exception e) {
assertTrue(e instanceof IllegalArgumentException);
}
try {
cv1.getSingleNodeSensitivity(2., -1);
throw new RuntimeException();
} catch (Exception e) {
assertTrue(e instanceof IllegalArgumentException);
}
try {
cv1.getSingleNodeSensitivity(2., num + 2);
throw new RuntimeException();
} catch (Exception e) {
assertTrue(e instanceof IllegalArgumentException);
}
try {
cv1.getSingleNodeRTSensitivity(-2., 1);
throw new RuntimeException();
} catch (Exception e) {
assertTrue(e instanceof IllegalArgumentException);
}
try {
cv1.getSingleNodeRTSensitivity(2., -1);
throw new RuntimeException();
} catch (Exception e) {
assertTrue(e instanceof IllegalArgumentException);
}
try {
cv1.getSingleNodeRTSensitivity(2., num + 2);
throw new RuntimeException();
} catch (Exception e) {
assertTrue(e instanceof IllegalArgumentException);
}
try {
cv1.withRate(2., -1);
throw new RuntimeException();
} catch (Exception e) {
assertTrue(e instanceof IllegalArgumentException);
}
try {
cv1.withRate(2., num + 2);
throw new RuntimeException();
} catch (Exception e) {
assertTrue(e instanceof IllegalArgumentException);
}
try {
cv1.setRate(2., -1);
throw new RuntimeException();
} catch (Exception e) {
assertTrue(e instanceof IllegalArgumentException);
}
try {
cv1.setRate(2., num + 2);
throw new RuntimeException();
} catch (Exception e) {
assertTrue(e instanceof IllegalArgumentException);
}
try {
cv1.withDiscountFactor(2., -1);
throw new RuntimeException();
} catch (Exception e) {
assertTrue(e instanceof IllegalArgumentException);
}
try {
cv1.withDiscountFactor(2., num + 2);
throw new RuntimeException();
} catch (Exception e) {
assertTrue(e instanceof IllegalArgumentException);
}
}
}