@Test
 /** Test the present value using the method with the direct formula with extrapolation. */
 public void presentValueAboveCutOff() {
   CurrencyAmount methodPrice = METHOD.presentValue(CAP_HIGH_LONG, SABR_BUNDLE);
   final double df =
       CURVES.getCurve(FUNDING_CURVE_NAME).getDiscountFactor(CAP_HIGH_LONG.getPaymentTime());
   final double forward = CAP_HIGH_LONG.accept(PRC, CURVES);
   final double maturity =
       CAP_HIGH_LONG.getFixingPeriodEndTime() - CAP_LONG.getFixingPeriodStartTime();
   final DoublesPair expiryMaturity = new DoublesPair(CAP_HIGH_LONG.getFixingTime(), maturity);
   final double alpha = SABR_PARAMETERS.getAlpha(expiryMaturity);
   final double beta = SABR_PARAMETERS.getBeta(expiryMaturity);
   final double rho = SABR_PARAMETERS.getRho(expiryMaturity);
   final double nu = SABR_PARAMETERS.getNu(expiryMaturity);
   final SABRFormulaData sabrParam = new SABRFormulaData(alpha, beta, rho, nu);
   final SABRExtrapolationRightFunction sabrExtrapolation =
       new SABRExtrapolationRightFunction(
           forward, sabrParam, CUT_OFF_STRIKE, CAP_HIGH_LONG.getFixingTime(), MU);
   final EuropeanVanillaOption option =
       new EuropeanVanillaOption(
           CAP_HIGH_LONG.getStrike(), CAP_HIGH_LONG.getFixingTime(), CAP_HIGH_LONG.isCap());
   final double expectedPrice =
       sabrExtrapolation.price(option)
           * CAP_HIGH_LONG.getNotional()
           * CAP_HIGH_LONG.getPaymentYearFraction()
           * df;
   assertEquals(
       "Cap/floor: SABR with extrapolation pricing", expectedPrice, methodPrice.getAmount(), 1E-2);
   methodPrice = METHOD.presentValue(CAP_HIGH_LONG, SABR_BUNDLE);
   assertEquals(
       "Cap/floor: SABR with extrapolation pricing", expectedPrice, methodPrice.getAmount(), 1E-2);
 }
