/**
* Copyright (C) 2013 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.analytics.financial.instrument.payment;
import org.threeten.bp.ZonedDateTime;
import com.opengamma.analytics.financial.instrument.InstrumentDefinitionVisitor;
import com.opengamma.analytics.financial.interestrate.payments.derivative.CouponFixedAccruedCompounding;
import com.opengamma.analytics.util.time.TimeCalculatorBUS252;
import com.opengamma.financial.convention.calendar.Calendar;
import com.opengamma.util.ArgumentChecker;
import com.opengamma.util.money.Currency;
/**
* Class describing a fixed compounded coupon. The fixed rate is compounded over several sub-periods.
* The amount paid is equal to
* $$
* \begin{equation*}
* (1+ r)^(\delta)
* \end{equation*}
* $$
* where $\delta$ is the accrual factor of the period and the $r$ the fixed rate for the same periods.
*
* This coupon is especially used for Brazilian swaps with the day count business/252.
*/
public class CouponFixedAccruedCompoundingDefinition extends CouponDefinition {
/**
* The fixed rate.
* All the coupon sub-periods use the same fixed rate.
*/
private final double _rate;
/**
* The amount to be paid by the fixed coupon (=getNotional() * (1+_rate) ^ getPaymentYearFraction())
*/
private final double _amount;
/**
* The calendar.
*/
private final Calendar _calendar;
/**
* Constructor from all details
* @param currency The coupon currency.
* @param paymentDate The coupon payment date.
* @param accrualStartDate The start date of the accrual period.
* @param accrualEndDate The end date of the accrual period.
* @param paymentYearFraction The accrual factor of the accrual period.
* @param notional The coupon notional.
* @param rate Fixed rate.
* @param calendar the calendar
*/
public CouponFixedAccruedCompoundingDefinition(final Currency currency, final ZonedDateTime paymentDate, final ZonedDateTime accrualStartDate, final ZonedDateTime accrualEndDate,
final double paymentYearFraction, final double notional, final double rate, final Calendar calendar) {
super(currency, paymentDate, accrualStartDate, accrualEndDate, paymentYearFraction, notional);
_rate = rate;
_amount = notional * Math.pow(1 + rate, paymentYearFraction);
_calendar = calendar;
}
/**
* Fixed coupon constructor from a coupon and the fixed rate.
* @param coupon Underlying coupon.
* @param rate Fixed rate.
* @param calendar the calendar
*/
public CouponFixedAccruedCompoundingDefinition(final CouponDefinition coupon, final double rate, final Calendar calendar) {
super(coupon.getCurrency(), coupon.getPaymentDate(), coupon.getAccrualStartDate(), coupon.getAccrualEndDate(), coupon.getPaymentYearFraction(), coupon.getNotional());
_rate = rate;
_amount = coupon.getNotional() * Math.pow(1 + rate, coupon.getPaymentYearFraction());
_calendar = calendar;
}
/**
* Static constructor for a fixed coupon definition.
* @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 paymentYearFraction Accrual factor of the accrual period.
* @param notional Coupon notional.
* @param rate Fixed rate.
* @param calendar the calendar
* @return The fixed coupon definition
*/
public static CouponFixedAccruedCompoundingDefinition from(final Currency currency, final ZonedDateTime paymentDate, final ZonedDateTime accrualStartDate,
final ZonedDateTime accrualEndDate, final double paymentYearFraction, final double notional, final double rate, final Calendar calendar) {
return new CouponFixedAccruedCompoundingDefinition(currency, paymentDate, accrualStartDate, accrualEndDate, paymentYearFraction, notional, rate, calendar);
}
/**
* Gets the fixed rate.
* @return The fixed rate
*/
public double getRate() {
return _rate;
}
/**
* Gets the amount.
* @return The amount
*/
public double getAmount() {
return _amount;
}
/**
* Gets the calendar.
* @return The calendar
*/
public Calendar getCalendar() {
return _calendar;
}
@Override
public String toString() {
return "CouponFixedAccruedCompoundingDefinition [_rate=" + _rate + "]";
}
@Override
public CouponFixedAccruedCompounding toDerivative(final ZonedDateTime date) {
ArgumentChecker.notNull(date, "date");
ArgumentChecker.isTrue(!date.isAfter(getPaymentDate()), "date {} is after payment date {}", date, getPaymentDate()); // Required: reference date <= payment date
final double paymentTime = TimeCalculatorBUS252.getTimeBetween(date, getPaymentDate(), _calendar);
return new CouponFixedAccruedCompounding(getCurrency(), paymentTime, getPaymentYearFraction(), getNotional(), getRate(), getAccrualStartDate(), getAccrualEndDate());
}
@Override
public <U, V> V accept(final InstrumentDefinitionVisitor<U, V> visitor, final U data) {
ArgumentChecker.notNull(visitor, "visitor");
return visitor.visitCouponFixedAccruedCompoundingDefinition(this, data);
}
@Override
public <V> V accept(final InstrumentDefinitionVisitor<?, V> visitor) {
ArgumentChecker.notNull(visitor, "visitor");
return visitor.visitCouponFixedAccruedCompoundingDefinition(this);
}
/* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
long temp;
temp = Double.doubleToLongBits(_amount);
result = prime * result + (int) (temp ^ (temp >>> 32));
result = prime * result + ((_calendar == null) ? 0 : _calendar.hashCode());
temp = Double.doubleToLongBits(_rate);
result = prime * result + (int) (temp ^ (temp >>> 32));
return result;
}
/* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
@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 CouponFixedAccruedCompoundingDefinition other = (CouponFixedAccruedCompoundingDefinition) obj;
if (Double.doubleToLongBits(_amount) != Double.doubleToLongBits(other._amount)) {
return false;
}
if (_calendar == null) {
if (other._calendar != null) {
return false;
}
} else if (!_calendar.equals(other._calendar)) {
return false;
}
if (Double.doubleToLongBits(_rate) != Double.doubleToLongBits(other._rate)) {
return false;
}
return true;
}
}