//------------------------------------------------------------------------- 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 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()); }
//------------------------------------------------------------------------- /// <summary> /// Calculates the present value sensitivity to the SABR model parameters of the swaption product. /// <para> /// The sensitivity of the present value to the SABR model parameters, alpha, beta, rho and nu. /// /// </para> /// </summary> /// <param name="swaption"> the swaption product </param> /// <param name="ratesProvider"> the rates provider </param> /// <param name="swaptionVolatilities"> the volatilities </param> /// <returns> the point sensitivity to the SABR model parameters </returns> public virtual PointSensitivityBuilder presentValueSensitivityModelParamsSabr(ResolvedSwaption swaption, RatesProvider ratesProvider, SabrSwaptionVolatilities swaptionVolatilities) { validate(swaption, ratesProvider, swaptionVolatilities); double expiry = swaptionVolatilities.relativeTime(swaption.Expiry); ResolvedSwap underlying = swaption.Underlying; ResolvedSwapLeg fixedLeg = this.fixedLeg(underlying); double tenor = swaptionVolatilities.tenor(fixedLeg.StartDate, fixedLeg.EndDate); double shift = swaptionVolatilities.shift(expiry, tenor); double strike = calculateStrike(fixedLeg); if (expiry < 0d) { // Option has expired already return(PointSensitivityBuilder.none()); } double forward = SwapPricer.parRate(underlying, ratesProvider); double volatility = swaptionVolatilities.volatility(expiry, tenor, strike, forward); double numeraire = calculateNumeraire(swaption, fixedLeg, forward, ratesProvider); DoubleArray derivative = swaptionVolatilities.volatilityAdjoint(expiry, tenor, strike, forward).Derivatives; double vega = numeraire * swaption.LongShort.sign() * BlackFormulaRepository.vega(forward + shift, strike + shift, expiry, volatility); // sensitivities Currency ccy = fixedLeg.Currency; SwaptionVolatilitiesName name = swaptionVolatilities.Name; return(PointSensitivityBuilder.of(SwaptionSabrSensitivity.of(name, expiry, tenor, ALPHA, ccy, vega * derivative.get(2)), SwaptionSabrSensitivity.of(name, expiry, tenor, BETA, ccy, vega * derivative.get(3)), SwaptionSabrSensitivity.of(name, expiry, tenor, RHO, ccy, vega * derivative.get(4)), SwaptionSabrSensitivity.of(name, expiry, tenor, NU, ccy, vega * derivative.get(5)))); }
//------------------------------------------------------------------------- public virtual void explainPresentValue(FxResetNotionalExchange @event, RatesProvider provider, ExplainMapBuilder builder) { Currency currency = @event.Currency; LocalDate paymentDate = @event.PaymentDate; builder.put(ExplainKey.ENTRY_TYPE, "FxResetNotionalExchange"); builder.put(ExplainKey.PAYMENT_DATE, paymentDate); builder.put(ExplainKey.PAYMENT_CURRENCY, currency); builder.put(ExplainKey.TRADE_NOTIONAL, @event.NotionalAmount); 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.addListEntry(ExplainKey.OBSERVATIONS, child => { child.put(ExplainKey.ENTRY_TYPE, "FxObservation"); child.put(ExplainKey.INDEX, @event.Observation.Index); child.put(ExplainKey.FIXING_DATE, @event.Observation.FixingDate); child.put(ExplainKey.INDEX_VALUE, fxRate(@event, provider)); }); builder.put(ExplainKey.DISCOUNT_FACTOR, provider.discountFactor(currency, paymentDate)); builder.put(ExplainKey.FORECAST_VALUE, CurrencyAmount.of(currency, forecastValue(@event, provider))); builder.put(ExplainKey.PRESENT_VALUE, CurrencyAmount.of(currency, presentValue(@event, provider))); } }
/// <summary> /// Calculates the present value of the fixed coupon bond trade with z-spread from the /// clean price of the underlying product. /// <para> /// The present value of the trade is the value on the valuation date. /// The result is expressed using the payment currency of the bond. /// </para> /// <para> /// The z-spread is a parallel shift applied to continuously compounded rates or periodic /// compounded rates of the discounting curve. /// </para> /// <para> /// Coupon payments of the underlying product are considered based on the settlement date of the trade. /// /// </para> /// </summary> /// <param name="trade"> the trade </param> /// <param name="provider"> the discounting provider </param> /// <param name="refData"> the reference data used to calculate the settlement date </param> /// <param name="cleanPrice"> the clean price </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> /// <returns> the present value of the fixed coupon bond trade </returns> public virtual CurrencyAmount presentValueFromCleanPriceWithZSpread(ResolvedFixedCouponBondTrade trade, LegalEntityDiscountingProvider provider, ReferenceData refData, double cleanPrice, double zSpread, CompoundedRateType compoundedRateType, int periodsPerYear) { ResolvedFixedCouponBond product = trade.Product; LocalDate standardSettlementDate = this.standardSettlementDate(product, provider, refData); LocalDate tradeSettlementDate = settlementDate(trade, provider.ValuationDate); Currency currency = product.Currency; RepoCurveDiscountFactors repoDf = DiscountingFixedCouponBondProductPricer.repoCurveDf(product, provider); double df = repoDf.discountFactor(standardSettlementDate); double pvStandard = (cleanPrice * product.Notional + productPricer.accruedInterest(product, standardSettlementDate)) * df; if (standardSettlementDate.isEqual(tradeSettlementDate)) { return(presentValueFromProductPresentValue(trade, provider, CurrencyAmount.of(currency, pvStandard))); } // check coupon payment between two settlement dates IssuerCurveDiscountFactors issuerDf = DiscountingFixedCouponBondProductPricer.issuerCurveDf(product, provider); double pvDiff = 0d; if (standardSettlementDate.isAfter(tradeSettlementDate)) { pvDiff = productPricer.presentValueCouponWithZSpread(product, issuerDf, tradeSettlementDate, standardSettlementDate, zSpread, compoundedRateType, periodsPerYear); } else { pvDiff = -productPricer.presentValueCouponWithZSpread(product, issuerDf, standardSettlementDate, tradeSettlementDate, zSpread, compoundedRateType, periodsPerYear); } return(presentValueFromProductPresentValue(trade, provider, CurrencyAmount.of(currency, pvStandard + pvDiff))); }
/// <summary> /// Calibrate trinomial tree to Black volatilities. /// <para> /// {@code timeToExpiry} determines the coverage of the resulting trinomial tree. /// Thus this should match the time to expiry of the target instrument to price using the calibrated tree. /// /// </para> /// </summary> /// <param name="timeToExpiry"> the time to expiry </param> /// <param name="currencyPair"> the currency pair </param> /// <param name="ratesProvider"> the rates provider </param> /// <param name="volatilities"> the Black volatility provider </param> /// <returns> the trinomial tree data </returns> public virtual RecombiningTrinomialTreeData calibrateTrinomialTree(double timeToExpiry, CurrencyPair currencyPair, RatesProvider ratesProvider, BlackFxOptionVolatilities volatilities) { validate(ratesProvider, volatilities); if (timeToExpiry <= 0d) { throw new System.ArgumentException("option expired"); } Currency ccyBase = currencyPair.Base; Currency ccyCounter = currencyPair.Counter; double todayFx = ratesProvider.fxRate(currencyPair); DiscountFactors baseDiscountFactors = ratesProvider.discountFactors(ccyBase); DiscountFactors counterDiscountFactors = ratesProvider.discountFactors(ccyCounter); System.Func <double, double> interestRate = (double?t) => { return(counterDiscountFactors.zeroRate(t.Value)); }; System.Func <double, double> dividendRate = (double?t) => { return(baseDiscountFactors.zeroRate(t.Value)); }; System.Func <DoublesPair, double> impliedVolSurface = (DoublesPair tk) => { double dfBase = baseDiscountFactors.discountFactor(tk.First); double dfCounter = counterDiscountFactors.discountFactor(tk.First); double forward = todayFx * dfBase / dfCounter; return(volatilities.volatility(currencyPair, tk.First, tk.Second, forward)); }; ImpliedTrinomialTreeLocalVolatilityCalculator localVol = new ImpliedTrinomialTreeLocalVolatilityCalculator(nSteps, timeToExpiry); return(localVol.calibrateImpliedVolatility(impliedVolSurface, todayFx, interestRate, dividendRate)); }
/// <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))); } }
//------------------------------------------------------------------------- /// <summary> /// Calculates the forward exchange rate. /// </summary> /// <param name="ndf"> the product </param> /// <param name="provider"> the rates provider </param> /// <returns> the forward rate </returns> public virtual FxRate forwardFxRate(ResolvedFxNdf ndf, RatesProvider provider) { Currency ccySettle = ndf.SettlementCurrency; Currency ccyOther = ndf.NonDeliverableCurrency; double forwardRate = provider.fxIndexRates(ndf.Index).rate(ndf.Observation, ccySettle); return(FxRate.of(ccySettle, ccyOther, forwardRate)); }
//------------------------------------------------------------------------- /// <summary> /// Calculates the price of the deliverable swap futures product. /// <para> /// The price of the product is the price on the valuation date. /// /// </para> /// </summary> /// <param name="future"> the future </param> /// <param name="ratesProvider"> the rates provider </param> /// <returns> the price of the product, in decimal form </returns> public double price(ResolvedDsf future, RatesProvider ratesProvider) { ResolvedSwap swap = future.UnderlyingSwap; Currency currency = future.Currency; CurrencyAmount pvSwap = swapPricer.presentValue(swap, currency, ratesProvider); double df = ratesProvider.discountFactor(currency, future.DeliveryDate); return(1d + pvSwap.Amount / df); }
/// <summary> /// Assert that the {@code CurrencyAmount} is of the expected currency. /// </summary> /// <param name="ccy"> the expected currency </param> /// <returns> this if the currency matches the expectation, else /// throw an {@code AssertionError} </returns> public virtual CurrencyAmountAssert hasCurrency(Currency ccy) { NotNull; if (!actual.Currency.Equals(ccy)) { failWithMessage("Expected CurrencyAmount with currency: <%s> but was: <%s>", ccy, actual.Currency); } return(this); }
//------------------------------------------------------------------------- /// <summary> /// Calculates the deposit fair rate given the start and end time and the accrual factor. /// <para> /// When the deposit has already started the number may not be meaningful as the remaining period /// is not in line with the accrual factor. /// /// </para> /// </summary> /// <param name="deposit"> the product </param> /// <param name="provider"> the rates provider </param> /// <returns> the par rate </returns> public virtual double parRate(ResolvedTermDeposit deposit, RatesProvider provider) { Currency currency = deposit.Currency; DiscountFactors discountFactors = provider.discountFactors(currency); double dfStart = discountFactors.discountFactor(deposit.StartDate); double dfEnd = discountFactors.discountFactor(deposit.EndDate); double accrualFactor = deposit.YearFraction; return((dfStart / dfEnd - 1d) / accrualFactor); }
//------------------------------------------------------------------------- /// <summary> /// Calculates the price sensitivity of the deliverable swap futures product. /// <para> /// The price sensitivity of the product is the sensitivity of the price to the underlying curves. /// /// </para> /// </summary> /// <param name="future"> the future </param> /// <param name="ratesProvider"> the rates provider </param> /// <returns> the price curve sensitivity of the product </returns> public PointSensitivities priceSensitivity(ResolvedDsf future, RatesProvider ratesProvider) { ResolvedSwap swap = future.UnderlyingSwap; Currency currency = future.Currency; double pvSwap = swapPricer.presentValue(swap, currency, ratesProvider).Amount; double dfInv = 1d / ratesProvider.discountFactor(currency, future.DeliveryDate); PointSensitivityBuilder sensiSwapPv = swapPricer.presentValueSensitivity(swap, ratesProvider).multipliedBy(dfInv); PointSensitivityBuilder sensiDf = ratesProvider.discountFactors(currency).zeroRatePointSensitivity(future.DeliveryDate).multipliedBy(-pvSwap * dfInv * dfInv); return(sensiSwapPv.combinedWith(sensiDf).build()); }
public virtual void test_of_withSensitivityCurrency() { Currency sensiCurrency = GBP; IssuerCurveZeroRateSensitivity test = IssuerCurveZeroRateSensitivity.of(CURRENCY, YEARFRAC, sensiCurrency, GROUP, VALUE); assertEquals(test.LegalEntityGroup, GROUP); assertEquals(test.CurveCurrency, CURRENCY); assertEquals(test.Currency, sensiCurrency); assertEquals(test.YearFraction, YEARFRAC); assertEquals(test.Sensitivity, VALUE); }
// computes the sensitivity of the payment period to the rate observations (not to the discount factors) private PointSensitivityBuilder unitNotionalSensitivityNoCompounding(RatePaymentPeriod period, RatesProvider provider) { Currency ccy = period.Currency; PointSensitivityBuilder sensi = PointSensitivityBuilder.none(); foreach (RateAccrualPeriod accrualPeriod in period.AccrualPeriods) { sensi = sensi.combinedWith(unitNotionalSensitivityAccrual(accrualPeriod, ccy, provider)); } return(sensi); }
/// <summary> /// Calculates the par spread curve sensitivity. /// <para> /// The calculation is based on both of initial and final payments. /// Thus the number resulting may not be meaningful when deposit has already started and only the final /// payment remains (no initial payment). /// /// </para> /// </summary> /// <param name="deposit"> the product </param> /// <param name="provider"> the rates provider </param> /// <returns> the par spread curve sensitivity </returns> public virtual PointSensitivities parSpreadSensitivity(ResolvedTermDeposit deposit, RatesProvider provider) { Currency currency = deposit.Currency; double accrualFactorInv = 1d / deposit.YearFraction; double dfStart = provider.discountFactor(currency, deposit.StartDate); double dfEndInv = 1d / provider.discountFactor(currency, deposit.EndDate); DiscountFactors discountFactors = provider.discountFactors(currency); PointSensitivityBuilder sensStart = discountFactors.zeroRatePointSensitivity(deposit.StartDate).multipliedBy(dfEndInv * accrualFactorInv); PointSensitivityBuilder sensEnd = discountFactors.zeroRatePointSensitivity(deposit.EndDate).multipliedBy(-dfStart * dfEndInv * dfEndInv * accrualFactorInv); return(sensStart.combinedWith(sensEnd).build()); }
public virtual void test_of_zeroRateSensitivity() { Currency sensiCurrency = GBP; ZeroRateSensitivity zeroSensi = ZeroRateSensitivity.of(CURRENCY, YEARFRAC, sensiCurrency, VALUE); RepoCurveZeroRateSensitivity test = RepoCurveZeroRateSensitivity.of(zeroSensi, GROUP); assertEquals(test.RepoGroup, GROUP); assertEquals(test.CurveCurrency, CURRENCY); assertEquals(test.Currency, sensiCurrency); assertEquals(test.YearFraction, YEARFRAC); assertEquals(test.Sensitivity, VALUE); }
public virtual void test_legInitialNotional() { ResolvedSwapLeg firstLeg = SWAP_TRADE.Product.Legs.get(0); ResolvedSwapLeg secondLeg = SWAP_TRADE.Product.Legs.get(1); Currency ccy = firstLeg.Currency; RatePaymentPeriod firstPaymentPeriod = (RatePaymentPeriod)firstLeg.PaymentPeriods.get(0); double notional = firstPaymentPeriod.Notional; LegAmounts expected = LegAmounts.of(SwapLegAmount.of(firstLeg, CurrencyAmount.of(ccy, notional)), SwapLegAmount.of(secondLeg, CurrencyAmount.of(ccy, notional))); assertEquals(SwapMeasureCalculations.DEFAULT.legInitialNotional(SWAP_TRADE), expected); }
/// <summary> /// Calculates the present value sensitivity by discounting the final cash flow (nominal + interest) /// and the initial payment (initial amount). /// </summary> /// <param name="deposit"> the product </param> /// <param name="provider"> the rates provider </param> /// <returns> the point sensitivity of the present value </returns> public virtual PointSensitivities presentValueSensitivity(ResolvedTermDeposit deposit, RatesProvider provider) { Currency currency = deposit.Currency; // backward sweep double dfEndBar = deposit.Notional + deposit.Interest; double dfStartBar = -initialAmount(deposit, provider); // sensitivity DiscountFactors discountFactors = provider.discountFactors(currency); PointSensitivityBuilder sensStart = discountFactors.zeroRatePointSensitivity(deposit.StartDate).multipliedBy(dfStartBar); PointSensitivityBuilder sensEnd = discountFactors.zeroRatePointSensitivity(deposit.EndDate).multipliedBy(dfEndBar); return(sensStart.combinedWith(sensEnd).build()); }
/// <summary> /// Calculates the current cash of the NDF product. /// </summary> /// <param name="ndf"> the product </param> /// <param name="provider"> the rates provider </param> /// <returns> the current cash of the product in the settlement currency </returns> public virtual CurrencyAmount currentCash(ResolvedFxNdf ndf, RatesProvider provider) { Currency ccySettle = ndf.SettlementCurrency; if (provider.ValuationDate.isEqual(ndf.PaymentDate)) { Currency ccyOther = ndf.NonDeliverableCurrency; CurrencyAmount notionalSettle = ndf.SettlementCurrencyNotional; double agreedRate = ndf.AgreedFxRate.fxRate(ccySettle, ccyOther); double rate = provider.fxIndexRates(ndf.Index).rate(ndf.Observation, ccySettle); return(notionalSettle.multipliedBy(1d - agreedRate / rate)); } return(CurrencyAmount.zero(ccySettle)); }
//------------------------------------------------------------------------- /// <summary> /// Calculates the present value of the Ibor fixing deposit product. /// <para> /// The present value of the product is the value on the valuation date. /// /// </para> /// </summary> /// <param name="deposit"> the product </param> /// <param name="provider"> the rates provider </param> /// <returns> the present value of the product </returns> public virtual CurrencyAmount presentValue(ResolvedIborFixingDeposit deposit, RatesProvider provider) { Currency currency = deposit.Currency; if (provider.ValuationDate.isAfter(deposit.EndDate)) { return(CurrencyAmount.of(currency, 0.0d)); } double forwardRate = this.forwardRate(deposit, provider); double discountFactor = provider.discountFactor(currency, deposit.EndDate); double fv = deposit.Notional * deposit.YearFraction * (deposit.FixedRate - forwardRate); double pv = discountFactor * fv; return(CurrencyAmount.of(currency, pv)); }
//------------------------------------------------------------------------- public virtual PointSensitivityBuilder presentValueSensitivity(RatePaymentPeriod period, RatesProvider provider) { Currency ccy = period.Currency; DiscountFactors discountFactors = provider.discountFactors(ccy); LocalDate paymentDate = period.PaymentDate; double df = discountFactors.discountFactor(paymentDate); PointSensitivityBuilder forecastSensitivity = forecastValueSensitivity(period, provider); forecastSensitivity = forecastSensitivity.multipliedBy(df); double forecastValue = this.forecastValue(period, provider); PointSensitivityBuilder dscSensitivity = discountFactors.zeroRatePointSensitivity(paymentDate); dscSensitivity = dscSensitivity.multipliedBy(forecastValue); return(forecastSensitivity.combinedWith(dscSensitivity)); }
// convention-based // ideally we'd use the trade date plus "period to start" to get the spot/payment date // but we don't have all the data and it gets complicated in places like TRY, RUB and AED private static FxSingleTrade parseConvention(CsvRow row, TradeInfo info) { CurrencyPair pair = CurrencyPair.parse(row.getValue(CONVENTION_FIELD)); BuySell buySell = LoaderUtils.parseBuySell(row.getValue(BUY_SELL_FIELD)); Currency currency = Currency.parse(row.getValue(CURRENCY_FIELD)); double notional = LoaderUtils.parseDouble(row.getValue(NOTIONAL_FIELD)); double fxRate = LoaderUtils.parseDouble(row.getValue(FX_RATE_FIELD)); LocalDate paymentDate = LoaderUtils.parseDate(row.getValue(PAYMENT_DATE_FIELD)); Optional <BusinessDayAdjustment> paymentAdj = parsePaymentDateAdjustment(row); CurrencyAmount amount = CurrencyAmount.of(currency, buySell.normalize(notional)); FxSingle fx = paymentAdj.map(adj => FxSingle.of(amount, FxRate.of(pair, fxRate), paymentDate, adj)).orElseGet(() => FxSingle.of(amount, FxRate.of(pair, fxRate), paymentDate)); return(FxSingleTrade.of(info, fx)); }
//------------------------------------------------------------------------- /// <summary> /// Calculates the currency exposure by discounting each payment in its own currency. /// </summary> /// <param name="ndf"> the product </param> /// <param name="provider"> the rates provider </param> /// <returns> the currency exposure </returns> public virtual MultiCurrencyAmount currencyExposure(ResolvedFxNdf ndf, RatesProvider provider) { if (provider.ValuationDate.isAfter(ndf.PaymentDate)) { return(MultiCurrencyAmount.empty()); } Currency ccySettle = ndf.SettlementCurrency; CurrencyAmount notionalSettle = ndf.SettlementCurrencyNotional; double dfSettle = provider.discountFactor(ccySettle, ndf.PaymentDate); Currency ccyOther = ndf.NonDeliverableCurrency; double agreedRate = ndf.AgreedFxRate.fxRate(ccySettle, ccyOther); double dfOther = provider.discountFactor(ccyOther, ndf.PaymentDate); return(MultiCurrencyAmount.of(notionalSettle.multipliedBy(dfSettle)).plus(CurrencyAmount.of(ccyOther, -notionalSettle.Amount * agreedRate * dfOther))); }
// spread exclusive compounding private PointSensitivityBuilder compoundedSpreadExclusiveSensitivity(RatePaymentPeriod paymentPeriod, RatesProvider provider) { double notionalAccrued = 1d; Currency ccy = paymentPeriod.Currency; PointSensitivityBuilder sensi = PointSensitivityBuilder.none(); foreach (RateAccrualPeriod accrualPeriod in paymentPeriod.AccrualPeriods) { double investFactor = 1 + unitNotionalAccrual(accrualPeriod, 0, provider); notionalAccrued *= investFactor; PointSensitivityBuilder investFactorSensi = unitNotionalSensitivityAccrual(accrualPeriod, ccy, provider).multipliedBy(1d / investFactor); sensi = sensi.combinedWith(investFactorSensi); } return(sensi.multipliedBy(notionalAccrued)); }
// parses the additional GenericSecurityPosition information internal static Position parseNonEtdPosition(CsvRow row, PositionInfo info, PositionCsvInfoResolver resolver) { SecurityPosition @base = parseSecurityPosition(row, info, resolver); double? tickSizeOpt = row.findValue(TICK_SIZE).map(str => LoaderUtils.parseDouble(str)); Optional <Currency> currencyOpt = row.findValue(CURRENCY).map(str => Currency.of(str)); double? tickValueOpt = row.findValue(TICK_VALUE).map(str => LoaderUtils.parseDouble(str)); double contractSize = row.findValue(CONTRACT_SIZE).map(str => LoaderUtils.parseDouble(str)).orElse(1d); if (tickSizeOpt.HasValue && currencyOpt.Present && tickValueOpt.HasValue) { SecurityPriceInfo priceInfo = SecurityPriceInfo.of(tickSizeOpt.Value, CurrencyAmount.of(currencyOpt.get(), tickValueOpt.Value), contractSize); GenericSecurity sec = GenericSecurity.of(SecurityInfo.of(@base.SecurityId, priceInfo)); return(GenericSecurityPosition.ofLongShort(@base.Info, sec, @base.LongQuantity, @base.ShortQuantity)); } return(@base); }
/// <summary> /// Get the curve name of the curve for a given currency. /// </summary> /// <param name="currency"> the currency </param> /// <returns> the curve name </returns> public static CurveName getCurveName(Currency currency) { if (currency.Equals(EUR)) { return(EUR_DSC.Name); } if (currency.Equals(USD)) { return(USD_DSC.Name); } if (currency.Equals(GBP)) { return(GBP_DSC.Name); } throw new System.ArgumentException(); }
//------------------------------------------------------------------------- /// <summary> /// Calculates the present value of the NDF product. /// <para> /// The present value of the product is the value on the valuation date. /// The present value is returned in the settlement currency. /// /// </para> /// </summary> /// <param name="ndf"> the product </param> /// <param name="provider"> the rates provider </param> /// <returns> the present value of the product in the settlement currency </returns> public virtual CurrencyAmount presentValue(ResolvedFxNdf ndf, RatesProvider provider) { Currency ccySettle = ndf.SettlementCurrency; if (provider.ValuationDate.isAfter(ndf.PaymentDate)) { return(CurrencyAmount.zero(ccySettle)); } Currency ccyOther = ndf.NonDeliverableCurrency; CurrencyAmount notionalSettle = ndf.SettlementCurrencyNotional; double agreedRate = ndf.AgreedFxRate.fxRate(ccySettle, ccyOther); double forwardRate = provider.fxIndexRates(ndf.Index).rate(ndf.Observation, ccySettle); double dfSettle = provider.discountFactor(ccySettle, ndf.PaymentDate); return(notionalSettle.multipliedBy(dfSettle * (1d - agreedRate / forwardRate))); }
//------------------------------------------------------------------------- /// <summary> /// Calculates the present value by discounting the final cash flow (nominal + interest) /// and the initial payment (initial amount). /// <para> /// The present value of the product is the value on the valuation date. /// /// </para> /// </summary> /// <param name="deposit"> the product </param> /// <param name="provider"> the rates provider </param> /// <returns> the present value of the product </returns> public virtual CurrencyAmount presentValue(ResolvedTermDeposit deposit, RatesProvider provider) { Currency currency = deposit.Currency; if (provider.ValuationDate.isAfter(deposit.EndDate)) { return(CurrencyAmount.of(currency, 0.0d)); } DiscountFactors discountFactors = provider.discountFactors(currency); double dfStart = discountFactors.discountFactor(deposit.StartDate); double dfEnd = discountFactors.discountFactor(deposit.EndDate); double pvStart = initialAmount(deposit, provider) * dfStart; double pvEnd = (deposit.Notional + deposit.Interest) * dfEnd; double pv = pvEnd - pvStart; return(CurrencyAmount.of(currency, pv)); }
// parses a trade from the CSV row internal static SecurityQuantityTrade parseTrade(CsvRow row, TradeInfo info, TradeCsvInfoResolver resolver) { SecurityTrade trade = parseSecurityTrade(row, info, resolver); SecurityTrade @base = resolver.completeTrade(row, trade); double?tickSizeOpt = row.findValue(TICK_SIZE).map(str => LoaderUtils.parseDouble(str)); Optional <Currency> currencyOpt = row.findValue(CURRENCY).map(str => Currency.of(str)); double?tickValueOpt = row.findValue(TICK_VALUE).map(str => LoaderUtils.parseDouble(str)); double contractSize = row.findValue(CONTRACT_SIZE).map(str => LoaderUtils.parseDouble(str)).orElse(1d); if (tickSizeOpt.HasValue && currencyOpt.Present && tickValueOpt.HasValue) { SecurityPriceInfo priceInfo = SecurityPriceInfo.of(tickSizeOpt.Value, CurrencyAmount.of(currencyOpt.get(), tickValueOpt.Value), contractSize); GenericSecurity sec = GenericSecurity.of(SecurityInfo.of(@base.SecurityId, priceInfo)); return(GenericSecurityTrade.of(@base.Info, sec, @base.Quantity, @base.Price)); } return(@base); }
// flat compounding private PointSensitivityBuilder compoundedFlatSensitivity(RatePaymentPeriod paymentPeriod, RatesProvider provider) { double cpaAccumulated = 0d; Currency ccy = paymentPeriod.Currency; PointSensitivityBuilder sensiAccumulated = PointSensitivityBuilder.none(); foreach (RateAccrualPeriod accrualPeriod in paymentPeriod.AccrualPeriods) { double rate = rawRate(accrualPeriod, provider); double accrualZeroSpread = unitNotionalAccrualRaw(accrualPeriod, rate, 0); PointSensitivityBuilder sensiCp = sensiAccumulated.cloned(); sensiCp = sensiCp.multipliedBy(accrualZeroSpread); PointSensitivityBuilder sensi2 = unitNotionalSensitivityAccrual(accrualPeriod, ccy, provider).multipliedBy(1d + cpaAccumulated); cpaAccumulated += cpaAccumulated * accrualZeroSpread + unitNotionalAccrualRaw(accrualPeriod, rate, accrualPeriod.Spread); sensiCp = sensiCp.combinedWith(sensi2); sensiAccumulated = sensiAccumulated.combinedWith(sensiCp).normalize(); } return(sensiAccumulated); }