/**
* Copyright (C) 2011 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.analytics.financial.model.interestrate;
import static org.testng.AssertJUnit.assertEquals;
import static org.testng.AssertJUnit.assertFalse;
import static org.testng.AssertJUnit.assertTrue;
import org.testng.annotations.Test;
import org.testng.internal.junit.ArrayAsserts;
import org.threeten.bp.LocalDate;
import org.threeten.bp.LocalDateTime;
import org.threeten.bp.LocalTime;
import org.threeten.bp.ZoneOffset;
import org.threeten.bp.ZonedDateTime;
import com.opengamma.analytics.financial.instrument.future.InterestRateFutureSecurityDefinition;
import com.opengamma.analytics.financial.instrument.index.IborIndex;
import com.opengamma.analytics.financial.instrument.index.IndexIborMaster;
import com.opengamma.analytics.financial.interestrate.future.derivative.InterestRateFutureSecurity;
import com.opengamma.analytics.financial.model.interestrate.definition.HullWhiteOneFactorPiecewiseConstantParameters;
import com.opengamma.analytics.financial.schedule.ScheduleCalculator;
import com.opengamma.financial.convention.calendar.Calendar;
import com.opengamma.financial.convention.calendar.MondayToFridayCalendar;
import com.opengamma.util.test.TestGroup;
import com.opengamma.util.time.DateUtils;
import com.opengamma.util.tuple.Pair;
/**
* Tests related to the construction of the Hull-White one factor model with piecewise constant volatility. The computation of several model related factors are also tested.
*/
@Test(groups = TestGroup.UNIT)
public class HullWhiteOneFactorPiecewiseConstantInterestRateModelTest {
private static final double MEAN_REVERSION = 0.01;
private static final double[] VOLATILITY = new double[] {0.01, 0.011, 0.012, 0.013, 0.014 };
private static final double[] VOLATILITY_TIME = new double[] {0.5, 1.0, 2.0, 5.0 };
private static final HullWhiteOneFactorPiecewiseConstantParameters MODEL_PARAMETERS = new HullWhiteOneFactorPiecewiseConstantParameters(MEAN_REVERSION, VOLATILITY, VOLATILITY_TIME);
private static final HullWhiteOneFactorPiecewiseConstantInterestRateModel MODEL = new HullWhiteOneFactorPiecewiseConstantInterestRateModel();
private static final double[] DCF_FIXED = new double[] {0.50, 0.48 };
private static final double[] ALPHA_FIXED = new double[] {0.02, 0.04 };
private static final double[] DCF_IBOR = new double[] {-1.0, -0.01, 0.01, -0.01, 0.95 };
private static final double[] ALPHA_IBOR = new double[] {0.00, 0.01, 0.02, 0.03, 0.04 };
private static final double TOLERANCE_RATE = 1.0E-10;
private static final double TOLERANCE_RATE_DELTA = 1.0E-8;
private static final double TOLERANCE_RATE_DELTA2 = 1.0E-7;
private static final double TOLERANCE_ALPHA = 1E-8;
private static final IborIndex EURIBOR3M = IndexIborMaster.getInstance().getIndex("EURIBOR3M");
@Test
/**
* Tests the class getters.
*/
public void getter() {
assertEquals(MEAN_REVERSION, MODEL_PARAMETERS.getMeanReversion());
for (int loopperiod = 0; loopperiod < VOLATILITY.length; loopperiod++) {
assertEquals(VOLATILITY[loopperiod], MODEL_PARAMETERS.getVolatility()[loopperiod]);
}
final double[] volTime = MODEL_PARAMETERS.getVolatilityTime();
for (int loopperiod = 0; loopperiod < VOLATILITY_TIME.length; loopperiod++) {
assertEquals(VOLATILITY_TIME[loopperiod], volTime[loopperiod + 1]);
}
}
@Test
/**
* Tests the class setters.
*/
public void setter() {
final double volReplaced = 0.02;
MODEL_PARAMETERS.setLastVolatility(volReplaced);
assertEquals(volReplaced, MODEL_PARAMETERS.getVolatility()[MODEL_PARAMETERS.getVolatility().length - 1]);
MODEL_PARAMETERS.setLastVolatility(VOLATILITY[VOLATILITY.length - 1]);
for (int loopperiod = 0; loopperiod < VOLATILITY.length; loopperiod++) {
assertEquals(VOLATILITY[loopperiod], MODEL_PARAMETERS.getVolatility()[loopperiod]);
}
}
@Test
/**
* Tests the equal and hash code methods.
*/
public void equalHash() {
final HullWhiteOneFactorPiecewiseConstantParameters newParameter = new HullWhiteOneFactorPiecewiseConstantParameters(MEAN_REVERSION, VOLATILITY, VOLATILITY_TIME);
assertTrue("Hull-White model equals", MODEL_PARAMETERS.equals(newParameter));
assertTrue("Hull-White model hash code", MODEL_PARAMETERS.hashCode() == newParameter.hashCode());
final HullWhiteOneFactorPiecewiseConstantParameters modifiedParameter = new HullWhiteOneFactorPiecewiseConstantParameters(MEAN_REVERSION + 0.01, VOLATILITY, VOLATILITY_TIME);
assertFalse("Hull-White model equals", MODEL_PARAMETERS.equals(modifiedParameter));
}
@Test
/**
* Test the future convexity adjustment factor v a hard-coded value.
*/
public void futureConvexityFactor() {
final Calendar calendar = new MondayToFridayCalendar("A");
final ZonedDateTime SPOT_LAST_TRADING_DATE = DateUtils.getUTCDate(2012, 9, 19);
final ZonedDateTime LAST_TRADING_DATE = ScheduleCalculator.getAdjustedDate(SPOT_LAST_TRADING_DATE, -EURIBOR3M.getSpotLag(), calendar);
final double noitonal = 1000000.0; // 1m
final double futuresAccrualFactor = 0.25;
final double referencePrice = 0.99;
final String name = "ERU2";
final LocalDate REFERENCE_DATE = LocalDate.of(2010, 8, 18);
final ZonedDateTime REFERENCE_DATE_ZONED = ZonedDateTime.of(LocalDateTime.of(REFERENCE_DATE, LocalTime.MIDNIGHT), ZoneOffset.UTC);
final InterestRateFutureSecurityDefinition eru2Definition = new InterestRateFutureSecurityDefinition(LAST_TRADING_DATE, EURIBOR3M, noitonal, futuresAccrualFactor, name, calendar);
final InterestRateFutureSecurity eru2 = eru2Definition.toDerivative(REFERENCE_DATE_ZONED);
final double factor = MODEL.futuresConvexityFactor(MODEL_PARAMETERS, eru2.getTradingLastTime(), eru2.getFixingPeriodStartTime(), eru2.getFixingPeriodEndTime());
final double expectedFactor = 1.000079130767980;
assertEquals("Hull-White one factor: future convexity adjusment factor", expectedFactor, factor, TOLERANCE_RATE);
// Derivative with respect to volatility parameters
final int nbSigma = MODEL_PARAMETERS.getVolatility().length;
final double[] sigmaBar = new double[nbSigma];
final double factor2 = MODEL.futuresConvexityFactor(MODEL_PARAMETERS, eru2.getTradingLastTime(), eru2.getFixingPeriodStartTime(), eru2.getFixingPeriodEndTime(), sigmaBar);
assertEquals("Hull-White one factor: future convexity adjusment factor", factor, factor2, TOLERANCE_RATE);
final double[] sigmaBarExpected = new double[nbSigma];
final double shift = 1E-6;
for (int loops = 0; loops < nbSigma; loops++) {
double[] volBumped = VOLATILITY.clone();
volBumped[loops] += shift;
HullWhiteOneFactorPiecewiseConstantParameters parametersBumped = new HullWhiteOneFactorPiecewiseConstantParameters(MEAN_REVERSION, volBumped, VOLATILITY_TIME);
double factorPlus = MODEL.futuresConvexityFactor(parametersBumped, eru2.getTradingLastTime(), eru2.getFixingPeriodStartTime(), eru2.getFixingPeriodEndTime());
volBumped[loops] -= 2 * shift;
parametersBumped = new HullWhiteOneFactorPiecewiseConstantParameters(MEAN_REVERSION, volBumped, VOLATILITY_TIME);
double factorMinus = MODEL.futuresConvexityFactor(parametersBumped, eru2.getTradingLastTime(), eru2.getFixingPeriodStartTime(), eru2.getFixingPeriodEndTime());
sigmaBarExpected[loops] = (factorPlus - factorMinus) / (2 * shift);
assertEquals("Hull-White one factor: future convexity adjusment factor", sigmaBarExpected[loops], sigmaBar[loops], TOLERANCE_RATE);
}
}
@Test
/**
* Test the payment delay convexity adjustment factor.
*/
public void paymentDelayConvexityFactor() {
final double startExpiryTime = 1.00;
final double endExpiryTime = 3.00;
final double startFixingPeriod = 3.05;
final double endFixingPeriod = 3.55;
final double paymentTime = 3.45;
final double hwMeanReversion = 0.011;
// Constant volatility
final double hwEta = 0.02;
final HullWhiteOneFactorPiecewiseConstantParameters parameters = new HullWhiteOneFactorPiecewiseConstantParameters(hwMeanReversion, new double[] {hwEta }, new double[0]);
final double factor1 = (Math.exp(-hwMeanReversion * endFixingPeriod) - Math.exp(-hwMeanReversion * paymentTime)) *
(Math.exp(-hwMeanReversion * endFixingPeriod) - Math.exp(-hwMeanReversion * startFixingPeriod));
final double num = 2 * Math.pow(hwMeanReversion, 3);
final double factor2 = hwEta * hwEta * (Math.exp(2 * hwMeanReversion * endExpiryTime) - Math.exp(2 * hwMeanReversion * startExpiryTime));
final double factorExpected = Math.exp(factor1 * factor2 / num);
final double factorComputed = MODEL.paymentDelayConvexityFactor(parameters, startExpiryTime, endExpiryTime, startFixingPeriod, endFixingPeriod, paymentTime);
assertEquals("Hull-White one factor: payment delay adjustment factor", factorExpected, factorComputed, TOLERANCE_RATE);
// Piecewise constant constant volatility
final double[] hwEtaP = new double[] {0.02, 0.021, 0.022, 0.023 };
final double[] hwTime = new double[] {0.5, 1.0, 2.0 };
final HullWhiteOneFactorPiecewiseConstantParameters parametersP = new HullWhiteOneFactorPiecewiseConstantParameters(hwMeanReversion, hwEtaP, hwTime);
double factorP2 = hwEtaP[2] * hwEtaP[2] * (Math.exp(2 * hwMeanReversion * hwTime[2]) - Math.exp(2 * hwMeanReversion * startExpiryTime));
factorP2 += hwEtaP[3] * hwEtaP[3] * (Math.exp(2 * hwMeanReversion * endExpiryTime) - Math.exp(2 * hwMeanReversion * hwTime[2]));
final double factorPExpected = Math.exp(factor1 * factorP2 / num);
final double factorPComputed = MODEL.paymentDelayConvexityFactor(parametersP, startExpiryTime, endExpiryTime, startFixingPeriod, endFixingPeriod, paymentTime);
assertEquals("Hull-White one factor: payment delay adjustment factor", factorPExpected, factorPComputed, TOLERANCE_RATE);
}
@Test
/**
* Test the bond volatility (called alpha) vs a hard-coded value.
*/
public void alpha() {
final double expiry1 = 0.25;
final double expiry2 = 2.25;
final double numeraire = 10.0;
final double maturity = 9.0;
double alphaExpected = -0.015191631;
double alpha = MODEL.alpha(MODEL_PARAMETERS, expiry1, expiry2, numeraire, maturity); //All data
assertEquals("Hull-White one factor: bond volatility (alpha) - all", alphaExpected, alpha, TOLERANCE_ALPHA);
alphaExpected = -0.015859116;
alpha = MODEL.alpha(MODEL_PARAMETERS, 0.0, expiry2, numeraire, maturity);//From today
assertEquals("Hull-White one factor: bond volatility (alpha)- today", alphaExpected, alpha, TOLERANCE_ALPHA);
alphaExpected = 0.111299267;
alpha = MODEL.alpha(MODEL_PARAMETERS, 0.0, expiry2, expiry2, maturity);// From today with expiry numeraire
assertEquals("Hull-White one factor: bond volatility (alpha) - today and expiry numeraire", alphaExpected, alpha, TOLERANCE_ALPHA);
alpha = MODEL.alpha(MODEL_PARAMETERS, 0.0, 0.0, numeraire, maturity); // From 0 to 0
assertEquals("Hull-White one factor: bond volatility (alpha) - today and expiry numeraire", 0.0d, alpha, TOLERANCE_ALPHA);
}
@Test
/**
* Test the adjoint algorithmic differentiation version of alpha.
*/
public void alphaDSigma() {
final double expiry1 = 0.25;
final double expiry2 = 2.25;
final double numeraire = 10.0;
final double maturity = 9.0;
final int nbVolatility = VOLATILITY.length;
final double[] alphaDerivatives = new double[nbVolatility];
final double alpha = MODEL.alpha(MODEL_PARAMETERS, expiry1, expiry2, numeraire, maturity, alphaDerivatives);
final double alpha2 = MODEL.alpha(MODEL_PARAMETERS, expiry1, expiry2, numeraire, maturity);
assertEquals("Alpha adjoint: value", alpha2, alpha, 1.0E-10);
final double shiftVol = 1.0E-6;
final double[] volatilityBumped = new double[nbVolatility];
System.arraycopy(VOLATILITY, 0, volatilityBumped, 0, nbVolatility);
final double[] alphaBumpedPlus = new double[nbVolatility];
final double[] alphaBumpedMinus = new double[nbVolatility];
HullWhiteOneFactorPiecewiseConstantParameters parametersBumped;
for (int loopvol = 0; loopvol < nbVolatility; loopvol++) {
volatilityBumped[loopvol] += shiftVol;
parametersBumped = new HullWhiteOneFactorPiecewiseConstantParameters(MEAN_REVERSION, volatilityBumped, VOLATILITY_TIME);
alphaBumpedPlus[loopvol] = MODEL.alpha(parametersBumped, expiry1, expiry2, numeraire, maturity);
volatilityBumped[loopvol] -= 2 * shiftVol;
parametersBumped = new HullWhiteOneFactorPiecewiseConstantParameters(MEAN_REVERSION, volatilityBumped, VOLATILITY_TIME);
alphaBumpedMinus[loopvol] = MODEL.alpha(parametersBumped, expiry1, expiry2, numeraire, maturity);
assertEquals("Alpha adjoint: derivative " + loopvol + " - Difference: " + ((alphaBumpedPlus[loopvol] - alphaBumpedMinus[loopvol]) / (2 * shiftVol) - alphaDerivatives[loopvol]),
(alphaBumpedPlus[loopvol] - alphaBumpedMinus[loopvol]) / (2 * shiftVol), alphaDerivatives[loopvol], 1.0E-9);
volatilityBumped[loopvol] = VOLATILITY[loopvol];
}
}
@Test
/**
* Test the swaption exercise boundary.
*/
public void kappa() {
final double[] cashFlowAmount = new double[] {-1.0, 0.05, 0.05, 0.05, 0.05, 1.05 };
final double notional = 100000000; // 100m
final double[] cashFlowTime = new double[] {10.0, 11.0, 12.0, 13.0, 14.00, 15.00 };
final double expiryTime = cashFlowTime[0] - 2.0 / 365.0;
final int nbCF = cashFlowAmount.length;
final double[] discountedCashFlow = new double[nbCF];
final double[] alpha = new double[nbCF];
final double rate = 0.04;
for (int loopcf = 0; loopcf < nbCF; loopcf++) {
discountedCashFlow[loopcf] = cashFlowAmount[loopcf] * Math.exp(-rate * cashFlowTime[loopcf]) * notional;
alpha[loopcf] = MODEL.alpha(MODEL_PARAMETERS, 0.0, expiryTime, expiryTime, cashFlowTime[loopcf]);
}
final double kappa = MODEL.kappa(discountedCashFlow, alpha);
double swapValue = 0.0;
for (int loopcf = 0; loopcf < nbCF; loopcf++) {
swapValue += discountedCashFlow[loopcf] * Math.exp(-Math.pow(alpha[loopcf], 2.0) / 2.0 - alpha[loopcf] * kappa);
}
assertEquals("Exercise boundary", 0.0, swapValue, 1.0E-1);
}
@Test
public void swapRate() {
final double shift = 1.0E-4;
final double x = 0.1;
double numerator = 0.0;
for (int loopcf = 0; loopcf < DCF_IBOR.length; loopcf++) {
numerator += DCF_IBOR[loopcf] * Math.exp(-ALPHA_IBOR[loopcf] * x - 0.5 * ALPHA_IBOR[loopcf] * ALPHA_IBOR[loopcf]);
}
double denominator = 0.0;
for (int loopcf = 0; loopcf < DCF_FIXED.length; loopcf++) {
denominator += DCF_FIXED[loopcf] * Math.exp(-ALPHA_FIXED[loopcf] * x - 0.5 * ALPHA_FIXED[loopcf] * ALPHA_FIXED[loopcf]);
}
final double swapRateExpected = -numerator / denominator;
final double swapRateComputed = MODEL.swapRate(x, DCF_FIXED, ALPHA_FIXED, DCF_IBOR, ALPHA_IBOR);
assertEquals("Hull-White model: swap rate", swapRateExpected, swapRateComputed, TOLERANCE_RATE);
final double swapRatePlus = MODEL.swapRate(x + shift, DCF_FIXED, ALPHA_FIXED, DCF_IBOR, ALPHA_IBOR);
final double swapRateMinus = MODEL.swapRate(x - shift, DCF_FIXED, ALPHA_FIXED, DCF_IBOR, ALPHA_IBOR);
final double swapRateDx1Expected = (swapRatePlus - swapRateMinus) / (2 * shift);
final double swapRateDx1Computed = MODEL.swapRateDx1(x, DCF_FIXED, ALPHA_FIXED, DCF_IBOR, ALPHA_IBOR);
assertEquals("Hull-White model: swap rate", swapRateDx1Expected, swapRateDx1Computed, TOLERANCE_RATE_DELTA);
final double swapRateDx2Expected = (swapRatePlus + swapRateMinus - 2 * swapRateComputed) / (shift * shift);
final double swapRateDx2Computed = MODEL.swapRateDx2(x, DCF_FIXED, ALPHA_FIXED, DCF_IBOR, ALPHA_IBOR);
assertEquals("Hull-White model: swap rate", swapRateDx2Expected, swapRateDx2Computed, TOLERANCE_RATE_DELTA2);
}
@Test
public void swapRateDdcf() {
final double shift = 1.0E-8;
final double x = 0.0;
final double[] ddcffComputed = MODEL.swapRateDdcff1(x, DCF_FIXED, ALPHA_FIXED, DCF_IBOR, ALPHA_IBOR);
final double[] ddcffExpected = new double[DCF_FIXED.length];
for (int loopcf = 0; loopcf < DCF_FIXED.length; loopcf++) {
final double[] dsf_bumped = DCF_FIXED.clone();
dsf_bumped[loopcf] += shift;
final double swapRatePlus = MODEL.swapRate(x, dsf_bumped, ALPHA_FIXED, DCF_IBOR, ALPHA_IBOR);
dsf_bumped[loopcf] -= 2 * shift;
final double swapRateMinus = MODEL.swapRate(x, dsf_bumped, ALPHA_FIXED, DCF_IBOR, ALPHA_IBOR);
ddcffExpected[loopcf] = (swapRatePlus - swapRateMinus) / (2 * shift);
}
ArrayAsserts.assertArrayEquals("Hull-White model: swap rate", ddcffExpected, ddcffComputed, TOLERANCE_RATE_DELTA);
final double[] ddcfiExpected = new double[DCF_IBOR.length];
for (int loopcf = 0; loopcf < DCF_IBOR.length; loopcf++) {
final double[] dsf_bumped = DCF_IBOR.clone();
dsf_bumped[loopcf] += shift;
final double swapRatePlus = MODEL.swapRate(x, DCF_FIXED, ALPHA_FIXED, dsf_bumped, ALPHA_IBOR);
dsf_bumped[loopcf] -= 2 * shift;
final double swapRateMinus = MODEL.swapRate(x, DCF_FIXED, ALPHA_FIXED, dsf_bumped, ALPHA_IBOR);
ddcfiExpected[loopcf] = (swapRatePlus - swapRateMinus) / (2 * shift);
}
final double[] ddcfiComputed = MODEL.swapRateDdcfi1(x, DCF_FIXED, ALPHA_FIXED, DCF_IBOR, ALPHA_IBOR);
ArrayAsserts.assertArrayEquals("Hull-White model: swap rate", ddcfiExpected, ddcfiComputed, TOLERANCE_RATE_DELTA);
}
@Test
public void swapRateDa() {
final double shift = 1.0E-8;
final double x = 0.0;
final double[] dafComputed = MODEL.swapRateDaf1(x, DCF_FIXED, ALPHA_FIXED, DCF_IBOR, ALPHA_IBOR);
final double[] dafExpected = new double[ALPHA_FIXED.length];
for (int loopcf = 0; loopcf < ALPHA_FIXED.length; loopcf++) {
final double[] afBumped = ALPHA_FIXED.clone();
afBumped[loopcf] += shift;
final double swapRatePlus = MODEL.swapRate(x, DCF_FIXED, afBumped, DCF_IBOR, ALPHA_IBOR);
afBumped[loopcf] -= 2 * shift;
final double swapRateMinus = MODEL.swapRate(x, DCF_FIXED, afBumped, DCF_IBOR, ALPHA_IBOR);
dafExpected[loopcf] = (swapRatePlus - swapRateMinus) / (2 * shift);
}
ArrayAsserts.assertArrayEquals("Hull-White model: swap rate dAlphaFixed", dafExpected, dafComputed, TOLERANCE_RATE_DELTA);
final double[] daiExpected = new double[DCF_IBOR.length];
for (int loopcf = 0; loopcf < DCF_IBOR.length; loopcf++) {
final double[] aiBumped = ALPHA_IBOR.clone();
aiBumped[loopcf] += shift;
final double swapRatePlus = MODEL.swapRate(x, DCF_FIXED, ALPHA_FIXED, DCF_IBOR, aiBumped);
aiBumped[loopcf] -= 2 * shift;
final double swapRateMinus = MODEL.swapRate(x, DCF_FIXED, ALPHA_FIXED, DCF_IBOR, aiBumped);
daiExpected[loopcf] = (swapRatePlus - swapRateMinus) / (2 * shift);
}
final double[] daiComputed = MODEL.swapRateDai1(x, DCF_FIXED, ALPHA_FIXED, DCF_IBOR, ALPHA_IBOR);
ArrayAsserts.assertArrayEquals("Hull-White model: swap rate dAlphaIbor", daiExpected, daiComputed, TOLERANCE_RATE_DELTA);
}
@Test
public void swapRateDx2Ddcf() {
final double shift = 1.0E-7;
final double x = 0.0;
final Pair<double[], double[]> dx2ddcfComputed = MODEL.swapRateDx2Ddcf1(x, DCF_FIXED, ALPHA_FIXED, DCF_IBOR, ALPHA_IBOR);
final double[] dx2DdcffExpected = new double[DCF_FIXED.length];
for (int loopcf = 0; loopcf < DCF_FIXED.length; loopcf++) {
final double[] dsf_bumped = DCF_FIXED.clone();
dsf_bumped[loopcf] += shift;
final double swapRatePlus = MODEL.swapRateDx2(x, dsf_bumped, ALPHA_FIXED, DCF_IBOR, ALPHA_IBOR);
dsf_bumped[loopcf] -= 2 * shift;
final double swapRateMinus = MODEL.swapRateDx2(x, dsf_bumped, ALPHA_FIXED, DCF_IBOR, ALPHA_IBOR);
dx2DdcffExpected[loopcf] = (swapRatePlus - swapRateMinus) / (2 * shift);
}
ArrayAsserts.assertArrayEquals("Hull-White model: swap rate", dx2DdcffExpected, dx2ddcfComputed.getFirst(), TOLERANCE_RATE_DELTA2);
final double[] dx2DdcfiExpected = new double[DCF_IBOR.length];
for (int loopcf = 0; loopcf < DCF_IBOR.length; loopcf++) {
final double[] dsf_bumped = DCF_IBOR.clone();
dsf_bumped[loopcf] += shift;
final double swapRatePlus = MODEL.swapRateDx2(x, DCF_FIXED, ALPHA_FIXED, dsf_bumped, ALPHA_IBOR);
dsf_bumped[loopcf] -= 2 * shift;
final double swapRateMinus = MODEL.swapRateDx2(x, DCF_FIXED, ALPHA_FIXED, dsf_bumped, ALPHA_IBOR);
dx2DdcfiExpected[loopcf] = (swapRatePlus - swapRateMinus) / (2 * shift);
}
ArrayAsserts.assertArrayEquals("Hull-White model: swap rate", dx2DdcfiExpected, dx2ddcfComputed.getSecond(), TOLERANCE_RATE_DELTA2);
}
@Test
public void swapRateDx2Da() {
final double shift = 1.0E-7;
final double x = 0.0;
final Pair<double[], double[]> dx2DaComputed = MODEL.swapRateDx2Da1(x, DCF_FIXED, ALPHA_FIXED, DCF_IBOR, ALPHA_IBOR);
final double[] dx2DafExpected = new double[DCF_FIXED.length];
for (int loopcf = 0; loopcf < DCF_FIXED.length; loopcf++) {
final double[] afBumped = ALPHA_FIXED.clone();
afBumped[loopcf] += shift;
final double swapRatePlus = MODEL.swapRateDx2(x, DCF_FIXED, afBumped, DCF_IBOR, ALPHA_IBOR);
afBumped[loopcf] -= 2 * shift;
final double swapRateMinus = MODEL.swapRateDx2(x, DCF_FIXED, afBumped, DCF_IBOR, ALPHA_IBOR);
dx2DafExpected[loopcf] = (swapRatePlus - swapRateMinus) / (2 * shift);
}
ArrayAsserts.assertArrayEquals("Hull-White model: swap rate - dx2 dAlphaFixed", dx2DafExpected, dx2DaComputed.getFirst(), TOLERANCE_RATE_DELTA2);
final double[] dx2DaiExpected = new double[DCF_IBOR.length];
for (int loopcf = 0; loopcf < DCF_IBOR.length; loopcf++) {
final double[] aiBumped = ALPHA_IBOR.clone();
aiBumped[loopcf] += shift;
final double swapRatePlus = MODEL.swapRateDx2(x, DCF_FIXED, ALPHA_FIXED, DCF_IBOR, aiBumped);
aiBumped[loopcf] -= 2 * shift;
final double swapRateMinus = MODEL.swapRateDx2(x, DCF_FIXED, ALPHA_FIXED, DCF_IBOR, aiBumped);
dx2DaiExpected[loopcf] = (swapRatePlus - swapRateMinus) / (2 * shift);
}
ArrayAsserts.assertArrayEquals("Hull-White model: swap rate - dx2 dAlphaIbor", dx2DaiExpected, dx2DaComputed.getSecond(), TOLERANCE_RATE_DELTA2);
}
@Test(enabled = false)
/**
* Tests of performance. "enabled = false" for the standard testing.
*/
public void performanceAlphaAdjoint() {
final double expiry1 = 0.25;
final double expiry2 = 2.25;
final double numeraire = 10.0;
final double maturity = 9.0;
final int nbVolatility = VOLATILITY.length;
final double[] alphaDerivatives = new double[nbVolatility];
long startTime, endTime;
final int nbTest = 100000;
double alpha = 0.0;
startTime = System.currentTimeMillis();
for (int looptest = 0; looptest < nbTest; looptest++) {
alpha = MODEL.alpha(MODEL_PARAMETERS, expiry1, expiry2, numeraire, maturity);
}
endTime = System.currentTimeMillis();
System.out.println(nbTest + " alpha Hull-White: " + (endTime - startTime) + " ms");
startTime = System.currentTimeMillis();
for (int looptest = 0; looptest < nbTest; looptest++) {
alpha = MODEL.alpha(MODEL_PARAMETERS, expiry1, expiry2, numeraire, maturity, alphaDerivatives);
}
endTime = System.currentTimeMillis();
System.out.println(nbTest + " alpha Hull-White adjoint (value+" + nbVolatility + " derivatives): " + (endTime - startTime) + " ms");
// Performance note: value: 31-Aug-11: On Mac Pro 3.2 GHz Quad-Core Intel Xeon: 75 ms for 1000000 swaptions.
// Performance note: value+derivatives: 31-Aug-11: On Mac Pro 3.2 GHz Quad-Core Intel Xeon: 100 ms for 1000000 swaptions.
System.out.println("Alpha: " + alpha);
}
@Test(enabled = false)
/**
* Test the payment delay convexity adjustment factor. Analysis of the size.
* In normal test, should have (enabled=false)
*/
public void paymentDelayConvexityFactorAnalysis() {
final double hwMeanReversion = 0.01;
final double rate = 0.02;
final double[] tenorTime = {0.25, 0.50 };
final int nbTenors = tenorTime.length;
final double[] lagPayTime = {1.0d / 365.0d, 2.0d / 365.0d, 7.0d / 365.0d };
final int nbLags = lagPayTime.length;
final double lagFixTime = 2.0d / 365.0d;
final int nbPeriods = 120;
final double startTimeFirst = 0.25;
final double startTimeStep = 0.25;
final double[] startTime = new double[nbPeriods];
for (int loopp = 0; loopp < nbPeriods; loopp++) {
startTime[loopp] = startTimeFirst + loopp * startTimeStep;
}
// Constant volatility
final double hwEta = 0.02;
final HullWhiteOneFactorPiecewiseConstantParameters parameters = new HullWhiteOneFactorPiecewiseConstantParameters(hwMeanReversion, new double[] {hwEta }, new double[0]);
final double[][][] factor = new double[nbTenors][nbLags][nbPeriods];
final double[][][] adj = new double[nbTenors][nbLags][nbPeriods];
for (int loopt = 0; loopt < nbTenors; loopt++) {
for (int loopl = 0; loopl < nbLags; loopl++) {
for (int loopp = 0; loopp < nbPeriods; loopp++) {
factor[loopt][loopl][loopp] = MODEL.paymentDelayConvexityFactor(parameters, 0, startTime[loopp] - lagFixTime, startTime[loopp], startTime[loopp] + tenorTime[loopt],
startTime[loopp] + tenorTime[loopt] - lagPayTime[loopl]);
adj[loopt][loopl][loopp] = (1.0d / tenorTime[loopt] - rate) * (factor[loopt][loopl][loopp] - 1);
}
}
}
@SuppressWarnings("unused")
int t = 0;
t++;
}
}