All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.opengamma.strata.pricer.fx.DiscountingFxNdfProductPricer Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (C) 2015 - present by OpenGamma Inc. and the OpenGamma group of companies
 *
 * Please see distribution for license.
 */
package com.opengamma.strata.pricer.fx;

import java.time.LocalDate;
import java.util.OptionalDouble;

import com.opengamma.strata.basics.currency.Currency;
import com.opengamma.strata.basics.currency.CurrencyAmount;
import com.opengamma.strata.basics.currency.FxRate;
import com.opengamma.strata.basics.currency.MultiCurrencyAmount;
import com.opengamma.strata.collect.Messages;
import com.opengamma.strata.collect.timeseries.LocalDateDoubleTimeSeries;
import com.opengamma.strata.market.sensitivity.PointSensitivities;
import com.opengamma.strata.market.sensitivity.PointSensitivityBuilder;
import com.opengamma.strata.pricer.rate.RatesProvider;
import com.opengamma.strata.product.fx.ResolvedFxNdf;

/**
 * Pricer for FX non-deliverable forward (NDF) products.
 * 

* This provides the ability to price an {@link ResolvedFxNdf}. * The product is priced using forward curves for the currency pair. */ public class DiscountingFxNdfProductPricer { /** * Default implementation. */ public static final DiscountingFxNdfProductPricer DEFAULT = new DiscountingFxNdfProductPricer(); /** * Creates an instance. */ public DiscountingFxNdfProductPricer() { } //------------------------------------------------------------------------- /** * Calculates the present value of the NDF product. *

* The present value of the product is the value on the valuation date. * The present value is returned in the settlement currency. * * @param ndf the product * @param provider the rates provider * @return the present value of the product in the settlement currency */ public CurrencyAmount presentValue(ResolvedFxNdf ndf, RatesProvider provider) { Currency ccySettle = ndf.getSettlementCurrency(); if (provider.getValuationDate().isAfter(ndf.getPaymentDate())) { return CurrencyAmount.zero(ccySettle); } Currency ccyOther = ndf.getNonDeliverableCurrency(); CurrencyAmount notionalSettle = ndf.getSettlementCurrencyNotional(); double agreedRate = ndf.getAgreedFxRate().fxRate(ccySettle, ccyOther); double forwardRate = provider.fxIndexRates(ndf.getIndex()).rate(ndf.getObservation(), ccySettle); double dfSettle = provider.discountFactor(ccySettle, ndf.getPaymentDate()); return notionalSettle.multipliedBy(dfSettle * (1d - agreedRate / forwardRate)); } /** * Calculates the present value curve sensitivity of the NDF product. *

* The present value sensitivity of the product is the sensitivity of the present value to * the underlying curves. * * @param ndf the product * @param provider the rates provider * @return the point sensitivity of the present value */ public PointSensitivities presentValueSensitivity(ResolvedFxNdf ndf, RatesProvider provider) { if (provider.getValuationDate().isAfter(ndf.getPaymentDate())) { return PointSensitivities.empty(); } Currency ccySettle = ndf.getSettlementCurrency(); Currency ccyOther = ndf.getNonDeliverableCurrency(); double notionalSettle = ndf.getSettlementNotional(); double agreedRate = ndf.getAgreedFxRate().fxRate(ccySettle, ccyOther); double forwardRate = provider.fxIndexRates(ndf.getIndex()).rate(ndf.getObservation(), ccySettle); double dfSettle = provider.discountFactor(ccySettle, ndf.getPaymentDate()); double ratio = agreedRate / forwardRate; double dscBar = (1d - ratio) * notionalSettle; PointSensitivityBuilder sensiDsc = provider.discountFactors(ccySettle).zeroRatePointSensitivity(ndf.getPaymentDate()).multipliedBy(dscBar); double forwardRateBar = dfSettle * notionalSettle * ratio / forwardRate; PointSensitivityBuilder sensiFx = provider.fxIndexRates(ndf.getIndex()) .ratePointSensitivity(ndf.getObservation(), ccySettle).withCurrency(ccySettle).multipliedBy(forwardRateBar); return sensiDsc.combinedWith(sensiFx).build(); } //------------------------------------------------------------------------- /** * Calculates the currency exposure by discounting each payment in its own currency before fixing and one amount in * the delivery currency after. * * @param ndf the product * @param provider the rates provider * @return the currency exposure */ public MultiCurrencyAmount currencyExposure(ResolvedFxNdf ndf, RatesProvider provider) { if (provider.getValuationDate().isAfter(ndf.getPaymentDate())) { return MultiCurrencyAmount.empty(); } Currency ccySettle = ndf.getSettlementCurrency(); CurrencyAmount notionalSettle = ndf.getSettlementCurrencyNotional(); double dfSettle = provider.discountFactor(ccySettle, ndf.getPaymentDate()); Currency ccyOther = ndf.getNonDeliverableCurrency(); double agreedRate = ndf.getAgreedFxRate().fxRate(ccySettle, ccyOther); LocalDate fixingDate = ndf.getObservation().getFixingDate(); LocalDate valuationDate = provider.getValuationDate(); if (fixingDate.isAfter(valuationDate)) { double dfOther = provider.discountFactor(ccyOther, ndf.getPaymentDate()); return MultiCurrencyAmount.of(notionalSettle.multipliedBy(dfSettle)) .plus(CurrencyAmount.of(ccyOther, -notionalSettle.getAmount() * agreedRate * dfOther)); } if (fixingDate.equals(valuationDate)) { FxIndexRates fxIndexRates = provider.fxIndexRates(ndf.getObservation().getIndex()); LocalDateDoubleTimeSeries fixings = fxIndexRates.getFixings(); OptionalDouble fixedRate = fixings.get(fixingDate); if (fixedRate.isPresent()) { return MultiCurrencyAmount.of(notionalSettle.multipliedBy(dfSettle * (1 - agreedRate / fixedRate.getAsDouble()))); } else { double dfOther = provider.discountFactor(ccyOther, ndf.getPaymentDate()); return MultiCurrencyAmount.of(notionalSettle.multipliedBy(dfSettle)) .plus(CurrencyAmount.of(ccyOther, -notionalSettle.getAmount() * agreedRate * dfOther)); } } else { // fixing before valuation date FxIndexRates fxIndexRates = provider.fxIndexRates(ndf.getObservation().getIndex()); LocalDateDoubleTimeSeries fixings = fxIndexRates.getFixings(); OptionalDouble fixedRate = fixings.get(fixingDate); if (fixedRate.isPresent()) { return MultiCurrencyAmount.of(notionalSettle.multipliedBy(dfSettle * (1 - agreedRate / fixedRate.getAsDouble()))); } else { throw new IllegalArgumentException(Messages.format("Unable to get fixing for {} on date {}", ndf.getObservation().getIndex(), fixingDate)); } } } /** * Calculates the current cash of the NDF product. * * @param ndf the product * @param provider the rates provider * @return the current cash of the product in the settlement currency */ public CurrencyAmount currentCash(ResolvedFxNdf ndf, RatesProvider provider) { Currency ccySettle = ndf.getSettlementCurrency(); if (provider.getValuationDate().isEqual(ndf.getPaymentDate())) { Currency ccyOther = ndf.getNonDeliverableCurrency(); CurrencyAmount notionalSettle = ndf.getSettlementCurrencyNotional(); double agreedRate = ndf.getAgreedFxRate().fxRate(ccySettle, ccyOther); double rate = provider.fxIndexRates(ndf.getIndex()).rate(ndf.getObservation(), ccySettle); return notionalSettle.multipliedBy(1d - agreedRate / rate); } return CurrencyAmount.zero(ccySettle); } //------------------------------------------------------------------------- /** * Calculates the forward exchange rate. * * @param ndf the product * @param provider the rates provider * @return the forward rate */ public FxRate forwardFxRate(ResolvedFxNdf ndf, RatesProvider provider) { Currency ccySettle = ndf.getSettlementCurrency(); Currency ccyOther = ndf.getNonDeliverableCurrency(); double forwardRate = provider.fxIndexRates(ndf.getIndex()).rate(ndf.getObservation(), ccySettle); return FxRate.of(ccySettle, ccyOther, forwardRate); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy