/** * Copyright (C) 2011 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.analytics.financial.forex.provider; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import com.opengamma.analytics.financial.forex.derivative.ForexNonDeliverableForward; import com.opengamma.analytics.financial.provider.description.interestrate.MulticurveProviderInterface; import com.opengamma.analytics.financial.provider.sensitivity.multicurve.MulticurveSensitivity; import com.opengamma.analytics.financial.provider.sensitivity.multicurve.MultipleCurrencyMulticurveSensitivity; import com.opengamma.util.ArgumentChecker; import com.opengamma.util.money.Currency; import com.opengamma.util.money.MultipleCurrencyAmount; import com.opengamma.util.tuple.DoublesPair; /** * Pricing method for Forex non-deliverable forward transactions by discounting. */ public final class ForexNonDeliverableForwardDiscountingMethod { /** * The method unique instance. */ private static final ForexNonDeliverableForwardDiscountingMethod INSTANCE = new ForexNonDeliverableForwardDiscountingMethod(); /** * Private constructor. */ private ForexNonDeliverableForwardDiscountingMethod() { } /** * Return the unique instance of the class. * @return The instance. */ public static ForexNonDeliverableForwardDiscountingMethod getInstance() { return INSTANCE; } /** * Computes the present value of the non-deliverable forward. The present value is in currency2 and equal to P*N*(1-X/F) where * <i>P</i> is the currency2 discount factor for the payment date, <i>N</i> is the notional, <i>X</i> is NDF rate and <i>F</i> the estimated forward exchange rate at the payment date. * @param ndf The non-deliverable forward. * @param multicurves The multi-curves provider. * @return The present value. */ public MultipleCurrencyAmount presentValue(final ForexNonDeliverableForward ndf, final MulticurveProviderInterface multicurves) { ArgumentChecker.notNull(ndf, "Non deliverable forward"); ArgumentChecker.notNull(multicurves, "Multi-curves provider"); final double df2 = multicurves.getDiscountFactor(ndf.getCurrency2(), ndf.getPaymentTime()); final double df1 = multicurves.getDiscountFactor(ndf.getCurrency1(), ndf.getPaymentTime()); final double spot = multicurves.getFxRate(ndf.getCurrency2(), ndf.getCurrency1()); final double pv2 = ndf.getNotionalCurrency2() * (df2 - ndf.getExchangeRate() / spot * df1); return MultipleCurrencyAmount.of(ndf.getCurrency2(), pv2); } /** * Computes the currency exposure of the non-deliverable forward. The currency exposure is P_2 * N in currency2 and -P_1 * N * X in currency1 * where <i>P_2</i> is the currency2 discount factor for the payment date, <i>N</i> is the notional, <i>P_1</i> is the currency1 discount factor for the payment date * and <i>X</i> is NDF rate. * @param ndf The non-deliverable forward. * @param multicurves The multi-curves provider. * @return The currency exposure. */ public MultipleCurrencyAmount currencyExposure(final ForexNonDeliverableForward ndf, final MulticurveProviderInterface multicurves) { ArgumentChecker.notNull(ndf, "Non deliverable forward"); ArgumentChecker.notNull(multicurves, "Multi-curves provider"); final double df2 = multicurves.getDiscountFactor(ndf.getCurrency2(), ndf.getPaymentTime()); final double df1 = multicurves.getDiscountFactor(ndf.getCurrency1(), ndf.getPaymentTime()); final double pv1 = -ndf.getNotionalCurrency2() * ndf.getExchangeRate() * df1; final double pv2 = ndf.getNotionalCurrency2() * df2; return MultipleCurrencyAmount.of(new Currency[] {ndf.getCurrency1(), ndf.getCurrency2()}, new double[] {pv1, pv2}); } /** * Computes the forward exchange rate associated to the NDF (1 Cyy2 = fwd Cyy1). * @param ndf The non-deliverable forward. * @param multicurves The multi-curves provider. * @return The forward rate. */ public double forwardForexRate(final ForexNonDeliverableForward ndf, final MulticurveProviderInterface multicurves) { ArgumentChecker.notNull(ndf, "Non deliverable forward"); ArgumentChecker.notNull(multicurves, "Multi-curves provider"); final double dfDelivery = multicurves.getDiscountFactor(ndf.getCurrency2(), ndf.getPaymentTime()); final double dfNonDelivery = multicurves.getDiscountFactor(ndf.getCurrency1(), ndf.getPaymentTime()); final double spot = multicurves.getFxRate(ndf.getCurrency2(), ndf.getCurrency1()); return spot * dfDelivery / dfNonDelivery; } /** * The present value curve sensitivity for the non-deliverable forward. * @param ndf The non-deliverable forward. * @param multicurves The multi-curves provider. * @return The present value currency exposure. */ public MultipleCurrencyMulticurveSensitivity presentValueCurveSensitivity(final ForexNonDeliverableForward ndf, final MulticurveProviderInterface multicurves) { ArgumentChecker.notNull(ndf, "Non deliverable forward"); ArgumentChecker.notNull(multicurves, "Multi-curves provider"); final double df2 = multicurves.getDiscountFactor(ndf.getCurrency2(), ndf.getPaymentTime()); final double df1 = multicurves.getDiscountFactor(ndf.getCurrency1(), ndf.getPaymentTime()); final double spot = multicurves.getFxRate(ndf.getCurrency2(), ndf.getCurrency1()); // Backward sweep final double pvBar = 1.0; final double df1Bar = -ndf.getNotionalCurrency2() * ndf.getExchangeRate() / spot * pvBar; final double df2Bar = ndf.getNotionalCurrency2() * pvBar; final Map<String, List<DoublesPair>> resultMap = new HashMap<>(); final List<DoublesPair> listDiscounting1 = new ArrayList<>(); listDiscounting1.add(DoublesPair.of(ndf.getPaymentTime(), -ndf.getPaymentTime() * df1 * df1Bar)); resultMap.put(multicurves.getName(ndf.getCurrency1()), listDiscounting1); final List<DoublesPair> listDiscounting2 = new ArrayList<>(); listDiscounting2.add(DoublesPair.of(ndf.getPaymentTime(), -ndf.getPaymentTime() * df2 * df2Bar)); resultMap.put(multicurves.getName(ndf.getCurrency2()), listDiscounting2); final MulticurveSensitivity result = MulticurveSensitivity.ofYieldDiscounting(resultMap); return MultipleCurrencyMulticurveSensitivity.of(ndf.getCurrency2(), result); } }