Package com.opengamma.analytics.financial.interestrate.payments.provider

Source Code of com.opengamma.analytics.financial.interestrate.payments.provider.CapFloorIborInArrearsReplicationMethodTest$InArrearsIntegrant

/**
* Copyright (C) 2011 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.analytics.financial.interestrate.payments.provider;

import static org.testng.AssertJUnit.assertEquals;
import static org.testng.AssertJUnit.assertTrue;

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

import com.opengamma.analytics.financial.instrument.index.IborIndex;
import com.opengamma.analytics.financial.instrument.payment.CapFloorIborDefinition;
import com.opengamma.analytics.financial.instrument.payment.CouponFixedDefinition;
import com.opengamma.analytics.financial.instrument.payment.CouponIborDefinition;
import com.opengamma.analytics.financial.interestrate.payments.derivative.CapFloorIbor;
import com.opengamma.analytics.financial.interestrate.payments.derivative.CouponFixed;
import com.opengamma.analytics.financial.interestrate.payments.derivative.CouponIbor;
import com.opengamma.analytics.financial.model.option.definition.SABRInterestRateParameters;
import com.opengamma.analytics.financial.provider.calculator.discounting.PresentValueDiscountingCalculator;
import com.opengamma.analytics.financial.provider.calculator.sabrcap.PresentValueSABRCapCalculator;
import com.opengamma.analytics.financial.provider.description.MulticurveProviderDiscountDataSets;
import com.opengamma.analytics.financial.provider.description.SABRDataSets;
import com.opengamma.analytics.financial.provider.description.interestrate.MulticurveProviderDiscount;
import com.opengamma.analytics.financial.provider.description.interestrate.SABRCapProviderDiscount;
import com.opengamma.analytics.financial.provider.description.interestrate.SABRCapProviderInterface;
import com.opengamma.analytics.financial.provider.method.CapFloorIborSABRCapMethodInterface;
import com.opengamma.analytics.financial.schedule.ScheduleCalculator;
import com.opengamma.analytics.math.MathException;
import com.opengamma.analytics.math.function.Function1D;
import com.opengamma.analytics.math.integration.RungeKuttaIntegrator1D;
import com.opengamma.financial.convention.calendar.Calendar;
import com.opengamma.util.money.Currency;
import com.opengamma.util.money.MultipleCurrencyAmount;
import com.opengamma.util.time.DateUtils;

/**
* Tests regarding the pricing of in-arrears Ibor products by replication.
*/
public class CapFloorIborInArrearsReplicationMethodTest {

  private static final MulticurveProviderDiscount MULTICURVES = MulticurveProviderDiscountDataSets.createMulticurveEurUsd();
  private static final IborIndex EURIBOR6M = MulticurveProviderDiscountDataSets.getIndexesIborMulticurveEurUsd()[1];
  private static final Currency EUR = EURIBOR6M.getCurrency();
  private static final Calendar CALENDAR = MulticurveProviderDiscountDataSets.getEURCalendar();

  private static final SABRInterestRateParameters SABR_PARAMETER = SABRDataSets.createSABR1();
  private static final SABRCapProviderDiscount SABR_MULTICURVES = new SABRCapProviderDiscount(MULTICURVES, SABR_PARAMETER, EURIBOR6M);

