/// <summary>
	  /// Test present value sensitivity for AFMA FRA discounting method.
	  /// </summary>
	  public virtual void test_presentValueSensitivity_AFMA()
	  {
		RateComputationFn<RateComputation> mockObs = mock(typeof(RateComputationFn));
		DiscountFactors mockDf = mock(typeof(DiscountFactors));
		SimpleRatesProvider simpleProv = new SimpleRatesProvider(VAL_DATE, mockDf);

		ResolvedFra fraExp = RFRA_AFMA;
		double forwardRate = 0.05;
		double discountRate = 0.025;
		double paymentTime = 0.3;
		double discountFactor = Math.Exp(-discountRate * paymentTime);
		LocalDate fixingDate = FRA_AFMA.StartDate;
		IborIndexObservation obs = IborIndexObservation.of(FRA.Index, fixingDate, REF_DATA);
		PointSensitivityBuilder sens = IborRateSensitivity.of(obs, 1d);
		when(mockDf.discountFactor(fraExp.PaymentDate)).thenReturn(discountFactor);
		when(mockDf.zeroRatePointSensitivity(fraExp.PaymentDate)).thenReturn(ZeroRateSensitivity.of(fraExp.Currency, paymentTime, -discountFactor * paymentTime));
		when(mockObs.rateSensitivity(fraExp.FloatingRate, fraExp.StartDate, fraExp.EndDate, simpleProv)).thenReturn(sens);
		when(mockObs.rate(fraExp.FloatingRate, FRA_AFMA.StartDate, FRA_AFMA.EndDate, simpleProv)).thenReturn(forwardRate);
		DiscountingFraProductPricer test = new DiscountingFraProductPricer(mockObs);
		PointSensitivities sensitivity = test.presentValueSensitivity(fraExp, simpleProv);
		double eps = 1.e-7;
		double fdDscSense = dscSensitivity(RFRA_AFMA, forwardRate, discountFactor, paymentTime, eps);
		double fdSense = presentValueFwdSensitivity(RFRA_AFMA, forwardRate, discountFactor, eps);

		ImmutableList<PointSensitivity> sensitivities = sensitivity.Sensitivities;
		assertEquals(sensitivities.size(), 2);
		IborRateSensitivity sensitivity0 = (IborRateSensitivity) sensitivities.get(0);
		assertEquals(sensitivity0.Index, FRA_AFMA.Index);
		assertEquals(sensitivity0.Observation.FixingDate, fixingDate);
		assertEquals(sensitivity0.Sensitivity, fdSense, FRA_AFMA.Notional * eps);
		ZeroRateSensitivity sensitivity1 = (ZeroRateSensitivity) sensitivities.get(1);
		assertEquals(sensitivity1.Currency, FRA_AFMA.Currency);
		assertEquals(sensitivity1.YearFraction, paymentTime);
		assertEquals(sensitivity1.Sensitivity, fdDscSense, FRA_AFMA.Notional * eps);
	  }
        // calculate the last fixing date
        private LocalDate calculateLastFixingDate(LocalDate valuationDate, ReferenceData refData)
        {
            FraTrade    trade       = template.createTrade(valuationDate, BuySell.BUY, 1, 1, refData);
            ResolvedFra resolvedFra = trade.Product.resolve(refData);

            return(((IborRateComputation)resolvedFra.FloatingRate).FixingDate);
        }
        // calculate the end date
        private LocalDate calculateEnd(LocalDate valuationDate, ReferenceData refData)
        {
            FraTrade    trade       = template.createTrade(valuationDate, BuySell.BUY, 1, 1, refData);
            ResolvedFra resolvedFra = trade.Product.resolve(refData);

            return(resolvedFra.EndDate);
        }
	  //-------------------------------------------------------------------------
	  // creates a simple provider
	  private SimpleRatesProvider createProvider(ResolvedFra fraExp)
	  {
		DiscountFactors mockDf = SimpleDiscountFactors.of(GBP, VAL_DATE, ConstantCurve.of(Curves.discountFactors("DSC", DAY_COUNT), DISCOUNT_FACTOR));
		LocalDateDoubleTimeSeries timeSeries = LocalDateDoubleTimeSeries.of(VAL_DATE, FORWARD_RATE);
		IborIndexRates mockIbor = SimpleIborIndexRates.of(GBP_LIBOR_3M, VAL_DATE, ConstantCurve.of(Curves.forwardRates("L3M", DAY_COUNT), FORWARD_RATE), timeSeries);
		SimpleRatesProvider prov = new SimpleRatesProvider(VAL_DATE, mockDf);
		prov.IborRates = mockIbor;
		return prov;
	  }
	  /// <summary>
	  /// Test FRA paying in the past.
	  /// </summary>
	  public virtual void test_presentValue_inPast()
	  {
		ResolvedFra fra = RFRA.toBuilder().paymentDate(VAL_DATE.minusDays(1)).build();
		SimpleRatesProvider prov = createProvider(fra);

		DiscountingFraProductPricer test = DiscountingFraProductPricer.DEFAULT;
		CurrencyAmount computed = test.presentValue(fra, prov);
		assertEquals(computed.Amount, 0d, TOLERANCE);
	  }
	  /// <summary>
	  /// Test par spread for AFMA FRA Discounting method.
	  /// </summary>
	  public virtual void test_parSpread_AFMA()
	  {
		ResolvedFra fraExp = RFRA_AFMA;
		SimpleRatesProvider prov = createProvider(fraExp);

		DiscountingFraProductPricer test = DiscountingFraProductPricer.DEFAULT;
		double parSpread = test.parSpread(fraExp, prov);
		ResolvedFra fra = createNewFra(FRA_AFMA, FRA_AFMA.FixedRate + parSpread);
		CurrencyAmount pv = test.presentValue(fra, prov);
		assertEquals(pv.Amount, 0.0, TOLERANCE);
	  }
	  //-------------------------------------------------------------------------
	  private double forecastValueFwdSensitivity(ResolvedFra fra, double forwardRate, double eps)
	  {

		RateComputationFn<RateComputation> obsFuncNew = mock(typeof(RateComputationFn));
		RatesProvider provNew = mock(typeof(RatesProvider));
		when(provNew.ValuationDate).thenReturn(VAL_DATE);
		when(obsFuncNew.rate(fra.FloatingRate, fra.StartDate, fra.EndDate, provNew)).thenReturn(forwardRate + eps);
		CurrencyAmount upValue = (new DiscountingFraProductPricer(obsFuncNew)).forecastValue(fra, provNew);
		when(obsFuncNew.rate(fra.FloatingRate, fra.StartDate, fra.EndDate, provNew)).thenReturn(forwardRate - eps);
		CurrencyAmount downValue = (new DiscountingFraProductPricer(obsFuncNew)).forecastValue(fra, provNew);
		return upValue.minus(downValue).multipliedBy(0.5 / eps).Amount;
	  }
	  public virtual void test_presentValueSensitivity_dfCurve_FD()
	  {
		double eps = 1.0e-6;
		ImmutableRatesProvider prov = RatesProviderDataSets.MULTI_GBP_USD_SIMPLE;
		RatesFiniteDifferenceSensitivityCalculator cal = new RatesFiniteDifferenceSensitivityCalculator(eps);
		DiscountingFraProductPricer pricer = DiscountingFraProductPricer.DEFAULT;
		ResolvedFra fraExp = RFRA;
		PointSensitivities point = pricer.presentValueSensitivity(fraExp, prov);
		CurrencyParameterSensitivities computed = prov.parameterSensitivity(point);
		CurrencyParameterSensitivities expected = cal.sensitivity(prov, p => pricer.presentValue(fraExp, p));
		assertTrue(computed.equalWithTolerance(expected, eps * FRA.Notional));
	  }
	  /// <summary>
	  /// Test par rate for NONE FRA Discounting method.
	  /// </summary>
	  public virtual void test_parRate_NONE()
	  {
		ResolvedFra fraExp = RFRA_NONE;
		SimpleRatesProvider prov = createProvider(fraExp);

		DiscountingFraProductPricer test = DiscountingFraProductPricer.DEFAULT;
		double parRate = test.parRate(fraExp, prov);
		assertEquals(parRate, FORWARD_RATE);
		ResolvedFra fra = createNewFra(FRA_NONE, parRate);
		CurrencyAmount pv = test.presentValue(fra, prov);
		assertEquals(pv.Amount, 0.0, TOLERANCE);
	  }
        public virtual void test_metadata_last_fixing()
        {
            FraCurveNode           node          = FraCurveNode.of(TEMPLATE, QUOTE_ID, SPREAD).withDate(CurveNodeDate.LAST_FIXING);
            LocalDate              valuationDate = LocalDate.of(2015, 1, 22);
            ImmutableMarketData    marketData    = ImmutableMarketData.builder(valuationDate).addValue(QUOTE_ID, 0.0d).build();
            FraTrade               trade         = node.trade(1d, marketData, REF_DATA);
            ResolvedFra            resolved      = trade.Product.resolve(REF_DATA);
            LocalDate              fixingDate    = ((IborRateComputation)(resolved.FloatingRate)).FixingDate;
            DatedParameterMetadata metadata      = node.metadata(valuationDate, REF_DATA);

            assertEquals(((TenorDateParameterMetadata)metadata).Date, fixingDate);
            assertEquals(((TenorDateParameterMetadata)metadata).Tenor, TENOR_5M);
        }
	  private double dscSensitivity(ResolvedFra fra, double forwardRate, double discountFactor, double paymentTime, double eps)
	  {

		RatesProvider provNew = mock(typeof(RatesProvider));
		when(provNew.ValuationDate).thenReturn(VAL_DATE);
		RateComputationFn<RateComputation> obsFuncNew = mock(typeof(RateComputationFn));
		when(obsFuncNew.rate(fra.FloatingRate, fra.StartDate, fra.EndDate, provNew)).thenReturn(forwardRate);
		when(provNew.discountFactor(fra.Currency, fra.PaymentDate)).thenReturn(discountFactor * Math.Exp(-eps * paymentTime));
		CurrencyAmount upDscValue = (new DiscountingFraProductPricer(obsFuncNew)).presentValue(fra, provNew);
		when(provNew.discountFactor(fra.Currency, fra.PaymentDate)).thenReturn(discountFactor * Math.Exp(eps * paymentTime));
		CurrencyAmount downDscValue = (new DiscountingFraProductPricer(obsFuncNew)).presentValue(fra, provNew);
		return upDscValue.minus(downDscValue).multipliedBy(0.5 / eps).Amount;
	  }
	  /// <summary>
	  /// Test par spread for ISDA FRA Discounting method.
	  /// </summary>
	  public virtual void test_parSpread_ISDA()
	  {
		ResolvedFra fraExp = RFRA;
		SimpleRatesProvider prov = createProvider(fraExp);

		DiscountingFraProductPricer test = DiscountingFraProductPricer.DEFAULT;
		double parSpread = test.parSpread(fraExp, prov);
		ResolvedFra fra = createNewFra(FRA, FRA.FixedRate + parSpread);
		CurrencyAmount pv = test.presentValue(fra, prov);
		assertEquals(pv.Amount, 0.0, TOLERANCE);

		// test via FraTrade
		DiscountingFraTradePricer testTrade = new DiscountingFraTradePricer(test);
		assertEquals(testTrade.parSpread(RFRA_TRADE, prov), test.parSpread(RFRA, prov));
	  }
        public virtual void test_pv01()
        {
            FraTradeCalculationFunction function = new FraTradeCalculationFunction();
            ScenarioMarketData          md       = marketData();
            RatesProvider provider                                 = RATES_LOOKUP.marketDataView(md.scenario(0)).ratesProvider();
            DiscountingFraProductPricer pricer                     = DiscountingFraProductPricer.DEFAULT;
            ResolvedFra                    resolved                = TRADE.Product.resolve(REF_DATA);
            PointSensitivities             pvPointSens             = pricer.presentValueSensitivity(resolved, provider);
            CurrencyParameterSensitivities pvParamSens             = provider.parameterSensitivity(pvPointSens);
            MultiCurrencyAmount            expectedPv01Cal         = pvParamSens.total().multipliedBy(1e-4);
            CurrencyParameterSensitivities expectedPv01CalBucketed = pvParamSens.multipliedBy(1e-4);

            ISet <Measure> measures = ImmutableSet.of(Measures.PV01_CALIBRATED_SUM, Measures.PV01_CALIBRATED_BUCKETED);

            assertThat(function.calculate(TRADE, measures, PARAMS, md, REF_DATA)).containsEntry(Measures.PV01_CALIBRATED_SUM, Result.success(MultiCurrencyScenarioArray.of(ImmutableList.of(expectedPv01Cal)))).containsEntry(Measures.PV01_CALIBRATED_BUCKETED, Result.success(ScenarioArray.of(ImmutableList.of(expectedPv01CalBucketed))));
        }
	  //-------------------------------------------------------------------------
	  /// <summary>
	  /// Test explain.
	  /// </summary>
	  public virtual void test_explainPresentValue_ISDA()
	  {
		ResolvedFra fraExp = RFRA;
		SimpleRatesProvider prov = createProvider(fraExp);

		DiscountingFraProductPricer test = DiscountingFraProductPricer.DEFAULT;
		CurrencyAmount fvExpected = test.forecastValue(fraExp, prov);
		CurrencyAmount pvExpected = test.presentValue(fraExp, prov);

		ExplainMap explain = test.explainPresentValue(fraExp, prov);
		Currency currency = fraExp.Currency;
		int daysBetween = (int) DAYS.between(fraExp.StartDate, fraExp.EndDate);
		assertEquals(explain.get(ExplainKey.ENTRY_TYPE).get(), "FRA");
		assertEquals(explain.get(ExplainKey.PAYMENT_DATE).get(), fraExp.PaymentDate);
		assertEquals(explain.get(ExplainKey.START_DATE).get(), fraExp.StartDate);
		assertEquals(explain.get(ExplainKey.END_DATE).get(), fraExp.EndDate);
		assertEquals(explain.get(ExplainKey.ACCRUAL_YEAR_FRACTION).Value, fraExp.YearFraction);
		assertEquals(explain.get(ExplainKey.DAYS).Value, (int?)(int) daysBetween);
		assertEquals(explain.get(ExplainKey.PAYMENT_CURRENCY).get(), currency);
		assertEquals(explain.get(ExplainKey.NOTIONAL).get().Amount, fraExp.Notional, TOLERANCE);
		assertEquals(explain.get(ExplainKey.TRADE_NOTIONAL).get().Amount, fraExp.Notional, TOLERANCE);

		assertEquals(explain.get(ExplainKey.OBSERVATIONS).get().size(), 1);
		ExplainMap explainObs = explain.get(ExplainKey.OBSERVATIONS).get().get(0);
		IborRateComputation floatingRate = (IborRateComputation) fraExp.FloatingRate;
		assertEquals(explainObs.get(ExplainKey.INDEX).get(), floatingRate.Index);
		assertEquals(explainObs.get(ExplainKey.FIXING_DATE).get(), floatingRate.FixingDate);
		assertEquals(explainObs.get(ExplainKey.INDEX_VALUE).Value, FORWARD_RATE, TOLERANCE);
		assertEquals(explainObs.get(ExplainKey.FROM_FIXING_SERIES).HasValue, false);
		assertEquals(explain.get(ExplainKey.DISCOUNT_FACTOR).Value, DISCOUNT_FACTOR, TOLERANCE);
		assertEquals(explain.get(ExplainKey.FIXED_RATE).Value, fraExp.FixedRate, TOLERANCE);
		assertEquals(explain.get(ExplainKey.PAY_OFF_RATE).Value, FORWARD_RATE, TOLERANCE);
		assertEquals(explain.get(ExplainKey.COMBINED_RATE).Value, FORWARD_RATE, TOLERANCE);
		assertEquals(explain.get(ExplainKey.UNIT_AMOUNT).Value, fvExpected.Amount / fraExp.Notional, TOLERANCE);
		assertEquals(explain.get(ExplainKey.FORECAST_VALUE).get().Currency, currency);
		assertEquals(explain.get(ExplainKey.FORECAST_VALUE).get().Amount, fvExpected.Amount, TOLERANCE);
		assertEquals(explain.get(ExplainKey.PRESENT_VALUE).get().Currency, currency);
		assertEquals(explain.get(ExplainKey.PRESENT_VALUE).get().Amount, pvExpected.Amount, TOLERANCE);

		// test via FraTrade
		DiscountingFraTradePricer testTrade = new DiscountingFraTradePricer(test);
		assertEquals(testTrade.explainPresentValue(RFRA_TRADE, prov), test.explainPresentValue(RFRA, prov));
	  }
	  //-------------------------------------------------------------------------
	  /// <summary>
	  /// Test cash flow for ISDA FRA Discounting method.
	  /// </summary>
	  public virtual void test_cashFlows_ISDA()
	  {
		ResolvedFra fraExp = RFRA;
		SimpleRatesProvider prov = createProvider(fraExp);

		double fixedRate = FRA.FixedRate;
		double yearFraction = fraExp.YearFraction;
		double notional = fraExp.Notional;
		double expected = notional * yearFraction * (FORWARD_RATE - fixedRate) / (1.0 + yearFraction * FORWARD_RATE);

		DiscountingFraProductPricer test = DiscountingFraProductPricer.DEFAULT;
		CashFlows computed = test.cashFlows(fraExp, prov);
		assertEquals(computed.getCashFlows().size(), 1);
		assertEquals(computed.getCashFlows().size(), 1);
		assertEquals(computed.getCashFlows().get(0).PaymentDate, fraExp.PaymentDate);
		assertEquals(computed.getCashFlows().get(0).ForecastValue.Currency, fraExp.Currency);
		assertEquals(computed.getCashFlows().get(0).ForecastValue.Amount, expected, TOLERANCE);

		// test via FraTrade
		DiscountingFraTradePricer testTrade = new DiscountingFraTradePricer(test);
		assertEquals(testTrade.cashFlows(RFRA_TRADE, prov), test.cashFlows(fraExp, prov));
	  }