Skip to content
This repository has been archived by the owner on May 29, 2018. It is now read-only.

Commit

Permalink
Merge pull request #288 from OpenGamma/topic/REQS-648
Browse files Browse the repository at this point in the history
Topic/reqs 648
  • Loading branch information
marc-henrard committed Dec 19, 2014
2 parents 9f3a9ae + fa1e18b commit 10f44e9
Show file tree
Hide file tree
Showing 5 changed files with 645 additions and 0 deletions.
Expand Up @@ -191,6 +191,7 @@ public Annuity<? extends Payment> toDerivative(final ZonedDateTime date, final D
final List<Payment> resultList = new ArrayList<>();
for (final P payment : _payments) {
//TODO check this
//TODO The comparison should be done on LocalDate and not on ZonedDateTime, to avoid jumps during the day. PLAT-6872
if (!date.isAfter(payment.getPaymentDate())) {
if (payment instanceof InstrumentDefinitionWithData) {
resultList.add(((InstrumentDefinitionWithData<? extends Payment, DoubleTimeSeries<ZonedDateTime>>) payment).toDerivative(date, indexFixingTS));
Expand Down
Expand Up @@ -208,6 +208,25 @@ public SwapFixedIborDefinition generateInstrument(final ZonedDateTime date, fina
return SwapFixedIborDefinition.from(startDate, attribute.getEndPeriod(), this, notional, rate, true);
}

/**
* Generate fixed-for-ibor swap definition
* @param date The reference date
* @param rate The fixed rate
* @param notional The notional
* @param attribute The instrument attributes, as given by a GeneratorAttribute.
* @param isFixedPayer True if fixed rate payer
* @return Fixed-for-ibor swap definition
*/
public SwapFixedIborDefinition generateInstrument(final ZonedDateTime date, final double rate, final double notional,
final GeneratorAttributeIR attribute, final boolean isFixedPayer) {
ArgumentChecker.notNull(date, "Reference date");
ArgumentChecker.notNull(attribute, "Attributes");
final ZonedDateTime spot = ScheduleCalculator.getAdjustedDate(date, _spotLag, _calendar);
final ZonedDateTime startDate = ScheduleCalculator.getAdjustedDate(spot, attribute.getStartPeriod(), _iborIndex,
_calendar);
return SwapFixedIborDefinition.from(startDate, attribute.getEndPeriod(), this, notional, rate, isFixedPayer);
}

@Override
public String toString() {
return getName();
Expand Down
@@ -0,0 +1,166 @@
/**
* Copyright (C) 2014 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.analytics.financial.interestrate;

import org.threeten.bp.LocalDate;
import org.threeten.bp.ZonedDateTime;

import com.opengamma.analytics.financial.instrument.annuity.AnnuityCouponFixedDefinition;
import com.opengamma.analytics.financial.instrument.annuity.AnnuityCouponIborDefinition;
import com.opengamma.analytics.financial.instrument.annuity.AnnuityDefinition;
import com.opengamma.analytics.financial.instrument.payment.CouponDefinition;
import com.opengamma.analytics.financial.instrument.payment.CouponFixedDefinition;
import com.opengamma.analytics.financial.instrument.payment.CouponIborDefinition;
import com.opengamma.analytics.financial.instrument.swap.SwapFixedIborDefinition;
import com.opengamma.analytics.financial.interestrate.annuity.derivative.Annuity;
import com.opengamma.analytics.financial.interestrate.annuity.derivative.AnnuityCouponFixed;
import com.opengamma.analytics.financial.interestrate.payments.derivative.Coupon;
import com.opengamma.analytics.financial.interestrate.payments.derivative.CouponFixed;
import com.opengamma.analytics.financial.interestrate.swap.derivative.SwapFixedCoupon;
import com.opengamma.analytics.financial.interestrate.swap.provider.SwapFixedCouponDiscountingMethod;
import com.opengamma.analytics.financial.provider.calculator.discounting.ParRateDiscountingCalculator;
import com.opengamma.analytics.financial.provider.calculator.discounting.PresentValueDiscountingCalculator;
import com.opengamma.analytics.financial.provider.description.interestrate.MulticurveProviderDiscount;
import com.opengamma.financial.convention.calendar.Calendar;
import com.opengamma.financial.convention.daycount.DayCount;
import com.opengamma.timeseries.precise.zdt.ZonedDateTimeDoubleTimeSeries;
import com.opengamma.util.ArgumentChecker;
import com.opengamma.util.money.MultipleCurrencyAmount;

/**
* Computes par rate (excluding accrued interests) and accrued interest. <br>
* <b>Use {@link ParRateDiscountingCalculator} for standard definition of par rate.<b>
*/
public class SwapCleanDiscountingCalculator {
private static final PresentValueDiscountingCalculator PVDC = PresentValueDiscountingCalculator.getInstance();
private static final SwapFixedCouponDiscountingMethod METHOD_SWAP = SwapFixedCouponDiscountingMethod.getInstance();

/**
* Computes par rate excluding accrued interest.
* @param swapDefinition Fixed vs Ibor swap definition
* @param fixedLegDayCount Day count for fixed leg
* @param iborLegDayCount Day count for Ibor leg
* @param calendar The calendar
* @param valuationDate The valuation date
* @param indexTimeSeries Index fixing time series
* @param multicurves The multi-curve
* @return The par rate
*/
public Double parRate(SwapFixedIborDefinition swapDefinition, DayCount fixedLegDayCount,
DayCount iborLegDayCount, Calendar calendar, ZonedDateTime valuationDate,
ZonedDateTimeDoubleTimeSeries indexTimeSeries, MulticurveProviderDiscount multicurves) {
ArgumentChecker.notNull(swapDefinition, "swapDefinition");
ArgumentChecker.notNull(fixedLegDayCount, "fixedLegDayCount");
ArgumentChecker.notNull(iborLegDayCount, "iborLegDayCount");
ArgumentChecker.notNull(calendar, "calendar");
ArgumentChecker.notNull(valuationDate, "valuationDate");
ArgumentChecker.notNull(indexTimeSeries, "indexTimeSeries");
ArgumentChecker.notNull(multicurves, "multicurves");
checkNotionalAndFixedRate(swapDefinition);

Annuity<? extends Coupon> iborLeg = swapDefinition.getIborLeg().toDerivative(valuationDate, indexTimeSeries);
double dirtyIborLegPV = iborLeg.accept(PVDC, multicurves).getAmount(iborLeg.getCurrency());
double iborLegAccruedInterest = getAccrued(iborLegDayCount, calendar, valuationDate,
swapDefinition.getIborLeg(), indexTimeSeries);
double cleanFloatingPV = (dirtyIborLegPV - iborLegAccruedInterest) *
Math.signum(iborLeg.getNthPayment(0).getNotional());

AnnuityCouponFixed fixedLeg = swapDefinition.getFixedLeg().toDerivative(valuationDate);
double accruedAmount = getAccrued(fixedLegDayCount, calendar, valuationDate, swapDefinition.getFixedLeg(),
indexTimeSeries) * Math.signum(fixedLeg.getNthPayment(0).getNotional());
double dirtyAnnuity = METHOD_SWAP.presentValueBasisPoint(new SwapFixedCoupon<>(fixedLeg, iborLeg),
multicurves);
double cleanAnnuity = dirtyAnnuity - accruedAmount;

return cleanFloatingPV / cleanAnnuity;
}

/**
* Computes accrued interest
* @param swapDefinition Fixed vs Ibor swap definition
* @param fixedLegDayCount Day count for fixed leg
* @param iborLegDayCount Day count for Ibor leg
* @param calendar The calendar
* @param valuationDate The valuation date
* @param indexTimeSeries Index fixing time series
* @param multicurves The multi-curve
* @return The accrued interest
*/
public MultipleCurrencyAmount accruedInterest(SwapFixedIborDefinition swapDefinition, DayCount fixedLegDayCount,
DayCount iborLegDayCount, Calendar calendar, ZonedDateTime valuationDate,
ZonedDateTimeDoubleTimeSeries indexTimeSeries, MulticurveProviderDiscount multicurves) {
ArgumentChecker.notNull(swapDefinition, "swapDefinition");
ArgumentChecker.notNull(fixedLegDayCount, "fixedLegDayCount");
ArgumentChecker.notNull(iborLegDayCount, "iborLegDayCount");
ArgumentChecker.notNull(calendar, "calendar");
ArgumentChecker.notNull(valuationDate, "valuationDate");
ArgumentChecker.notNull(indexTimeSeries, "indexTimeSeries");
ArgumentChecker.notNull(multicurves, "multicurves");
checkNotionalAndFixedRate(swapDefinition);

double iborLegAccruedInterest = getAccrued(iborLegDayCount, calendar, valuationDate, swapDefinition.getIborLeg(),
indexTimeSeries);

CouponFixedDefinition refFixed = swapDefinition.getFixedLeg().getNthPayment(0);
double fixedLegAccruedInterest = getAccrued(fixedLegDayCount, calendar, valuationDate,
swapDefinition.getFixedLeg(), indexTimeSeries) * refFixed.getRate();

return MultipleCurrencyAmount.of(swapDefinition.getCurrency(), iborLegAccruedInterest + fixedLegAccruedInterest);
}

private double getAccrued(DayCount dayCount, Calendar calendar, ZonedDateTime valuationDate,
AnnuityDefinition<? extends CouponDefinition> annuity, ZonedDateTimeDoubleTimeSeries indexTimeSeries) {
LocalDate date = valuationDate.toLocalDate();
double res = 0.0;
CouponDefinition[] payments = annuity.getPayments();
for (CouponDefinition payment : payments) {
if (payment.getAccrualStartDate().toLocalDate().isBefore(date) &&
!payment.getPaymentDate().toLocalDate().isBefore(date)) {
double rate;
if (payment instanceof CouponIborDefinition) {
CouponIborDefinition casted = (CouponIborDefinition) payment;
Coupon coupon = casted.toDerivative(valuationDate, indexTimeSeries);
ArgumentChecker.isTrue(coupon instanceof CouponFixed,
"index should be fixed before accrual starts for standard vanilla swap");
CouponFixed couponFixed = (CouponFixed) coupon;
rate = couponFixed.getFixedRate();
} else if (payment instanceof CouponFixedDefinition) {
rate = 1.0;
} else {
throw new IllegalArgumentException("This annuity type is not supported");
}
res += getAccrued(dayCount, calendar, valuationDate, payment) * rate;
}
}
return res;
}

private double getAccrued(DayCount dayCount, Calendar calendar, ZonedDateTime valuationDate, CouponDefinition coupon) {
double accruedYearFraction = dayCount.getDayCountFraction(coupon.getAccrualStartDate(), valuationDate, calendar);
return accruedYearFraction * coupon.getNotional();
}

private void checkNotionalAndFixedRate(SwapFixedIborDefinition swapDefinition) {
AnnuityCouponIborDefinition iborLeg = swapDefinition.getIborLeg();
int nIbor = iborLeg.getNumberOfPayments();
double notioanl = iborLeg.getNthPayment(0).getNotional();
for (int i = 1; i < nIbor; ++i) {
ArgumentChecker.isTrue(notioanl == iborLeg.getNthPayment(i).getNotional(),
"Notional should be constant in both the legs");
}
AnnuityCouponFixedDefinition fixedLeg = swapDefinition.getFixedLeg();
int nFixed = fixedLeg.getNumberOfPayments();
double rate = fixedLeg.getNthPayment(0).getRate();
notioanl *= -1.0; // payer/receiver conversion
ArgumentChecker.isTrue(notioanl == fixedLeg.getNthPayment(0).getNotional(),
"Notional should be constant in both the legs");
for (int i = 1; i < nFixed; ++i) {
ArgumentChecker.isTrue(rate == fixedLeg.getNthPayment(i).getRate(), "Fixed rate should be constant");
ArgumentChecker.isTrue(notioanl == fixedLeg.getNthPayment(i).getNotional(),
"Notional should be constant in both the legs");
}
}
}
Expand Up @@ -11,7 +11,11 @@

import org.testng.annotations.Test;
import org.threeten.bp.Period;
import org.threeten.bp.ZonedDateTime;

import com.opengamma.analytics.financial.instrument.payment.CouponFixedDefinition;
import com.opengamma.analytics.financial.instrument.payment.CouponIborDefinition;
import com.opengamma.analytics.financial.instrument.swap.SwapFixedIborDefinition;
import com.opengamma.financial.convention.businessday.BusinessDayConvention;
import com.opengamma.financial.convention.businessday.BusinessDayConventions;
import com.opengamma.financial.convention.calendar.Calendar;
Expand All @@ -20,6 +24,7 @@
import com.opengamma.financial.convention.daycount.DayCounts;
import com.opengamma.util.money.Currency;
import com.opengamma.util.test.TestGroup;
import com.opengamma.util.time.DateUtils;

/**
* Test.
Expand Down Expand Up @@ -79,4 +84,45 @@ public void equalHash() {
assertFalse(GENERATOR_FROM_INDEX.equals(CUR));
}

/**
* Test fixed payer and fixed receiver
*/
@Test
public void fixedPayerAndReceiverTest() {
double fixedRate = 0.015;
GeneratorAttributeIR attribute = new GeneratorAttributeIR(Period.ofYears(7));
double notional = 1.0e8;
ZonedDateTime date = DateUtils.getUTCDate(2013, 9, 10);
SwapFixedIborDefinition def1 = GENERATOR_FROM_INDEX.generateInstrument(date, fixedRate, notional, attribute);
SwapFixedIborDefinition def2 = GENERATOR_FROM_INDEX.generateInstrument(date, fixedRate, notional, attribute, true);
assertEquals(def1, def2);
SwapFixedIborDefinition def3 = GENERATOR_FROM_INDEX.generateInstrument(date, fixedRate, notional, attribute, false);
assertFalse(def1.equals(def3));
int nIbor = def1.getIborLeg().getNumberOfPayments();
int nFixed = def1.getFixedLeg().getNumberOfPayments();
assertEquals(nIbor, def3.getIborLeg().getNumberOfPayments());
assertEquals(nFixed, def3.getFixedLeg().getNumberOfPayments());
assertEquals(def1.getIborLeg().getIborIndex(), def3.getIborLeg().getIborIndex());
assertEquals(def1.getIborLeg().getCalendar(), def3.getIborLeg().getCalendar());
assertEquals(def1.getCurrency(), def3.getIborLeg().getCurrency());
for (int i = 0; i < nIbor; ++i) {
CouponIborDefinition ibor1 = def1.getIborLeg().getNthPayment(i);
CouponIborDefinition ibor3 = def3.getIborLeg().getNthPayment(i);
assertEquals(ibor1.getNotional(), -ibor3.getNotional());
assertEquals(ibor1.getAccrualStartDate(), ibor3.getAccrualStartDate());
assertEquals(ibor1.getAccrualEndDate(), ibor3.getAccrualEndDate());
assertEquals(ibor1.getFixingDate(), ibor3.getFixingDate());
assertEquals(ibor1.getPaymentDate(), ibor3.getPaymentDate());
assertEquals(ibor1.getPaymentYearFraction(), ibor3.getPaymentYearFraction());
}
for (int i = 0; i < nFixed; ++i) {
CouponFixedDefinition fixed1 = def1.getFixedLeg().getNthPayment(i);
CouponFixedDefinition fixed3 = def3.getFixedLeg().getNthPayment(i);
assertEquals(fixed1.getNotional(), -fixed3.getNotional());
assertEquals(fixed1.getAccrualStartDate(), fixed3.getAccrualStartDate());
assertEquals(fixed1.getAccrualEndDate(), fixed3.getAccrualEndDate());
assertEquals(fixed1.getPaymentDate(), fixed3.getPaymentDate());
assertEquals(fixed1.getPaymentYearFraction(), fixed3.getPaymentYearFraction());
}
}
}

0 comments on commit 10f44e9

Please sign in to comment.