  // Dates
  private static final ZonedDateTime REFERENCE_DATE = DateUtils.getUTCDate(2011, 6, 7);
  private static final ZonedDateTime START_ACCRUAL_DATE = ScheduleCalculator.getAdjustedDate(REFERENCE_DATE, Period.ofYears(9), EURIBOR6M, CALENDAR);
  private static final ZonedDateTime END_ACCRUAL_DATE = ScheduleCalculator.getAdjustedDate(START_ACCRUAL_DATE, EURIBOR6M, CALENDAR);
  private static final double ACCRUAL_FACTOR = EURIBOR6M.getDayCount().getDayCountFraction(START_ACCRUAL_DATE, END_ACCRUAL_DATE, CALENDAR);
  private static final ZonedDateTime FIXING_DATE = ScheduleCalculator.getAdjustedDate(END_ACCRUAL_DATE, -EURIBOR6M.getSpotLag(), CALENDAR);
  private static final double NOTIONAL = 100000000; //100m
  private static final double STRIKE = 0.03;
  private static final boolean IS_CAP = true;
  // Definition description: In arrears
  private static final CapFloorIborDefinition CAP_IA_LONG_DEFINITION = new CapFloorIborDefinition(EUR, END_ACCRUAL_DATE, START_ACCRUAL_DATE, END_ACCRUAL_DATE, ACCRUAL_FACTOR, NOTIONAL, FIXING_DATE,
      EURIBOR6M, STRIKE, IS_CAP, CALENDAR);
  private static final CouponIborDefinition COUPON_IBOR_IA_DEFINITION = new CouponIborDefinition(EUR, END_ACCRUAL_DATE, START_ACCRUAL_DATE, END_ACCRUAL_DATE, ACCRUAL_FACTOR, NOTIONAL, FIXING_DATE,
      EURIBOR6M, CALENDAR);
  private static final CouponFixedDefinition COUPON_STRIKE_DEFINITION = new CouponFixedDefinition(COUPON_IBOR_IA_DEFINITION, STRIKE);
  private static final CapFloorIborDefinition CAP_IA_SHORT_DEFINITION = new CapFloorIborDefinition(EUR, END_ACCRUAL_DATE, START_ACCRUAL_DATE, END_ACCRUAL_DATE, ACCRUAL_FACTOR, -NOTIONAL, FIXING_DATE,
      EURIBOR6M, STRIKE, IS_CAP, CALENDAR);
  private static final CapFloorIborDefinition FLOOR_IA_SHORT_DEFINITION = new CapFloorIborDefinition(EUR, END_ACCRUAL_DATE, START_ACCRUAL_DATE, END_ACCRUAL_DATE, ACCRUAL_FACTOR, -NOTIONAL,
      FIXING_DATE, EURIBOR6M, STRIKE, !IS_CAP, CALENDAR);
  // To derivative
  private static final CapFloorIbor CAP_LONG = (CapFloorIbor) CAP_IA_LONG_DEFINITION.toDerivative(REFERENCE_DATE);
  private static final CouponIbor COUPON_IBOR = (CouponIbor) COUPON_IBOR_IA_DEFINITION.toDerivative(REFERENCE_DATE);
  private static final CouponFixed COUPON_STRIKE = COUPON_STRIKE_DEFINITION.toDerivative(REFERENCE_DATE);
  private static final CapFloorIbor CAP_SHORT = (CapFloorIbor) CAP_IA_SHORT_DEFINITION.toDerivative(REFERENCE_DATE);
  private static final CapFloorIbor FLOOR_SHORT = (CapFloorIbor) FLOOR_IA_SHORT_DEFINITION.toDerivative(REFERENCE_DATE);
  // Methods
  private static final PresentValueSABRCapCalculator PVSCC = PresentValueSABRCapCalculator.getInstance();
  private static final PresentValueDiscountingCalculator PVDC = PresentValueDiscountingCalculator.getInstance();
  private static final double CUT_OFF_STRIKE = 0.08;
  private static final double MU = 8.00;
  private static final CapFloorIborSABRCapExtrapolationRightMethod METHOD_SABREXTRA_STD = new CapFloorIborSABRCapExtrapolationRightMethod(CUT_OFF_STRIKE, MU);
  private static final CouponIborInArrearsReplicationMethod METHOD_SABREXTRA_COUPON_IA = new CouponIborInArrearsReplicationMethod(METHOD_SABREXTRA_STD);
  private static final CapFloorIborInArrearsSABRCapGenericReplicationMethod METHOD_SABREXTRA_CAP_IA = new CapFloorIborInArrearsSABRCapGenericReplicationMethod(METHOD_SABREXTRA_STD);

  private static final double TOLERANCE_PV = 1.0E-0;

  //  private static final double TOLERANCE_PV_DELTA = 1.0E+2;

