//------------------------------------------------------------------------- /// <summary> /// Explains the present value of the FRA product. /// <para> /// This returns explanatory information about the calculation. /// /// </para> /// </summary> /// <param name="fra"> the FRA product for which present value should be computed </param> /// <param name="provider"> the rates provider </param> /// <returns> the explanatory information </returns> public virtual ExplainMap explainPresentValue(ResolvedFra fra, RatesProvider provider) { ExplainMapBuilder builder = ExplainMap.builder(); Currency currency = fra.Currency; builder.put(ExplainKey.ENTRY_TYPE, "FRA"); builder.put(ExplainKey.PAYMENT_DATE, fra.PaymentDate); builder.put(ExplainKey.START_DATE, fra.StartDate); builder.put(ExplainKey.END_DATE, fra.EndDate); builder.put(ExplainKey.ACCRUAL_YEAR_FRACTION, fra.YearFraction); builder.put(ExplainKey.DAYS, (int)DAYS.between(fra.StartDate, fra.EndDate)); builder.put(ExplainKey.PAYMENT_CURRENCY, currency); builder.put(ExplainKey.NOTIONAL, CurrencyAmount.of(currency, fra.Notional)); builder.put(ExplainKey.TRADE_NOTIONAL, CurrencyAmount.of(currency, fra.Notional)); if (fra.PaymentDate.isBefore(provider.ValuationDate)) { builder.put(ExplainKey.COMPLETED, true); builder.put(ExplainKey.FORECAST_VALUE, CurrencyAmount.zero(currency)); builder.put(ExplainKey.PRESENT_VALUE, CurrencyAmount.zero(currency)); } else { double rate = rateComputationFn.explainRate(fra.FloatingRate, fra.StartDate, fra.EndDate, provider, builder); builder.put(ExplainKey.FIXED_RATE, fra.FixedRate); builder.put(ExplainKey.DISCOUNT_FACTOR, provider.discountFactor(currency, fra.PaymentDate)); builder.put(ExplainKey.PAY_OFF_RATE, rate); builder.put(ExplainKey.UNIT_AMOUNT, unitAmount(fra, provider)); builder.put(ExplainKey.FORECAST_VALUE, forecastValue(fra, provider)); builder.put(ExplainKey.PRESENT_VALUE, presentValue(fra, provider)); } return(builder.build()); }
public virtual void test_before() { LocalDate startDate = date(2018, 2, 1); LocalDate endDate = date(2018, 2, 28); OvernightAveragedDailyRateComputation cmp = OvernightAveragedDailyRateComputation.of(USD_FED_FUND, startDate, endDate, REF_DATA); ImmutableRatesProvider rates = getRatesProvider(date(2018, 1, 24)); double computedRate = FUNCTION.rate(cmp, DUMMY_ACCRUAL_START_DATE, DUMMY_ACCRUAL_END_DATE, rates); PointSensitivityBuilder sensiComputed = FUNCTION.rateSensitivity(cmp, startDate, endDate, rates); ExplainMapBuilder builder = ExplainMap.builder(); double explainRate = FUNCTION.explainRate(cmp, startDate, endDate, rates, builder); double expectedRate = 0d; PointSensitivityBuilder sensiExpected = PointSensitivityBuilder.none(); LocalDate date = startDate; while (!date.isAfter(endDate)) { OvernightIndexObservation obs = OvernightIndexObservation.of(USD_FED_FUND, date, REF_DATA); double rate = rates.overnightIndexRates(USD_FED_FUND).rate(obs); PointSensitivityBuilder rateSensi = rates.overnightIndexRates(USD_FED_FUND).ratePointSensitivity(obs); LocalDate nextDate = cmp.FixingCalendar.next(date); long days = DAYS.between(date, nextDate); expectedRate += rate * days; sensiExpected = sensiComputed.combinedWith(rateSensi.multipliedBy(days)); date = nextDate; } double nDays = 28d; expectedRate /= nDays; sensiExpected = sensiExpected.multipliedBy(1d / nDays); assertEquals(computedRate, expectedRate, TOL); assertTrue(sensiComputed.build().equalWithTolerance(sensiExpected.build(), TOL)); assertEquals(explainRate, computedRate, TOL); assertEquals(builder.build().get(ExplainKey.COMBINED_RATE).Value, expectedRate, TOL); }
//------------------------------------------------------------------------- public virtual void explainPresentValue(KnownAmountSwapPaymentPeriod period, RatesProvider provider, ExplainMapBuilder builder) { Currency currency = period.Currency; LocalDate paymentDate = period.PaymentDate; builder.put(ExplainKey.ENTRY_TYPE, "KnownAmountPaymentPeriod"); builder.put(ExplainKey.PAYMENT_DATE, paymentDate); builder.put(ExplainKey.PAYMENT_CURRENCY, currency); builder.put(ExplainKey.START_DATE, period.StartDate); builder.put(ExplainKey.UNADJUSTED_START_DATE, period.UnadjustedStartDate); builder.put(ExplainKey.END_DATE, period.EndDate); builder.put(ExplainKey.UNADJUSTED_END_DATE, period.UnadjustedEndDate); builder.put(ExplainKey.DAYS, (int)DAYS.between(period.StartDate, period.EndDate)); if (paymentDate.isBefore(provider.ValuationDate)) { builder.put(ExplainKey.COMPLETED, true); builder.put(ExplainKey.FORECAST_VALUE, CurrencyAmount.zero(currency)); builder.put(ExplainKey.PRESENT_VALUE, CurrencyAmount.zero(currency)); } else { builder.put(ExplainKey.DISCOUNT_FACTOR, provider.discountFactor(currency, paymentDate)); builder.put(ExplainKey.FORECAST_VALUE, CurrencyAmount.of(currency, forecastValue(period, provider))); builder.put(ExplainKey.PRESENT_VALUE, CurrencyAmount.of(currency, presentValue(period, provider))); } }
/// <summary> /// Explains the present value of a single payment period with z-spread. /// <para> /// This adds information to the <seealso cref="ExplainMapBuilder"/> to aid understanding of the calculation. /// /// </para> /// </summary> /// <param name="period"> the period to price </param> /// <param name="ratesProvider"> the rates provider, used to determine price index values </param> /// <param name="issuerDiscountFactors"> the discount factor provider </param> /// <param name="zSpread"> the z-spread </param> /// <param name="compoundedRateType"> the compounded rate type </param> /// <param name="periodsPerYear"> the number of periods per year </param> /// <param name="builder"> the builder to populate </param> public virtual void explainPresentValueWithZSpread(CapitalIndexedBondPaymentPeriod period, RatesProvider ratesProvider, IssuerCurveDiscountFactors issuerDiscountFactors, ExplainMapBuilder builder, double zSpread, CompoundedRateType compoundedRateType, int periodsPerYear) { Currency currency = period.Currency; LocalDate paymentDate = period.PaymentDate; builder.put(ExplainKey.ENTRY_TYPE, "CapitalIndexedBondPaymentPeriod"); builder.put(ExplainKey.PAYMENT_DATE, paymentDate); builder.put(ExplainKey.PAYMENT_CURRENCY, currency); builder.put(ExplainKey.START_DATE, period.StartDate); builder.put(ExplainKey.UNADJUSTED_START_DATE, period.UnadjustedStartDate); builder.put(ExplainKey.END_DATE, period.EndDate); builder.put(ExplainKey.UNADJUSTED_END_DATE, period.UnadjustedEndDate); builder.put(ExplainKey.DAYS, (int)DAYS.between(period.UnadjustedStartDate, period.UnadjustedEndDate)); if (paymentDate.isBefore(ratesProvider.ValuationDate)) { builder.put(ExplainKey.COMPLETED, true); builder.put(ExplainKey.FORECAST_VALUE, CurrencyAmount.zero(currency)); builder.put(ExplainKey.PRESENT_VALUE, CurrencyAmount.zero(currency)); } else { builder.put(ExplainKey.DISCOUNT_FACTOR, issuerDiscountFactors.discountFactor(paymentDate)); builder.put(ExplainKey.FORECAST_VALUE, CurrencyAmount.of(currency, forecastValue(period, ratesProvider))); builder.put(ExplainKey.PRESENT_VALUE, CurrencyAmount.of(currency, presentValueWithZSpread(period, ratesProvider, issuerDiscountFactors, zSpread, compoundedRateType, periodsPerYear))); } }
public virtual void test_explainPresentValue_inPast() { RatesProvider prov = createProvider(VAL_DATE); ExplainMapBuilder builder = ExplainMap.builder(); PRICER.explainPresentValue(PERIOD_PAST, prov, builder); ExplainMap explain = builder.build(); assertEquals(explain.get(ExplainKey.ENTRY_TYPE).get(), "KnownAmountPaymentPeriod"); assertEquals(explain.get(ExplainKey.PAYMENT_DATE).get(), PERIOD_PAST.PaymentDate); assertEquals(explain.get(ExplainKey.PAYMENT_CURRENCY).get(), PERIOD_PAST.Currency); int daysBetween = (int)DAYS.between(DATE_1, DATE_2); assertEquals(explain.get(ExplainKey.START_DATE).get(), PERIOD_PAST.StartDate); assertEquals(explain.get(ExplainKey.UNADJUSTED_START_DATE).get(), PERIOD_PAST.UnadjustedStartDate); assertEquals(explain.get(ExplainKey.END_DATE).get(), PERIOD_PAST.EndDate); assertEquals(explain.get(ExplainKey.UNADJUSTED_END_DATE).get(), PERIOD_PAST.UnadjustedEndDate); assertEquals(explain.get(ExplainKey.DAYS).Value, (int?)daysBetween); assertEquals(explain.get(ExplainKey.FORECAST_VALUE).get().Currency, PERIOD_PAST.Currency); assertEquals(explain.get(ExplainKey.FORECAST_VALUE).get().Amount, 0, TOLERANCE_PV); assertEquals(explain.get(ExplainKey.PRESENT_VALUE).get().Currency, PERIOD_PAST.Currency); assertEquals(explain.get(ExplainKey.PRESENT_VALUE).get().Amount, 0 * DISCOUNT_FACTOR, TOLERANCE_PV); }
// common parts of explain private void explainBasics(FixedCouponBondPaymentPeriod period, ExplainMapBuilder builder, Currency currency, LocalDate paymentDate) { builder.put(ExplainKey.ENTRY_TYPE, "FixedCouponBondPaymentPeriod"); builder.put(ExplainKey.PAYMENT_DATE, paymentDate); builder.put(ExplainKey.PAYMENT_CURRENCY, currency); builder.put(ExplainKey.START_DATE, period.StartDate); builder.put(ExplainKey.UNADJUSTED_START_DATE, period.UnadjustedStartDate); builder.put(ExplainKey.END_DATE, period.EndDate); builder.put(ExplainKey.UNADJUSTED_END_DATE, period.UnadjustedEndDate); builder.put(ExplainKey.ACCRUAL_YEAR_FRACTION, period.YearFraction); builder.put(ExplainKey.DAYS, (int)DAYS.between(period.StartDate, period.EndDate)); }
public virtual void test_explainPresentValueWithZSpread_past() { ExplainMapBuilder builder = ExplainMap.builder(); PRICER.explainPresentValueWithZSpread(PERIOD_INTERP, IRP_AFTER_PAY, ICDF_AFTER_PAY, builder, Z_SPREAD, PERIODIC, PERIOD_PER_YEAR); ExplainMap explain = builder.build(); assertEquals(explain.get(ExplainKey.ENTRY_TYPE).get(), "CapitalIndexedBondPaymentPeriod"); assertEquals(explain.get(ExplainKey.PAYMENT_DATE).get(), PERIOD_INTERP.PaymentDate); assertEquals(explain.get(ExplainKey.PAYMENT_CURRENCY).get(), PERIOD_INTERP.Currency); assertEquals(explain.get(ExplainKey.START_DATE).get(), START); assertEquals(explain.get(ExplainKey.UNADJUSTED_START_DATE).get(), START_UNADJ); assertEquals(explain.get(ExplainKey.END_DATE).get(), END); assertEquals(explain.get(ExplainKey.UNADJUSTED_END_DATE).get(), END_UNADJ); assertEquals(explain.get(ExplainKey.DAYS).Value.intValue(), (int)DAYS.between(START_UNADJ, END_UNADJ)); assertEquals(explain.get(ExplainKey.FORECAST_VALUE).get().Amount, 0d, NOTIONAL * TOL); assertEquals(explain.get(ExplainKey.PRESENT_VALUE).get().Amount, 0d, NOTIONAL * TOL); }
//------------------------------------------------------------------------- /// <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)); }
//------------------------------------------------------------------------- public virtual void test_explainPresentValue() { ExplainMapBuilder builder = ExplainMap.builder(); PRICER.explainPresentValue(PERIOD_INTERP, IRP_BEFORE_START, ICDF_BEFORE_START, builder); ExplainMap explain = builder.build(); assertEquals(explain.get(ExplainKey.ENTRY_TYPE).get(), "CapitalIndexedBondPaymentPeriod"); assertEquals(explain.get(ExplainKey.PAYMENT_DATE).get(), PERIOD_INTERP.PaymentDate); assertEquals(explain.get(ExplainKey.PAYMENT_CURRENCY).get(), PERIOD_INTERP.Currency); assertEquals(explain.get(ExplainKey.START_DATE).get(), START); assertEquals(explain.get(ExplainKey.UNADJUSTED_START_DATE).get(), START_UNADJ); assertEquals(explain.get(ExplainKey.END_DATE).get(), END); assertEquals(explain.get(ExplainKey.UNADJUSTED_END_DATE).get(), END_UNADJ); assertEquals(explain.get(ExplainKey.DAYS).Value.intValue(), (int)DAYS.between(START_UNADJ, END_UNADJ)); assertEquals(explain.get(ExplainKey.DISCOUNT_FACTOR).Value, ICDF_BEFORE_START.discountFactor(END)); assertEquals(explain.get(ExplainKey.FORECAST_VALUE).get().Amount, PRICER.forecastValue(PERIOD_INTERP, IRP_BEFORE_START), NOTIONAL * TOL); assertEquals(explain.get(ExplainKey.PRESENT_VALUE).get().Amount, PRICER.presentValue(PERIOD_INTERP, IRP_BEFORE_START, ICDF_BEFORE_START), NOTIONAL * TOL); }
// explain PV for an accrual period, ignoring compounding private void explainPresentValue(RateAccrualPeriod accrualPeriod, DayCount dayCount, Currency currency, double notional, RatesProvider provider, ExplainMapBuilder builder) { double rawRate = rateComputationFn.explainRate(accrualPeriod.RateComputation, accrualPeriod.StartDate, accrualPeriod.EndDate, provider, builder); double payOffRate = rawRate * accrualPeriod.Gearing + accrualPeriod.Spread; double ua = unitNotionalAccrual(accrualPeriod, accrualPeriod.Spread, provider); // Note that the forecast value is not published since this is potentially misleading when // compounding is being applied, and when it isn't then it's the same as the forecast // value of the payment period. builder.put(ExplainKey.ENTRY_TYPE, "AccrualPeriod"); builder.put(ExplainKey.START_DATE, accrualPeriod.StartDate); builder.put(ExplainKey.UNADJUSTED_START_DATE, accrualPeriod.UnadjustedStartDate); builder.put(ExplainKey.END_DATE, accrualPeriod.EndDate); builder.put(ExplainKey.UNADJUSTED_END_DATE, accrualPeriod.UnadjustedEndDate); builder.put(ExplainKey.ACCRUAL_YEAR_FRACTION, accrualPeriod.YearFraction); builder.put(ExplainKey.ACCRUAL_DAYS, dayCount.days(accrualPeriod.StartDate, accrualPeriod.EndDate)); builder.put(ExplainKey.DAYS, (int)DAYS.between(accrualPeriod.StartDate, accrualPeriod.EndDate)); builder.put(ExplainKey.GEARING, accrualPeriod.Gearing); builder.put(ExplainKey.SPREAD, accrualPeriod.Spread); builder.put(ExplainKey.PAY_OFF_RATE, accrualPeriod.NegativeRateMethod.adjust(payOffRate)); builder.put(ExplainKey.UNIT_AMOUNT, ua); }
/// <summary> /// Data is not held for weekends. /// </summary> //JAVA TO C# CONVERTER TODO TASK: Enum value-specific class bodies are not converted by Java to C# Converter: public static readonly DenseTimeSeriesCalculation SKIP_WEEKENDS = new DenseTimeSeriesCalculation() { int calculatePosition(java.time.LocalDate startDate, java.time.LocalDate date) { int unadjusted = (int)DAYS.between(startDate, date); int weekendAdjustment = startDate.getDayOfWeek().compareTo(date.getDayOfWeek()) > 0 ? 1 : 0; int numWeekends = (unadjusted / 7) + weekendAdjustment; return(unadjusted - (2 * numWeekends)); } java.time.LocalDate calculateDateFromPosition(java.time.LocalDate startDate, int position) { int numWeekends = position / 5; int remaining = position % 5; int endPointAdjustment = (remaining < (6 - startDate.get(DAY_OF_WEEK))) ? 0 : 2; return(startDate.plusDays((7 * numWeekends) + remaining + endPointAdjustment)); } boolean allowsDate(java.time.LocalDate date) { return(!isWeekend(date)); }
//------------------------------------------------------------------------- public InterpolatedNodalCurveDefinition filtered(LocalDate valuationDate, ReferenceData refData) { // mutable list of date-node pairs //JAVA TO C# CONVERTER TODO TASK: Method reference constructor syntax is not converted by Java to C# Converter: //JAVA TO C# CONVERTER TODO TASK: Most Java stream collectors are not converted by Java to C# Converter: List <Pair <LocalDate, CurveNode> > nodeDates = nodes.Select(node => Pair.of(node.date(valuationDate, refData), node)).collect(toCollection(List <object>::new)); // delete nodes if clash, but don't throw exceptions yet for (int i = 0; i < nodeDates.Count; i++) { Pair <LocalDate, CurveNode> pair = nodeDates[i]; CurveNodeDateOrder restriction = pair.Second.DateOrder; // compare node to previous node if (i > 0) { Pair <LocalDate, CurveNode> pairBefore = nodeDates[i - 1]; if (DAYS.between(pairBefore.First, pair.First) < restriction.MinGapInDays) { switch (restriction.Action) { case DROP_THIS: nodeDates.RemoveAt(i); i = -1; // restart loop goto loopContinue; case DROP_OTHER: nodeDates.RemoveAt(i - 1); i = -1; // restart loop goto loopContinue; case EXCEPTION: break; // do nothing yet break; } } } // compare node to next node if (i < nodeDates.Count - 1) { Pair <LocalDate, CurveNode> pairAfter = nodeDates[i + 1]; if (DAYS.between(pair.First, pairAfter.First) < restriction.MinGapInDays) { switch (restriction.Action) { case DROP_THIS: nodeDates.Remove(i); i = -1; // restart loop goto loopContinue; case DROP_OTHER: nodeDates.Remove(i + 1); i = -1; // restart loop goto loopContinue; case EXCEPTION: break; // do nothing yet break; } } } loopContinue :; } loopBreak : // throw exceptions if rules breached for (int i = 0; i < nodeDates.Count; i++) { Pair <LocalDate, CurveNode> pair = nodeDates[i]; CurveNodeDateOrder restriction = pair.Second.DateOrder; // compare node to previous node if (i > 0) { Pair <LocalDate, CurveNode> pairBefore = nodeDates[i - 1]; if (DAYS.between(pairBefore.First, pair.First) < restriction.MinGapInDays) { throw new System.ArgumentException(Messages.format("Curve node dates clash, node '{}' and '{}' resolved to dates '{}' and '{}' respectively", pairBefore.Second.Label, pair.Second.Label, pairBefore.First, pair.First)); } } // compare node to next node if (i < nodeDates.Count - 1) { Pair <LocalDate, CurveNode> pairAfter = nodeDates[i + 1]; if (DAYS.between(pair.First, pairAfter.First) < restriction.MinGapInDays) { throw new System.ArgumentException(Messages.format("Curve node dates clash, node '{}' and '{}' resolved to dates '{}' and '{}' respectively", pair.Second.Label, pairAfter.Second.Label, pair.First, pairAfter.First)); } } } // return the resolved definition //JAVA TO C# CONVERTER TODO TASK: Most Java stream collectors are not converted by Java to C# Converter: IList <CurveNode> filteredNodes = nodeDates.Select(p => p.Second).collect(toImmutableList()); return(new InterpolatedNodalCurveDefinition(name, xValueType, yValueType, dayCount, filteredNodes, interpolator, extrapolatorLeft, extrapolatorRight)); }