/**
* Copyright (C) 2011 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.analytics.financial.instrument.index;
import org.apache.commons.lang.ObjectUtils;
import org.threeten.bp.Period;
import org.threeten.bp.ZonedDateTime;
import com.opengamma.analytics.financial.instrument.annuity.AnnuityDefinition;
import com.opengamma.analytics.financial.instrument.annuity.AnnuityDefinitionBuilder;
import com.opengamma.analytics.financial.instrument.payment.CouponIborCompoundingFlatSpreadDefinition;
import com.opengamma.analytics.financial.instrument.payment.CouponIborDefinition;
import com.opengamma.analytics.financial.instrument.swap.SwapDefinition;
import com.opengamma.analytics.financial.schedule.ScheduleCalculator;
import com.opengamma.financial.convention.StubType;
import com.opengamma.financial.convention.businessday.BusinessDayConvention;
import com.opengamma.financial.convention.calendar.Calendar;
import com.opengamma.util.ArgumentChecker;
/**
* Class with the description of swap characteristics.
*/
public class GeneratorSwapIborCompoundingIbor extends GeneratorInstrument<GeneratorAttributeIR> {
/**
* The Ibor index of the first leg.
*/
private final IborIndex _iborIndex1;
/**
* The period on which the first leg is compounded.
*/
private final Period _compoundingPeriod1;
/**
* The Ibor index of the second leg. The two index should be related to the same currency.
*/
private final IborIndex _iborIndex2;
/**
* The business day convention associated to the swap.
*/
private final BusinessDayConvention _businessDayConvention;
/**
* The flag indicating if the end-of-month rule is used for the swap.
*/
private final boolean _endOfMonth;
/**
* The index spot lag in days between trade and settlement date (usually 2 or 0).
*/
private final int _spotLag;
/**
* The holiday calendar for the first ibor leg.
*/
private final Calendar _calendar1;
/**
* The holiday calendar for the second ibor leg.
*/
private final Calendar _calendar2;
// REVIEW: Do we need stubShort and stubFirst flags?
/**
* Constructor from the details. The business day conventions, end-of-month and spot lag are from the first Ibor index.
* @param name The generator name. Not null.
* @param iborIndex1 The Ibor index of the first leg.
* @param compoundingPeriod1 The compounding period.
* @param iborIndex2 The Ibor index of the second leg.
* @param calendar1 The holiday calendar for the first ibor leg.
* @param calendar2 The holiday calendar for the second ibor leg.
*/
public GeneratorSwapIborCompoundingIbor(final String name, final IborIndex iborIndex1, Period compoundingPeriod1, final IborIndex iborIndex2, final Calendar calendar1, final Calendar calendar2) {
super(name);
ArgumentChecker.notNull(iborIndex1, "ibor index 1");
ArgumentChecker.notNull(compoundingPeriod1, "compounding period 1");
ArgumentChecker.notNull(iborIndex2, "ibor index 2");
ArgumentChecker.notNull(calendar1, "calendar 1");
ArgumentChecker.notNull(calendar2, "calendar 2");
ArgumentChecker.isTrue(iborIndex1.getCurrency().equals(iborIndex2.getCurrency()), "Currencies of both index should be identical");
_iborIndex1 = iborIndex1;
_compoundingPeriod1 = compoundingPeriod1;
_iborIndex2 = iborIndex2;
_businessDayConvention = iborIndex1.getBusinessDayConvention();
_endOfMonth = iborIndex1.isEndOfMonth();
_spotLag = iborIndex1.getSpotLag();
_calendar1 = calendar1;
_calendar2 = calendar2;
}
/**
* Constructor from the details. The business day conventions, end-of-month and spot lag are from the Ibor index.
* @param name The generator name. Not null.
* @param iborIndex1 The Ibor index of the first leg.
* @param compoundingPeriod1 The compounding period.
* @param iborIndex2 The Ibor index of the second leg.
* @param businessDayConvention The business day convention associated to the index.
* @param endOfMonth The end-of-month flag.
* @param spotLag The swap spot lag (usually 2 or 0).
* @param calendar1 The holiday calendar for the first ibor leg.
* @param calendar2 The holiday calendar for the second ibor leg.
*/
public GeneratorSwapIborCompoundingIbor(final String name, final IborIndex iborIndex1, Period compoundingPeriod1, final IborIndex iborIndex2, final BusinessDayConvention businessDayConvention,
final boolean endOfMonth, final int spotLag, final Calendar calendar1, final Calendar calendar2) {
super(name);
ArgumentChecker.notNull(iborIndex1, "ibor index 1");
ArgumentChecker.notNull(compoundingPeriod1, "compounding period 1");
ArgumentChecker.notNull(iborIndex2, "ibor index 2");
ArgumentChecker.notNull(calendar1, "calendar 1");
ArgumentChecker.notNull(calendar2, "calendar 2");
ArgumentChecker.isTrue(iborIndex1.getCurrency().equals(iborIndex2.getCurrency()), "Currencies of both index should be identical");
_iborIndex1 = iborIndex1;
_compoundingPeriod1 = compoundingPeriod1;
_iborIndex2 = iborIndex2;
_businessDayConvention = businessDayConvention;
_endOfMonth = endOfMonth;
_spotLag = spotLag;
_calendar1 = calendar1;
_calendar2 = calendar2;
}
/**
* Gets the Ibor index of the first leg.
* @return The index.
*/
public IborIndex getIborIndex1() {
return _iborIndex1;
}
/**
* Returns the compounding period of the first leg.
* @return The period.
*/
public Period getCompoundingPeriod1() {
return _compoundingPeriod1;
}
/**
* Gets the Ibor index of the second leg.
* @return The index.
*/
public IborIndex getIborIndex2() {
return _iborIndex2;
}
/**
* Gets the swap generator business day convention.
* @return The convention.
*/
public BusinessDayConvention getBusinessDayConvention() {
return _businessDayConvention;
}
/**
* Gets the swap generator spot lag.
* @return The lag (in days).
*/
public int getSpotLag() {
return _spotLag;
}
/**
* Gets the swap generator end-of-month rule.
* @return The EOM.
*/
public Boolean isEndOfMonth() {
return _endOfMonth;
}
/**
* Gets the holiday calendar for the first leg.
* @return The holiday calendar
*/
public Calendar getCalendar1() {
return _calendar1;
}
/**
* Gets the holiday calendar for the second leg.
* @return The holiday calendar
*/
public Calendar getCalendar2() {
return _calendar2;
}
@Override
public SwapDefinition generateInstrument(final ZonedDateTime date, final double spread, final double notional, final GeneratorAttributeIR attribute) {
ArgumentChecker.notNull(date, "Reference date");
ArgumentChecker.notNull(attribute, "Attributes");
final ZonedDateTime spot = ScheduleCalculator.getAdjustedDate(date, _spotLag, _calendar1);
final ZonedDateTime startDate = ScheduleCalculator.getAdjustedDate(spot, attribute.getStartPeriod(), _iborIndex1, _calendar1);
final ZonedDateTime maturityDate = startDate.plus(attribute.getEndPeriod());
final AnnuityDefinition<CouponIborCompoundingFlatSpreadDefinition> leg1 = AnnuityDefinitionBuilder.couponIborCompoundingFlatSpread(startDate, maturityDate,
_compoundingPeriod1, notional, spread, _iborIndex1, StubType.SHORT_START, true, _businessDayConvention, _endOfMonth, _calendar1, StubType.SHORT_START);
final AnnuityDefinition<CouponIborDefinition> leg2 = AnnuityDefinitionBuilder.couponIbor(startDate, maturityDate, _iborIndex2.getTenor(), notional, _iborIndex2, false,
_iborIndex2.getDayCount(), _businessDayConvention, _endOfMonth, _calendar2, StubType.SHORT_START, 0);
return new SwapDefinition(leg1, leg2);
}
@Override
public String toString() {
return getName();
}
@Override
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
result = prime * result + _businessDayConvention.hashCode();
result = prime * result + (_endOfMonth ? 1231 : 1237);
result = prime * result + _iborIndex1.hashCode();
result = prime * result + _iborIndex2.hashCode();
result = prime * result + _spotLag;
result = prime * result + _calendar1.hashCode();
result = prime * result + _calendar2.hashCode();
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 GeneratorSwapIborCompoundingIbor other = (GeneratorSwapIborCompoundingIbor) obj;
if (!ObjectUtils.equals(_businessDayConvention, other._businessDayConvention)) {
return false;
}
if (_endOfMonth != other._endOfMonth) {
return false;
}
if (!ObjectUtils.equals(_iborIndex2, other._iborIndex2)) {
return false;
}
if (!ObjectUtils.equals(_iborIndex1, other._iborIndex1)) {
return false;
}
if (_spotLag != other._spotLag) {
return false;
}
if (!ObjectUtils.equals(_calendar1, other._calendar1)) {
return false;
}
if (!ObjectUtils.equals(_calendar2, other._calendar2)) {
return false;
}
return true;
}
}