コード例 #2
0
 @Override
 public DecisionSchedule visitCapFloorIbor(
     final CapFloorIbor payment, final MulticurveProviderInterface multicurves) {
   final double[] decisionTime = new double[] {payment.getFixingTime()};
   final double fixingStartTime = payment.getFixingPeriodStartTime();
   final double fixingEndTime = payment.getFixingPeriodEndTime();
   final double paymentTime = payment.getPaymentTime();
   final double[][] impactTime = new double[1][];
   impactTime[0] = new double[] {fixingStartTime, fixingEndTime, paymentTime};
   final double[][] impactAmount = new double[1][];
   double forward =
       multicurves.getForwardRate(
           payment.getIndex(),
           payment.getFixingPeriodStartTime(),
           payment.getFixingPeriodEndTime(),
           payment.getFixingAccrualFactor());
   final double beta =
       (1.0 + payment.getFixingAccrualFactor() * forward)
           * multicurves.getDiscountFactor(payment.getCurrency(), payment.getFixingPeriodEndTime())
           / multicurves.getDiscountFactor(
               payment.getCurrency(), payment.getFixingPeriodStartTime());
   impactAmount[0] = new double[] {beta, -1.0, 1.0};
   final DecisionSchedule decision = new DecisionSchedule(decisionTime, impactTime, impactAmount);
   return decision;
 }
 public InArrearsDeltaIntegrant(
     final CapFloorIbor capStandard, final MulticurveProviderInterface curves) {
   _capStandard = capStandard;
   _forward =
       curves.getSimplyCompoundForwardRate(
           capStandard.getIndex(),
           capStandard.getFixingPeriodStartTime(),
           capStandard.getFixingPeriodEndTime(),
           capStandard.getFixingAccrualFactor());
   _expiry = capStandard.getFixingTime();
   _df = curves.getDiscountFactor(capStandard.getCurrency(), capStandard.getPaymentTime());
 }
 @Test
 /**
  * Test the present value SABR parameters sensitivity against a finite difference computation;
  * strike above the cut-off strike.
  */
 public void testPresentValueSABRSensitivityAboveCutOff() {
   final YieldCurveBundle curves = TestsDataSetsSABR.createCurves1();
   final SABRInterestRateParameters sabrParameter = TestsDataSetsSABR.createSABR1();
   final SABRInterestRateDataBundle sabrBundle =
       new SABRInterestRateDataBundle(sabrParameter, curves);
   final CurrencyAmount pv = METHOD.presentValue(CAP_HIGH_LONG, sabrBundle);
   final PresentValueSABRSensitivityDataBundle pvsCapLong =
       METHOD.presentValueSABRSensitivity(CAP_HIGH_LONG, sabrBundle);
   PresentValueSABRSensitivityDataBundle pvsCapShort =
       METHOD.presentValueSABRSensitivity(CAP_HIGH_SHORT, sabrBundle);
   // Long/short parity
   pvsCapShort = pvsCapShort.multiplyBy(-1.0);
   assertEquals(pvsCapShort.getAlpha(), pvsCapLong.getAlpha());
   // SABR sensitivity vs finite difference
   final double shift = 0.0001;
   final double shiftAlpha = 0.00001;
   final DoublesPair expectedExpiryTenor =
       new DoublesPair(
           CAP_HIGH_LONG.getFixingTime(),
           CAP_HIGH_LONG.getFixingPeriodEndTime() - CAP_HIGH_LONG.getFixingPeriodStartTime());
   // Alpha sensitivity vs finite difference computation
   final SABRInterestRateParameters sabrParameterAlphaBumped =
       TestsDataSetsSABR.createSABR1AlphaBumped(shiftAlpha);
   final SABRInterestRateDataBundle sabrBundleAlphaBumped =
       new SABRInterestRateDataBundle(sabrParameterAlphaBumped, curves);
   final CurrencyAmount pvLongPayerAlphaBumped =
       METHOD.presentValue(CAP_HIGH_LONG, sabrBundleAlphaBumped);
   final double expectedAlphaSensi =
       (pvLongPayerAlphaBumped.getAmount() - pv.getAmount()) / shiftAlpha;
   assertEquals("Number of alpha sensitivity", pvsCapLong.getAlpha().getMap().keySet().size(), 1);
   assertEquals(
       "Alpha sensitivity expiry/tenor",
       pvsCapLong.getAlpha().getMap().keySet().contains(expectedExpiryTenor),
       true);
   assertEquals(
       "Alpha sensitivity value",
       expectedAlphaSensi,
       pvsCapLong.getAlpha().getMap().get(expectedExpiryTenor),
       1.0E-0);
   // Rho sensitivity vs finite difference computation
   final SABRInterestRateParameters sabrParameterRhoBumped =
       TestsDataSetsSABR.createSABR1RhoBumped();
   final SABRInterestRateDataBundle sabrBundleRhoBumped =
       new SABRInterestRateDataBundle(sabrParameterRhoBumped, curves);
   final CurrencyAmount pvLongPayerRhoBumped =
       METHOD.presentValue(CAP_HIGH_LONG, sabrBundleRhoBumped);
   final double expectedRhoSensi = (pvLongPayerRhoBumped.getAmount() - pv.getAmount()) / shift;
   assertEquals("Number of rho sensitivity", pvsCapLong.getRho().getMap().keySet().size(), 1);
   assertEquals(
       "Rho sensitivity expiry/tenor",
       pvsCapLong.getRho().getMap().keySet().contains(expectedExpiryTenor),
       true);
   assertEquals(
       "Rho sensitivity value",
       pvsCapLong.getRho().getMap().get(expectedExpiryTenor),
       expectedRhoSensi,
       1.0E-1);
   // Alpha sensitivity vs finite difference computation
   final SABRInterestRateParameters sabrParameterNuBumped =
       TestsDataSetsSABR.createSABR1NuBumped();
   final SABRInterestRateDataBundle sabrBundleNuBumped =
       new SABRInterestRateDataBundle(sabrParameterNuBumped, curves);
   final CurrencyAmount pvLongPayerNuBumped =
       METHOD.presentValue(CAP_HIGH_LONG, sabrBundleNuBumped);
   final double expectedNuSensi = (pvLongPayerNuBumped.getAmount() - pv.getAmount()) / shift;
   assertEquals("Number of nu sensitivity", pvsCapLong.getNu().getMap().keySet().size(), 1);
   assertEquals(
       "Nu sensitivity expiry/tenor",
       pvsCapLong.getNu().getMap().keySet().contains(expectedExpiryTenor),
       true);
   assertEquals(
       "Nu sensitivity value",
       pvsCapLong.getNu().getMap().get(expectedExpiryTenor),
       expectedNuSensi,
       2.0E-1);
 }
  /**
   * Computes the present value of an Ibor cap/floor in arrears by replication based on the paper,
   * "Swap and Cap/Floors with Fixing in Arrears or Payment Delay," OpenGamma Quantitative
   * Documentation
   * http://developers.opengamma.com/quantitative-research/In-Arrears-and-Payment-Delay-Swaps-and-Caps-OpenGamma.pdf
   *
   * @param cap The cap/floor
   * @param curves The curves
   * @return The present value
   */
  public MultipleCurrencyAmount presentValue(
      final CapFloorIbor cap, final MulticurveProviderInterface curves) {
    ArgumentChecker.notNull(cap, "The cap/floor shoud not be null");
    ArgumentChecker.notNull(curves, "curves");
    final Currency ccy = cap.getCurrency();
    // Construct a "standard" CapFloorIbor whose paymentTime is set to be fixingPeriodEndTime
    CapFloorIbor capStandard =
        new CapFloorIbor(
            cap.getCurrency(),
            cap.getFixingPeriodEndTime(),
            cap.getPaymentYearFraction(),
            cap.getNotional(),
            cap.getFixingTime(),
            cap.getIndex(),
            cap.getFixingPeriodStartTime(),
            cap.getFixingPeriodEndTime(),
            cap.getFixingAccrualFactor(),
            cap.getStrike(),
            cap.isCap());
    final double forward =
        curves.getSimplyCompoundForwardRate(
            cap.getIndex(),
            cap.getFixingPeriodStartTime(),
            cap.getFixingPeriodEndTime(),
            cap.getFixingAccrualFactor());
    final double beta =
        (1.0 + cap.getFixingAccrualFactor() * forward)
            * curves.getDiscountFactor(ccy, cap.getFixingPeriodEndTime())
            / curves.getDiscountFactor(ccy, cap.getFixingPeriodStartTime());

    final double df =
        curves.getDiscountFactor(capStandard.getCurrency(), capStandard.getPaymentTime());
    final double strikePart =
        (1.0 + cap.getFixingAccrualFactor() * capStandard.getStrike())
            * presentValueStandard(
                forward,
                capStandard.getStrike(),
                capStandard.getFixingTime(),
                capStandard.isCap(),
                df,
                capStandard.getNotional(),
                capStandard.getPaymentYearFraction());

    final InArrearsIntegrant integrant = new InArrearsIntegrant(capStandard, curves);
    double integralPart;
    try {
      if (cap.isCap()) {
        double atmVol = _smileFunction.getVolatility(forward);
        double upper = forward * Math.exp(6.0 * atmVol * Math.sqrt(cap.getFixingTime()));
        double strike = cap.getStrike();
        integralPart = INTEGRATOR.integrate(integrant, strike, upper);
        double reminder = integrant.evaluate(upper) * upper;
        double error = reminder / integralPart;

        int count = 0;
        while (Math.abs(error) > REL_ERROR && count < MAX_COUNT) {
          integralPart += INTEGRATOR.integrate(integrant, upper, 2.0 * upper);
          upper *= 2.0;
          // The increase of integralPart in the next loop is bounded by reminder
          reminder = integrant.evaluate(upper) * upper;
          error = reminder / integralPart;
          ++count;
          if (count == MAX_COUNT) {
            LOGGER.info(
                "Maximum iteration count, "
                    + MAX_COUNT
                    + ", has been reached. Relative error is greater than "
                    + REL_ERROR);
          }
        }
      } else {
        double strike = cap.getStrike();
        integralPart = INTEGRATOR.integrate(integrant, REL_TOL * strike, strike);
      }
    } catch (final Exception e) {
      throw new MathException(e);
    }
    integralPart *= 2.0 * cap.getFixingAccrualFactor();
    final double pv = (strikePart + integralPart) / beta;
    return MultipleCurrencyAmount.of(cap.getCurrency(), pv);
  }
  /**
   * Computes the pv sensitivity of an Ibor cap/floor in arrears
   *
   * @param cap The cap/floor
   * @param curves The curves
   * @return The sensitivity
   */
  public MultipleCurrencyMulticurveSensitivity presentValueCurveSensitivity(
      final CapFloorIbor cap, final MulticurveProviderInterface curves) {
    ArgumentChecker.notNull(cap, "The cap/floor shoud not be null");
    ArgumentChecker.notNull(curves, "curves");
    final Currency ccy = cap.getCurrency();
    // Construct a "standard" CapFloorIbor whose paymentTime is set to be fixingPeriodEndTime
    CapFloorIbor capStandard =
        new CapFloorIbor(
            cap.getCurrency(),
            cap.getFixingPeriodEndTime(),
            cap.getPaymentYearFraction(),
            cap.getNotional(),
            cap.getFixingTime(),
            cap.getIndex(),
            cap.getFixingPeriodStartTime(),
            cap.getFixingPeriodEndTime(),
            cap.getFixingAccrualFactor(),
            cap.getStrike(),
            cap.isCap());
    final double forward =
        curves.getSimplyCompoundForwardRate(
            cap.getIndex(),
            cap.getFixingPeriodStartTime(),
            cap.getFixingPeriodEndTime(),
            cap.getFixingAccrualFactor());
    final double beta =
        (1.0 + cap.getFixingAccrualFactor() * forward)
            * curves.getDiscountFactor(ccy, cap.getFixingPeriodEndTime())
            / curves.getDiscountFactor(ccy, cap.getFixingPeriodStartTime());

    double df = curves.getDiscountFactor(capStandard.getCurrency(), capStandard.getPaymentTime());
    double strikePart =
        (1.0 + cap.getFixingAccrualFactor() * capStandard.getStrike())
            * presentValueStandard(
                forward,
                capStandard.getStrike(),
                capStandard.getFixingTime(),
                capStandard.isCap(),
                df,
                capStandard.getNotional(),
                capStandard.getPaymentYearFraction());
    double strikePartDelta =
        (1.0 + cap.getFixingAccrualFactor() * capStandard.getStrike())
            * presentValueDeltaStandard(
                forward,
                capStandard.getStrike(),
                capStandard.getFixingTime(),
                capStandard.isCap(),
                df,
                capStandard.getNotional(),
                capStandard.getPaymentYearFraction());

    final InArrearsIntegrant integrant = new InArrearsIntegrant(capStandard, curves);
    double integralPart;
    double upper = 0.0;
    try {
      if (cap.isCap()) {
        double atmVol = _smileFunction.getVolatility(forward);
        upper = forward * Math.exp(6.0 * atmVol * Math.sqrt(cap.getFixingTime()));
        double strike = cap.getStrike();
        integralPart = INTEGRATOR.integrate(integrant, strike, upper);
        double reminder = integrant.evaluate(upper) * upper;
        double error = reminder / integralPart;

        int count = 0;
        while (Math.abs(error) > REL_ERROR && count < MAX_COUNT) {
          integralPart += INTEGRATOR.integrate(integrant, upper, 2.0 * upper);
          upper *= 2.0;
          // The increase of integralPart in the next loop is bounded by reminder
          reminder = integrant.evaluate(upper) * upper;
          error = reminder / integralPart;
          ++count;
          if (count == MAX_COUNT) {
            LOGGER.info(
                "Maximum iteration count, "
                    + MAX_COUNT
                    + ", has been reached. Relative error is greater than "
                    + REL_ERROR);
          }
        }
      } else {
        double strike = cap.getStrike();
        integralPart = INTEGRATOR.integrate(integrant, REL_TOL * strike, strike);
      }
    } catch (final Exception e) {
      throw new MathException(e);
    }
    integralPart *= 2.0 * cap.getFixingAccrualFactor();
    double pv = (strikePart + integralPart) / beta;

    double betaFwd =
        cap.getFixingAccrualFactor()
            * curves.getDiscountFactor(ccy, cap.getFixingPeriodEndTime())
            / curves.getDiscountFactor(ccy, cap.getFixingPeriodStartTime());
    double betaDscStart =
        (1.0 + cap.getFixingAccrualFactor() * forward)
            * curves.getDiscountFactor(ccy, cap.getFixingPeriodEndTime())
            * cap.getFixingPeriodStartTime()
            / curves.getDiscountFactor(ccy, cap.getFixingPeriodStartTime());
    double betaDscEnd =
        -(1.0 + cap.getFixingAccrualFactor() * forward)
            * curves.getDiscountFactor(ccy, cap.getFixingPeriodEndTime())
            * cap.getFixingPeriodEndTime()
            / curves.getDiscountFactor(ccy, cap.getFixingPeriodStartTime());

    List<DoublesPair> listDiscounting = new ArrayList<>();
    double strikePartDsc = -capStandard.getPaymentTime() * strikePart;
    double integralPartDsc = -capStandard.getPaymentTime() * integralPart;
    listDiscounting.add(
        DoublesPair.of(capStandard.getPaymentTime(), (strikePartDsc + integralPartDsc) / beta));
    listDiscounting.add(DoublesPair.of(cap.getFixingPeriodStartTime(), -pv * betaDscStart / beta));
    listDiscounting.add(DoublesPair.of(cap.getFixingPeriodEndTime(), -pv * betaDscEnd / beta));
    Map<String, List<DoublesPair>> mapDsc = new HashMap<>();
    mapDsc.put(curves.getName(capStandard.getCurrency()), listDiscounting);

    final List<ForwardSensitivity> listForward = new ArrayList<>();
    double strikePartFwd = strikePartDelta;
    double integralPartFwd = 0.0;
    final InArrearsDeltaIntegrant integrantFwd = new InArrearsDeltaIntegrant(capStandard, curves);
    try {
      if (cap.isCap()) {
        double strike = cap.getStrike();
        integralPartFwd = INTEGRATOR.integrate(integrantFwd, strike, upper);
      } else {
        double strike = cap.getStrike();
        integralPartFwd = INTEGRATOR.integrate(integrantFwd, REL_TOL * strike, strike);
      }
    } catch (final Exception e) {
      throw new MathException(e);
    }
    integralPartFwd *= 2.0 * cap.getFixingAccrualFactor();
    listForward.add(
        new SimplyCompoundedForwardSensitivity(
            capStandard.getFixingPeriodStartTime(),
            capStandard.getFixingPeriodEndTime(),
            capStandard.getFixingAccrualFactor(),
            (strikePartFwd + integralPartFwd - pv * betaFwd) / beta));
    Map<String, List<ForwardSensitivity>> mapFwd = new HashMap<>();
    mapFwd.put(curves.getName(capStandard.getIndex()), listForward);

    return MultipleCurrencyMulticurveSensitivity.of(
        cap.getCurrency(), MulticurveSensitivity.of(mapDsc, mapFwd));
  }