/** * 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.apache.commons.lang.ObjectUtils; import org.threeten.bp.Period; import org.threeten.bp.ZonedDateTime; import com.opengamma.analytics.financial.instrument.InstrumentDefinitionVisitor; import com.opengamma.analytics.financial.instrument.index.IndexON; import com.opengamma.analytics.financial.interestrate.payments.derivative.CouponONArithmeticAverageSpreadSimplified; import com.opengamma.analytics.financial.schedule.ScheduleCalculator; import com.opengamma.analytics.util.time.TimeCalculator; import com.opengamma.financial.convention.businessday.BusinessDayConvention; import com.opengamma.financial.convention.calendar.Calendar; import com.opengamma.util.ArgumentChecker; import com.opengamma.util.money.Currency; /** * Class describing a Fed Fund swap-like floating coupon (arithmetic average on overnight rates) with a spread. * Simplified definition which contains only the starting date and end date (not all intermediary dates). The fixing and accrual dates are equal. * Can not be used for "aged" coupon but only for forward coupons when all the details of intermediary fixing are not required. * In particular can be used for */ public class CouponONArithmeticAverageSpreadSimplifiedDefinition extends CouponDefinition { /** * The overnight index on which the coupon fixes. The index currency should be the same as the coupon currency. Not null. */ private final IndexON _index; /** * The spread rate paid above the arithmetic average. */ private final double _spread; /** * The fixed amount related to the spread. */ private final double _spreadAmount; /** * Constructor from all the coupon details. * @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 index The OIS-like index on which the coupon fixes. * @param spread The spread rate paid above the arithmetic average. */ public CouponONArithmeticAverageSpreadSimplifiedDefinition(final Currency currency, final ZonedDateTime paymentDate, final ZonedDateTime accrualStartDate, final ZonedDateTime accrualEndDate, final double paymentYearFraction, final double notional, final IndexON index, final double spread) { super(currency, paymentDate, accrualStartDate, accrualEndDate, paymentYearFraction, notional); ArgumentChecker.notNull(index, "CouponOISDefinition: index"); ArgumentChecker.isTrue(currency.equals(index.getCurrency()), "Coupon and index currencies are not compatible. Expected to be the same"); _index = index; _spread = spread; _spreadAmount = spread * paymentYearFraction * notional; } /** * Builder from financial details. The accrual and fixing start and end dates are the same. The day count for the payment is the same as the one for the index. * The payment date is adjusted by the publication lag and the settlement days. * @param index The OIS index. * @param fixingPeriodStartDate The coupon settlement date and start of the fixing period. * @param tenor The coupon tenor. * @param notional The notional. * @param paymentLag The number of days between last fixing date and the payment date (also called payment delay). * @param businessDayConvention The business day convention to compute the end date of the coupon. * @param isEOM The end-of-month convention to compute the end date of the coupon. * @param spread The spread rate paid above the arithmetic average. * @param calendar The holiday calendar for the overnight index. * @return The OIS coupon. */ public static CouponONArithmeticAverageSpreadSimplifiedDefinition from(final IndexON index, final ZonedDateTime fixingPeriodStartDate, final Period tenor, final double notional, final int paymentLag, final BusinessDayConvention businessDayConvention, final boolean isEOM, final double spread, final Calendar calendar) { final ZonedDateTime fixingPeriodEndDate = ScheduleCalculator.getAdjustedDate(fixingPeriodStartDate, tenor, businessDayConvention, calendar, isEOM); return from(index, fixingPeriodStartDate, fixingPeriodEndDate, notional, paymentLag, spread, calendar); } /** * Builder from financial details. The accrual and fixing start and end dates are the same. The day count for the payment is the same as the one for the index. * The payment date is adjusted by the publication lag and the settlement days. * @param index The OIS index. * @param fixingPeriodStartDate The coupon settlement date and start of the fixing period. * @param fixingPeriodEndDate The last date of the fixing period. Interest accrues up to this date. If publicationLag==0, 1 day following publication. If lag==1, the publication date. * @param notional The notional. * @param paymentLag The number of days between last fixing date and the payment date (also called payment delay). * @param spread The spread rate paid above the arithmetic average. * @param calendar The holiday calendar for the overnight index. * @return The OIS coupon. */ public static CouponONArithmeticAverageSpreadSimplifiedDefinition from(final IndexON index, final ZonedDateTime fixingPeriodStartDate, final ZonedDateTime fixingPeriodEndDate, final double notional, final int paymentLag, final double spread, final Calendar calendar) { final ZonedDateTime paymentDate = ScheduleCalculator.getAdjustedDate(fixingPeriodEndDate, -1 + index.getPublicationLag() + paymentLag, calendar); final double paymentYearFraction = index.getDayCount().getDayCountFraction(fixingPeriodStartDate, fixingPeriodEndDate, calendar); return new CouponONArithmeticAverageSpreadSimplifiedDefinition(index.getCurrency(), paymentDate, fixingPeriodStartDate, fixingPeriodEndDate, paymentYearFraction, notional, index, spread); } /** * Gets the OIS index of the instrument. * @return The index. */ public IndexON getIndex() { return _index; } /** * Returns the spread rate paid above the arithmetic average. * @return The spread. */ public double getSpread() { return _spread; } /** * Returns the fixed amount related to the spread. * @return The amount. */ public double getSpreadAmount() { return _spreadAmount; } @Override public CouponONArithmeticAverageSpreadSimplified toDerivative(final ZonedDateTime date) { ArgumentChecker.isTrue(!getAccrualStartDate().plusDays(_index.getPublicationLag()).isBefore(date), "First fixing publication strictly before reference date"); final double paymentTime = TimeCalculator.getTimeBetween(date, getPaymentDate()); final double fixingPeriodStartTimes = TimeCalculator.getTimeBetween(date, getAccrualStartDate()); final double fixingPeriodEndTimes = TimeCalculator.getTimeBetween(date, getAccrualEndDate()); return CouponONArithmeticAverageSpreadSimplified.from(paymentTime, getPaymentYearFraction(), getNotional(), _index, fixingPeriodStartTimes, fixingPeriodEndTimes, getPaymentYearFraction(), _spread); } @Override public <U, V> V accept(final InstrumentDefinitionVisitor<U, V> visitor, final U data) { ArgumentChecker.notNull(visitor, "visitor"); return visitor.visitCouponArithmeticAverageONSpreadSimplifiedDefinition(this, data); } @Override public <V> V accept(final InstrumentDefinitionVisitor<?, V> visitor) { ArgumentChecker.notNull(visitor, "visitor"); return visitor.visitCouponArithmeticAverageONSpreadSimplifiedDefinition(this); } @Override public int hashCode() { final int prime = 31; int result = super.hashCode(); result = prime * result + _index.hashCode(); long temp; temp = Double.doubleToLongBits(_spread); result = prime * result + (int) (temp ^ (temp >>> 32)); temp = Double.doubleToLongBits(_spreadAmount); result = prime * result + (int) (temp ^ (temp >>> 32)); 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 CouponONArithmeticAverageSpreadSimplifiedDefinition other = (CouponONArithmeticAverageSpreadSimplifiedDefinition) obj; if (!ObjectUtils.equals(_index, other._index)) { return false; } if (Double.doubleToLongBits(_spread) != Double.doubleToLongBits(other._spread)) { return false; } if (Double.doubleToLongBits(_spreadAmount) != Double.doubleToLongBits(other._spreadAmount)) { return false; } return true; } }