/**
* Copyright (C) 2012 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.analytics.financial.instrument.cash;
import org.apache.commons.lang.ObjectUtils;
import org.threeten.bp.ZonedDateTime;
import com.opengamma.analytics.financial.instrument.InstrumentDefinition;
import com.opengamma.analytics.financial.instrument.InstrumentDefinitionVisitor;
import com.opengamma.analytics.financial.interestrate.InterestRate;
import com.opengamma.analytics.financial.interestrate.PeriodicInterestRate;
import com.opengamma.analytics.financial.interestrate.cash.derivative.DepositZero;
import com.opengamma.analytics.util.time.TimeCalculator;
import com.opengamma.financial.convention.calendar.Calendar;
import com.opengamma.financial.convention.daycount.DayCount;
import com.opengamma.util.ArgumentChecker;
import com.opengamma.util.money.Currency;
/**
* Class describing a deposit where the rate is expressed in a specific composition convention.
* Used mainly for curve construction with rates directly provided (not calibrated).
*/
public class DepositZeroDefinition implements InstrumentDefinition<DepositZero> {
/**
* The deposit currency.
*/
private final Currency _currency;
/**
* The deposit start date (a good business day, adjusted by the business day convention if required).
*/
private final ZonedDateTime _startDate;
/**
* The deposit end (or maturity) date (a good business day, adjusted by the business day convention if required).
*/
private final ZonedDateTime _endDate;
/**
* The deposit notional.
*/
private final double _notional;
/**
* The accrual factor (or year fraction).
*/
private final double _paymentAccrualFactor;
/**
* The interest rate and its composition type.
*/
private final InterestRate _rate;
/**
* The interest amount to be paid at end date.
*/
private final double _interestAmount;
/**
* The holiday calendar.
*/
private final Calendar _calendar;
/**
* The day count.
*/
private final DayCount _dayCount;
/**
* Constructor from all details.
* @param currency The currency.
* @param startDate The start date.
* @param endDate The end date.
* @param notional The notional.
* @param paymentAccrualFactor The accrual factor (or year fraction).
* @param rate The interest rate and its composition type.
* @param calendar The holiday calendar.
* @param dayCount The day count.
*/
public DepositZeroDefinition(final Currency currency, final ZonedDateTime startDate, final ZonedDateTime endDate, final double notional, final double paymentAccrualFactor,
final InterestRate rate, final Calendar calendar, final DayCount dayCount) {
ArgumentChecker.notNull(currency, "Currency");
ArgumentChecker.notNull(startDate, "Start date");
ArgumentChecker.notNull(endDate, "End date");
ArgumentChecker.notNull(rate, "Rate");
ArgumentChecker.notNull(calendar, "calendar");
ArgumentChecker.notNull(dayCount, "day count");
_currency = currency;
_startDate = startDate;
_endDate = endDate;
_notional = notional;
_paymentAccrualFactor = paymentAccrualFactor;
_rate = rate;
_interestAmount = (1.0 / rate.getDiscountFactor(paymentAccrualFactor) - 1.0) * notional;
_calendar = calendar;
_dayCount = dayCount;
}
/**
* Builder. The day count is used to compute the accrual factor. The notional is 1.
* @param currency The currency.
* @param startDate The start date.
* @param endDate The end date.
* @param daycount The day count.
* @param rate The interest rate and its composition type.
* @param calendar The holiday calendar.
* @param dayCount The day count
* @return The deposit.
*/
public static DepositZeroDefinition from(final Currency currency, final ZonedDateTime startDate, final ZonedDateTime endDate, final DayCount daycount, final InterestRate rate,
final Calendar calendar, final DayCount dayCount) {
ArgumentChecker.notNull(daycount, "day count");
return new DepositZeroDefinition(currency, startDate, endDate, 1.0, daycount.getDayCountFraction(startDate, endDate, calendar), rate, calendar, dayCount);
}
/**
* Builder. The day count is used to compute the accrual factor. The notional is 1.
* @param currency The currency.
* @param startDate The start date.
* @param endDate The end date.
* @param daycount The day count.
* @param rate The interest rate and its composition type.
* @param calendar The holiday calendar.
* @return The deposit.
*/
public static DepositZeroDefinition withAdjustedRate(final Currency currency, final ZonedDateTime startDate, final ZonedDateTime endDate, final DayCount daycount, final InterestRate rate,
final Calendar calendar) {
ArgumentChecker.notNull(daycount, "day count");
double adjustedRate;
if (currency.equals(Currency.BRL)) {
adjustedRate = rate.getRate() * daycount.getDayCountFraction(startDate, endDate, calendar) / TimeCalculator.getTimeBetween(startDate, endDate);
} else {
adjustedRate = rate.getRate();
}
final InterestRate adjustedInterestRate = new PeriodicInterestRate(adjustedRate, 1);
return new DepositZeroDefinition(currency, startDate, endDate, 1.0, daycount.getDayCountFraction(startDate, endDate, calendar), adjustedInterestRate, calendar, daycount);
}
/**
* Gets the deposit currency.
* @return The currency.
*/
public Currency getCurrency() {
return _currency;
}
/**
* Gets the deposit start date
* @return The date.
*/
public ZonedDateTime getStartDate() {
return _startDate;
}
/**
* Gets the deposit end date
* @return The date.
*/
public ZonedDateTime getEndDate() {
return _endDate;
}
/**
* Gets the deposit notional.
* @return The notional.
*/
public double getNotional() {
return _notional;
}
/**
* Gets the accrual factor (or year fraction).
* @return The factor.
*/
public double getPaymentAccrualFactor() {
return _paymentAccrualFactor;
}
/**
* Gets the rate (figure and composition rule).
* @return The rate.
*/
public InterestRate getRate() {
return _rate;
}
/**
* Gets the interest rate amount.
* @return The amount.
*/
public double getInterestAmount() {
return _interestAmount;
}
@Override
public String toString() {
return "DepositZero " + _currency + " [" + _startDate + " - " + _endDate + "] - notional: " + _notional + " - rate: " + _rate;
}
@Override
public DepositZero toDerivative(final ZonedDateTime date) {
ArgumentChecker.isTrue(!date.isAfter(_endDate), "date is after end date");
double startTime;
if (date.toLocalDate().isBefore(_startDate.toLocalDate())) {
startTime = _dayCount.getDayCountFraction(date.toLocalDate(), _startDate.toLocalDate(), _calendar);
} else if (date.toLocalDate().equals(_startDate.toLocalDate())) {
startTime = 0;
} else {
startTime = _dayCount.getDayCountFraction(_startDate.toLocalDate(), date.toLocalDate(), _calendar);
}
final double endTime = _dayCount.getDayCountFraction(date.toLocalDate(), _endDate.toLocalDate(), _calendar);
if (startTime < 0) {
return new DepositZero(_currency, 0, endTime, 0, _notional, _paymentAccrualFactor, _rate, _interestAmount);
}
return new DepositZero(_currency, startTime, endTime, _notional, _notional, _paymentAccrualFactor, _rate, _interestAmount);
}
@Override
public <U, V> V accept(final InstrumentDefinitionVisitor<U, V> visitor, final U data) {
ArgumentChecker.notNull(visitor, "visitor");
return visitor.visitDepositZeroDefinition(this, data);
}
@Override
public <V> V accept(final InstrumentDefinitionVisitor<?, V> visitor) {
ArgumentChecker.notNull(visitor, "visitor");
return visitor.visitDepositZeroDefinition(this);
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + _currency.hashCode();
result = prime * result + _endDate.hashCode();
long temp;
temp = Double.doubleToLongBits(_interestAmount);
result = prime * result + (int) (temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(_notional);
result = prime * result + (int) (temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(_paymentAccrualFactor);
result = prime * result + (int) (temp ^ (temp >>> 32));
result = prime * result + _rate.hashCode();
result = prime * result + _startDate.hashCode();
return result;
}
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final DepositZeroDefinition other = (DepositZeroDefinition) obj;
if (!ObjectUtils.equals(_currency, other._currency)) {
return false;
}
if (!ObjectUtils.equals(_endDate, other._endDate)) {
return false;
}
if (!ObjectUtils.equals(_startDate, other._startDate)) {
return false;
}
if (Double.doubleToLongBits(_interestAmount) != Double.doubleToLongBits(other._interestAmount)) {
return false;
}
if (Double.doubleToLongBits(_notional) != Double.doubleToLongBits(other._notional)) {
return false;
}
if (Double.doubleToLongBits(_paymentAccrualFactor) != Double.doubleToLongBits(other._paymentAccrualFactor)) {
return false;
}
if (!ObjectUtils.equals(_rate, other._rate)) {
return false;
}
return true;
}
}