/** * Copyright (C) 2013 - 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.Forex; import com.opengamma.analytics.financial.provider.description.interestrate.MulticurveForwardPointsProviderInterface; 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.analytics.math.curve.DoublesCurve; import com.opengamma.util.ArgumentChecker; import com.opengamma.util.money.Currency; import com.opengamma.util.money.MultipleCurrencyAmount; import com.opengamma.util.tuple.DoublesPair; import com.opengamma.util.tuple.Pair; /** * Pricing method for Forex transactions (spot or forward) by forward points. * <p>Documentation: Forex Swaps and Cross-currency Swaps. OpenGamma Documentation n. 21 */ public final class ForexForwardPointsMethod { /** * The method unique instance. */ private static final ForexForwardPointsMethod INSTANCE = new ForexForwardPointsMethod(); /** * Return the unique instance of the class. * @return The instance. */ public static ForexForwardPointsMethod getInstance() { return INSTANCE; } /** * Private constructor. */ private ForexForwardPointsMethod() { } /** * Compute the present value by estimating the forward points. The present value is computed in the second currency in the ccyPair. * No coherence check is done between the interest curves and the forward points curves. * @param fx The Forex derivative. * @param multicurves The multi-curves provider. * @param forwardRates The curve with the forward points. * @param ccyPair The ordered currency pair for which the forwardRates are valid. * @return The multi-currency present value (in currency 2). */ public MultipleCurrencyAmount presentValue(final Forex fx, final MulticurveProviderInterface multicurves, final DoublesCurve forwardRates, final Pair<Currency, Currency> ccyPair) { final double payTime = fx.getPaymentTime(); final double fwdRate = forwardRates.getYValue(payTime); final Currency ccy2; final double amount1; final double amount2; // Implementation note: The "if" is used to check in which order the fx is given with respect to the order of the forward rates. if (checkCurrency(fx, ccyPair)) { // Currency1 of fx is first currency in ccyPair ccy2 = fx.getCurrency2(); amount1 = fx.getPaymentCurrency1().getAmount(); amount2 = fx.getPaymentCurrency2().getAmount(); } else { ccy2 = fx.getCurrency1(); amount1 = fx.getPaymentCurrency2().getAmount(); amount2 = fx.getPaymentCurrency1().getAmount(); } final double df2 = multicurves.getDiscountFactor(ccy2, payTime); final double pv = df2 * (amount2 + amount1 * fwdRate); return MultipleCurrencyAmount.of(ccy2, pv); } /** * Returns the present value for data stored in a unique Provider. * @param fx The Forex derivative. * @param multicurvesForward The multi-curve provider with forward rates for a currency pair. * @return The present value. */ public MultipleCurrencyAmount presentValue(final Forex fx, final MulticurveForwardPointsProviderInterface multicurvesForward) { ArgumentChecker.notNull(multicurvesForward, "multi-curve provider"); return presentValue(fx, multicurvesForward.getMulticurveProvider(), multicurvesForward.getForwardPointsCurve(), multicurvesForward.getCurrencyPair()); } /** * Compute the currency exposure by estimating the forward points. * @param fx The Forex derivative. * @param multicurves The multi-curves provider. * @param forwardRates The curve with the forward points. The order of the currencies is the order of ccy0 and ccy1 in the FXMatrix of the multicurves provider. * @param ccyPair The ordered currency pair for which the forwardRates are valid. * @return The currency exposure. */ public MultipleCurrencyAmount currencyExposure(final Forex fx, final MulticurveProviderInterface multicurves, final DoublesCurve forwardRates, final Pair<Currency, Currency> ccyPair) { final double payTime = fx.getPaymentTime(); final double fwdRate = forwardRates.getYValue(payTime); final Currency ccy1; final Currency ccy2; final double amount1; final double amount2; // Implementation note: The "if" is used to check in which order the fx is given with respect to the order of the forward rates. if (checkCurrency(fx, ccyPair)) { // Currency1 of fx is first currency in ccyPair ccy1 = fx.getCurrency1(); ccy2 = fx.getCurrency2(); amount1 = fx.getPaymentCurrency1().getAmount(); amount2 = fx.getPaymentCurrency2().getAmount(); } else { ccy1 = fx.getCurrency2(); ccy2 = fx.getCurrency1(); amount1 = fx.getPaymentCurrency2().getAmount(); amount2 = fx.getPaymentCurrency1().getAmount(); } final double df2 = multicurves.getDiscountFactor(ccy2, payTime); final double ce2 = amount2 * df2; final double todayRate = multicurves.getFxRate(ccy1, ccy2); final double ce1 = amount1 * df2 * (fwdRate / todayRate); MultipleCurrencyAmount ce = MultipleCurrencyAmount.of(ccy1, ce1); ce = ce.plus(ccy2, ce2); return ce; } /** * Computes the present value curve sensitivity for forex by forward point method. * The sensitivity is only to the final discounting, not to the forward points. * @param fx The Forex derivative. * @param multicurves The multi-curve provider. * @param forwardRates The curve with the forward points. The order of the currencies is the order of ccy0 and ccy1 in the FXMatrix of the multicurves provider. * @param ccyPair The ordered currency pair for which the forwardRates are valid. * @return The sensitivity. */ public MultipleCurrencyMulticurveSensitivity presentValueCurveSensitivity(final Forex fx, final MulticurveProviderInterface multicurves, final DoublesCurve forwardRates, final Pair<Currency, Currency> ccyPair) { final double payTime = fx.getPaymentTime(); final double fwdRate = forwardRates.getYValue(payTime); final Currency ccy2; final double amount1; final double amount2; // Implementation note: The "if" is used to check in which order the fx is given with respect to the order of the forward rates. if (checkCurrency(fx, ccyPair)) { // Currency1 of fx is first currency in ccyPair ccy2 = fx.getCurrency2(); amount1 = fx.getPaymentCurrency1().getAmount(); amount2 = fx.getPaymentCurrency2().getAmount(); } else { ccy2 = fx.getCurrency1(); amount1 = fx.getPaymentCurrency2().getAmount(); amount2 = fx.getPaymentCurrency1().getAmount(); } final double df2 = multicurves.getDiscountFactor(ccy2, payTime); // final double pv = df2 * (amount2 + amount1 * fwdRate); // Backward sweep final double pvBar = 1.0; final double df2Bar = (amount2 + amount1 * fwdRate) * pvBar; final DoublesPair s = DoublesPair.of(payTime, -payTime * df2 * df2Bar); final List<DoublesPair> list = new ArrayList<>(); list.add(s); final Map<String, List<DoublesPair>> result = new HashMap<>(); result.put(multicurves.getName(ccy2), list); return MultipleCurrencyMulticurveSensitivity.of(ccy2, MulticurveSensitivity.ofYieldDiscounting(result)); } public MultipleCurrencyMulticurveSensitivity presentValueCurveSensitivity(final Forex fx, final MulticurveForwardPointsProviderInterface multicurvesForward) { ArgumentChecker.notNull(multicurvesForward, "multi-curve provider"); return presentValueCurveSensitivity(fx, multicurvesForward.getMulticurveProvider(), multicurvesForward.getForwardPointsCurve(), multicurvesForward.getCurrencyPair()); } /** * Computes the sensitivity of the present value to the figures in the forward points curves. * @param fx The Forex derivative. * @param multicurves The multi-curve provider. * @param forwardRates The curve with the forward points. The order of the currencies is the order of ccy0 and ccy1 in the FXMatrix of the multicurves provider. * @param ccyPair The ordered currency pair for which the forwardRates are valid. * @return The sensitivity. */ public double[] presentValueForwardPointsSensitivity(final Forex fx, final MulticurveProviderInterface multicurves, final DoublesCurve forwardRates, final Pair<Currency, Currency> ccyPair) { final double payTime = fx.getPaymentTime(); final Currency ccy2; final double amount1; // Implementation note: The "if" is used to check in which order the fx is given with respect to the order of the forward rates. if (checkCurrency(fx, ccyPair)) { // Currency1 of fx is first currency in ccyPair ccy2 = fx.getCurrency2(); amount1 = fx.getPaymentCurrency1().getAmount(); } else { ccy2 = fx.getCurrency1(); amount1 = fx.getPaymentCurrency2().getAmount(); } final double df2 = multicurves.getDiscountFactor(ccy2, payTime); // Backward sweep final double pvBar = 1.0; final double fwdRateBar = df2 * amount1 * pvBar; final Double[] fwdRateDp = forwardRates.getYValueParameterSensitivity(payTime); final double[] sensitivity = new double[fwdRateDp.length]; for (int loops = 0; loops < fwdRateDp.length; loops++) { sensitivity[loops] = fwdRateDp[loops] * fwdRateBar; } return sensitivity; } /** * Check that the Forex currencies are compatible with the currency pair. Returns a flag indicating if the first currency in the Forex is the first currency in the pair. * @param fx The Forex derivative. * @param ccyPair The ordered currency pair. * @return The first currency flag. */ private boolean checkCurrency(final Forex fx, final Pair<Currency, Currency> ccyPair) { ArgumentChecker.isTrue(fx.getCurrency1().equals(ccyPair.getFirst()) || fx.getCurrency1().equals(ccyPair.getSecond()), fx.getCurrency1() + "not in currency pair for forward point method"); ArgumentChecker.isTrue(fx.getCurrency2().equals(ccyPair.getFirst()) || fx.getCurrency2().equals(ccyPair.getSecond()), fx.getCurrency2() + "not in currency pair for forward point method"); return fx.getCurrency1().equals(ccyPair.getFirst()); } }