@Override
  public DoubleMatrix2D evaluate(final DoubleMatrix1D x) {

    YieldCurveBundle curves = _curveBuilderFunction.evaluate(x);

    final YieldCurveBundle knownCurves = _data.getKnownCurves();
    // set any known (i.e. fixed) curves
    if (knownCurves != null) {
      curves.addAll(knownCurves);
    }

    final int totalNodes = _data.getTotalNodes();
    final List<String> curveNames = _data.getCurveNames();

    final double[][] res = new double[_data.getNumInstruments()][totalNodes];
    for (int i = 0; i < _data.getNumInstruments(); i++) { // loop over all instruments
      InstrumentDerivative deriv = _data.getDerivative(i);
      final Map<String, List<DoublesPair>> senseMap =
          _calculator.visit(deriv, curves).getSensitivities();
      int offset = 0;
      for (final String name : curveNames) { // loop over all curves (by name)
        if (senseMap.containsKey(name)) {
          final Curve<Double, Double> curve = curves.getCurve(name).getCurve();
          if (!(curve instanceof InterpolatedDoublesCurve)) {
            throw new IllegalArgumentException("Can only handle InterpolatedDoublesCurve");
          }
          final InterpolatedDoublesCurve interpolatedCurve = (InterpolatedDoublesCurve) curve;
          final Interpolator1DDataBundle data = interpolatedCurve.getDataBundle();
          final Interpolator1D sensitivityCalculator = _data.getInterpolatorForCurve(name);
          final List<DoublesPair> senseList = senseMap.get(name);
          if (senseList.size() != 0) {
            final double[][] sensitivity = new double[senseList.size()][];
            int k = 0;
            for (final DoublesPair timeAndDF : senseList) {
              sensitivity[k++] =
                  sensitivityCalculator.getNodeSensitivitiesForValue(
                      data, timeAndDF.getFirst(), _data.useFiniteDifferenceForNodeSensitivities());
            }
            for (int j = 0; j < sensitivity[0].length; j++) {
              double temp = 0.0;
              k = 0;
              for (final DoublesPair timeAndDF : senseList) {
                temp += timeAndDF.getSecond() * sensitivity[k++][j];
              }
              res[i][j + offset] = temp;
            }
          }
        }
        offset += _data.getCurveNodePointsForCurve(name).length;
      }
    }
    return new DoubleMatrix2D(res);
  }
  @Override
  public Set<ComputedValue> execute(
      final FunctionExecutionContext executionContext,
      final FunctionInputs inputs,
      final ComputationTarget target,
      final Set<ValueRequirement> desiredValues) {
    final ValueRequirement desiredValue = desiredValues.iterator().next();
    final String curveName = desiredValue.getConstraint(ValuePropertyNames.CURVE);
    final String interpolatorName =
        desiredValue.getConstraint(
            ForwardCurveValuePropertyNames.PROPERTY_FORWARD_CURVE_INTERPOLATOR);
    final String leftExtrapolatorName =
        desiredValue.getConstraint(
            ForwardCurveValuePropertyNames.PROPERTY_FORWARD_CURVE_LEFT_EXTRAPOLATOR);
    final String rightExtrapolatorName =
        desiredValue.getConstraint(
            ForwardCurveValuePropertyNames.PROPERTY_FORWARD_CURVE_RIGHT_EXTRAPOLATOR);

    final Object objectFuturePriceData =
        inputs.getValue(ValueRequirementNames.FUTURE_PRICE_CURVE_DATA);
    if (objectFuturePriceData == null) {
      throw new OpenGammaRuntimeException("Could not get futures curve " + curveName);
    }
    final NodalDoublesCurve futurePriceData = (NodalDoublesCurve) objectFuturePriceData;

    final Interpolator1D interpolator =
        CombinedInterpolatorExtrapolatorFactory.getInterpolator(
            interpolatorName, leftExtrapolatorName, rightExtrapolatorName);

    final ForwardCurve curve =
        new ForwardCurve(
            InterpolatedDoublesCurve.from(
                futurePriceData.getXData(), futurePriceData.getYData(), interpolator));

    final ValueProperties properties =
        createValueProperties()
            .with(
                ForwardCurveValuePropertyNames.PROPERTY_FORWARD_CURVE_CALCULATION_METHOD,
                ForwardCurveValuePropertyNames.PROPERTY_FUTURE_PRICE_METHOD)
            .with(ValuePropertyNames.CURVE, curveName)
            .with(
                ForwardCurveValuePropertyNames.PROPERTY_FORWARD_CURVE_INTERPOLATOR,
                interpolatorName)
            .with(
                ForwardCurveValuePropertyNames.PROPERTY_FORWARD_CURVE_LEFT_EXTRAPOLATOR,
                leftExtrapolatorName)
            .with(
                ForwardCurveValuePropertyNames.PROPERTY_FORWARD_CURVE_RIGHT_EXTRAPOLATOR,
                rightExtrapolatorName)
            .with(
                InstrumentTypeProperties.PROPERTY_SURFACE_INSTRUMENT_TYPE,
                InstrumentTypeProperties.EQUITY_FUTURE_PRICE)
            .get();

    final ValueSpecification resultSpec =
        new ValueSpecification(
            ValueRequirementNames.FORWARD_CURVE, target.toSpecification(), properties);
    return Collections.singleton(new ComputedValue(resultSpec, curve));
  }
