Java tutorial
/** * Copyright (C) 2013 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.analytics.financial.credit.isdayieldcurve; import static com.opengamma.analytics.math.interpolation.Interpolator1DFactory.FLAT_EXTRAPOLATOR; import static com.opengamma.analytics.math.interpolation.Interpolator1DFactory.ISDA_EXTRAPOLATOR; import static com.opengamma.analytics.math.interpolation.Interpolator1DFactory.ISDA_INTERPOLATOR; import java.util.Arrays; import java.util.List; import org.apache.commons.lang.NotImplementedException; import org.apache.commons.lang.ObjectUtils; import org.threeten.bp.ZonedDateTime; import com.opengamma.analytics.financial.interestrate.PeriodicInterestRate; import com.opengamma.analytics.financial.model.interestrate.curve.YieldAndDiscountCurve; import com.opengamma.analytics.math.curve.ConstantDoublesCurve; import com.opengamma.analytics.math.curve.DoublesCurve; import com.opengamma.analytics.math.curve.InterpolatedDoublesCurve; import com.opengamma.analytics.math.interpolation.CombinedInterpolatorExtrapolator; import com.opengamma.analytics.math.interpolation.CombinedInterpolatorExtrapolatorFactory; import com.opengamma.financial.convention.daycount.DayCount; import com.opengamma.financial.convention.daycount.DayCountFactory; import com.opengamma.util.ArgumentChecker; /** *The underlying curve is the zero default rate to time t, H(t), defined as H(t) = -ln[Q(0,t)]/t, where Q(0,t) is the survival probably from now (time 0) *to time t. This currently extends YieldAndDiscountCurve and thus uses the nomenclature of the rates world. The links are *<ul> *<li>Discount factor P(0,t) <==> survival probability Q(0,t) </li> *<li>Zero rate (or yield) R(t) = -ln[P(0,t)]/t <==> Zero default rate H(t) = -ln[Q(0,t)]/t</li> *</ul> *The underlying curve is a linear interpolation of the quantity t*H(t) = -ln[Q(0,t)], which is the ISDA model standard */ public class ISDADateCurve extends YieldAndDiscountCurve { private static final DayCount ACT_365 = DayCountFactory.INSTANCE.getDayCount("ACT/365"); @SuppressWarnings("unused") private static final DayCount ACT_360 = DayCountFactory.INSTANCE.getDayCount("ACT/360"); // ------------------------------------------------------------------------------------------------------------------------------------ private static final CombinedInterpolatorExtrapolator INTERPOLATOR = CombinedInterpolatorExtrapolatorFactory .getInterpolator(ISDA_INTERPOLATOR, FLAT_EXTRAPOLATOR, ISDA_EXTRAPOLATOR); private final String _name; private final ZonedDateTime _baseDates; // RW added to aid conversion // TODO what is this? private final double _offset; private final ZonedDateTime[] _curveDates; private final DoublesCurve _curve; private final double[] _shiftedTimePoints; private final double _zeroDiscountFactor; private final int _n; // ------------------------------------------------------------------------------------------------------------------------------------ /** * A ISDA model zero default curve with ACT/365 day-count convention. This can take in the output from the native ISDA yield curve construction model * @param name The curve name * @param baseDate base date to convert other (future) dates into year fractions using the day-count convention * @param curveDates The dates of points on the curve * @param rates The zero default rates at points on the curve. <b>Note:</b>These as annually compounded rates * @param offset TODO find out what this does */ public ISDADateCurve(final String name, final ZonedDateTime baseDate, final ZonedDateTime[] curveDates, final double[] rates, final double offset) { this(name, baseDate, curveDates, rates, offset, ACT_365); } /** * A ISDA model zero default curve * @param name The curve name * @param baseDate base date to convert other (future) dates into year fractions using the day-count convention * @param curveDates The dates of points on the curve * @param rates The zero default rates at points on the curve. <b>Note:</b>These as annually compounded rates * @param offset TODO find out what this does * @param dayCount The day-count convention */ public ISDADateCurve(final String name, final ZonedDateTime baseDate, final ZonedDateTime[] curveDates, final double[] rates, final double offset, final DayCount dayCount) { super(name); ArgumentChecker.notNull(name, "name"); ArgumentChecker.notNull(baseDate, "base date"); ArgumentChecker.noNulls(curveDates, "curve dates"); ArgumentChecker.notEmpty(rates, "rates"); ArgumentChecker.notNull(dayCount, "day count"); _n = curveDates.length; ArgumentChecker.isTrue(_n != 0, "Data arrays were empty"); // TODO why is this test commented out? // ArgumentChecker.isTrue(_n == rates.length, "Have {} rates for {} dates", rates.length, _n); _baseDates = baseDate; _name = name; _offset = offset; _curveDates = new ZonedDateTime[_n]; System.arraycopy(curveDates, 0, _curveDates, 0, _n); final double[] times = new double[_n]; final double[] continuousRates = new double[_n]; _shiftedTimePoints = new double[_n]; for (int i = 0; i < _n; i++) { // Convert the ZonedDateTimes to doubles final double dayCountFraction = dayCount.getDayCountFraction(baseDate, curveDates[i]); times[i] = dayCountFraction; // Convert the discrete rates to continuous ones continuousRates[i] = new PeriodicInterestRate(rates[i], 1).toContinuous().getRate(); _shiftedTimePoints[i] = dayCountFraction + _offset; } // Choose interpolation/extrapolation to match the behavior of curves in the ISDA CDS reference code if (_n > 1) { _curve = InterpolatedDoublesCurve.fromSorted(times, continuousRates, INTERPOLATOR); } else { _curve = ConstantDoublesCurve.from(continuousRates[0]); // Unless the curve is flat, in which case use a constant curve } _zeroDiscountFactor = Math.exp(_offset * getInterestRate(0.0)); } /** * A ISDA model zero default curve * @param name The curve name * @param curveDates The dates of points on the curve * @param times Time in years to points on the curve (these should have been calculated from a base date using some day-count convention) * @param rates The zero default rates at points on the curve. <b>Note:</b>These are continually compounded rates, while the other constructors take * annually compounded rates * @param offset TODO find out what this does */ public ISDADateCurve(final String name, final ZonedDateTime[] curveDates, final double[] times, final double[] rates, final double offset) { super(name); ArgumentChecker.notNull(name, "name"); ArgumentChecker.noNulls(curveDates, "curve dates"); ArgumentChecker.notEmpty(times, "times"); ArgumentChecker.notEmpty(rates, "rates"); _n = curveDates.length; ArgumentChecker.isTrue(_n != 0, "Data arrays were empty"); // TODO why commented out? // ArgumentChecker.isTrue(_n == times.length, "Have {} times for {} dates", times.length, _n); // ArgumentChecker.isTrue(_n == rates.length, "Have {} rates for {} dates", rates.length, _n); _baseDates = null; _name = name; _offset = offset; _curveDates = new ZonedDateTime[_n]; System.arraycopy(curveDates, 0, _curveDates, 0, _n); // Choose interpolation/extrapolation to match the behavior of curves in the ISDA CDS reference code if (_n > 1) { _curve = InterpolatedDoublesCurve.fromSorted(times, rates, INTERPOLATOR); } else { _curve = ConstantDoublesCurve.from(rates[0]); // Unless the curve is flat, in which case use a constant curve } _shiftedTimePoints = new double[times.length]; for (int i = 0; i < times.length; ++i) { _shiftedTimePoints[i] = times[i] + _offset; } _zeroDiscountFactor = Math.exp(_offset * getInterestRate(0.0)); } // ------------------------------------------------------------------------------------------------------------------------------------ /** * * @return The dates of points on the curve */ public ZonedDateTime[] getCurveDates() { return _curveDates; } public ZonedDateTime getBaseDate() { return _baseDates; } @Override public String getName() { return _name; } /** * The zero default rate to time t * @param t time in years * @return The zero default rate as a fraction */ @Override public double getInterestRate(final Double t) { return _curve.getYValue(t - _offset); } /** * Get the time (in years) of point m on the curve (indexed from zero) * @param m the index * @return the time (in years) */ public double getTimenode(final int m) { return _curve.getXData()[m]; } /** * Get the zero default rate of point m on the curve (indexed from zero) * @param m the index * @return The zero default rate */ public double getInterestRate(final int m) { return _curve.getYData()[m]; } /** * The survival probability * @param t time in years * @return The survival probability to time t */ @Override public double getDiscountFactor(final double t) { return Math.exp((_offset - t) * getInterestRate(t)) / _zeroDiscountFactor; } /** * get the shifted time points * @return The shifted time points */ public double[] getTimePoints() { return _shiftedTimePoints; } /** * * @return The underlying curve */ public DoublesCurve getCurve() { return _curve; } /** * * @return The offset */ public double getOffset() { return _offset; } /** * This is 1.0 unless an offset is used, in which case it is Math.exp(offset * H(-offset)) * @return Zero Discount Factor */ public double getZeroDiscountFactor() { return _zeroDiscountFactor; } /** * * @return Number of points on curve */ public int getNumberOfCurvePoints() { return _n; } // ------------------------------------------------------------------------------------------------------------------------------------ @Override public String toString() { final StringBuilder sb = new StringBuilder("ISDADateCurve[name="); sb.append(_name); sb.append(", offset="); sb.append(_offset); sb.append(", curve dates="); sb.append(Arrays.asList(_curveDates)); sb.append(", shifted time points="); sb.append(Arrays.asList(_shiftedTimePoints)); sb.append(", interpolator="); sb.append(INTERPOLATOR); sb.append("]"); return sb.toString(); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + Arrays.hashCode(_curveDates); result = prime * result + _name.hashCode(); result = prime * result + Arrays.hashCode(_shiftedTimePoints); long temp; temp = Double.doubleToLongBits(_zeroDiscountFactor); result = prime * result + (int) (temp ^ (temp >>> 32)); return result; } @Override public boolean equals(final Object obj) { if (this == obj) { return true; } if (!(obj instanceof ISDADateCurve)) { return false; } final ISDADateCurve other = (ISDADateCurve) obj; if (!ObjectUtils.equals(_name, other._name)) { return false; } if (Double.compare(_zeroDiscountFactor, other._zeroDiscountFactor) != 0) { return false; } if (!Arrays.equals(_curveDates, other._curveDates)) { return false; } if (!Arrays.equals(_shiftedTimePoints, other._shiftedTimePoints)) { return false; } return true; } @Override public double[] getInterestRateParameterSensitivity(final double time) { throw new NotImplementedException(); } @Override public int getNumberOfParameters() { throw new NotImplementedException(); } @Override public List<String> getUnderlyingCurvesNames() { throw new NotImplementedException(); } @Override public double getForwardRate(final double t) { throw new NotImplementedException(); } }