/**
* Copyright (C) 2011 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.analytics.financial.instrument.payment;
import java.util.Arrays;
import org.threeten.bp.ZonedDateTime;
import com.opengamma.analytics.financial.instrument.InstrumentDefinitionVisitor;
import com.opengamma.analytics.financial.instrument.index.IborIndex;
import com.opengamma.analytics.financial.interestrate.payments.derivative.CouponIborRatchet;
import com.opengamma.analytics.financial.interestrate.payments.derivative.Payment;
import com.opengamma.analytics.financial.schedule.ScheduleCalculator;
import com.opengamma.analytics.util.time.TimeCalculator;
import com.opengamma.financial.convention.calendar.Calendar;
import com.opengamma.timeseries.DoubleTimeSeries;
import com.opengamma.util.ArgumentChecker;
import com.opengamma.util.money.Currency;
/**
* Class describing a Ratchet on Ibor coupon. The coupon payment depends on the
* previous coupon ($C_{i-1}$), the current Ibor fixing ($L_i$). The pay-off is:
* $$
* \begin{equation*}
* \alpha^M_i C_{i-1} + \beta^M_i L_i + \gamma^M_i
* \end{equation*}
* $$
* subject to the floor :
* $$
* \begin{equation*}
* \alpha^F_i C_{i-1} + \beta^F_i L_i + \gamma^F_i
* \end{equation*}
* $$
* and the cap:
* $$
* \begin{equation*}
* \alpha^C_i C_{i-1} + \beta^C_i L_i + \gamma^C_i
* \end{equation*}
* $$
*/
public class CouponIborRatchetDefinition extends CouponFloatingDefinition {
/**
* Ibor-like index on which the coupon fixes. The index currency should be the same as the coupon currency.
*/
private final IborIndex _index;
/**
* The start date of the fixing period.
*/
private final ZonedDateTime _fixingPeriodStartDate;
/**
* The end date of the fixing period.
*/
private final ZonedDateTime _fixingPeriodEndDate;
/**
* The accrual factor (or year fraction) associated to the fixing period in the Index day count convention.
*/
private final double _fixingPeriodAccrualFactor;
/**
* The coefficients of the main payment (before floor and cap). Array of length 3. The first coefficient is the previous coupon factor,
* the second is the Ibor factor and the third is the additive term.
*/
private final double[] _mainCoefficients;
/**
* The coefficients of the floor. Array of length 3. The first coefficient is the previous coupon factor,
* the second is the Ibor factor and the third is the additive term.
*/
private final double[] _floorCoefficients;
/**
* The coefficients of the cap. Array of length 3. The first coefficient is the previous coupon factor,
* the second is the Ibor factor and the third is the additive term.
*/
private final double[] _capCoefficients;
/**
* Constructor from all the details.
* @param currency The payment currency.
* @param paymentDate Coupon payment date.
* @param accrualStartDate Start date of the accrual period.
* @param accrualEndDate End date of the accrual period.
* @param accrualFactor Accrual factor of the accrual period.
* @param notional Coupon notional.
* @param fixingDate The coupon fixing date.
* @param index The coupon Ibor index. Should of the same currency as the payment.
* @param mainCoefficients The coefficients of the main payment (before floor and cap). Array of length 3.
* @param floorCoefficients The coefficients of the floor. Array of length 3. The first coefficient is the previous coupon factor,
* the second is the Ibor factor and the third is the additive term.
* @param capCoefficients The coefficients of the cap. Array of length 3.
* @param calendar The holiday calendar for the ibor index.
*/
public CouponIborRatchetDefinition(final Currency currency, final ZonedDateTime paymentDate, final ZonedDateTime accrualStartDate, final ZonedDateTime accrualEndDate, final double accrualFactor,
final double notional, final ZonedDateTime fixingDate, final IborIndex index, final double[] mainCoefficients, final double[] floorCoefficients, final double[] capCoefficients,
final Calendar calendar) {
super(currency, paymentDate, accrualStartDate, accrualEndDate, accrualFactor, notional, fixingDate);
ArgumentChecker.notNull(index, "index");
ArgumentChecker.isTrue(currency.equals(index.getCurrency()), "index currency different from payment currency");
ArgumentChecker.notNull(mainCoefficients, "Main coefficients");
ArgumentChecker.notNull(floorCoefficients, "Floor coefficients");
ArgumentChecker.notNull(capCoefficients, "Cap coefficients");
ArgumentChecker.isTrue(mainCoefficients.length == 3, "Requires 3 main coefficients");
ArgumentChecker.isTrue(floorCoefficients.length == 3, "Requires 3 floor coefficients");
ArgumentChecker.isTrue(capCoefficients.length == 3, "Requires 3 cap coefficients");
_index = index;
_fixingPeriodStartDate = ScheduleCalculator.getAdjustedDate(fixingDate, _index.getSpotLag(), calendar);
_fixingPeriodEndDate = ScheduleCalculator.getAdjustedDate(_fixingPeriodStartDate, index.getTenor(), index.getBusinessDayConvention(), calendar, index.isEndOfMonth());
_fixingPeriodAccrualFactor = index.getDayCount().getDayCountFraction(_fixingPeriodStartDate, _fixingPeriodEndDate, calendar);
_mainCoefficients = mainCoefficients;
_floorCoefficients = floorCoefficients;
_capCoefficients = capCoefficients;
}
/**
* Gets the Ibor index of the instrument.
* @return The index.
*/
public IborIndex getIndex() {
return _index;
}
/**
* Gets the start date of the fixing period.
* @return The start date of the fixing period.
*/
public ZonedDateTime getFixingPeriodStartDate() {
return _fixingPeriodStartDate;
}
/**
* Gets the end date of the fixing period.
* @return The end date of the fixing period.
*/
public ZonedDateTime getFixingPeriodEndDate() {
return _fixingPeriodEndDate;
}
/**
* Gets the accrual factor (or year fraction) associated to the fixing period in the Index day count convention.
* @return The accrual factor.
*/
public double getFixingPeriodAccrualFactor() {
return _fixingPeriodAccrualFactor;
}
/**
* Gets the coefficients of the main payment (before floor and cap).
* @return The coefficients of the main payment (before floor and cap).
*/
public double[] getMainCoefficients() {
return _mainCoefficients;
}
/**
* Gets the coefficients of the floor.
* @return The coefficients of the floor.
*/
public double[] getFloorCoefficients() {
return _floorCoefficients;
}
/**
* Gets the coefficients of the cap.
* @return The coefficients of the cap.
*/
public double[] getCapCoefficients() {
return _capCoefficients;
}
@Override
public <U, V> V accept(final InstrumentDefinitionVisitor<U, V> visitor, final U data) {
ArgumentChecker.notNull(visitor, "visitor");
return visitor.visitCouponIborRatchetDefinition(this, data);
}
@Override
public <V> V accept(final InstrumentDefinitionVisitor<?, V> visitor) {
ArgumentChecker.notNull(visitor, "visitor");
return visitor.visitCouponIborRatchetDefinition(this);
}
@Override
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
result = prime * result + Arrays.hashCode(_capCoefficients);
result = prime * result + Arrays.hashCode(_floorCoefficients);
result = prime * result + Arrays.hashCode(_mainCoefficients);
return result;
}
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (!super.equals(obj)) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final CouponIborRatchetDefinition other = (CouponIborRatchetDefinition) obj;
if (!Arrays.equals(_capCoefficients, other._capCoefficients)) {
return false;
}
if (!Arrays.equals(_floorCoefficients, other._floorCoefficients)) {
return false;
}
if (!Arrays.equals(_mainCoefficients, other._mainCoefficients)) {
return false;
}
return true;
}
@Override
public CouponIborRatchet toDerivative(final ZonedDateTime date) {
ArgumentChecker.notNull(date, "date");
ArgumentChecker.isTrue(!date.isAfter(getFixingDate()), "Do not have any fixing data but are asking for a derivative after the fixing date " + getFixingDate() + " " + date);
ArgumentChecker.isTrue(!date.isAfter(getPaymentDate()), "date is after payment date");
final double paymentTime = TimeCalculator.getTimeBetween(date, getPaymentDate());
final double fixingTime = TimeCalculator.getTimeBetween(date, getFixingDate());
final double fixingPeriodStartTime = TimeCalculator.getTimeBetween(date, getFixingPeriodStartDate());
final double fixingPeriodEndTime = TimeCalculator.getTimeBetween(date, getFixingPeriodEndDate());
return new CouponIborRatchet(getCurrency(), paymentTime, getPaymentYearFraction(), getNotional(), fixingTime, fixingPeriodStartTime, fixingPeriodEndTime,
getFixingPeriodAccrualFactor(), getIndex(), _mainCoefficients, _floorCoefficients, _capCoefficients);
}
@Override
public Payment toDerivative(final ZonedDateTime date, final DoubleTimeSeries<ZonedDateTime> data) {
return null;
//TODO: coupon with fixing!
}
}