/**
* Copyright (C) 2014 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.analytics.financial.instrument.future;
import java.util.Arrays;
import org.apache.commons.lang.NotImplementedException;
import org.apache.commons.lang.ObjectUtils;
import org.threeten.bp.ZonedDateTime;
import com.opengamma.analytics.financial.instrument.InstrumentDefinitionVisitor;
import com.opengamma.analytics.financial.instrument.bond.BondFixedSecurityDefinition;
import com.opengamma.analytics.financial.interestrate.bond.definition.BondFixedSecurity;
import com.opengamma.analytics.financial.interestrate.future.derivative.BondFuturesYieldAverageSecurity;
import com.opengamma.analytics.financial.schedule.ScheduleCalculator;
import com.opengamma.analytics.util.time.TimeCalculator;
import com.opengamma.financial.convention.calendar.Calendar;
import com.opengamma.util.ArgumentChecker;
/**
* Description of a bond future security with cash settlement against a price deduced from a yield average.
* In particular used for AUD-SFE bond futures.
* <P>Reference: Add a reference.
*/
public class BondFuturesYieldAverageSecurityDefinition extends FuturesSecurityDefinition<BondFuturesYieldAverageSecurity> {
/**
* The number of days between notice date and delivery date.
*/
private final int _settlementDays;
/**
* The basket of deliverable bonds.
*/
private final BondFixedSecurityDefinition[] _deliveryBasket;
/**
* Theoretical coupon rate. The coupon of the synthetic bond used to compute the settlement price from the yield.
*/
private final double _couponRate;
/**
* Underlying tenor in year. The tenor of the synthetic bond used to compute the settlement price from the yield.
*/
private final int _tenor;
/**
* The synthetic delivery date. The settlement date used for the computation of the yield at expiry.
*/
private final ZonedDateTime _deliveryDate;
/**
* The notional of the bond future (also called face value or contract value).
*/
private final double _notional;
/**
* The holiday calendar.
*/
private final Calendar _calendar;
/**
* Constructor from the trading and notice dates and the basket.
* @param tradingLastDate The last trading date.
* @param deliveryBasket The basket of deliverable bonds.
* @param couponRate The coupon rate of the synthetic bond used to compute the settlement price from the yield.
* @param tenor The underlying synthetic bond tenor (in years).
* @param notional The bond future notional.
*/
public BondFuturesYieldAverageSecurityDefinition(final ZonedDateTime tradingLastDate, final BondFixedSecurityDefinition[] deliveryBasket, final double couponRate,
final int tenor, final double notional) {
super(tradingLastDate);
ArgumentChecker.notNull(tradingLastDate, "Last trading date");
ArgumentChecker.notNull(deliveryBasket, "Delivery basket");
ArgumentChecker.isTrue(deliveryBasket.length > 0, "At least one bond in basket");
_deliveryBasket = deliveryBasket;
_couponRate = couponRate;
_tenor = tenor;
_settlementDays = _deliveryBasket[0].getSettlementDays();
_calendar = _deliveryBasket[0].getCalendar();
_deliveryDate = ScheduleCalculator.getAdjustedDate(tradingLastDate, _settlementDays, _calendar);
_notional = notional;
}
/**
* Gets the number of days between notice date and delivery date.
* @return The number of days between notice date and delivery date.
*/
public int getSettlementDays() {
return _settlementDays;
}
/**
* Gets the basket of deliverable bonds.
* @return The basket of deliverable bonds.
*/
public BondFixedSecurityDefinition[] getDeliveryBasket() {
return _deliveryBasket;
}
/**
* Returns the coupon rate of the synthetic bond used to compute the settlement price from the yield.
* @return The rate.
*/
public double getCouponRate() {
return _couponRate;
}
/**
* Returns The tenor of the synthetic bond used to compute the settlement price from the yield (in year).
* @return The tenor.
*/
public int getTenor() {
return _tenor;
}
/**
* Returns the theoretical delivery date for the bond underlying the futures.
* @return The delivery date.
*/
public ZonedDateTime getDeliveryDate() {
return _deliveryDate;
}
/**
* Gets the notional.
* @return The notional.
*/
public double getNotional() {
return _notional;
}
/**
* Gets the holiday calendar.
* @return The holiday calendar
*/
public Calendar getCalendar() {
return _calendar;
}
@Override
public BondFuturesYieldAverageSecurity toDerivative(final ZonedDateTime date) {
ArgumentChecker.notNull(date, "date");
ArgumentChecker.isTrue(!date.isAfter(getLastTradingDate()), "Date is after last trading date");
final double lastTradingTime = TimeCalculator.getTimeBetween(date, getLastTradingDate());
final ZonedDateTime spotDate = ScheduleCalculator.getAdjustedDate(date, _settlementDays, _calendar);
final BondFixedSecurity[] basketAtDelivery = new BondFixedSecurity[_deliveryBasket.length];
final BondFixedSecurity[] basketAtSpot = new BondFixedSecurity[_deliveryBasket.length];
for (int loopbasket = 0; loopbasket < _deliveryBasket.length; loopbasket++) {
basketAtDelivery[loopbasket] = _deliveryBasket[loopbasket].toDerivative(date, _deliveryDate);
basketAtSpot[loopbasket] = _deliveryBasket[loopbasket].toDerivative(date, spotDate);
}
return new BondFuturesYieldAverageSecurity(lastTradingTime, basketAtDelivery, basketAtDelivery, _couponRate, _tenor, _notional);
}
@Override
public <U, V> V accept(final InstrumentDefinitionVisitor<U, V> visitor, final U data) {
return visitor.visitBondFuturesYieldAverageSecurityDefinition(this, data);
}
@Override
public <V> V accept(final InstrumentDefinitionVisitor<?, V> visitor) {
return visitor.visitBondFuturesYieldAverageSecurityDefinition(this);
}
@Override
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
result = prime * result + _calendar.hashCode();
long temp;
temp = Double.doubleToLongBits(_couponRate);
result = prime * result + (int) (temp ^ (temp >>> 32));
result = prime * result + Arrays.hashCode(_deliveryBasket);
result = prime * result + _deliveryDate.hashCode();
temp = Double.doubleToLongBits(_notional);
result = prime * result + (int) (temp ^ (temp >>> 32));
result = prime * result + _settlementDays;
result = prime * result + _tenor;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!super.equals(obj)) {
return false;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
BondFuturesYieldAverageSecurityDefinition other = (BondFuturesYieldAverageSecurityDefinition) obj;
if (Double.doubleToLongBits(_couponRate) != Double.doubleToLongBits(other._couponRate)) {
return false;
}
if (!Arrays.equals(_deliveryBasket, other._deliveryBasket)) {
return false;
}
if (!ObjectUtils.equals(_deliveryDate, other._deliveryDate)) {
return false;
}
if (Double.doubleToLongBits(_notional) != Double.doubleToLongBits(other._notional)) {
return false;
}
if (_settlementDays != other._settlementDays) {
return false;
}
if (_tenor != other._tenor) {
return false;
}
return true;
}
}