/** * Copyright (C) 2012 - 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.ZonedDateTime; import com.opengamma.analytics.financial.instrument.swap.SwapXCcyIborIborDefinition; import com.opengamma.analytics.financial.schedule.ScheduleCalculator; 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 GeneratorSwapXCcyIborIbor extends GeneratorInstrument<GeneratorAttributeFX> { /** * The Ibor index of the first leg. The spread is added to this leg. */ private final IborIndex _iborIndex1; /** * The Ibor index of the second leg. */ 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 leg. */ private final Calendar _calendar1; /** * The holiday calendar for the second leg. */ private final Calendar _calendar2; // REVIEW: Do we need stub type? // TODO: Add a merged calendar? [PLAT-1747] /** * 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 iborIndex2 The Ibor index of the second leg. * @param calendar1 The holiday calendar for the first leg. * @param calendar2 The holiday calendar for the second leg. */ public GeneratorSwapXCcyIborIbor(final String name, final IborIndex iborIndex1, final IborIndex iborIndex2, final Calendar calendar1, final Calendar calendar2) { super(name); ArgumentChecker.notNull(iborIndex1, "ibor index"); ArgumentChecker.notNull(iborIndex2, "ibor index"); ArgumentChecker.notNull(calendar1, "calendar1"); ArgumentChecker.notNull(calendar2, "calendar2"); _iborIndex1 = iborIndex1; _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 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 leg. * @param calendar2 The holiday calendar for the second leg. */ public GeneratorSwapXCcyIborIbor(final String name, final IborIndex iborIndex1, 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"); ArgumentChecker.notNull(iborIndex2, "ibor index"); ArgumentChecker.notNull(calendar1, "calendar1"); ArgumentChecker.notNull(calendar2, "calendar2"); _iborIndex1 = iborIndex1; _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; } /** * 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; } /** * Generate the cross-currency swap from the spread and the FX exchange rate. * @param date The reference date (the effective date of the swap will be the spot lag of the generator after the reference date). * @param spread The spread above the index (is applied to the first leg). * @param notional The notional of the first leg. The second leg notional is that number multiplied by the FX rate (1 Ccy1 = x Ccy2). * @param attribute The FX instrument attributes. The start period is the date between the spot date and the effective period. * The end period is the period between the effective date and the maturity. * @return The cross-currency swap. */ @Override public SwapXCcyIborIborDefinition generateInstrument(final ZonedDateTime date, final double spread, final double notional, final GeneratorAttributeFX 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 double fx = attribute.getFXMatrix().getFxRate(_iborIndex1.getCurrency(), _iborIndex2.getCurrency()); return SwapXCcyIborIborDefinition.from(startDate, attribute.getEndPeriod(), this, notional, fx * notional, spread, true, _calendar1, _calendar2); } @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 GeneratorSwapXCcyIborIbor other = (GeneratorSwapXCcyIborIbor) 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; } }