Example #3
0
 // Test in so that it will break when the drift curve is serialized
 @Test(expectedExceptions = OpenGammaRuntimeException.class)
 public void testDriftCurveNotSerialized1() {
   final double spot = 100;
   final Curve<Double, Double> driftCurve =
       InterpolatedDoublesCurve.from(EXPIRIES, FORWARD, INTERPOLATOR);
   final ForwardCurve curve = new ForwardCurve(spot, driftCurve);
   cycleObject(ForwardCurve.class, curve);
 }
Example #4
0
 @Test
 public void testCurve2() {
   final ForwardCurve curve1 =
       new ForwardCurve(InterpolatedDoublesCurve.from(EXPIRIES, FORWARD, INTERPOLATOR));
   final ForwardCurve curve2 = cycleObject(ForwardCurve.class, curve1);
   assertEquals(curve1.getSpot(), curve2.getSpot(), EPS);
   assertTrue(curve2.getDriftCurve() instanceof FunctionalDoublesCurve);
   assertCurveEquals(curve1.getForwardCurve(), curve2.getForwardCurve());
   assertCurveEquals(curve1.getDriftCurve(), curve2.getDriftCurve());
 }
Example #5
0
  public static YieldCurveBundle getBundle() {
    YieldCurveBundle bundle = new YieldCurveBundle();

    Interpolator1D extrapolator =
        CombinedInterpolatorExtrapolatorFactory.getInterpolator(
            Interpolator1DFactory.DOUBLE_QUADRATIC, LINEAR_EXTRAPOLATOR, FLAT_EXTRAPOLATOR);

    InterpolatedDoublesCurve fCurve =
        InterpolatedDoublesCurve.from(FUNDING_CURVE_TIMES, FUNDING_YIELDS, extrapolator);
    YieldCurve fundingCurve = YieldCurve.from(fCurve);
    bundle.setCurve(FUNDING_CURVE_NAME, fundingCurve);

    InterpolatedDoublesCurve lcurve =
        InterpolatedDoublesCurve.from(LIBOR_CURVE_TIMES, LIBOR_YIELDS, extrapolator);
    YieldCurve liborCurve = YieldCurve.from(lcurve);
    bundle.setCurve(LIBOR_CURVE_NAME, liborCurve);

    return bundle;
  }
 @Override
 protected Object getResult(
     final PDELocalVolatilityCalculator<?> calculator,
     final LocalVolatilitySurfaceMoneyness localVolatility,
     final ForwardCurve forwardCurve,
     final EuropeanVanillaOption option,
     final YieldAndDiscountCurve discountingCurve) {
   final Interpolator1DDataBundle data =
       (Interpolator1DDataBundle)
           calculator.getResult(localVolatility, forwardCurve, option, discountingCurve);
   return InterpolatedDoublesCurve.from(
       data.getKeys(),
       data.getValues(),
       ((LocalVolatilityForwardPDEVolatilityGreeksGridCalculator) calculator).getInterpolator());
 }
  @Test
  public void convertNonEmpty() {
    final Map<Double, Double> map = new HashMap<Double, Double>();
    map.put(1., 0.03);
    map.put(2., 0.04);
    map.put(3.5, 0.05);

    Map<String, Double> expected = new HashMap<String, Double>();
    expected.put("Foo[1.0]", 0.03);
    expected.put("Foo[2.0]", 0.04);
    expected.put("Foo[3.5]", 0.05);

    Map<String, Double> actual =
        _converter.convert(
            "Foo",
            YieldCurve.from(
                InterpolatedDoublesCurve.from(
                    map, Interpolator1DFactory.getInterpolator("Linear"))));

    assertEquals(expected, actual);
  }
