/** * Copyright (C) 2013 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.analytics.financial.interestrate.payments.derivative; import java.util.Arrays; import org.apache.commons.lang.ObjectUtils; import com.opengamma.analytics.financial.instrument.index.IndexON; import com.opengamma.analytics.financial.interestrate.InstrumentDerivativeVisitor; 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). */ public final class CouponONArithmeticAverageSpread extends Coupon { /** * 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 times of the fixing periods. The length is one greater than the number of periods, as it includes accrual start and end. */ private final double[] _fixingPeriodTimes; /** * The accrual factors (or year fractions) associated to the fixing periods in the Index day count convention. */ private final double[] _fixingPeriodAccrualFactors; /** * The interest accrued over the periods already fixed multiplied by the accrual factors, i.e. the sum (\delta_i r_i). The spread is not included in the value. */ private final double _rateAccrued; /** * The accrual factor (or year fraction) associated to the remaining fixing period in the Index day count convention. */ private final double _fixingPeriodRemainingAccrualFactor; /** * The spread rate paid above the arithmetic average. */ private final double _spread; /** * The fixed amount related to the spread. */ private final double _spreadAmount; // TODO: Implement the rate cut-off mechanism (the two last periods use the same fixing) /** * Constructor. * @param currency The coupon currency. * @param paymentTime The coupon payment time. * @param paymentAccrualFactor The year fraction of the full coupon. * @param notional The coupon notional. * @param index The index associated to the coupon. * @param fixingPeriodTimes The times of the remaining fixing. The length is one greater than the number of periods, as it includes accrual start and end. * @param fixingPeriodAccrualFactors The accrual factors (or year fractions) associated to the fixing periods in the Index day count convention. * @param rateAccrued The interest accrued over the periods already fixed. * @param fixingPeriodRemainingAccrualFactor ?? * @param spread The spread rate paid above the arithmetic average. */ private CouponONArithmeticAverageSpread(final Currency currency, final double paymentTime, final double paymentYearFraction, final double notional, final IndexON index, final double[] fixingPeriodTimes, final double[] fixingPeriodAccrualFactors, final double rateAccrued, final double fixingPeriodRemainingAccrualFactor, final double spread) { super(currency, paymentTime, paymentYearFraction, notional); _index = index; _fixingPeriodTimes = fixingPeriodTimes; _fixingPeriodAccrualFactors = fixingPeriodAccrualFactors; _rateAccrued = rateAccrued; _fixingPeriodRemainingAccrualFactor = fixingPeriodRemainingAccrualFactor; _spread = spread; _spreadAmount = spread * paymentYearFraction * notional; } /** * Builder from financial details. * @param paymentTime The coupon payment time. * @param paymentAccrualFactor The year fraction of the full coupon. * @param notional The coupon notional. * @param index The index associated to the coupon. * @param fixingPeriodTimes The times of the remaining fixing. The length is one greater than the number of periods, as it includes accrual start and end. * @param fixingPeriodAccrualFactors The accrual factors (or year fractions) associated to the fixing periods in the Index day count convention. * @param rateAccrued The interest accrued over the periods already fixed. * @param spread The spread rate paid above the arithmetic average. * @return The coupon. */ public static CouponONArithmeticAverageSpread from(final double paymentTime, final double paymentAccrualFactor, final double notional, final IndexON index, final double[] fixingPeriodTimes, final double[] fixingPeriodAccrualFactors, final double rateAccrued, final double spread) { ArgumentChecker.notNull(index, "Index"); ArgumentChecker.notNull(fixingPeriodTimes, "Fixing Times"); ArgumentChecker.notNull(fixingPeriodAccrualFactors, "Accrual Factors"); double fixingPeriodRemainingAccrualFactor = 0.0; for (final double fixingPeriodAccrualFactor : fixingPeriodAccrualFactors) { fixingPeriodRemainingAccrualFactor += fixingPeriodAccrualFactor; } return new CouponONArithmeticAverageSpread(index.getCurrency(), paymentTime, paymentAccrualFactor, notional, index, fixingPeriodTimes, fixingPeriodAccrualFactors, rateAccrued, fixingPeriodRemainingAccrualFactor, spread); } /** * Gets the index. * @return The index. */ public IndexON getIndex() { return _index; } /** * Gets the times of the fixing periods. * @return The times. */ public double[] getFixingPeriodTimes() { return _fixingPeriodTimes; } /** * Gets the fixingPeriodAccrualFactors field. * @return the fixingPeriodAccrualFactors */ public double[] getFixingPeriodAccrualFactors() { return _fixingPeriodAccrualFactors; } /** * Gets the notionalAccrued field. * @return the notionalAccrued */ public double getRateAccrued() { return _rateAccrued; } /** * Gets the fixingPeriodTotalAccrualFactor field. * @return the fixingPeriodTotalAccrualFactor */ public double getFixingPeriodRemainingAccrualFactor() { return _fixingPeriodRemainingAccrualFactor; } /** * 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 Coupon withNotional(final double notional) { return null; // TODO } @Override public <S, T> T accept(final InstrumentDerivativeVisitor<S, T> visitor, final S data) { ArgumentChecker.notNull(visitor, "visitor"); return visitor.visitCouponONArithmeticAverageSpread(this, data); } @Override public <T> T accept(final InstrumentDerivativeVisitor<?, T> visitor) { ArgumentChecker.notNull(visitor, "visitor"); return visitor.visitCouponONArithmeticAverageSpread(this); } @Override public int hashCode() { final int prime = 31; int result = super.hashCode(); result = prime * result + Arrays.hashCode(_fixingPeriodAccrualFactors); long temp; temp = Double.doubleToLongBits(_fixingPeriodRemainingAccrualFactor); result = prime * result + (int) (temp ^ (temp >>> 32)); result = prime * result + Arrays.hashCode(_fixingPeriodTimes); result = prime * result + _index.hashCode(); temp = Double.doubleToLongBits(_rateAccrued); result = prime * result + (int) (temp ^ (temp >>> 32)); 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 CouponONArithmeticAverageSpread other = (CouponONArithmeticAverageSpread) obj; if (!Arrays.equals(_fixingPeriodAccrualFactors, other._fixingPeriodAccrualFactors)) { return false; } if (Double.doubleToLongBits(_fixingPeriodRemainingAccrualFactor) != Double.doubleToLongBits(other._fixingPeriodRemainingAccrualFactor)) { return false; } if (!Arrays.equals(_fixingPeriodTimes, other._fixingPeriodTimes)) { return false; } if (!ObjectUtils.equals(_index, other._index)) { return false; } if (Double.doubleToLongBits(_rateAccrued) != Double.doubleToLongBits(other._rateAccrued)) { return false; } if (Double.doubleToLongBits(_spread) != Double.doubleToLongBits(other._spread)) { return false; } if (Double.doubleToLongBits(_spreadAmount) != Double.doubleToLongBits(other._spreadAmount)) { return false; } return true; } }