/**
* Copyright (C) 2014 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.analytics.financial.interestrate.payments.provider;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.Validate;
import com.opengamma.analytics.financial.interestrate.payments.derivative.CouponFixedFxReset;
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.money.Currency;
import com.opengamma.util.money.MultipleCurrencyAmount;
import com.opengamma.util.tuple.DoublesPair;
/**
* Method to compute results for fixed coupon with FX reset notional.
* See documentation for the hypothesis used to obtain the explicit formula.
* <P>
* Reference: Coupon with FX Reset Notional, OpenGamma Documentation 26, September 2014.
*/
public final class CouponFixedFxResetDiscountingMethod {
/**
* The method unique instance.
*/
private static final CouponFixedFxResetDiscountingMethod INSTANCE = new CouponFixedFxResetDiscountingMethod();
/**
* Return the unique instance of the class.
* @return The instance.
*/
public static CouponFixedFxResetDiscountingMethod getInstance() {
return INSTANCE;
}
/**
* Private constructor.
*/
private CouponFixedFxResetDiscountingMethod() {
}
/**
* Compute the present value of a Fixed coupon with FX reset notional by discounting.
* See documentation for the hypothesis.
* @param coupon The coupon.
* @param multicurve The multi-curve provider.
* @return The present value.
*/
public MultipleCurrencyAmount presentValue(final CouponFixedFxReset coupon,
final MulticurveProviderInterface multicurve) {
Validate.notNull(coupon, "Coupon");
Validate.notNull(multicurve, "multicurve");
Currency ccyPayment = coupon.getCurrency();
Currency ccyReference = coupon.getReferenceCurrency();
double tp = coupon.getPaymentTime();
double t0 = coupon.getFxDeliveryTime();
double todayFxRate = multicurve.getFxRate(ccyReference, ccyPayment);
double amount = coupon.paymentAmount(todayFxRate);
double dfCcyPaymentAtPayment = multicurve.getDiscountFactor(ccyPayment, tp);
double dfCcyReferenceAtDelivery = multicurve.getDiscountFactor(ccyReference, t0);
double dfCcyPaymentAtDelivery = multicurve.getDiscountFactor(ccyPayment, t0);
double pv = amount * dfCcyPaymentAtPayment * dfCcyReferenceAtDelivery / dfCcyPaymentAtDelivery;
return MultipleCurrencyAmount.of(ccyPayment, pv);
}
/**
* Compute the present value curve sensitivity of a Fixed coupon with FX reset notional by discounting.
* See documentation for the hypothesis.
* @param coupon The coupon.
* @param multicurve The multi-curve provider.
* @return The present value curve sensitivity.
*/
public MultipleCurrencyMulticurveSensitivity presentValueCurveSensitivity(final CouponFixedFxReset coupon,
final MulticurveProviderInterface multicurve) {
Validate.notNull(coupon, "Coupon");
Validate.notNull(multicurve, "multicurve");
Currency ccyPayment = coupon.getCurrency();
Currency ccyReference = coupon.getReferenceCurrency();
double tp = coupon.getPaymentTime();
double t0 = coupon.getFxDeliveryTime();
double todayFxRate = multicurve.getFxRate(ccyReference, ccyPayment);
double amount = coupon.paymentAmount(todayFxRate);
double dfCcyPaymentAtPayment = multicurve.getDiscountFactor(ccyPayment, tp);
double dfCcyReferenceAtDelivery = multicurve.getDiscountFactor(ccyReference, t0);
double dfCcyPaymentAtDelivery = multicurve.getDiscountFactor(ccyPayment, t0);
// Backward sweep.
double pvBar = 1.0;
double dfCcyPaymentAtDeliveryBar = -amount *
dfCcyPaymentAtPayment * dfCcyReferenceAtDelivery / (dfCcyPaymentAtDelivery * dfCcyPaymentAtDelivery) * pvBar;
double dfCcyReferenceAtDeliveryBar = amount * dfCcyPaymentAtPayment / dfCcyPaymentAtDelivery * pvBar;
double dfCcyPaymentAtPaymentBar = amount * dfCcyReferenceAtDelivery / dfCcyPaymentAtDelivery * pvBar;
MultipleCurrencyMulticurveSensitivity result = new MultipleCurrencyMulticurveSensitivity();
final Map<String, List<DoublesPair>> mapDscCcyPayment = new HashMap<>();
final List<DoublesPair> listDscCcyPayment = new ArrayList<>();
listDscCcyPayment.add(DoublesPair.of(t0, -t0 * dfCcyPaymentAtDelivery * dfCcyPaymentAtDeliveryBar));
listDscCcyPayment.add(DoublesPair.of(tp, -tp * dfCcyPaymentAtPayment * dfCcyPaymentAtPaymentBar));
mapDscCcyPayment.put(multicurve.getName(ccyPayment), listDscCcyPayment);
result = result.plus(ccyPayment, MulticurveSensitivity.ofYieldDiscounting(mapDscCcyPayment));
final Map<String, List<DoublesPair>> mapDscCcyReference = new HashMap<>();
final List<DoublesPair> listDscCcyReference = new ArrayList<>();
listDscCcyReference.add(DoublesPair.of(t0, -t0 * dfCcyReferenceAtDelivery * dfCcyReferenceAtDeliveryBar));
mapDscCcyReference.put(multicurve.getName(ccyReference), listDscCcyReference);
result = result.plus(ccyPayment, MulticurveSensitivity.ofYieldDiscounting(mapDscCcyReference));
return result;
}
/**
* Compute the currency exposure of a Fixed coupon with FX reset notional by discounting.
* See documentation for the hypothesis.
* @param coupon The coupon.
* @param multicurves The multi-curve provider.
* @return The present value.
*/
public MultipleCurrencyAmount currencyExposure(final CouponFixedFxReset coupon,
final MulticurveProviderInterface multicurves) {
Validate.notNull(coupon, "Coupon");
Validate.notNull(multicurves, "multicurve");
Currency ccyPayment = coupon.getCurrency();
Currency ccyReference = coupon.getReferenceCurrency();
double dfCcyPaymentAtPayment = multicurves.getDiscountFactor(ccyPayment, coupon.getPaymentTime());
double dfCcyReferenceAtDelivery = multicurves.getDiscountFactor(ccyReference, coupon.getFxDeliveryTime());
double dfCcyPaymentAtDelivery = multicurves.getDiscountFactor(ccyPayment, coupon.getFxDeliveryTime());
double pv = coupon.getNotional() * coupon.getPaymentYearFraction() * coupon.getRate() *
dfCcyPaymentAtPayment * dfCcyReferenceAtDelivery / dfCcyPaymentAtDelivery;
return MultipleCurrencyAmount.of(ccyReference, pv);
}
}