/**
* Copyright (C) 2015 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.strata.pricer.bond;
import static com.opengamma.strata.basics.currency.Currency.EUR;
import static com.opengamma.strata.basics.date.DayCounts.ACT_365F;
import static com.opengamma.strata.collect.TestHelper.date;
import static com.opengamma.strata.pricer.CompoundedRateType.CONTINUOUS;
import static com.opengamma.strata.pricer.CompoundedRateType.PERIODIC;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
import java.time.LocalDate;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.opengamma.strata.basics.ReferenceData;
import com.opengamma.strata.basics.StandardId;
import com.opengamma.strata.basics.currency.Currency;
import com.opengamma.strata.basics.currency.CurrencyAmount;
import com.opengamma.strata.basics.currency.MultiCurrencyAmount;
import com.opengamma.strata.basics.currency.Payment;
import com.opengamma.strata.basics.date.BusinessDayAdjustment;
import com.opengamma.strata.basics.date.BusinessDayConventions;
import com.opengamma.strata.basics.date.DayCount;
import com.opengamma.strata.basics.date.DayCounts;
import com.opengamma.strata.basics.date.DaysAdjustment;
import com.opengamma.strata.basics.date.HolidayCalendarId;
import com.opengamma.strata.basics.date.HolidayCalendarIds;
import com.opengamma.strata.basics.schedule.Frequency;
import com.opengamma.strata.basics.schedule.PeriodicSchedule;
import com.opengamma.strata.basics.schedule.StubConvention;
import com.opengamma.strata.collect.array.DoubleArray;
import com.opengamma.strata.collect.tuple.Pair;
import com.opengamma.strata.market.curve.CurveMetadata;
import com.opengamma.strata.market.curve.CurveName;
import com.opengamma.strata.market.curve.Curves;
import com.opengamma.strata.market.curve.InterpolatedNodalCurve;
import com.opengamma.strata.market.curve.interpolator.CurveInterpolator;
import com.opengamma.strata.market.curve.interpolator.CurveInterpolators;
import com.opengamma.strata.market.param.CurrencyParameterSensitivities;
import com.opengamma.strata.market.sensitivity.PointSensitivities;
import com.opengamma.strata.pricer.DiscountFactors;
import com.opengamma.strata.pricer.DiscountingPaymentPricer;
import com.opengamma.strata.pricer.ZeroRateDiscountFactors;
import com.opengamma.strata.pricer.sensitivity.RatesFiniteDifferenceSensitivityCalculator;
import com.opengamma.strata.product.SecurityId;
import com.opengamma.strata.product.TradeInfo;
import com.opengamma.strata.product.bond.FixedCouponBond;
import com.opengamma.strata.product.bond.FixedCouponBondPaymentPeriod;
import com.opengamma.strata.product.bond.FixedCouponBondYieldConvention;
import com.opengamma.strata.product.bond.ResolvedFixedCouponBond;
import com.opengamma.strata.product.bond.ResolvedFixedCouponBondTrade;
/**
* Test {@link DiscountingFixedCouponBondTradePricer}.
*/
@Test
public class DiscountingFixedCouponBondTradePricerTest {
private static final ReferenceData REF_DATA = ReferenceData.standard();
// dates
private static final LocalDate SETTLEMENT = date(2016, 4, 29); // after coupon date
private static final LocalDate VAL_DATE = date(2016, 4, 25);
private static final LocalDate TRADE_BEFORE = date(2016, 3, 18);
private static final LocalDate SETTLE_BEFORE = date(2016, 3, 22); // before coupon date
private static final LocalDate TRADE_ON_COUPON = date(2016, 4, 8);
private static final LocalDate SETTLE_ON_COUPON = date(2016, 4, 12); // coupon date
private static final LocalDate TRADE_BTWN_DETACHMENT_COUPON = date(2016, 4, 5);
private static final LocalDate SETTLE_BTWN_DETACHMENT_COUPON = date(2016, 4, 8); // between detachment date and coupon date
private static final LocalDate TRADE_ON_DETACHMENT = date(2016, 4, 4);
private static final LocalDate SETTLE_ON_DETACHMENT = date(2016, 4, 7); // detachment date
// pricers
private static final double TOL = 1.0e-12;
private static final double EPS = 1.0e-6;
private static final DiscountingFixedCouponBondTradePricer TRADE_PRICER = DiscountingFixedCouponBondTradePricer.DEFAULT;
// when refactoring, existing tests needed a pricer that has zero upfront payment,
// and where the settlement date is artificially set to always be SETTLEMENT
private static final DiscountingFixedCouponBondTradePricer TRADE_PRICER_NO_UPFRONT =
new DiscountingFixedCouponBondTradePricer(
DiscountingFixedCouponBondProductPricer.DEFAULT,
DiscountingPaymentPricer.DEFAULT) {
@Override
public Payment upfrontPayment(ResolvedFixedCouponBondTrade trade) {
return Payment.of(CurrencyAmount.zero(trade.getProduct().getCurrency()), SETTLEMENT);
}
};
private static final DiscountingFixedCouponBondProductPricer PRODUCT_PRICER =
DiscountingFixedCouponBondProductPricer.DEFAULT;
private static final DiscountingPaymentPricer PRICER_NOMINAL = DiscountingPaymentPricer.DEFAULT;
private static final DiscountingFixedCouponBondPaymentPeriodPricer COUPON_PRICER =
DiscountingFixedCouponBondPaymentPeriodPricer.DEFAULT;
private static final RatesFiniteDifferenceSensitivityCalculator FD_CAL = new RatesFiniteDifferenceSensitivityCalculator(EPS);
// fixed coupon bond
private static final StandardId SECURITY_ID = StandardId.of("OG-Ticker", "GOVT1-BOND1");
private static final StandardId ISSUER_ID = StandardId.of("OG-Ticker", "GOVT1");
private static final TradeInfo TRADE_INFO = TradeInfo.builder()
.tradeDate(VAL_DATE)
.settlementDate(SETTLEMENT)
.build();
private static final TradeInfo TRADE_INFO_BEFORE = TradeInfo.builder()
.tradeDate(TRADE_BEFORE)
.settlementDate(SETTLE_BEFORE)
.build();
private static final TradeInfo TRADE_INFO_ON_COUPON = TradeInfo.builder()
.tradeDate(TRADE_ON_COUPON)
.settlementDate(SETTLE_ON_COUPON)
.build();
private static final TradeInfo TRADE_INFO_BTWN_DETACHMENT_COUPON = TradeInfo.builder()
.tradeDate(TRADE_BTWN_DETACHMENT_COUPON)
.settlementDate(SETTLE_BTWN_DETACHMENT_COUPON)
.build();
private static final TradeInfo TRADE_INFO_ON_DETACHMENT = TradeInfo.builder()
.tradeDate(TRADE_ON_DETACHMENT)
.settlementDate(SETTLE_ON_DETACHMENT)
.build();
private static final long QUANTITY = 15L;
private static final FixedCouponBondYieldConvention YIELD_CONVENTION = FixedCouponBondYieldConvention.DE_BONDS;
private static final double NOTIONAL = 1.0e7;
private static final double FIXED_RATE = 0.015;
private static final HolidayCalendarId EUR_CALENDAR = HolidayCalendarIds.EUTA;
private static final DaysAdjustment DATE_OFFSET = DaysAdjustment.ofBusinessDays(3, EUR_CALENDAR);
private static final DayCount DAY_COUNT = DayCounts.ACT_365F;
private static final LocalDate START_DATE = LocalDate.of(2015, 4, 12);
private static final LocalDate END_DATE = LocalDate.of(2025, 4, 12);
private static final BusinessDayAdjustment BUSINESS_ADJUST =
BusinessDayAdjustment.of(BusinessDayConventions.MODIFIED_FOLLOWING, EUR_CALENDAR);
private static final PeriodicSchedule PERIOD_SCHEDULE = PeriodicSchedule.of(
START_DATE, END_DATE, Frequency.P6M, BUSINESS_ADJUST, StubConvention.SHORT_INITIAL, false);
private static final DaysAdjustment EX_COUPON = DaysAdjustment.ofCalendarDays(-5, BUSINESS_ADJUST);
private static final ResolvedFixedCouponBond PRODUCT = FixedCouponBond.builder()
.securityId(SecurityId.of(SECURITY_ID))
.dayCount(DAY_COUNT)
.fixedRate(FIXED_RATE)
.legalEntityId(ISSUER_ID)
.currency(EUR)
.notional(NOTIONAL)
.accrualSchedule(PERIOD_SCHEDULE)
.settlementDateOffset(DATE_OFFSET)
.yieldConvention(YIELD_CONVENTION)
.exCouponPeriod(EX_COUPON)
.build()
.resolve(REF_DATA);
private static final double CLEAN_PRICE = 0.98;
private static final double DIRTY_PRICE = PRODUCT_PRICER.dirtyPriceFromCleanPrice(PRODUCT, SETTLEMENT, CLEAN_PRICE);
private static final Payment UPFRONT_PAYMENT = Payment.of(
CurrencyAmount.of(EUR, -QUANTITY * NOTIONAL * DIRTY_PRICE), SETTLEMENT);
/** nonzero ex-coupon period */
private static final ResolvedFixedCouponBondTrade TRADE = ResolvedFixedCouponBondTrade.builder()
.info(TRADE_INFO)
.product(PRODUCT)
.quantity(QUANTITY)
.price(CLEAN_PRICE)
.build();
private static final ResolvedFixedCouponBond PRODUCT_NO_EXCOUPON = FixedCouponBond.builder()
.securityId(SecurityId.of(SECURITY_ID))
.dayCount(DAY_COUNT)
.fixedRate(FIXED_RATE)
.legalEntityId(ISSUER_ID)
.currency(EUR)
.notional(NOTIONAL)
.accrualSchedule(PERIOD_SCHEDULE)
.settlementDateOffset(DATE_OFFSET)
.yieldConvention(YIELD_CONVENTION)
.build()
.resolve(REF_DATA);
/** no ex-coupon period */
private static final ResolvedFixedCouponBondTrade TRADE_NO_EXCOUPON = ResolvedFixedCouponBondTrade.builder()
.info(TRADE_INFO)
.product(PRODUCT_NO_EXCOUPON)
.quantity(QUANTITY)
.price(CLEAN_PRICE)
.build();
// rates provider
private static final CurveInterpolator INTERPOLATOR = CurveInterpolators.LINEAR;
private static final CurveName NAME_REPO = CurveName.of("TestRepoCurve");
private static final CurveMetadata METADATA_REPO = Curves.zeroRates(NAME_REPO, ACT_365F);
private static final InterpolatedNodalCurve CURVE_REPO = InterpolatedNodalCurve.of(
METADATA_REPO, DoubleArray.of(0.1, 2.0, 10.0), DoubleArray.of(0.05, 0.06, 0.09), INTERPOLATOR);
private static final RepoGroup GROUP_REPO = RepoGroup.of("GOVT1 BOND1");
private static final CurveName NAME_ISSUER = CurveName.of("TestIssuerCurve");
private static final CurveMetadata METADATA_ISSUER = Curves.zeroRates(NAME_ISSUER, ACT_365F);
private static final InterpolatedNodalCurve CURVE_ISSUER = InterpolatedNodalCurve.of(
METADATA_ISSUER, DoubleArray.of(0.2, 9.0, 15.0), DoubleArray.of(0.03, 0.05, 0.13), INTERPOLATOR);
private static final LegalEntityGroup GROUP_ISSUER = LegalEntityGroup.of("GOVT1");
private static final LegalEntityDiscountingProvider PROVIDER = createRatesProvider(VAL_DATE);
private static final LegalEntityDiscountingProvider PROVIDER_BEFORE = createRatesProvider(TRADE_BEFORE);
private static final double Z_SPREAD = 0.035;
private static final int PERIOD_PER_YEAR = 4;
//-------------------------------------------------------------------------
public void test_presentValue() {
CurrencyAmount computedTrade = TRADE_PRICER.presentValue(TRADE, PROVIDER);
CurrencyAmount computedProduct = PRODUCT_PRICER.presentValue(PRODUCT, PROVIDER, SETTLEMENT);
CurrencyAmount pvPayment =
PRICER_NOMINAL.presentValue(UPFRONT_PAYMENT, ZeroRateDiscountFactors.of(EUR, VAL_DATE, CURVE_REPO));
assertEquals(computedTrade.getAmount(),
computedProduct.multipliedBy(QUANTITY).plus(pvPayment).getAmount(), NOTIONAL * QUANTITY * TOL);
}
public void test_presentValueWithZSpread_continuous() {
CurrencyAmount computedTrade = TRADE_PRICER.presentValueWithZSpread(
TRADE, PROVIDER, Z_SPREAD, CONTINUOUS, 0);
CurrencyAmount computedProduct =
PRODUCT_PRICER.presentValueWithZSpread(PRODUCT, PROVIDER, Z_SPREAD, CONTINUOUS, 0, SETTLEMENT);
CurrencyAmount pvPayment =
PRICER_NOMINAL.presentValue(UPFRONT_PAYMENT, ZeroRateDiscountFactors.of(EUR, VAL_DATE, CURVE_REPO));
assertEquals(computedTrade.getAmount(),
computedProduct.multipliedBy(QUANTITY).plus(pvPayment).getAmount(), NOTIONAL * QUANTITY * TOL);
}
public void test_presentValueWithZSpread_periodic() {
CurrencyAmount computedTrade =
TRADE_PRICER.presentValueWithZSpread(TRADE, PROVIDER, Z_SPREAD, PERIODIC, PERIOD_PER_YEAR);
CurrencyAmount computedProduct = PRODUCT_PRICER.presentValueWithZSpread(
PRODUCT, PROVIDER, Z_SPREAD, PERIODIC, PERIOD_PER_YEAR, SETTLEMENT);
CurrencyAmount pvPayment =
PRICER_NOMINAL.presentValue(UPFRONT_PAYMENT, ZeroRateDiscountFactors.of(EUR, VAL_DATE, CURVE_REPO));
assertEquals(computedTrade.getAmount(),
computedProduct.multipliedBy(QUANTITY).plus(pvPayment).getAmount(), NOTIONAL * QUANTITY * TOL);
}
public void test_presentValue_noExcoupon() {
CurrencyAmount computedTrade = TRADE_PRICER.presentValue(TRADE_NO_EXCOUPON, PROVIDER);
CurrencyAmount computedProduct = PRODUCT_PRICER.presentValue(PRODUCT_NO_EXCOUPON, PROVIDER, SETTLEMENT);
CurrencyAmount pvPayment =
PRICER_NOMINAL.presentValue(UPFRONT_PAYMENT, ZeroRateDiscountFactors.of(EUR, VAL_DATE, CURVE_REPO));
assertEquals(computedTrade.getAmount(),
computedProduct.multipliedBy(QUANTITY).plus(pvPayment).getAmount(), NOTIONAL * QUANTITY * TOL);
}
public void test_presentValueWithZSpread_continuous_noExcoupon() {
CurrencyAmount computedTrade =
TRADE_PRICER.presentValueWithZSpread(TRADE_NO_EXCOUPON, PROVIDER, Z_SPREAD, CONTINUOUS, 0);
CurrencyAmount computedProduct = PRODUCT_PRICER.presentValueWithZSpread(
PRODUCT_NO_EXCOUPON, PROVIDER, Z_SPREAD, CONTINUOUS, 0, SETTLEMENT);
CurrencyAmount pvPayment =
PRICER_NOMINAL.presentValue(UPFRONT_PAYMENT, ZeroRateDiscountFactors.of(EUR, VAL_DATE, CURVE_REPO));
assertEquals(computedTrade.getAmount(),
computedProduct.multipliedBy(QUANTITY).plus(pvPayment).getAmount(), NOTIONAL * QUANTITY * TOL);
}
public void test_presentValueWithZSpread_periodic_noExcoupon() {
CurrencyAmount computedTrade = TRADE_PRICER.presentValueWithZSpread(
TRADE_NO_EXCOUPON, PROVIDER, Z_SPREAD, PERIODIC, PERIOD_PER_YEAR);
CurrencyAmount computedProduct = PRODUCT_PRICER.presentValueWithZSpread(
PRODUCT_NO_EXCOUPON, PROVIDER, Z_SPREAD, PERIODIC, PERIOD_PER_YEAR, SETTLEMENT);
CurrencyAmount pvPayment =
PRICER_NOMINAL.presentValue(UPFRONT_PAYMENT, ZeroRateDiscountFactors.of(EUR, VAL_DATE, CURVE_REPO));
assertEquals(computedTrade.getAmount(),
computedProduct.multipliedBy(QUANTITY).plus(pvPayment).getAmount(), NOTIONAL * QUANTITY * TOL);
}
//-------------------------------------------------------------------------
public void test_presentValue_dateLogic() {
ResolvedFixedCouponBondTrade tradeAfter = ResolvedFixedCouponBondTrade.builder()
.info(TRADE_INFO)
.product(PRODUCT)
.quantity(QUANTITY)
.price(CLEAN_PRICE)
.build();
CurrencyAmount computedTradeAfter = TRADE_PRICER_NO_UPFRONT.presentValue(tradeAfter, PROVIDER_BEFORE);
// settle before detachment date
ResolvedFixedCouponBondTrade tradeBefore = ResolvedFixedCouponBondTrade.builder()
.info(TRADE_INFO_BEFORE)
.product(PRODUCT)
.quantity(QUANTITY)
.price(CLEAN_PRICE)
.build();
CurrencyAmount computedTradeBefore = TRADE_PRICER_NO_UPFRONT.presentValue(tradeBefore, PROVIDER_BEFORE);
FixedCouponBondPaymentPeriod periodExtra = findPeriod(PRODUCT, SETTLE_BEFORE, SETTLEMENT);
double pvExtra = COUPON_PRICER.presentValue(periodExtra, PROVIDER_BEFORE.issuerCurveDiscountFactors(ISSUER_ID, EUR));
assertEquals(computedTradeBefore.getAmount(), computedTradeAfter.plus(pvExtra * QUANTITY).getAmount(),
NOTIONAL * QUANTITY * TOL);
// settle on detachment date
ResolvedFixedCouponBondTrade tradeOnDetachment = ResolvedFixedCouponBondTrade.builder()
.info(TRADE_INFO_ON_DETACHMENT)
.product(PRODUCT)
.quantity(QUANTITY)
.price(CLEAN_PRICE)
.build();
CurrencyAmount computedTradeOnDetachment = TRADE_PRICER_NO_UPFRONT.presentValue(tradeOnDetachment, PROVIDER_BEFORE);
assertEquals(computedTradeOnDetachment.getAmount(), computedTradeAfter.getAmount(), NOTIONAL * QUANTITY * TOL);
// settle between detachment date and coupon date
ResolvedFixedCouponBondTrade tradeBtwnDetachmentCoupon = ResolvedFixedCouponBondTrade.builder()
.info(TRADE_INFO_BTWN_DETACHMENT_COUPON)
.product(PRODUCT)
.quantity(QUANTITY)
.price(CLEAN_PRICE)
.build();
CurrencyAmount computedTradeBtwnDetachmentCoupon =
TRADE_PRICER_NO_UPFRONT.presentValue(tradeBtwnDetachmentCoupon, PROVIDER_BEFORE);
assertEquals(computedTradeBtwnDetachmentCoupon.getAmount(), computedTradeAfter.getAmount(), NOTIONAL * QUANTITY * TOL);
}
public void test_presentValue_dateLogic_pastSettle() {
ResolvedFixedCouponBondTrade tradeAfter = ResolvedFixedCouponBondTrade.builder()
.info(TRADE_INFO)
.product(PRODUCT)
.quantity(QUANTITY)
.price(CLEAN_PRICE)
.build();
CurrencyAmount computedTradeAfter = TRADE_PRICER_NO_UPFRONT.presentValue(tradeAfter, PROVIDER);
// settle before detachment date
ResolvedFixedCouponBondTrade tradeBefore = ResolvedFixedCouponBondTrade.builder()
.info(TRADE_INFO_BEFORE)
.product(PRODUCT)
.quantity(QUANTITY)
.price(CLEAN_PRICE)
.build();
CurrencyAmount computedTradeBefore = TRADE_PRICER_NO_UPFRONT.presentValue(tradeBefore, PROVIDER);
assertEquals(computedTradeBefore.getAmount(), computedTradeAfter.getAmount(), NOTIONAL * QUANTITY * TOL);
// settle on detachment date
ResolvedFixedCouponBondTrade tradeOnDetachment = ResolvedFixedCouponBondTrade.builder()
.info(TRADE_INFO_ON_DETACHMENT)
.product(PRODUCT)
.quantity(QUANTITY)
.price(CLEAN_PRICE)
.build();
CurrencyAmount computedTradeOnDetachment = TRADE_PRICER_NO_UPFRONT.presentValue(tradeOnDetachment, PROVIDER);
assertEquals(computedTradeOnDetachment.getAmount(), computedTradeAfter.getAmount(), NOTIONAL * QUANTITY * TOL);
// settle between detachment date and coupon date
ResolvedFixedCouponBondTrade tradeBtwnDetachmentCoupon = ResolvedFixedCouponBondTrade.builder()
.info(TRADE_INFO_BTWN_DETACHMENT_COUPON)
.product(PRODUCT)
.quantity(QUANTITY)
.price(CLEAN_PRICE)
.build();
CurrencyAmount computedTradeBtwnDetachmentCoupon =
TRADE_PRICER_NO_UPFRONT.presentValue(tradeBtwnDetachmentCoupon, PROVIDER);
assertEquals(computedTradeBtwnDetachmentCoupon.getAmount(), computedTradeAfter.getAmount(), NOTIONAL * QUANTITY * TOL);
}
public void test_presentValue_dateLogic_noExcoupon() {
ResolvedFixedCouponBondTrade tradeAfter = ResolvedFixedCouponBondTrade.builder()
.info(TRADE_INFO)
.product(PRODUCT_NO_EXCOUPON)
.quantity(QUANTITY)
.price(CLEAN_PRICE)
.build();
CurrencyAmount computedTradeAfter = TRADE_PRICER_NO_UPFRONT.presentValue(tradeAfter, PROVIDER_BEFORE);
// settle before coupon date
ResolvedFixedCouponBondTrade tradeBefore = ResolvedFixedCouponBondTrade.builder()
.info(TRADE_INFO_BEFORE)
.product(PRODUCT_NO_EXCOUPON)
.quantity(QUANTITY)
.price(CLEAN_PRICE)
.build();
CurrencyAmount computedTradeBefore = TRADE_PRICER_NO_UPFRONT.presentValue(tradeBefore, PROVIDER_BEFORE);
FixedCouponBondPaymentPeriod periodExtra = findPeriod(PRODUCT_NO_EXCOUPON, SETTLE_BEFORE, SETTLEMENT);
double pvExtra = COUPON_PRICER.presentValue(periodExtra, PROVIDER_BEFORE.issuerCurveDiscountFactors(ISSUER_ID, EUR));
assertEquals(computedTradeBefore.getAmount(), computedTradeAfter.plus(pvExtra * QUANTITY).getAmount(),
NOTIONAL * QUANTITY * TOL);
// settle on coupon date
ResolvedFixedCouponBondTrade tradeOnCoupon = ResolvedFixedCouponBondTrade.builder()
.info(TRADE_INFO_ON_COUPON)
.product(PRODUCT_NO_EXCOUPON)
.quantity(QUANTITY)
.price(CLEAN_PRICE)
.build();
CurrencyAmount computedTradeOnCoupon = TRADE_PRICER_NO_UPFRONT.presentValue(tradeOnCoupon, PROVIDER_BEFORE);
assertEquals(computedTradeOnCoupon.getAmount(), computedTradeAfter.getAmount(), NOTIONAL * QUANTITY * TOL);
}
public void test_presentValue_dateLogic_pastSettle_noExcoupon() {
ResolvedFixedCouponBondTrade tradeAfter = ResolvedFixedCouponBondTrade.builder()
.info(TRADE_INFO)
.product(PRODUCT_NO_EXCOUPON)
.quantity(QUANTITY)
.price(CLEAN_PRICE)
.build();
CurrencyAmount computedTradeAfter = TRADE_PRICER_NO_UPFRONT.presentValue(tradeAfter, PROVIDER);
// settle before coupon date
ResolvedFixedCouponBondTrade tradeBefore = ResolvedFixedCouponBondTrade.builder()
.info(TRADE_INFO_BEFORE)
.product(PRODUCT_NO_EXCOUPON)
.quantity(QUANTITY)
.price(CLEAN_PRICE)
.build();
CurrencyAmount computedTradeBefore = TRADE_PRICER_NO_UPFRONT.presentValue(tradeBefore, PROVIDER);
assertEquals(computedTradeBefore.getAmount(), computedTradeAfter.getAmount(),
NOTIONAL * QUANTITY * TOL);
// settle on coupon date
ResolvedFixedCouponBondTrade tradeOnCoupon = ResolvedFixedCouponBondTrade.builder()
.info(TRADE_INFO_ON_COUPON)
.product(PRODUCT_NO_EXCOUPON)
.quantity(QUANTITY)
.price(CLEAN_PRICE)
.build();
CurrencyAmount computedTradeOnCoupon = TRADE_PRICER_NO_UPFRONT.presentValue(tradeOnCoupon, PROVIDER);
assertEquals(computedTradeOnCoupon.getAmount(), computedTradeAfter.getAmount(), NOTIONAL * QUANTITY * TOL);
}
//-------------------------------------------------------------------------
public void test_presentValueFromCleanPrice() {
double cleanPrice = 0.985;
CurrencyAmount computed = TRADE_PRICER.presentValueFromCleanPrice(TRADE, PROVIDER, REF_DATA, cleanPrice);
LocalDate standardSettlement = PRODUCT.getSettlementDateOffset().adjust(VAL_DATE, REF_DATA);
double df = ZeroRateDiscountFactors.of(EUR, VAL_DATE, CURVE_REPO).discountFactor(standardSettlement);
double accruedInterest = PRODUCT_PRICER.accruedInterest(PRODUCT, standardSettlement);
double pvPayment = PRICER_NOMINAL
.presentValue(UPFRONT_PAYMENT, ZeroRateDiscountFactors.of(EUR, VAL_DATE, CURVE_REPO)).getAmount();
double expected = QUANTITY * (cleanPrice * df * NOTIONAL + accruedInterest * df) + pvPayment;
assertEquals(computed.getCurrency(), EUR);
assertEquals(computed.getAmount(), expected, NOTIONAL * QUANTITY * TOL);
}
public void test_presentValueFromCleanPriceWithZSpread_continuous() {
double cleanPrice = 0.985;
CurrencyAmount computed = TRADE_PRICER.presentValueFromCleanPriceWithZSpread(
TRADE, PROVIDER, REF_DATA, cleanPrice, Z_SPREAD, CONTINUOUS, 0);
LocalDate standardSettlement = PRODUCT.getSettlementDateOffset().adjust(VAL_DATE, REF_DATA);
double df = ZeroRateDiscountFactors.of(EUR, VAL_DATE, CURVE_REPO).discountFactor(standardSettlement);
double accruedInterest = PRODUCT_PRICER.accruedInterest(PRODUCT, standardSettlement);
double pvPayment = PRICER_NOMINAL
.presentValue(UPFRONT_PAYMENT, ZeroRateDiscountFactors.of(EUR, VAL_DATE, CURVE_REPO)).getAmount();
double expected = QUANTITY * (cleanPrice * df * NOTIONAL + accruedInterest * df) + pvPayment;
assertEquals(computed.getCurrency(), EUR);
assertEquals(computed.getAmount(), expected, NOTIONAL * QUANTITY * TOL);
}
public void test_presentValueFromCleanPriceWithZSpread_periodic() {
double cleanPrice = 0.985;
CurrencyAmount computed = TRADE_PRICER.presentValueFromCleanPriceWithZSpread(
TRADE, PROVIDER, REF_DATA, cleanPrice, Z_SPREAD, PERIODIC, PERIOD_PER_YEAR);
LocalDate standardSettlement = PRODUCT.getSettlementDateOffset().adjust(VAL_DATE, REF_DATA);
double df = ZeroRateDiscountFactors.of(EUR, VAL_DATE, CURVE_REPO).discountFactor(standardSettlement);
double accruedInterest = PRODUCT_PRICER.accruedInterest(PRODUCT, standardSettlement);
double pvPayment = PRICER_NOMINAL
.presentValue(UPFRONT_PAYMENT, ZeroRateDiscountFactors.of(EUR, VAL_DATE, CURVE_REPO)).getAmount();
double expected = QUANTITY * (cleanPrice * df * NOTIONAL + accruedInterest * df) + pvPayment;
assertEquals(computed.getCurrency(), EUR);
assertEquals(computed.getAmount(), expected, NOTIONAL * QUANTITY * TOL);
}
public void test_presentValueFromCleanPrice_noExcoupon() {
double cleanPrice = 0.985;
CurrencyAmount computed = TRADE_PRICER.presentValueFromCleanPrice(TRADE_NO_EXCOUPON, PROVIDER, REF_DATA, cleanPrice);
LocalDate standardSettlement = PRODUCT_NO_EXCOUPON.getSettlementDateOffset().adjust(VAL_DATE, REF_DATA);
double df = ZeroRateDiscountFactors.of(EUR, VAL_DATE, CURVE_REPO).discountFactor(standardSettlement);
double accruedInterest = PRODUCT_PRICER.accruedInterest(PRODUCT_NO_EXCOUPON, standardSettlement);
double pvPayment = PRICER_NOMINAL
.presentValue(UPFRONT_PAYMENT, ZeroRateDiscountFactors.of(EUR, VAL_DATE, CURVE_REPO)).getAmount();
double expected = QUANTITY * (cleanPrice * df * NOTIONAL + accruedInterest * df) + pvPayment;
assertEquals(computed.getCurrency(), EUR);
assertEquals(computed.getAmount(), expected, NOTIONAL * QUANTITY * TOL);
}
public void test_presentValueFromCleanPriceWithZSpread_continuous_noExcoupon() {
double cleanPrice = 0.985;
CurrencyAmount computed = TRADE_PRICER.presentValueFromCleanPriceWithZSpread(
TRADE_NO_EXCOUPON, PROVIDER, REF_DATA, cleanPrice, Z_SPREAD, CONTINUOUS, 0);
LocalDate standardSettlement = PRODUCT_NO_EXCOUPON.getSettlementDateOffset().adjust(VAL_DATE, REF_DATA);
double df = ZeroRateDiscountFactors.of(EUR, VAL_DATE, CURVE_REPO).discountFactor(standardSettlement);
double accruedInterest = PRODUCT_PRICER.accruedInterest(PRODUCT_NO_EXCOUPON, standardSettlement);
double pvPayment = PRICER_NOMINAL
.presentValue(UPFRONT_PAYMENT, ZeroRateDiscountFactors.of(EUR, VAL_DATE, CURVE_REPO)).getAmount();
double expected = QUANTITY * (cleanPrice * df * NOTIONAL + accruedInterest * df) + pvPayment;
assertEquals(computed.getCurrency(), EUR);
assertEquals(computed.getAmount(), expected, NOTIONAL * QUANTITY * TOL);
}
public void test_presentValueFromCleanPriceWithZSpread_periodic_noExcoupon() {
double cleanPrice = 0.985;
CurrencyAmount computed = TRADE_PRICER.presentValueFromCleanPriceWithZSpread(
TRADE_NO_EXCOUPON, PROVIDER, REF_DATA, cleanPrice, Z_SPREAD, PERIODIC, PERIOD_PER_YEAR);
LocalDate standardSettlement = PRODUCT_NO_EXCOUPON.getSettlementDateOffset().adjust(VAL_DATE, REF_DATA);
double df = ZeroRateDiscountFactors.of(EUR, VAL_DATE, CURVE_REPO).discountFactor(standardSettlement);
double accruedInterest = PRODUCT_PRICER.accruedInterest(PRODUCT_NO_EXCOUPON, standardSettlement);
double pvPayment = PRICER_NOMINAL
.presentValue(UPFRONT_PAYMENT, ZeroRateDiscountFactors.of(EUR, VAL_DATE, CURVE_REPO)).getAmount();
double expected = QUANTITY * (cleanPrice * df * NOTIONAL + accruedInterest * df) + pvPayment;
assertEquals(computed.getCurrency(), EUR);
assertEquals(computed.getAmount(), expected, NOTIONAL * QUANTITY * TOL);
}
//-------------------------------------------------------------------------
public void test_presentValueFromCleanPrice_dateLogic() {
double cleanPrice = 0.985;
FixedCouponBondPaymentPeriod periodExtra = findPeriod(PRODUCT, SETTLE_BEFORE, SETTLEMENT);
// trade settlement < detachment date < standard settlement
LocalDate valuation1 = SETTLE_ON_DETACHMENT.minusDays(1);
TradeInfo tradeInfo1 = TradeInfo.builder()
.tradeDate(valuation1)
.settlementDate(valuation1)
.build();
ResolvedFixedCouponBondTrade trade1 = ResolvedFixedCouponBondTrade.builder()
.info(tradeInfo1)
.product(PRODUCT)
.quantity(QUANTITY)
.price(CLEAN_PRICE)
.build();
LegalEntityDiscountingProvider provider1 = createRatesProvider(valuation1);
LocalDate standardSettlement1 = PRODUCT.getSettlementDateOffset().adjust(valuation1, REF_DATA);
double df1 = ZeroRateDiscountFactors.of(EUR, valuation1, CURVE_REPO).discountFactor(standardSettlement1);
double accruedInterest1 = PRODUCT_PRICER.accruedInterest(PRODUCT, standardSettlement1);
double basePv1 = cleanPrice * df1 * NOTIONAL + accruedInterest1 * df1;
double pvExtra1 = COUPON_PRICER.presentValue(periodExtra, provider1.issuerCurveDiscountFactors(ISSUER_ID, EUR));
double pvExtra1Continuous = COUPON_PRICER.presentValueWithSpread(
periodExtra, provider1.issuerCurveDiscountFactors(ISSUER_ID, EUR), Z_SPREAD, CONTINUOUS, 0);
double pvExtra1Periodic = COUPON_PRICER.presentValueWithSpread(
periodExtra, provider1.issuerCurveDiscountFactors(ISSUER_ID, EUR), Z_SPREAD, PERIODIC, PERIOD_PER_YEAR);
CurrencyAmount computed1 = TRADE_PRICER_NO_UPFRONT.presentValueFromCleanPrice(trade1, provider1, REF_DATA, cleanPrice);
CurrencyAmount computed1Continuous = TRADE_PRICER_NO_UPFRONT.presentValueFromCleanPriceWithZSpread(
trade1, provider1, REF_DATA, cleanPrice, Z_SPREAD, CONTINUOUS, 0);
CurrencyAmount computed1Periodic = TRADE_PRICER_NO_UPFRONT.presentValueFromCleanPriceWithZSpread(
trade1, provider1, REF_DATA, cleanPrice, Z_SPREAD, PERIODIC, PERIOD_PER_YEAR);
assertEquals(computed1.getAmount(), QUANTITY * (basePv1 + pvExtra1), NOTIONAL * QUANTITY * TOL);
assertEquals(computed1Continuous.getAmount(), QUANTITY * (basePv1 + pvExtra1Continuous), NOTIONAL * QUANTITY * TOL);
assertEquals(computed1Periodic.getAmount(), QUANTITY * (basePv1 + pvExtra1Periodic), NOTIONAL * QUANTITY * TOL);
// detachment date < trade settlement < standard settlement
TradeInfo tradeInfo2 = TradeInfo.builder()
.tradeDate(valuation1)
.settlementDate(SETTLE_ON_DETACHMENT.plusDays(2))
.build();
ResolvedFixedCouponBondTrade trade2 = ResolvedFixedCouponBondTrade.builder()
.info(tradeInfo2)
.product(PRODUCT)
.quantity(QUANTITY)
.price(CLEAN_PRICE)
.build();
CurrencyAmount computed2 = TRADE_PRICER_NO_UPFRONT.presentValueFromCleanPrice(trade2, provider1, REF_DATA, cleanPrice);
CurrencyAmount computed2Continuous = TRADE_PRICER_NO_UPFRONT.presentValueFromCleanPriceWithZSpread(
trade2, provider1, REF_DATA, cleanPrice, Z_SPREAD, CONTINUOUS, 0);
CurrencyAmount computed2Periodic = TRADE_PRICER_NO_UPFRONT.presentValueFromCleanPriceWithZSpread(
trade2, provider1, REF_DATA, cleanPrice, Z_SPREAD, PERIODIC, PERIOD_PER_YEAR);
assertEquals(computed2.getAmount(), QUANTITY * basePv1, NOTIONAL * QUANTITY * TOL);
assertEquals(computed2Continuous.getAmount(), QUANTITY * basePv1, NOTIONAL * QUANTITY * TOL);
assertEquals(computed2Periodic.getAmount(), QUANTITY * basePv1, NOTIONAL * QUANTITY * TOL);
// detachment date < standard settlement < trade sinfo
TradeInfo tradeInfo3 = TradeInfo.builder()
.tradeDate(valuation1)
.settlementDate(SETTLE_ON_DETACHMENT.plusDays(7))
.build();
ResolvedFixedCouponBondTrade trade3 = ResolvedFixedCouponBondTrade.builder()
.info(tradeInfo3)
.product(PRODUCT)
.quantity(QUANTITY)
.price(CLEAN_PRICE)
.build();
CurrencyAmount computed3 = TRADE_PRICER_NO_UPFRONT.presentValueFromCleanPrice(trade3, provider1, REF_DATA, cleanPrice);
CurrencyAmount computed3Continuous = TRADE_PRICER_NO_UPFRONT.presentValueFromCleanPriceWithZSpread(
trade3, provider1, REF_DATA, cleanPrice, Z_SPREAD, CONTINUOUS, 0);
CurrencyAmount computed3Periodic = TRADE_PRICER_NO_UPFRONT.presentValueFromCleanPriceWithZSpread(
trade3, provider1, REF_DATA, cleanPrice, Z_SPREAD, PERIODIC, PERIOD_PER_YEAR);
assertEquals(computed3.getAmount(), QUANTITY * basePv1, NOTIONAL * QUANTITY * TOL);
assertEquals(computed3Continuous.getAmount(), QUANTITY * basePv1, NOTIONAL * QUANTITY * TOL);
assertEquals(computed3Periodic.getAmount(), QUANTITY * basePv1, NOTIONAL * QUANTITY * TOL);
// standard settlement < detachment date < trade settlement
LocalDate settlement4 = SETTLE_ON_DETACHMENT.plusDays(1);
TradeInfo tradeInfo4 = TradeInfo.builder()
.tradeDate(TRADE_BEFORE)
.settlementDate(settlement4)
.build();
ResolvedFixedCouponBondTrade trade4 = ResolvedFixedCouponBondTrade.builder()
.info(tradeInfo4)
.product(PRODUCT)
.quantity(QUANTITY)
.price(CLEAN_PRICE)
.build();
LocalDate standardSettlement4 = PRODUCT.getSettlementDateOffset().adjust(TRADE_BEFORE, REF_DATA);
double df4 = ZeroRateDiscountFactors.of(EUR, TRADE_BEFORE, CURVE_REPO).discountFactor(standardSettlement4);
double accruedInterest4 = PRODUCT_PRICER.accruedInterest(PRODUCT, standardSettlement4);
double basePv4 = cleanPrice * df4 * NOTIONAL + accruedInterest4 * df4;
double pvExtra4 = COUPON_PRICER.presentValue(periodExtra, PROVIDER_BEFORE.issuerCurveDiscountFactors(ISSUER_ID, EUR));
double pvExtra4Continuous = COUPON_PRICER.presentValueWithSpread(
periodExtra, PROVIDER_BEFORE.issuerCurveDiscountFactors(ISSUER_ID, EUR), Z_SPREAD, CONTINUOUS, 0);
double pvExtra4Periodic = COUPON_PRICER.presentValueWithSpread(periodExtra,
PROVIDER_BEFORE.issuerCurveDiscountFactors(ISSUER_ID, EUR), Z_SPREAD, PERIODIC, PERIOD_PER_YEAR);
CurrencyAmount computed4 = TRADE_PRICER_NO_UPFRONT.presentValueFromCleanPrice(trade4, PROVIDER_BEFORE, REF_DATA, cleanPrice);
CurrencyAmount computed4Continuous = TRADE_PRICER_NO_UPFRONT.presentValueFromCleanPriceWithZSpread(
trade4, PROVIDER_BEFORE, REF_DATA, cleanPrice, Z_SPREAD, CONTINUOUS, 0);
CurrencyAmount computed4Periodic = TRADE_PRICER_NO_UPFRONT.presentValueFromCleanPriceWithZSpread(
trade4, PROVIDER_BEFORE, REF_DATA, cleanPrice, Z_SPREAD, PERIODIC, PERIOD_PER_YEAR);
assertEquals(computed4.getAmount(), QUANTITY * (basePv4 - pvExtra4), NOTIONAL * QUANTITY * TOL);
assertEquals(computed4Continuous.getAmount(), QUANTITY * (basePv4 - pvExtra4Continuous), NOTIONAL * QUANTITY * TOL);
assertEquals(computed4Periodic.getAmount(), QUANTITY * (basePv4 - pvExtra4Periodic), NOTIONAL * QUANTITY * TOL);
// standard settlement < trade settlement < detachment date
TradeInfo tradeInfo5 = TradeInfo.builder()
.tradeDate(TRADE_BEFORE)
.settlementDate(TRADE_BEFORE.plusDays(7))
.build();
ResolvedFixedCouponBondTrade trade5 = ResolvedFixedCouponBondTrade.builder()
.info(tradeInfo5)
.product(PRODUCT)
.quantity(QUANTITY)
.price(CLEAN_PRICE)
.build();
CurrencyAmount computed5 = TRADE_PRICER_NO_UPFRONT.presentValueFromCleanPrice(trade5, PROVIDER_BEFORE, REF_DATA, cleanPrice);
CurrencyAmount computed5Continuous = TRADE_PRICER_NO_UPFRONT.presentValueFromCleanPriceWithZSpread(
trade5, PROVIDER_BEFORE, REF_DATA, cleanPrice, Z_SPREAD, CONTINUOUS, 0);
CurrencyAmount computed5Periodic = TRADE_PRICER_NO_UPFRONT.presentValueFromCleanPriceWithZSpread(
trade5, PROVIDER_BEFORE, REF_DATA, cleanPrice, Z_SPREAD, PERIODIC, PERIOD_PER_YEAR);
assertEquals(computed5.getAmount(), QUANTITY * basePv4, NOTIONAL * QUANTITY * TOL);
assertEquals(computed5Continuous.getAmount(), QUANTITY * basePv4, NOTIONAL * QUANTITY * TOL);
assertEquals(computed5Periodic.getAmount(), QUANTITY * basePv4, NOTIONAL * QUANTITY * TOL);
// trade settlement < standard settlement < detachment date
ResolvedFixedCouponBondTrade trade6 = ResolvedFixedCouponBondTrade.builder()
.info(TRADE_INFO_BEFORE)
.product(PRODUCT)
.quantity(QUANTITY)
.price(CLEAN_PRICE)
.build();
CurrencyAmount computed6 = TRADE_PRICER_NO_UPFRONT.presentValueFromCleanPrice(trade6, PROVIDER_BEFORE, REF_DATA, cleanPrice);
CurrencyAmount computed6Continuous = TRADE_PRICER_NO_UPFRONT.presentValueFromCleanPriceWithZSpread(
trade6, PROVIDER_BEFORE, REF_DATA, cleanPrice, Z_SPREAD, CONTINUOUS, 0);
CurrencyAmount computed6Periodic = TRADE_PRICER_NO_UPFRONT.presentValueFromCleanPriceWithZSpread(
trade6, PROVIDER_BEFORE, REF_DATA, cleanPrice, Z_SPREAD, PERIODIC, PERIOD_PER_YEAR);
assertEquals(computed6.getAmount(), QUANTITY * basePv4, NOTIONAL * QUANTITY * TOL);
assertEquals(computed6Continuous.getAmount(), QUANTITY * basePv4, NOTIONAL * QUANTITY * TOL);
assertEquals(computed6Periodic.getAmount(), QUANTITY * basePv4, NOTIONAL * QUANTITY * TOL);
}
public void test_presentValueFromCleanPrice_dateLogic_noExcoupon() {
double cleanPrice = 0.985;
FixedCouponBondPaymentPeriod periodExtra = findPeriod(PRODUCT_NO_EXCOUPON, SETTLE_BEFORE, SETTLEMENT);
// trade settlement < coupon date < standard settlement
LocalDate valuation1 = SETTLE_ON_COUPON.minusDays(1);
TradeInfo tradeInfo1 = TradeInfo.builder()
.tradeDate(valuation1)
.settlementDate(valuation1)
.build();
ResolvedFixedCouponBondTrade trade1 = ResolvedFixedCouponBondTrade.builder()
.info(tradeInfo1)
.product(PRODUCT_NO_EXCOUPON)
.quantity(QUANTITY)
.price(CLEAN_PRICE)
.build();
LegalEntityDiscountingProvider provider1 = createRatesProvider(valuation1);
LocalDate standardSettlement1 = PRODUCT_NO_EXCOUPON.getSettlementDateOffset().adjust(valuation1, REF_DATA);
double df1 = ZeroRateDiscountFactors.of(EUR, valuation1, CURVE_REPO).discountFactor(standardSettlement1);
double accruedInterest1 = PRODUCT_PRICER.accruedInterest(PRODUCT_NO_EXCOUPON, standardSettlement1);
double basePv1 = cleanPrice * df1 * NOTIONAL + accruedInterest1 * df1;
double pvExtra1 = COUPON_PRICER.presentValue(periodExtra, provider1.issuerCurveDiscountFactors(ISSUER_ID, EUR));
double pvExtra1Continuous = COUPON_PRICER.presentValueWithSpread(
periodExtra, provider1.issuerCurveDiscountFactors(ISSUER_ID, EUR), Z_SPREAD, CONTINUOUS, 0);
double pvExtra1Periodic = COUPON_PRICER.presentValueWithSpread(
periodExtra, provider1.issuerCurveDiscountFactors(ISSUER_ID, EUR), Z_SPREAD, PERIODIC, PERIOD_PER_YEAR);
CurrencyAmount computed1 = TRADE_PRICER_NO_UPFRONT.presentValueFromCleanPrice(trade1, provider1, REF_DATA, cleanPrice);
CurrencyAmount computed1Continuous = TRADE_PRICER_NO_UPFRONT.presentValueFromCleanPriceWithZSpread(
trade1, provider1, REF_DATA, cleanPrice, Z_SPREAD, CONTINUOUS, 0);
CurrencyAmount computed1Periodic = TRADE_PRICER_NO_UPFRONT.presentValueFromCleanPriceWithZSpread(
trade1, provider1, REF_DATA, cleanPrice, Z_SPREAD, PERIODIC, PERIOD_PER_YEAR);
assertEquals(computed1.getAmount(), QUANTITY * (basePv1 + pvExtra1), NOTIONAL * QUANTITY * TOL);
assertEquals(computed1Continuous.getAmount(), QUANTITY * (basePv1 + pvExtra1Continuous), NOTIONAL * QUANTITY * TOL);
assertEquals(computed1Periodic.getAmount(), QUANTITY * (basePv1 + pvExtra1Periodic), NOTIONAL * QUANTITY * TOL);
// coupon date < trade settlement < standard settlement
TradeInfo tradeInfo2 = TradeInfo.builder()
.tradeDate(valuation1)
.settlementDate(SETTLE_ON_COUPON.plusDays(2))
.build();
ResolvedFixedCouponBondTrade trade2 = ResolvedFixedCouponBondTrade.builder()
.info(tradeInfo2)
.product(PRODUCT_NO_EXCOUPON)
.quantity(QUANTITY)
.price(CLEAN_PRICE)
.build();
CurrencyAmount computed2 = TRADE_PRICER_NO_UPFRONT.presentValueFromCleanPrice(trade2, provider1, REF_DATA, cleanPrice);
CurrencyAmount computed2Continuous = TRADE_PRICER_NO_UPFRONT.presentValueFromCleanPriceWithZSpread(
trade2, provider1, REF_DATA, cleanPrice, Z_SPREAD, CONTINUOUS, 0);
CurrencyAmount computed2Periodic = TRADE_PRICER_NO_UPFRONT.presentValueFromCleanPriceWithZSpread(
trade2, provider1, REF_DATA, cleanPrice, Z_SPREAD, PERIODIC, PERIOD_PER_YEAR);
assertEquals(computed2.getAmount(), QUANTITY * basePv1, NOTIONAL * QUANTITY * TOL);
assertEquals(computed2Continuous.getAmount(), QUANTITY * basePv1, NOTIONAL * QUANTITY * TOL);
assertEquals(computed2Periodic.getAmount(), QUANTITY * basePv1, NOTIONAL * QUANTITY * TOL);
// coupon date < standard settlement < trade settlement
TradeInfo tradeInfo3 = TradeInfo.builder()
.tradeDate(valuation1)
.settlementDate(SETTLE_ON_COUPON.plusDays(7))
.build();
ResolvedFixedCouponBondTrade trade3 = ResolvedFixedCouponBondTrade.builder()
.info(tradeInfo3)
.product(PRODUCT_NO_EXCOUPON)
.quantity(QUANTITY)
.price(CLEAN_PRICE)
.build();
CurrencyAmount computed3 = TRADE_PRICER_NO_UPFRONT.presentValueFromCleanPrice(trade3, provider1, REF_DATA, cleanPrice);
CurrencyAmount computed3Continuous = TRADE_PRICER_NO_UPFRONT.presentValueFromCleanPriceWithZSpread(
trade3, provider1, REF_DATA, cleanPrice, Z_SPREAD, CONTINUOUS, 0);
CurrencyAmount computed3Periodic = TRADE_PRICER_NO_UPFRONT.presentValueFromCleanPriceWithZSpread(
trade3, provider1, REF_DATA, cleanPrice, Z_SPREAD, PERIODIC, PERIOD_PER_YEAR);
assertEquals(computed3.getAmount(), QUANTITY * basePv1, NOTIONAL * QUANTITY * TOL);
assertEquals(computed3Continuous.getAmount(), QUANTITY * basePv1, NOTIONAL * QUANTITY * TOL);
assertEquals(computed3Periodic.getAmount(), QUANTITY * basePv1, NOTIONAL * QUANTITY * TOL);
// standard settlement < coupon date < trade settlement
LocalDate settlement4 = SETTLE_ON_COUPON.plusDays(1);
TradeInfo tradeInfo4 = TradeInfo.builder()
.tradeDate(TRADE_BEFORE)
.settlementDate(settlement4)
.build();
ResolvedFixedCouponBondTrade trade4 = ResolvedFixedCouponBondTrade.builder()
.info(tradeInfo4)
.product(PRODUCT_NO_EXCOUPON)
.quantity(QUANTITY)
.price(CLEAN_PRICE)
.build();
LocalDate standardSettlement4 = PRODUCT_NO_EXCOUPON.getSettlementDateOffset().adjust(TRADE_BEFORE, REF_DATA);
double df4 = ZeroRateDiscountFactors.of(EUR, TRADE_BEFORE, CURVE_REPO).discountFactor(standardSettlement4);
double accruedInterest4 = PRODUCT_PRICER.accruedInterest(PRODUCT_NO_EXCOUPON, standardSettlement4);
double basePv4 = cleanPrice * df4 * NOTIONAL + accruedInterest4 * df4;
double pvExtra4 = COUPON_PRICER.presentValue(periodExtra,
PROVIDER_BEFORE.issuerCurveDiscountFactors(ISSUER_ID, EUR));
double pvExtra4Continuous = COUPON_PRICER.presentValueWithSpread(periodExtra,
PROVIDER_BEFORE.issuerCurveDiscountFactors(ISSUER_ID, EUR), Z_SPREAD, CONTINUOUS, 0);
double pvExtra4Periodic = COUPON_PRICER.presentValueWithSpread(periodExtra,
PROVIDER_BEFORE.issuerCurveDiscountFactors(ISSUER_ID, EUR), Z_SPREAD, PERIODIC, PERIOD_PER_YEAR);
CurrencyAmount computed4 = TRADE_PRICER_NO_UPFRONT.presentValueFromCleanPrice(trade4, PROVIDER_BEFORE, REF_DATA, cleanPrice);
CurrencyAmount computed4Continuous = TRADE_PRICER_NO_UPFRONT.presentValueFromCleanPriceWithZSpread(
trade4, PROVIDER_BEFORE, REF_DATA, cleanPrice, Z_SPREAD, CONTINUOUS, 0);
CurrencyAmount computed4Periodic = TRADE_PRICER_NO_UPFRONT.presentValueFromCleanPriceWithZSpread(
trade4, PROVIDER_BEFORE, REF_DATA, cleanPrice, Z_SPREAD, PERIODIC, PERIOD_PER_YEAR);
assertEquals(computed4.getAmount(), QUANTITY * (basePv4 - pvExtra4), NOTIONAL * QUANTITY * TOL);
assertEquals(computed4Continuous.getAmount(), QUANTITY * (basePv4 - pvExtra4Continuous), NOTIONAL * QUANTITY * TOL);
assertEquals(computed4Periodic.getAmount(), QUANTITY * (basePv4 - pvExtra4Periodic), NOTIONAL * QUANTITY * TOL);
// standard settlement < trade settlement < coupon date
TradeInfo tradeInfo5 = TradeInfo.builder()
.tradeDate(TRADE_BEFORE)
.settlementDate(TRADE_BEFORE.plusDays(7))
.build();
ResolvedFixedCouponBondTrade trade5 = ResolvedFixedCouponBondTrade.builder()
.info(tradeInfo5)
.product(PRODUCT_NO_EXCOUPON)
.quantity(QUANTITY)
.price(CLEAN_PRICE)
.build();
CurrencyAmount computed5 = TRADE_PRICER_NO_UPFRONT.presentValueFromCleanPrice(trade5, PROVIDER_BEFORE, REF_DATA, cleanPrice);
CurrencyAmount computed5Continuous = TRADE_PRICER_NO_UPFRONT.presentValueFromCleanPriceWithZSpread(
trade5, PROVIDER_BEFORE, REF_DATA, cleanPrice, Z_SPREAD, CONTINUOUS, 0);
CurrencyAmount computed5Periodic = TRADE_PRICER_NO_UPFRONT.presentValueFromCleanPriceWithZSpread(
trade5, PROVIDER_BEFORE, REF_DATA, cleanPrice, Z_SPREAD, PERIODIC, PERIOD_PER_YEAR);
assertEquals(computed5.getAmount(), QUANTITY * basePv4, NOTIONAL * QUANTITY * TOL);
assertEquals(computed5Continuous.getAmount(), QUANTITY * basePv4, NOTIONAL * QUANTITY * TOL);
assertEquals(computed5Periodic.getAmount(), QUANTITY * basePv4, NOTIONAL * QUANTITY * TOL);
// trade settlement < standard settlement < coupon date
ResolvedFixedCouponBondTrade trade6 = ResolvedFixedCouponBondTrade.builder()
.info(TRADE_INFO_BEFORE)
.product(PRODUCT_NO_EXCOUPON)
.quantity(QUANTITY)
.price(CLEAN_PRICE)
.build();
CurrencyAmount computed6 = TRADE_PRICER_NO_UPFRONT.presentValueFromCleanPrice(trade6, PROVIDER_BEFORE, REF_DATA, cleanPrice);
CurrencyAmount computed6Continuous = TRADE_PRICER_NO_UPFRONT.presentValueFromCleanPriceWithZSpread(
trade6, PROVIDER_BEFORE, REF_DATA, cleanPrice, Z_SPREAD, CONTINUOUS, 0);
CurrencyAmount computed6Periodic = TRADE_PRICER_NO_UPFRONT.presentValueFromCleanPriceWithZSpread(
trade6, PROVIDER_BEFORE, REF_DATA, cleanPrice, Z_SPREAD, PERIODIC, PERIOD_PER_YEAR);
assertEquals(computed6.getAmount(), QUANTITY * basePv4, NOTIONAL * QUANTITY * TOL);
assertEquals(computed6Continuous.getAmount(), QUANTITY * basePv4, NOTIONAL * QUANTITY * TOL);
assertEquals(computed6Periodic.getAmount(), QUANTITY * basePv4, NOTIONAL * QUANTITY * TOL);
}
//-------------------------------------------------------------------------
public void test_presentValueFromCleanPrice_coherency() {
double priceDirty = PRODUCT_PRICER.dirtyPriceFromCurves(PRODUCT, PROVIDER, REF_DATA);
LocalDate standardSettlementDate = PRODUCT.getSettlementDateOffset().adjust(PROVIDER.getValuationDate(), REF_DATA);
double priceCleanComputed = PRODUCT_PRICER.cleanPriceFromDirtyPrice(PRODUCT, standardSettlementDate, priceDirty);
CurrencyAmount pvCleanPrice = TRADE_PRICER.presentValueFromCleanPrice(TRADE, PROVIDER, REF_DATA, priceCleanComputed);
CurrencyAmount pvCurves = TRADE_PRICER.presentValue(TRADE, PROVIDER);
assertEquals(pvCleanPrice.getAmount(), pvCurves.getAmount(), NOTIONAL * TOL);
}
public void test_presentValueFromCleanPriceWithZSpread_continuous_coherency() {
double priceDirty = PRODUCT_PRICER
.dirtyPriceFromCurvesWithZSpread(PRODUCT, PROVIDER, REF_DATA, Z_SPREAD, CONTINUOUS, 0);
LocalDate standardSettlementDate = PRODUCT.getSettlementDateOffset().adjust(PROVIDER.getValuationDate(), REF_DATA);
double priceCleanComputed = PRODUCT_PRICER.cleanPriceFromDirtyPrice(PRODUCT, standardSettlementDate, priceDirty);
CurrencyAmount pvCleanPrice = TRADE_PRICER.presentValueFromCleanPriceWithZSpread(
TRADE, PROVIDER, REF_DATA, priceCleanComputed, Z_SPREAD, CONTINUOUS, 0);
CurrencyAmount pvCurves = TRADE_PRICER.presentValueWithZSpread(TRADE, PROVIDER, Z_SPREAD, CONTINUOUS, 0);
assertEquals(pvCleanPrice.getAmount(), pvCurves.getAmount(), NOTIONAL * TOL);
}
public void test_presentValueFromCleanPriceWithZSpread_periodic_coherency() {
double priceDirty = PRODUCT_PRICER.dirtyPriceFromCurvesWithZSpread(
PRODUCT, PROVIDER, REF_DATA, Z_SPREAD, PERIODIC, PERIOD_PER_YEAR);
LocalDate standardSettlementDate = PRODUCT.getSettlementDateOffset().adjust(PROVIDER.getValuationDate(), REF_DATA);
double priceCleanComputed = PRODUCT_PRICER.cleanPriceFromDirtyPrice(PRODUCT, standardSettlementDate, priceDirty);
CurrencyAmount pvCleanPrice = TRADE_PRICER.presentValueFromCleanPriceWithZSpread(
TRADE, PROVIDER, REF_DATA, priceCleanComputed, Z_SPREAD, PERIODIC, PERIOD_PER_YEAR);
CurrencyAmount pvCurves = TRADE_PRICER
.presentValueWithZSpread(TRADE, PROVIDER, Z_SPREAD, PERIODIC, PERIOD_PER_YEAR);
assertEquals(pvCleanPrice.getAmount(), pvCurves.getAmount(), NOTIONAL * TOL);
}
public void test_presentValueFromCleanPrice_noExcoupon_coherency() {
double priceDirty = PRODUCT_PRICER.dirtyPriceFromCurves(PRODUCT_NO_EXCOUPON, PROVIDER, REF_DATA);
LocalDate standardSettlementDate = PRODUCT.getSettlementDateOffset().adjust(PROVIDER.getValuationDate(), REF_DATA);
double priceCleanComputed = PRODUCT_PRICER.cleanPriceFromDirtyPrice(PRODUCT, standardSettlementDate, priceDirty);
CurrencyAmount pvCleanPrice = TRADE_PRICER.presentValueFromCleanPrice(
TRADE_NO_EXCOUPON, PROVIDER, REF_DATA, priceCleanComputed);
CurrencyAmount pvCurves = TRADE_PRICER.presentValue(TRADE_NO_EXCOUPON, PROVIDER);
assertEquals(pvCleanPrice.getAmount(), pvCurves.getAmount(), NOTIONAL * TOL);
}
public void test_presentValueFromCleanPriceWithZSpread_continuous_noExcoupon_coherency() {
double priceDirty = PRODUCT_PRICER.dirtyPriceFromCurvesWithZSpread(
PRODUCT_NO_EXCOUPON, PROVIDER, REF_DATA, Z_SPREAD, CONTINUOUS, 0);
LocalDate standardSettlementDate = PRODUCT.getSettlementDateOffset().adjust(PROVIDER.getValuationDate(), REF_DATA);
double priceCleanComputed = PRODUCT_PRICER.cleanPriceFromDirtyPrice(PRODUCT, standardSettlementDate, priceDirty);
CurrencyAmount pvCleanPrice = TRADE_PRICER.presentValueFromCleanPriceWithZSpread(
TRADE_NO_EXCOUPON, PROVIDER, REF_DATA, priceCleanComputed, Z_SPREAD, CONTINUOUS, 0);
CurrencyAmount pvCurves = TRADE_PRICER
.presentValueWithZSpread(TRADE_NO_EXCOUPON, PROVIDER, Z_SPREAD, CONTINUOUS, 0);
assertEquals(pvCleanPrice.getAmount(), pvCurves.getAmount(), NOTIONAL * TOL);
}
public void test_presentValueFromCleanPriceWithZSpread_periodic_noExcoupon_coherency() {
double priceDirty = PRODUCT_PRICER.dirtyPriceFromCurvesWithZSpread(
PRODUCT_NO_EXCOUPON, PROVIDER, REF_DATA, Z_SPREAD, PERIODIC, PERIOD_PER_YEAR);
LocalDate standardSettlementDate = PRODUCT.getSettlementDateOffset().adjust(PROVIDER.getValuationDate(), REF_DATA);
double priceCleanComputed = PRODUCT_PRICER.cleanPriceFromDirtyPrice(PRODUCT, standardSettlementDate, priceDirty);
CurrencyAmount pvCleanPrice = TRADE_PRICER.presentValueFromCleanPriceWithZSpread(
TRADE_NO_EXCOUPON, PROVIDER, REF_DATA, priceCleanComputed, Z_SPREAD, PERIODIC, PERIOD_PER_YEAR);
CurrencyAmount pvCurves = TRADE_PRICER.presentValueWithZSpread(
TRADE_NO_EXCOUPON, PROVIDER, Z_SPREAD, PERIODIC, PERIOD_PER_YEAR);
assertEquals(pvCleanPrice.getAmount(), pvCurves.getAmount(), NOTIONAL * TOL);
}
//-------------------------------------------------------------------------
public void test_presentValueSensitivity() {
PointSensitivities pointTrade = TRADE_PRICER.presentValueSensitivity(TRADE, PROVIDER);
CurrencyParameterSensitivities computedTrade = PROVIDER.parameterSensitivity(pointTrade);
CurrencyParameterSensitivities expectedTrade = FD_CAL.sensitivity(PROVIDER,
(p) -> TRADE_PRICER.presentValue(TRADE, (p)));
assertTrue(computedTrade.equalWithTolerance(expectedTrade, 30d * NOTIONAL * QUANTITY * EPS));
}
public void test_presentValueSensitivityWithZSpread_continuous() {
PointSensitivities pointTrade =
TRADE_PRICER.presentValueSensitivityWithZSpread(TRADE, PROVIDER, Z_SPREAD, CONTINUOUS, 0);
CurrencyParameterSensitivities computedTrade = PROVIDER.parameterSensitivity(pointTrade);
CurrencyParameterSensitivities expectedTrade = FD_CAL.sensitivity(
PROVIDER, (p) -> TRADE_PRICER.presentValueWithZSpread(TRADE, (p), Z_SPREAD, CONTINUOUS, 0));
assertTrue(computedTrade.equalWithTolerance(expectedTrade, 20d * NOTIONAL * QUANTITY * EPS));
}
public void test_presentValueSensitivityWithZSpread_periodic() {
PointSensitivities pointTrade =
TRADE_PRICER.presentValueSensitivityWithZSpread(TRADE, PROVIDER, Z_SPREAD, PERIODIC, PERIOD_PER_YEAR);
CurrencyParameterSensitivities computedTrade = PROVIDER.parameterSensitivity(pointTrade);
CurrencyParameterSensitivities expectedTrade = FD_CAL.sensitivity(PROVIDER,
(p) -> TRADE_PRICER.presentValueWithZSpread(TRADE, (p), Z_SPREAD, PERIODIC, PERIOD_PER_YEAR));
assertTrue(computedTrade.equalWithTolerance(expectedTrade, 20d * NOTIONAL * QUANTITY * EPS));
}
public void test_presentValueProductSensitivity_noExcoupon() {
PointSensitivities pointTrade = TRADE_PRICER.presentValueSensitivity(TRADE_NO_EXCOUPON, PROVIDER);
CurrencyParameterSensitivities computedTrade = PROVIDER.parameterSensitivity(pointTrade);
CurrencyParameterSensitivities expectedTrade = FD_CAL.sensitivity(
PROVIDER, (p) -> TRADE_PRICER.presentValue(TRADE_NO_EXCOUPON, (p)));
assertTrue(computedTrade.equalWithTolerance(expectedTrade, 30d * NOTIONAL * QUANTITY * EPS));
}
public void test_presentValueSensitivityWithZSpread_continuous_noExcoupon() {
PointSensitivities pointTrade =
TRADE_PRICER.presentValueSensitivityWithZSpread(TRADE_NO_EXCOUPON, PROVIDER, Z_SPREAD, CONTINUOUS, 0);
CurrencyParameterSensitivities computedTrade = PROVIDER.parameterSensitivity(pointTrade);
CurrencyParameterSensitivities expectedTrade = FD_CAL.sensitivity(PROVIDER, (p) ->
TRADE_PRICER.presentValueWithZSpread(TRADE_NO_EXCOUPON, (p), Z_SPREAD, CONTINUOUS, 0));
assertTrue(computedTrade.equalWithTolerance(expectedTrade, 20d * NOTIONAL * QUANTITY * EPS));
}
public void test_presentValueSensitivityWithZSpread_periodic_noExcoupon() {
PointSensitivities pointTrade = TRADE_PRICER.presentValueSensitivityWithZSpread(
TRADE_NO_EXCOUPON, PROVIDER, Z_SPREAD, PERIODIC, PERIOD_PER_YEAR);
CurrencyParameterSensitivities computedTrade = PROVIDER.parameterSensitivity(pointTrade);
CurrencyParameterSensitivities expectedTrade = FD_CAL.sensitivity(PROVIDER, (p) ->
TRADE_PRICER.presentValueWithZSpread(TRADE_NO_EXCOUPON, (p), Z_SPREAD, PERIODIC, PERIOD_PER_YEAR));
assertTrue(computedTrade.equalWithTolerance(expectedTrade, 20d * NOTIONAL * QUANTITY * EPS));
}
//-------------------------------------------------------------------------
public void test_presentValueSensitivity_dateLogic() {
ResolvedFixedCouponBondTrade tradeAfter = ResolvedFixedCouponBondTrade.builder()
.info(TRADE_INFO)
.product(PRODUCT)
.quantity(QUANTITY)
.price(CLEAN_PRICE)
.build();
PointSensitivities computedTradeAfter = TRADE_PRICER_NO_UPFRONT.presentValueSensitivity(tradeAfter, PROVIDER_BEFORE);
// settle before detachment date
ResolvedFixedCouponBondTrade tradeBefore = ResolvedFixedCouponBondTrade.builder()
.info(TRADE_INFO_BEFORE)
.product(PRODUCT)
.quantity(QUANTITY)
.price(CLEAN_PRICE)
.build();
PointSensitivities computedTradeBefore =
TRADE_PRICER_NO_UPFRONT.presentValueSensitivity(tradeBefore, PROVIDER_BEFORE);
FixedCouponBondPaymentPeriod periodExtra = findPeriod(PRODUCT, SETTLE_BEFORE, SETTLEMENT);
PointSensitivities sensiExtra = COUPON_PRICER
.presentValueSensitivity(periodExtra, PROVIDER_BEFORE.issuerCurveDiscountFactors(ISSUER_ID, EUR)).build();
assertTrue(computedTradeBefore.normalized().equalWithTolerance(
computedTradeAfter.combinedWith(sensiExtra.multipliedBy(QUANTITY)).normalized(), NOTIONAL * QUANTITY * TOL));
// settle on detachment date
ResolvedFixedCouponBondTrade tradeOnDetachment = ResolvedFixedCouponBondTrade.builder()
.info(TRADE_INFO_ON_DETACHMENT)
.product(PRODUCT)
.quantity(QUANTITY)
.price(CLEAN_PRICE)
.build();
PointSensitivities computedTradeOnDetachment =
TRADE_PRICER_NO_UPFRONT.presentValueSensitivity(tradeOnDetachment, PROVIDER_BEFORE);
assertTrue(computedTradeOnDetachment.equalWithTolerance(computedTradeAfter, NOTIONAL * QUANTITY * TOL));
// settle between detachment date and coupon date
ResolvedFixedCouponBondTrade tradeBtwnDetachmentCoupon = ResolvedFixedCouponBondTrade.builder()
.info(TRADE_INFO_BTWN_DETACHMENT_COUPON)
.product(PRODUCT)
.quantity(QUANTITY)
.price(CLEAN_PRICE)
.build();
PointSensitivities computedTradeBtwnDetachmentCoupon =
TRADE_PRICER_NO_UPFRONT.presentValueSensitivity(tradeBtwnDetachmentCoupon, PROVIDER_BEFORE);
assertTrue(computedTradeBtwnDetachmentCoupon.equalWithTolerance(computedTradeAfter, NOTIONAL * QUANTITY * TOL));
}
public void test_presentValueSensitivity_dateLogic_pastSettle() {
ResolvedFixedCouponBondTrade tradeAfter = ResolvedFixedCouponBondTrade.builder()
.info(TRADE_INFO)
.product(PRODUCT)
.quantity(QUANTITY)
.price(CLEAN_PRICE)
.build();
PointSensitivities computedTradeAfter = TRADE_PRICER_NO_UPFRONT.presentValueSensitivity(tradeAfter, PROVIDER);
// settle before detachment date
ResolvedFixedCouponBondTrade tradeBefore = ResolvedFixedCouponBondTrade.builder()
.info(TRADE_INFO_BEFORE)
.product(PRODUCT)
.quantity(QUANTITY)
.price(CLEAN_PRICE)
.build();
PointSensitivities computedTradeBefore = TRADE_PRICER_NO_UPFRONT.presentValueSensitivity(tradeBefore, PROVIDER);
assertTrue(computedTradeBefore.equalWithTolerance(computedTradeAfter, NOTIONAL * QUANTITY * TOL));
// settle on detachment date
ResolvedFixedCouponBondTrade tradeOnDetachment = ResolvedFixedCouponBondTrade.builder()
.info(TRADE_INFO_ON_DETACHMENT)
.product(PRODUCT)
.quantity(QUANTITY)
.price(CLEAN_PRICE)
.build();
PointSensitivities computedTradeOnDetachment =
TRADE_PRICER_NO_UPFRONT.presentValueSensitivity(tradeOnDetachment, PROVIDER);
assertTrue(computedTradeOnDetachment.equalWithTolerance(computedTradeAfter, NOTIONAL * QUANTITY * TOL));
// settle between detachment date and coupon date
ResolvedFixedCouponBondTrade tradeBtwnDetachmentCoupon = ResolvedFixedCouponBondTrade.builder()
.info(TRADE_INFO_BTWN_DETACHMENT_COUPON)
.product(PRODUCT)
.quantity(QUANTITY)
.price(CLEAN_PRICE)
.build();
PointSensitivities computedTradeBtwnDetachmentCoupon =
TRADE_PRICER_NO_UPFRONT.presentValueSensitivity(tradeBtwnDetachmentCoupon, PROVIDER);
assertTrue(computedTradeBtwnDetachmentCoupon.equalWithTolerance(computedTradeAfter, NOTIONAL * QUANTITY * TOL));
}
public void test_presentValueSensitivity_dateLogic_noExcoupon() {
ResolvedFixedCouponBondTrade tradeAfter = ResolvedFixedCouponBondTrade.builder()
.info(TRADE_INFO)
.product(PRODUCT_NO_EXCOUPON)
.quantity(QUANTITY)
.price(CLEAN_PRICE)
.build();
PointSensitivities computedTradeAfter = TRADE_PRICER_NO_UPFRONT.presentValueSensitivity(tradeAfter, PROVIDER_BEFORE);
// settle before coupon date
ResolvedFixedCouponBondTrade tradeBefore = ResolvedFixedCouponBondTrade.builder()
.info(TRADE_INFO_BEFORE)
.product(PRODUCT_NO_EXCOUPON)
.quantity(QUANTITY)
.price(CLEAN_PRICE)
.build();
PointSensitivities computedTradeBefore =
TRADE_PRICER_NO_UPFRONT.presentValueSensitivity(tradeBefore, PROVIDER_BEFORE);
FixedCouponBondPaymentPeriod periodExtra = findPeriod(PRODUCT_NO_EXCOUPON, SETTLE_BEFORE, SETTLEMENT);
PointSensitivities sensiExtra = COUPON_PRICER
.presentValueSensitivity(periodExtra, PROVIDER_BEFORE.issuerCurveDiscountFactors(ISSUER_ID, EUR)).build();
assertTrue(computedTradeBefore.normalized().equalWithTolerance(
computedTradeAfter.combinedWith(sensiExtra.multipliedBy(QUANTITY)).normalized(), NOTIONAL * QUANTITY * TOL));
// settle on coupon date
ResolvedFixedCouponBondTrade tradeOnCoupon = ResolvedFixedCouponBondTrade.builder()
.info(TRADE_INFO_ON_COUPON)
.product(PRODUCT_NO_EXCOUPON)
.quantity(QUANTITY)
.price(CLEAN_PRICE)
.build();
PointSensitivities computedTradeOnCoupon = TRADE_PRICER_NO_UPFRONT.presentValueSensitivity(tradeOnCoupon, PROVIDER_BEFORE);
assertTrue(computedTradeOnCoupon.equalWithTolerance(computedTradeAfter, NOTIONAL * QUANTITY * TOL));
}
public void test_presentValueSensitivity_dateLogic_pastSettle_noExcoupon() {
ResolvedFixedCouponBondTrade tradeAfter = ResolvedFixedCouponBondTrade.builder()
.info(TRADE_INFO)
.product(PRODUCT_NO_EXCOUPON)
.quantity(QUANTITY)
.price(CLEAN_PRICE)
.build();
PointSensitivities computedTradeAfter = TRADE_PRICER_NO_UPFRONT.presentValueSensitivity(tradeAfter, PROVIDER);
// settle before coupon date
ResolvedFixedCouponBondTrade tradeBefore = ResolvedFixedCouponBondTrade.builder()
.info(TRADE_INFO_BEFORE)
.product(PRODUCT_NO_EXCOUPON)
.quantity(QUANTITY)
.price(CLEAN_PRICE)
.build();
PointSensitivities computedTradeBefore = TRADE_PRICER_NO_UPFRONT.presentValueSensitivity(tradeBefore, PROVIDER);
assertTrue(computedTradeBefore.equalWithTolerance(computedTradeAfter, NOTIONAL * QUANTITY * TOL));
// settle on coupon date
ResolvedFixedCouponBondTrade tradeOnCoupon = ResolvedFixedCouponBondTrade.builder()
.info(TRADE_INFO_ON_COUPON)
.product(PRODUCT_NO_EXCOUPON)
.quantity(QUANTITY)
.price(CLEAN_PRICE)
.build();
PointSensitivities computedTradeOnCoupon = TRADE_PRICER_NO_UPFRONT.presentValueSensitivity(tradeOnCoupon, PROVIDER);
assertTrue(computedTradeOnCoupon.equalWithTolerance(computedTradeAfter, NOTIONAL * QUANTITY * TOL));
}
//-------------------------------------------------------------------------
public void test_currencyExposure() {
MultiCurrencyAmount ceComputed = TRADE_PRICER.currencyExposure(TRADE, PROVIDER);
CurrencyAmount pv = TRADE_PRICER.presentValue(TRADE, PROVIDER);
assertEquals(ceComputed, MultiCurrencyAmount.of(pv));
}
public void test_currencyExposureWithZSpread() {
MultiCurrencyAmount ceComputed = TRADE_PRICER.currencyExposureWithZSpread(
TRADE, PROVIDER, Z_SPREAD, PERIODIC, PERIOD_PER_YEAR);
CurrencyAmount pv = TRADE_PRICER.presentValueWithZSpread(TRADE, PROVIDER, Z_SPREAD, PERIODIC, PERIOD_PER_YEAR);
assertEquals(ceComputed, MultiCurrencyAmount.of(pv));
}
public void test_currentCash_zero() {
CurrencyAmount ccComputed = TRADE_PRICER.currentCash(TRADE, VAL_DATE);
assertEquals(ccComputed, CurrencyAmount.zero(EUR));
}
public void test_currentCash_valuationAtSettlement() {
CurrencyAmount ccComputed = TRADE_PRICER.currentCash(TRADE, SETTLEMENT);
assertEquals(ccComputed, UPFRONT_PAYMENT.getValue());
}
public void test_currentCash_valuationAtPayment() {
LocalDate paymentDate = LocalDate.of(2016, 10, 12);
CurrencyAmount ccComputed = TRADE_PRICER.currentCash(TRADE, paymentDate);
assertEquals(ccComputed, CurrencyAmount.zero(EUR));
}
public void test_currentCash_valuationAtPayment_noExcoupon() {
LocalDate startDate = LocalDate.of(2016, 4, 12);
LocalDate paymentDate = LocalDate.of(2016, 10, 12);
double yc = DAY_COUNT.relativeYearFraction(startDate, paymentDate);
CurrencyAmount ccComputed = TRADE_PRICER.currentCash(TRADE_NO_EXCOUPON, paymentDate);
assertEquals(ccComputed, CurrencyAmount.of(EUR, FIXED_RATE * NOTIONAL * yc * QUANTITY));
}
public void test_currentCash_valuationAtMaturity() {
LocalDate paymentDate = LocalDate.of(2025, 4, 14);
CurrencyAmount ccComputed = TRADE_PRICER.currentCash(TRADE, paymentDate);
assertEquals(ccComputed, CurrencyAmount.of(EUR, NOTIONAL * QUANTITY));
}
public void test_currentCash_valuationAtMaturity_noExcoupon() {
LocalDate startDate = LocalDate.of(2024, 10, 14);
LocalDate paymentDate = LocalDate.of(2025, 4, 14);
double yc = DAY_COUNT.relativeYearFraction(startDate, paymentDate);
CurrencyAmount ccComputed = TRADE_PRICER.currentCash(TRADE_NO_EXCOUPON, paymentDate);
assertEquals(ccComputed, CurrencyAmount.of(EUR, NOTIONAL * (1d + yc * FIXED_RATE) * QUANTITY));
}
//-------------------------------------------------------------------------
public void test_upfrontPayment() {
Payment payment = TRADE_PRICER.upfrontPayment(TRADE);
assertEquals(payment.getCurrency(), EUR);
assertEquals(payment.getAmount(), -NOTIONAL * QUANTITY * DIRTY_PRICE, TOL);
assertEquals(payment.getDate(), SETTLEMENT);
}
//-------------------------------------------------------------------------
private static LegalEntityDiscountingProvider createRatesProvider(LocalDate valuationDate) {
DiscountFactors dscRepo = ZeroRateDiscountFactors.of(EUR, valuationDate, CURVE_REPO);
DiscountFactors dscIssuer = ZeroRateDiscountFactors.of(EUR, valuationDate, CURVE_ISSUER);
LegalEntityDiscountingProvider provider = ImmutableLegalEntityDiscountingProvider.builder()
.issuerCurves(ImmutableMap.<Pair<LegalEntityGroup, Currency>, DiscountFactors>of(
Pair.<LegalEntityGroup, Currency>of(GROUP_ISSUER, EUR), dscIssuer))
.issuerCurveGroups(ImmutableMap.<StandardId, LegalEntityGroup>of(ISSUER_ID, GROUP_ISSUER))
.repoCurves(ImmutableMap.<Pair<RepoGroup, Currency>, DiscountFactors>of(
Pair.<RepoGroup, Currency>of(GROUP_REPO, EUR), dscRepo))
.repoCurveGroups(ImmutableMap.<StandardId, RepoGroup>of(SECURITY_ID, GROUP_REPO))
.valuationDate(valuationDate)
.build();
return provider;
}
private FixedCouponBondPaymentPeriod findPeriod(ResolvedFixedCouponBond bond, LocalDate date1, LocalDate date2) {
ImmutableList<FixedCouponBondPaymentPeriod> list = bond.getPeriodicPayments();
for (FixedCouponBondPaymentPeriod period : list) {
if (period.getDetachmentDate().equals(period.getPaymentDate())) {
if (period.getPaymentDate().isAfter(date1) && period.getPaymentDate().isBefore(date2)) {
return period;
}
} else {
if (period.getDetachmentDate().isAfter(date1) && period.getDetachmentDate().isBefore(date2)) {
return period;
}
}
}
return null;
}
}