  @Test
  /**
   * Tests the present value using the SABR with extrapolation to the right method to price standard cap/floor.
   * It is suggested not to use the standard SABR method as it can lead to exploding prices for long term contracts.
   */
  public void persentValueSABRExtrapolation() {
    final CapFloorIbor capStandard = new CapFloorIbor(EUR, CAP_LONG.getFixingPeriodEndTime(), CAP_LONG.getPaymentYearFraction(), NOTIONAL, CAP_LONG.getFixingTime(), EURIBOR6M,
        CAP_LONG.getFixingPeriodStartTime(), CAP_LONG.getFixingPeriodEndTime(), CAP_LONG.getFixingAccrualFactor(), STRIKE, IS_CAP);
    final MultipleCurrencyAmount priceStandard = capStandard.accept(PVSCC, SABR_MULTICURVES);
    final double forward = MULTICURVES.getForwardRate(CAP_LONG.getIndex(), CAP_LONG.getFixingPeriodStartTime(), CAP_LONG.getFixingPeriodEndTime(), CAP_LONG.getFixingAccrualFactor());
    final double beta = (1.0 + CAP_LONG.getFixingAccrualFactor() * forward) * MULTICURVES.getDiscountFactor(EUR, CAP_LONG.getFixingPeriodEndTime())
        / MULTICURVES.getDiscountFactor(EUR, CAP_LONG.getFixingPeriodStartTime());
    final double strikePart = (1.0 + CAP_LONG.getFixingAccrualFactor() * STRIKE) * priceStandard.getAmount(EUR);
    final RungeKuttaIntegrator1D integrator = new RungeKuttaIntegrator1D(1.0, 1E-8, 10);
    final InArrearsIntegrant integrant = new InArrearsIntegrant(METHOD_SABREXTRA_STD, capStandard, SABR_MULTICURVES);
    double integralPart;
    try {
      integralPart = integrator.integrate(integrant, STRIKE, STRIKE + 2.0);
    } catch (final Exception e) {
      throw new MathException(e);
    }
    integralPart *= 2.0 * CAP_LONG.getFixingAccrualFactor();
    final MultipleCurrencyAmount price = METHOD_SABREXTRA_CAP_IA.presentValue(CAP_LONG, SABR_MULTICURVES);
    final double priceExpected = (strikePart + integralPart) / beta;
    assertEquals("Cap/floor IA - SABR pricing", priceExpected, price.getAmount(EUR), TOLERANCE_PV);
    final double priceExpected2 = 203548.836; // From previous run
    assertEquals("Cap/floor IA - SABR pricing", priceExpected2, price.getAmount(EUR), TOLERANCE_PV);
  }

  @Test
  /**
   * Compare the present value by replication to a value without adjustment.
   */
  public void presentValueSABRNoAdjustment() {
    final double forward = MULTICURVES.getForwardRate(EURIBOR6M, CAP_LONG.getFixingPeriodStartTime(), CAP_LONG.getFixingPeriodEndTime(), CAP_LONG.getFixingAccrualFactor());
    final MultipleCurrencyAmount priceIbor = METHOD_SABREXTRA_COUPON_IA.presentValue(COUPON_IBOR, SABR_MULTICURVES);
    assertTrue("Coupon IA - SABR pricing: coupon = cap with strike eps",
        priceIbor.getAmount(EUR) > forward * NOTIONAL * CAP_LONG.getPaymentYearFraction() * MULTICURVES.getDiscountFactor(EUR, CAP_LONG.getPaymentTime()));
  }

