/** * Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.analytics.financial.model.interestrate; import org.apache.commons.lang.Validate; import org.threeten.bp.ZonedDateTime; import com.opengamma.analytics.financial.model.interestrate.definition.HullWhiteTwoFactorDataBundle; import com.opengamma.analytics.math.function.Function1D; import com.opengamma.util.time.DateUtils; /** * */ public class HullWhiteTwoFactorInterestRateModel implements DiscountBondModel<HullWhiteTwoFactorDataBundle> { @Override public Function1D<HullWhiteTwoFactorDataBundle, Double> getDiscountBondFunction(final ZonedDateTime time, final ZonedDateTime maturity) { Validate.notNull(time, "time"); Validate.notNull(maturity, "maturity"); return new Function1D<HullWhiteTwoFactorDataBundle, Double>() { @Override public Double evaluate(final HullWhiteTwoFactorDataBundle data) { Validate.notNull(data, "data"); final double t1 = 0; final double t2 = DateUtils.getDifferenceInYears(data.getDate(), time); final double t3 = DateUtils.getDifferenceInYears(data.getDate(), maturity); final double r2 = data.getShortRate(t2); final double r3 = data.getShortRate(t3); final double p2 = Math.exp(-r2 * t2); final double p3 = Math.exp(-r3 * t3); final double alpha = data.getFirstSpeed(); final double beta = data.getSecondSpeed(); final double sigma1 = data.getShortRateVolatility(t1); final double sigma2 = data.getSecondVolatility(t1); final double rho = data.getCorrelation(); final double eta = getEta(t1, t2, t3, alpha, beta, sigma1, sigma2, rho); final double b = getB(t3 - t2, alpha); final double c = getC(t3 - t2, alpha, beta); final double u = data.getMeanReversionLevel(); final double f = data.getForwardRate(t1); final double lnA = Math.log(p3 / p2) + b * f - eta; return Math.exp(lnA - r2 * b - u * c); } }; } protected Double getB(final Double dt, final Double a) { return (1 - Math.exp(-a * dt)) / a; } protected Double getC(final Double dt, final Double a, final Double b) { return Math.exp(-a * dt) / (a * (a - b)) - Math.exp(-b * dt) / (b * (a - b)) + 1. / (a * b); } protected Double getEta(final double t1, final double t2, final double t3, final double a, final double b, final double sigma1, final double sigma2, final double rho) { final double dt12 = t2 - t1; final double dt13 = t3 - t1; final double dt23 = t3 - t2; final double b12 = getB(dt12, a); final double b12Sq = b12 * b12; final double b13 = getB(dt13, a); final double b13Sq = b13 * b13; final double b23 = getB(dt23, a); final double b23Sq = b23 * b23; final double c12 = getC(dt12, a, b); final double c12Sq = c12 * c12; final double c13 = getC(dt13, a, b); final double c13Sq = c13 * c13; final double c23 = getC(dt23, a, b); final double c23Sq = c23 * c23; final double abP = a + b; final double abM = a - b; final double gamma1 = Math.exp(-abP * dt13) * (Math.exp(abP * dt12) - 1) / (abP * abM) - Math.exp(-2 * a * dt13) * (Math.exp(2 * a * dt12) - 1) / (2 * a * abM); final double gamma2 = (gamma1 + c23 - c13 + 0.5 * b23Sq - 0.5 * b13Sq + dt12 / a - (Math.exp(-a * dt23) - Math.exp(-a * dt13)) / (a * a)) / (a * b); final double gamma3 = -(Math.exp(-abP * dt12) - 1) / (abP * abM) + (Math.exp(-2 * a * dt12) - 1) / (2 * a * abM); final double gamma4 = (gamma3 - c12 - 0.5 * b12Sq + dt12 / a + (Math.exp(-a * dt12) - 1) / (a * a)) / (a * b); final double gamma5 = (0.5 * (c23Sq - c13Sq) + gamma2) / b; final double gamma6 = (gamma4 - 0.5 * c12Sq) / b; return sigma1 * sigma1 * (1 - Math.exp(-2 * a * dt12)) * b23Sq / (4 * a) - rho * sigma1 * sigma2 * (b12 * c12 * b23 + gamma4 - gamma2) - 0.5 * sigma2 * sigma2 * (c12Sq * b23 + gamma6 - gamma5); } }