This repository has been archived by the owner on May 29, 2018. It is now read-only.
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #288 from OpenGamma/topic/REQS-648
Topic/reqs 648
- Loading branch information
Showing
5 changed files
with
645 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
166 changes: 166 additions & 0 deletions
166
...n/java/com/opengamma/analytics/financial/interestrate/SwapCleanDiscountingCalculator.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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"); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.