Example #8
0
  public void test() throws Exception {
    IRSwapTradeParser tradeParser = new IRSwapTradeParser();
    Resource resource =
        ResourceUtils.createResource(
            "classpath:com/opengamma/financial/analytics/test/Trades14Oct.csv");
    List<IRSwapSecurity> trades = tradeParser.parseCSVFile(resource.getURL());
    List<IRSwapSecurity> tradesClean = Lists.newArrayList();
    for (IRSwapSecurity irSwapSecurity : trades) {

      String currency = irSwapSecurity.getRawInput().getString(PAY_CURRENCY);
      if (currency.equals(CURRENCY)) {
        tradesClean.add(irSwapSecurity);
      }
    }
    // Build the curve bundle
    final HashMap<String, Currency> ccyMap = new HashMap<>();
    ccyMap.put(discountingCurvename, ccy);
    ccyMap.put(forward3MCurveName, ccy);
    ccyMap.put(forward6MCurveName, ccy);
    final FXMatrix fx = new FXMatrix(ccy);
    final YieldCurveBundle curvesClean = new YieldCurveBundle(fx, ccyMap);

    IRCurveParser curveParser = new IRCurveParser();
    Resource resourceCurve =
        ResourceUtils.createResource(
            "classpath:com/opengamma/financial/analytics/test/Base_Curves_20131014_Clean.csv");
    List<InterpolatedDoublesCurve> curves = curveParser.parseCSVFile(resourceCurve.getURL());

    for (InterpolatedDoublesCurve interpolatedDoublesCurve : curves) {

      String name = interpolatedDoublesCurve.getName();
      if (name.equals(ON_NAME)) {
        curvesClean.setCurve(discountingCurvename, DiscountCurve.from(interpolatedDoublesCurve));
      }
      if (name.equals(ONE_MONTH_NAME)) {
        curvesClean.setCurve(forward1MCurveName, DiscountCurve.from(interpolatedDoublesCurve));
      }
      if (name.equals(THREE_MONTH_NAME)) {
        curvesClean.setCurve(forward3MCurveName, DiscountCurve.from(interpolatedDoublesCurve));
      }
      if (name.equals(SIX_MONTH_NAME)) {
        curvesClean.setCurve(forward6MCurveName, DiscountCurve.from(interpolatedDoublesCurve));
      }
    }

    // Convert the swap security into a swap definition
    final SwapSecurityConverterDeprecated swapConverter =
        new SwapSecurityConverterDeprecated(
            _holidaySource, _conventionBundleSource, _regionSource, false);
    final FRASecurityConverterDeprecated fraConverter =
        new FRASecurityConverterDeprecated(_holidaySource, _regionSource, _conventionBundleSource);
    final ZeroDepositConverter ZeroCouponConverter =
        new ZeroDepositConverter(_conventionBundleSource, _holidaySource);
    List<SwapDefinition> swapsDefinition = Lists.newArrayList();
    List<ForwardRateAgreementDefinition> frasDefinition = Lists.newArrayList();
    List<DepositZeroDefinition> zcsDefinition = Lists.newArrayList();
    /*for (IRSwapSecurity irSwapSecurity : tradesClean) {
      switch (irSwapSecurity.getRawInput().getString("PRODUCT_TYPE")) {
        case "SWAP":
          swapsDefinition.add((SwapDefinition) swapConverter.visitSwapSecurity(irSwapSecurity.getSwapSecurity()));

          // we don't treat the fra case at the moment
          case "FRA":
            frasDefinition.add((ForwardRateAgreementDefinition) fraConverter.visitSwapSecurity(irSwapSecurity.getSwapSecurity()));
          case "OIS":
            swapsDefinition.add((SwapDefinition) swapConverter.visitSwapSecurity(irSwapSecurity.getSwapSecurity()));

          // we don't treat the fra case at the moment
           case "ZCS":
             zcsDefinition.add((DepositZeroDefinition) ZeroCouponConverter.visitSwapSecurity(irSwapSecurity.getSwapSecurity()));
      }
    }
    */
    // Load the historical time series from a csv file

    /* NonVersionedRedisHistoricalTimeSeriesSource source = new NonVersionedRedisHistoricalTimeSeriesSource(getJedisPool(), getRedisPrefix());
    CMECurveFixingTSLoader loader = new CMECurveFixingTSLoader(source);*/
    /*  loader.loadCurveFixingCSVFile("/vols/ogdev/CME/curve-fixing/sample-cme-curve-fixing.csv");

    HistoricalTimeSeries historicalTimeSeries = source.getHistoricalTimeSeries(UniqueId.of(ExternalSchemes.ISDA.getName(), "CHF-LIBOR-BBA-6M"));
    assertNotNull(historicalTimeSeries);
    LocalDateDoubleTimeSeries timeSeries = historicalTimeSeries.getTimeSeries();
    assertNotNull(timeSeries);
    assertEquals(5996, timeSeries.size());*/

    // convert the definition into a derivative
    /*   List<Swap> swapDerivatives = Lists.newArrayList();
    for (SwapDefinition swapDefinition : swapsDefinition) {
      swapDerivatives.add(swapDefinition.toDerivative(TODAY, data, curvesClean));
    }
    List<Swap> frasDerivatives = Lists.newArrayList();
    for (ForwardRateAgreementDefinition fraDefinition : frasDefinition) {
      frasDerivatives.add(fraDefinition.toDerivative(TODAY, data, curvesClean));
    }
    List<Swap> zcsDerivatives = Lists.newArrayList();
    for (DepositZeroDefinition zcDefinition : zcsDefinition) {
      zcsDerivatives.add(zcDefinition.toDerivative(TODAY, data, curvesClean));
    }*/

    // Check the npv

    s_logger.warn("Got {} trades", trades.size());
  }
 /**
  * Compute the sensitivity by finite difference on all points. The curves must be interpolated
  * yield curves. Only the discounting and forward curves sensitivity is computed.
  *
  * @param instrument The instrument.
  * @param hwcurves The provider: all discounting, forward and issuer curves should be of the type
  *     YieldCurve with InterpolatedDoublesCurve.
  * @return The parameter sensitivity.
  */
 public SimpleParameterSensitivity calculateSensitivity(
     final InstrumentDerivative instrument, final HullWhiteOneFactorProviderDiscount hwcurves) {
   SimpleParameterSensitivity result = new SimpleParameterSensitivity();
   // Discounting
   final Set<Currency> ccyDiscounting = hwcurves.getMulticurveProvider().getCurrencies();
   for (final Currency ccy : ccyDiscounting) {
     final YieldAndDiscountCurve curve = hwcurves.getMulticurveProvider().getCurve(ccy);
     ArgChecker.isTrue(curve instanceof YieldCurve, "Curve should be a YieldCurve");
     final YieldCurve curveYield = (YieldCurve) curve;
     ArgChecker.isTrue(
         curveYield.getCurve() instanceof InterpolatedDoublesCurve,
         "Yield curve should be based on InterpolatedDoublesCurve");
     final InterpolatedDoublesCurve curveInt = (InterpolatedDoublesCurve) curveYield.getCurve();
     final int nbNodePoint = curveInt.getXDataAsPrimitive().length;
     final double[] sensitivity = new double[nbNodePoint];
     for (int loopnode = 0; loopnode < nbNodePoint; loopnode++) {
       final double[] yieldBumpedPlus = curveInt.getYDataAsPrimitive().clone();
       yieldBumpedPlus[loopnode] += _shift;
       final YieldAndDiscountCurve dscBumpedPlus =
           new YieldCurve(
               curveInt.getName(),
               new InterpolatedDoublesCurve(
                   curveInt.getXDataAsPrimitive(),
                   yieldBumpedPlus,
                   curveInt.getInterpolator(),
                   true));
       final HullWhiteOneFactorProviderDiscount marketDscBumpedPlus =
           new HullWhiteOneFactorProviderDiscount(
               hwcurves.getMulticurveProvider().withDiscountFactor(ccy, dscBumpedPlus),
               hwcurves.getHullWhiteParameters(),
               hwcurves.getHullWhiteCurrency());
       final double valueBumpedPlus = instrument.accept(_valueCalculator, marketDscBumpedPlus);
       final double[] yieldBumpedMinus = curveInt.getYDataAsPrimitive().clone();
       yieldBumpedMinus[loopnode] -= _shift;
       final YieldAndDiscountCurve dscBumpedMinus =
           new YieldCurve(
               curveInt.getName(),
               new InterpolatedDoublesCurve(
                   curveInt.getXDataAsPrimitive(),
                   yieldBumpedMinus,
                   curveInt.getInterpolator(),
                   true));
       final HullWhiteOneFactorProviderDiscount marketDscBumpedMinus =
           new HullWhiteOneFactorProviderDiscount(
               hwcurves.getMulticurveProvider().withDiscountFactor(ccy, dscBumpedMinus),
               hwcurves.getHullWhiteParameters(),
               hwcurves.getHullWhiteCurrency());
       final double valueBumpedMinus = instrument.accept(_valueCalculator, marketDscBumpedMinus);
       sensitivity[loopnode] = (valueBumpedPlus - valueBumpedMinus) / (2 * _shift);
     }
     final String name = hwcurves.getMulticurveProvider().getName(ccy);
     result = result.plus(name, new DoubleMatrix1D(sensitivity));
   }
   // Forward ON
   final Set<IndexON> indexON = hwcurves.getMulticurveProvider().getIndexesON();
   for (final IndexON index : indexON) {
     final YieldAndDiscountCurve curve = hwcurves.getMulticurveProvider().getCurve(index);
     ArgChecker.isTrue(curve instanceof YieldCurve, "Curve should be a YieldCurve");
     final YieldCurve curveYield = (YieldCurve) curve;
     ArgChecker.isTrue(
         curveYield.getCurve() instanceof InterpolatedDoublesCurve,
         "Yield curve should be based on InterpolatedDoublesCurve");
     final InterpolatedDoublesCurve curveInt = (InterpolatedDoublesCurve) curveYield.getCurve();
     final int nbNodePoint = curveInt.getXDataAsPrimitive().length;
     final double[] sensitivity = new double[nbNodePoint];
     for (int loopnode = 0; loopnode < nbNodePoint; loopnode++) {
       final double[] yieldBumpedPlus = curveInt.getYDataAsPrimitive().clone();
       yieldBumpedPlus[loopnode] += _shift;
       final YieldAndDiscountCurve dscBumpedPlus =
           new YieldCurve(
               curveInt.getName(),
               new InterpolatedDoublesCurve(
                   curveInt.getXDataAsPrimitive(),
                   yieldBumpedPlus,
                   curveInt.getInterpolator(),
                   true));
       final HullWhiteOneFactorProviderDiscount marketFwdBumpedPlus =
           new HullWhiteOneFactorProviderDiscount(
               hwcurves.getMulticurveProvider().withForward(index, dscBumpedPlus),
               hwcurves.getHullWhiteParameters(),
               hwcurves.getHullWhiteCurrency());
       final double valueBumpedPlus = instrument.accept(_valueCalculator, marketFwdBumpedPlus);
       final double[] yieldBumpedMinus = curveInt.getYDataAsPrimitive().clone();
       yieldBumpedMinus[loopnode] -= _shift;
       final YieldAndDiscountCurve dscBumpedMinus =
           new YieldCurve(
               curveInt.getName(),
               new InterpolatedDoublesCurve(
                   curveInt.getXDataAsPrimitive(),
                   yieldBumpedMinus,
                   curveInt.getInterpolator(),
                   true));
       final HullWhiteOneFactorProviderDiscount marketFwdBumpedMinus =
           new HullWhiteOneFactorProviderDiscount(
               hwcurves.getMulticurveProvider().withForward(index, dscBumpedMinus),
               hwcurves.getHullWhiteParameters(),
               hwcurves.getHullWhiteCurrency());
       final double valueBumpedMinus = instrument.accept(_valueCalculator, marketFwdBumpedMinus);
       sensitivity[loopnode] = (valueBumpedPlus - valueBumpedMinus) / (2 * _shift);
     }
     final String name = hwcurves.getMulticurveProvider().getName(index);
     result = result.plus(name, new DoubleMatrix1D(sensitivity));
   }
   // Forward Ibor - symmetrical
   final Set<IborIndex> indexForward = hwcurves.getMulticurveProvider().getIndexesIbor();
   for (final IborIndex index : indexForward) {
     final YieldAndDiscountCurve curve = hwcurves.getMulticurveProvider().getCurve(index);
     ArgChecker.isTrue(curve instanceof YieldCurve, "Curve should be a YieldCurve");
     final YieldCurve curveYield = (YieldCurve) curve;
     ArgChecker.isTrue(
         curveYield.getCurve() instanceof InterpolatedDoublesCurve,
         "Yield curve should be based on InterpolatedDoublesCurve");
     final InterpolatedDoublesCurve curveInt = (InterpolatedDoublesCurve) curveYield.getCurve();
     final int nbNodePoint = curveInt.getXDataAsPrimitive().length;
     final double[] sensitivity = new double[nbNodePoint];
     for (int loopnode = 0; loopnode < nbNodePoint; loopnode++) {
       final double[] yieldBumpedPlus = curveInt.getYDataAsPrimitive().clone();
       yieldBumpedPlus[loopnode] += _shift;
       final YieldAndDiscountCurve dscBumpedPlus =
           new YieldCurve(
               curveInt.getName(),
               new InterpolatedDoublesCurve(
                   curveInt.getXDataAsPrimitive(),
                   yieldBumpedPlus,
                   curveInt.getInterpolator(),
                   true));
       final HullWhiteOneFactorProviderDiscount marketFwdBumpedPlus =
           new HullWhiteOneFactorProviderDiscount(
               hwcurves.getMulticurveProvider().withForward(index, dscBumpedPlus),
               hwcurves.getHullWhiteParameters(),
               hwcurves.getHullWhiteCurrency());
       final double valueBumpedPlus = instrument.accept(_valueCalculator, marketFwdBumpedPlus);
       final double[] yieldBumpedMinus = curveInt.getYDataAsPrimitive().clone();
       yieldBumpedMinus[loopnode] -= _shift;
       final YieldAndDiscountCurve dscBumpedMinus =
           new YieldCurve(
               curveInt.getName(),
               new InterpolatedDoublesCurve(
                   curveInt.getXDataAsPrimitive(),
                   yieldBumpedMinus,
                   curveInt.getInterpolator(),
                   true));
       final HullWhiteOneFactorProviderDiscount marketFwdBumpedMinus =
           new HullWhiteOneFactorProviderDiscount(
               hwcurves.getMulticurveProvider().withForward(index, dscBumpedMinus),
               hwcurves.getHullWhiteParameters(),
               hwcurves.getHullWhiteCurrency());
       final double valueBumpedMinus = instrument.accept(_valueCalculator, marketFwdBumpedMinus);
       sensitivity[loopnode] = (valueBumpedPlus - valueBumpedMinus) / (2 * _shift);
     }
     final String name = hwcurves.getMulticurveProvider().getName(index);
     result = result.plus(name, new DoubleMatrix1D(sensitivity));
   }
   return result;
 }
  @Test
  public void curveSensitivityFRA() {
    final YieldCurveBundle curves = TestsDataSetsSABR.createCurves1();
    final double deltaShift = 1.0E-8;
    final double pv = FRA_METHOD.presentValue(FRA, curves).getAmount();
    // 1. Forward curve sensitivity
    final String bumpedCurveName = "Bumped Curve";
    final String[] bumpedCurvesForwardName = {FUNDING_CURVE_NAME, bumpedCurveName};
    final ForwardRateAgreement fraBumpedForward =
        (ForwardRateAgreement) FRA_DEFINITION.toDerivative(REFERENCE_DATE, bumpedCurvesForwardName);
    final YieldAndDiscountCurve curveForward = curves.getCurve(FORWARD_CURVE_NAME);
    final double[] timeForward = new double[2];
    timeForward[0] = FRA.getFixingPeriodStartTime();
    timeForward[1] = FRA.getFixingPeriodEndTime();
    final int nbForwardDate = timeForward.length;
    final double[] yieldsForward = new double[nbForwardDate + 1];
    final double[] nodeTimesForward = new double[nbForwardDate + 1];
    yieldsForward[0] = curveForward.getInterestRate(0.0);
    for (int i = 0; i < nbForwardDate; i++) {
      nodeTimesForward[i + 1] = timeForward[i];
      yieldsForward[i + 1] = curveForward.getInterestRate(nodeTimesForward[i + 1]);
    }
    final YieldAndDiscountCurve tempCurveForward =
        YieldCurve.from(
            InterpolatedDoublesCurve.fromSorted(
                nodeTimesForward, yieldsForward, new LinearInterpolator1D()));
    final double[] sensiPvForwardFD = new double[nbForwardDate];
    for (int i = 0; i < nbForwardDate; i++) {
      final YieldAndDiscountCurve bumpedCurveForward =
          tempCurveForward.withSingleShift(nodeTimesForward[i + 1], deltaShift);
      final YieldCurveBundle curvesBumpedForward = new YieldCurveBundle();
      curvesBumpedForward.addAll(curves);
      curvesBumpedForward.setCurve("Bumped Curve", bumpedCurveForward);
      final double bumpedPv =
          FRA_METHOD.presentValue(fraBumpedForward, curvesBumpedForward).getAmount();
      sensiPvForwardFD[i] = (bumpedPv - pv) / deltaShift;
    }

    final double[] nodeTimesForwardMethod =
        new double[] {FRA.getFixingPeriodStartTime(), FRA.getFixingPeriodEndTime()};
    final double[] sensiForwardMethod =
        SensitivityFiniteDifference.curveSensitivity(
            fraBumpedForward,
            curves,
            pv,
            FORWARD_CURVE_NAME,
            bumpedCurveName,
            nodeTimesForwardMethod,
            deltaShift,
            FRA_METHOD);
    assertEquals(
        "Sensitivity finite difference method: number of node", 2, sensiForwardMethod.length);
    for (int loopnode = 0; loopnode < sensiForwardMethod.length; loopnode++) {
      assertEquals(
          "Sensitivity finite difference method: node sensitivity",
          sensiPvForwardFD[loopnode],
          sensiForwardMethod[loopnode]);
    }

    // 2. Funding curve sensitivity
    final String[] bumpedCurvesFundingName = {bumpedCurveName, FORWARD_CURVE_NAME};
    final ForwardRateAgreement fraBumped =
        (ForwardRateAgreement) FRA_DEFINITION.toDerivative(REFERENCE_DATE, bumpedCurvesFundingName);
    final YieldAndDiscountCurve curveFunding = curves.getCurve(FUNDING_CURVE_NAME);
    final double[] yieldsFunding = new double[2];
    final double[] nodeTimesFunding = new double[2];
    yieldsFunding[0] = curveFunding.getInterestRate(0.0);
    nodeTimesFunding[1] = FRA.getPaymentTime();
    yieldsFunding[1] = curveFunding.getInterestRate(nodeTimesFunding[1]);
    final YieldAndDiscountCurve tempCurveFunding =
        YieldCurve.from(
            InterpolatedDoublesCurve.fromSorted(
                nodeTimesFunding, yieldsFunding, new LinearInterpolator1D()));
    final YieldAndDiscountCurve bumpedCurve =
        tempCurveFunding.withSingleShift(nodeTimesFunding[1], deltaShift);
    final YieldCurveBundle curvesBumped = new YieldCurveBundle();
    curvesBumped.addAll(curves);
    curvesBumped.replaceCurve("Bumped Curve", bumpedCurve);
    final double bumpedPvDsc = FRA_METHOD.presentValue(fraBumped, curvesBumped).getAmount();
    final double[] resDsc = new double[1];
    resDsc[0] = (bumpedPvDsc - pv) / deltaShift;

    final double[] nodeTimesFundingMethod = new double[] {FRA.getPaymentTime()};
    final double[] sensiFundingMethod =
        SensitivityFiniteDifference.curveSensitivity(
            fraBumped,
            curves,
            pv,
            FUNDING_CURVE_NAME,
            bumpedCurveName,
            nodeTimesFundingMethod,
            deltaShift,
            FRA_METHOD);
    assertEquals(
        "Sensitivity finite difference method: number of node", 1, sensiFundingMethod.length);
    for (int loopnode = 0; loopnode < sensiFundingMethod.length; loopnode++) {
      assertEquals(
          "Sensitivity finite difference method: node sensitivity",
          resDsc[loopnode],
          sensiFundingMethod[loopnode]);
    }
  }
    @Override
    public Set<ComputedValue> execute(
        final FunctionExecutionContext executionContext,
        final FunctionInputs inputs,
        final ComputationTarget target,
        final Set<ValueRequirement> desiredValues)
        throws AsynchronousExecution {
      final Object originalCurveObject = inputs.getValue(YIELD_CURVE);
      if (originalCurveObject == null) {
        throw new OpenGammaRuntimeException("Could not get original curve");
      }
      ValueProperties resultCurveProperties = null;
      String absoluteToleranceName = null;
      String relativeToleranceName = null;
      String iterationsName = null;
      String decompositionName = null;
      String useFiniteDifferenceName = null;
      for (final ValueRequirement desiredValue : desiredValues) {
        if (desiredValue.getValueName().equals(YIELD_CURVE)) {
          absoluteToleranceName =
              desiredValue.getConstraint(
                  MultiYieldCurvePropertiesAndDefaults.PROPERTY_ROOT_FINDER_ABSOLUTE_TOLERANCE);
          relativeToleranceName =
              desiredValue.getConstraint(
                  MultiYieldCurvePropertiesAndDefaults.PROPERTY_ROOT_FINDER_RELATIVE_TOLERANCE);
          iterationsName =
              desiredValue.getConstraint(
                  MultiYieldCurvePropertiesAndDefaults.PROPERTY_ROOT_FINDER_MAX_ITERATIONS);
          decompositionName =
              desiredValue.getConstraint(
                  MultiYieldCurvePropertiesAndDefaults.PROPERTY_DECOMPOSITION);
          useFiniteDifferenceName =
              desiredValue.getConstraint(
                  MultiYieldCurvePropertiesAndDefaults.PROPERTY_USE_FINITE_DIFFERENCE);
          resultCurveProperties = desiredValue.getConstraints().copy().get();
          break;
        }
      }
      if (resultCurveProperties == null) {
        throw new OpenGammaRuntimeException("Could not get result curve properties");
      }
      final ValueProperties resultJacobianProperties = resultCurveProperties.withoutAny(CURVE);
      ZonedDateTime valuationDateTime =
          executionContext
              .getValuationTime()
              .atZone(executionContext.getValuationClock().getZone());
      final HolidaySource holidaySource =
          OpenGammaExecutionContext.getHolidaySource(executionContext);
      final ConventionSource conventionSource =
          OpenGammaExecutionContext.getConventionSource(executionContext);
      final Calendar calendar = CalendarUtils.getCalendar(holidaySource, _currency);
      final DepositConvention convention =
          conventionSource.getSingle(
              ExternalId.of(SCHEME_NAME, getConventionName(_currency, DEPOSIT)),
              DepositConvention.class);
      final int spotLag = convention.getSettlementDays();
      final ExternalId conventionSettlementRegion = convention.getRegionCalendar();
      ZonedDateTime spotDate;
      if (spotLag == 0 && conventionSettlementRegion == null) {
        spotDate = valuationDateTime;
      } else {
        spotDate = ScheduleCalculator.getAdjustedDate(valuationDateTime, spotLag, calendar);
        ;
      }
      final YieldCurveBundle curves = new YieldCurveBundle();
      final String fullYieldCurveName = _originalCurveName + "_" + _currency;
      curves.setCurve(fullYieldCurveName, (YieldAndDiscountCurve) originalCurveObject);
      final int n = _impliedDefinition.getStrips().size();
      final double[] t = new double[n];
      final double[] r = new double[n];
      int i = 0;
      final DayCount dayCount =
          DayCountFactory.INSTANCE.getDayCount(
              "Act/360"); // TODO: Get the convention from the curve.

      final String impliedDepositCurveName = _curveCalculationConfig + "_" + _currency.getCode();
      final List<InstrumentDerivative> derivatives = new ArrayList<>();

      for (final FixedIncomeStrip strip : _impliedDefinition.getStrips()) {
        final Tenor tenor = strip.getCurveNodePointTime();
        final ZonedDateTime paymentDate =
            ScheduleCalculator.getAdjustedDate(
                spotDate, tenor.getPeriod(), MOD_FOL, calendar, true);
        final double startTime = TimeCalculator.getTimeBetween(valuationDateTime, spotDate);
        final double endTime = TimeCalculator.getTimeBetween(valuationDateTime, paymentDate);
        final double accrualFactor = dayCount.getDayCountFraction(spotDate, paymentDate, calendar);
        final Cash cashFXCurve =
            new Cash(_currency, startTime, endTime, 1, 0, accrualFactor, fullYieldCurveName);
        final double parRate = METHOD_CASH.parRate(cashFXCurve, curves);
        final Cash cashDepositCurve =
            new Cash(_currency, startTime, endTime, 1, 0, accrualFactor, impliedDepositCurveName);
        derivatives.add(cashDepositCurve);
        t[i] = endTime;
        r[i++] = parRate;
      }
      final CombinedInterpolatorExtrapolator interpolator =
          CombinedInterpolatorExtrapolatorFactory.getInterpolator(
              _interpolatorName, _leftExtrapolatorName, _rightExtrapolatorName);
      final double absoluteTolerance = Double.parseDouble(absoluteToleranceName);
      final double relativeTolerance = Double.parseDouble(relativeToleranceName);
      final int iterations = Integer.parseInt(iterationsName);
      final Decomposition<?> decomposition =
          DecompositionFactory.getDecomposition(decompositionName);
      final boolean useFiniteDifference = Boolean.parseBoolean(useFiniteDifferenceName);
      final LinkedHashMap<String, double[]> curveNodes = new LinkedHashMap<>();
      final LinkedHashMap<String, Interpolator1D> interpolators = new LinkedHashMap<>();
      curveNodes.put(impliedDepositCurveName, t);
      interpolators.put(impliedDepositCurveName, interpolator);
      final FXMatrix fxMatrix = new FXMatrix();
      final YieldCurveBundle knownCurve = new YieldCurveBundle();
      final MultipleYieldCurveFinderDataBundle data =
          new MultipleYieldCurveFinderDataBundle(
              derivatives, r, knownCurve, curveNodes, interpolators, useFiniteDifference, fxMatrix);
      final NewtonVectorRootFinder rootFinder =
          new BroydenVectorRootFinder(
              absoluteTolerance, relativeTolerance, iterations, decomposition);
      final Function1D<DoubleMatrix1D, DoubleMatrix1D> curveCalculator =
          new MultipleYieldCurveFinderFunction(data, PAR_RATE_CALCULATOR);
      final Function1D<DoubleMatrix1D, DoubleMatrix2D> jacobianCalculator =
          new MultipleYieldCurveFinderJacobian(data, PAR_RATE_SENSITIVITY_CALCULATOR);
      final double[] fittedYields =
          rootFinder.getRoot(curveCalculator, jacobianCalculator, new DoubleMatrix1D(r)).getData();
      final DoubleMatrix2D jacobianMatrix =
          jacobianCalculator.evaluate(new DoubleMatrix1D(fittedYields));
      final YieldCurve impliedDepositCurve =
          new YieldCurve(
              impliedDepositCurveName,
              InterpolatedDoublesCurve.from(t, fittedYields, interpolator));
      final ValueSpecification curveSpec =
          new ValueSpecification(YIELD_CURVE, target.toSpecification(), resultCurveProperties);
      final ValueSpecification jacobianSpec =
          new ValueSpecification(
              YIELD_CURVE_JACOBIAN, target.toSpecification(), resultJacobianProperties);
      return Sets.newHashSet(
          new ComputedValue(curveSpec, impliedDepositCurve),
          new ComputedValue(jacobianSpec, jacobianMatrix));
    }