  @Test
  /**
   * Check different parity relationship for the present value: long/short, coupon with cap with strike 0.
   */
  public void persentValueSABRExtrapolationParity() {
    final MultipleCurrencyAmount priceCapLong = METHOD_SABREXTRA_CAP_IA.presentValue(CAP_LONG, SABR_MULTICURVES);
    final MultipleCurrencyAmount priceCapShort = METHOD_SABREXTRA_CAP_IA.presentValue(CAP_SHORT, SABR_MULTICURVES);
    assertEquals("Cap/floor IA - SABR pricing: long-short parity", priceCapLong.getAmount(EUR), -priceCapShort.getAmount(EUR), TOLERANCE_PV);
    final MultipleCurrencyAmount priceIbor = METHOD_SABREXTRA_COUPON_IA.presentValue(COUPON_IBOR, SABR_MULTICURVES);
    final CapFloorIborDefinition cap0Definition = new CapFloorIborDefinition(EUR, END_ACCRUAL_DATE, START_ACCRUAL_DATE, END_ACCRUAL_DATE, ACCRUAL_FACTOR, NOTIONAL, FIXING_DATE, EURIBOR6M, 0.0, IS_CAP, CALENDAR);
    final CapFloorIbor cap0 = (CapFloorIbor) cap0Definition.toDerivative(REFERENCE_DATE);
    final MultipleCurrencyAmount priceCap0 = METHOD_SABREXTRA_CAP_IA.presentValue(cap0, SABR_MULTICURVES);
    assertEquals("Coupon IA - SABR pricing: coupon = cap with strike 0", priceCap0.getAmount(EUR), priceIbor.getAmount(EUR), TOLERANCE_PV);
    final MultipleCurrencyAmount priceFloorShort = METHOD_SABREXTRA_CAP_IA.presentValue(FLOOR_SHORT, SABR_MULTICURVES);
    final MultipleCurrencyAmount priceStrike = COUPON_STRIKE.accept(PVDC, MULTICURVES);
    assertEquals("Cap/floor IA - SABR pricing: cap/floor parity", priceIbor.getAmount(EUR) - priceStrike.getAmount(EUR), priceCapLong.getAmount(EUR) + priceFloorShort.getAmount(EUR), 5.0E+4);
    //TODO: check further the difference (numerical?)
  }

  @Test(enabled = false)
  /**
   * Performance test. "enabled = false" for the standard testing.
   */
  public void sabrExtrapolationPerformance() {
    long startTime, endTime;
    final int nbTest = 100;
    final double[] prices = new double[nbTest];
    @SuppressWarnings("unused")
    double sum = 0.0;
    startTime = System.currentTimeMillis();
    for (int looptest = 0; looptest < nbTest; looptest++) {
      final CapFloorIborSABRCapExtrapolationRightMethod methodSABRExtraStd = new CapFloorIborSABRCapExtrapolationRightMethod(CUT_OFF_STRIKE, MU); //To start with a "clean" method
      final CapFloorIborInArrearsSABRCapGenericReplicationMethod methodSABRExtraIA = new CapFloorIborInArrearsSABRCapGenericReplicationMethod(methodSABRExtraStd);
      prices[looptest] = methodSABRExtraIA.presentValue(CAP_LONG, SABR_MULTICURVES).getAmount(EUR);
      sum += prices[looptest];
    }
    endTime = System.currentTimeMillis();
    System.out.println(nbTest + " IA cap by replication (price): " + (endTime - startTime) + " ms");
    // Performance note: price: 07-Jun-11: On Mac Pro 3.2 GHz Quad-Core Intel Xeon: 385 ms for 100 cap 9Y.
    // TODO: review performance: the SABR extrapolation calibration is done at each integration step: result could be stored.
  }

  /**
   * Inner class to implement the integration used in price replication.
   */
  private static class InArrearsIntegrant extends Function1D<Double, Double> {

    /**
     * The base method for the pricing of standard cap/floors.
     */
    private final CapFloorIborSABRCapMethodInterface _baseMethod;
    /**
     * The standard cap/floor used for replication.
     */
    private final CapFloorIbor _capStandard;
    /**
     * The SABR data bundle used in the standard cap/floor pricing.
     */
    private final SABRCapProviderInterface _sabrData;

    /**
     * Constructor with the required data.
     * @param baseMethod The base method for the pricing of standard cap/floors.
     * @param capStandard The standard cap/floor used for replication.
     * @param sabrData The SABR data bundle used in the standard cap/floor pricing.
     */
    public InArrearsIntegrant(final CapFloorIborSABRCapMethodInterface baseMethod, final CapFloorIbor capStandard, final SABRCapProviderInterface sabr) {
      this._baseMethod = baseMethod;
      this._capStandard = capStandard;
      this._sabrData = sabr;
    }

    @SuppressWarnings("synthetic-access")
    @Override
    public Double evaluate(final Double x) {
      final CapFloorIbor capStrike = _capStandard.withStrike(x);
      return _baseMethod.presentValue(capStrike, _sabrData).getAmount(EUR);
    }
  }

}
TOP

Related Classes of com.opengamma.analytics.financial.interestrate.payments.provider.CapFloorIborInArrearsReplicationMethodTest$InArrearsIntegrant

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.