/**
* 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 com.opengamma.analytics.financial.interestrate.payments.derivative.CouponIborFxReset;
import com.opengamma.analytics.financial.provider.description.interestrate.MulticurveProviderInterface;
import com.opengamma.analytics.financial.provider.sensitivity.multicurve.ForwardSensitivity;
import com.opengamma.analytics.financial.provider.sensitivity.multicurve.MulticurveSensitivity;
import com.opengamma.analytics.financial.provider.sensitivity.multicurve.MultipleCurrencyMulticurveSensitivity;
import com.opengamma.analytics.financial.provider.sensitivity.multicurve.SimplyCompoundedForwardSensitivity;
import com.opengamma.util.ArgumentChecker;
import com.opengamma.util.money.Currency;
import com.opengamma.util.money.MultipleCurrencyAmount;
import com.opengamma.util.tuple.DoublesPair;
/**
* Method to compute present value and present value sensitivity for Ibor coupon with FX reset.
* <P>
* Reference: Coupon with FX Reset Notional, OpenGamma Documentation 26, September 2014.
*/
public final class CouponIborFxResetDiscountingMethod {
/**
* The method unique instance.
*/
private static final CouponIborFxResetDiscountingMethod INSTANCE = new CouponIborFxResetDiscountingMethod();
/**
* Return the unique instance of the class.
* @return The instance.
*/
public static CouponIborFxResetDiscountingMethod getInstance() {
return INSTANCE;
}
/**
* Private constructor.
*/
private CouponIborFxResetDiscountingMethod() {
}
/**
* Compute the present value of a Ibor coupon with spread using a specific forward rate provider by discounting.
* @param coupon The coupon with FX reset.
* @param multicurves The multi-curve provider.
* @return The present value.
*/
public MultipleCurrencyAmount presentValue(final CouponIborFxReset coupon,
final MulticurveProviderInterface multicurves) {
ArgumentChecker.notNull(coupon, "coupon");
ArgumentChecker.notNull(multicurves, "multicurves");
double forward = multicurves.getSimplyCompoundForwardRate(coupon.getIndex(),
coupon.getIborIndexFixingPeriodStartTime(), coupon.getIborIndexFixingPeriodEndTime(),
coupon.getIborIndexFixingAccrualFactor());
double tp = coupon.getPaymentTime();
double t0 = coupon.getFxDeliveryTime();
Currency ccyPayment = coupon.getCurrency();
Currency ccyReference = coupon.getReferenceCurrency();
double dfCcyPaymentAtPayment = multicurves.getDiscountFactor(ccyPayment, tp);
double dfCcyReferenceAtDelivery = multicurves.getDiscountFactor(ccyReference, t0);
double dfCcyPaymentAtDelivery = multicurves.getDiscountFactor(ccyPayment, t0);
double fxRate = multicurves.getFxRate(ccyReference, ccyPayment);
double notional = fxRate * coupon.getNotional();
double value = (forward + coupon.getSpread()) * coupon.getPaymentYearFraction() * notional * dfCcyPaymentAtPayment *
dfCcyReferenceAtDelivery / dfCcyPaymentAtDelivery;
return MultipleCurrencyAmount.of(ccyPayment, value);
}
/**
* Compute the present value sensitivity to rates of a Ibor coupon by discounting.
* @param coupon The coupon with FX reset.
* @param multicurves The multi-curve provider.
* @return The present value sensitivity.
*/
public MultipleCurrencyMulticurveSensitivity presentValueCurveSensitivity(final CouponIborFxReset coupon,
final MulticurveProviderInterface multicurves) {
ArgumentChecker.notNull(coupon, "Coupon");
ArgumentChecker.notNull(multicurves, "Multi-curves");
double forward = multicurves.getSimplyCompoundForwardRate(coupon.getIndex(),
coupon.getIborIndexFixingPeriodStartTime(), coupon.getIborIndexFixingPeriodEndTime(),
coupon.getIborIndexFixingAccrualFactor());
Currency ccyPayment = coupon.getCurrency();
Currency ccyReference = coupon.getReferenceCurrency();
double tp = coupon.getPaymentTime();
double t0 = coupon.getFxDeliveryTime();
double todayFxRate = multicurves.getFxRate(ccyReference, ccyPayment);
double notional = todayFxRate * coupon.getNotional();
double amount = notional * (forward + coupon.getSpread()) * coupon.getPaymentYearFraction();
double dfCcyPaymentAtPayment = multicurves.getDiscountFactor(ccyPayment, tp);
double dfCcyReferenceAtDelivery = multicurves.getDiscountFactor(ccyReference, t0);
double dfCcyPaymentAtDelivery = multicurves.getDiscountFactor(ccyPayment, t0);
double forwardBar = coupon.getPaymentYearFraction() * notional * dfCcyPaymentAtPayment *
dfCcyReferenceAtDelivery / dfCcyPaymentAtDelivery;
// 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(multicurves.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(multicurves.getName(ccyReference), listDscCcyReference);
result = result.plus(ccyPayment, MulticurveSensitivity.ofYieldDiscounting(mapDscCcyReference));
final Map<String, List<ForwardSensitivity>> mapFwd = new HashMap<>();
final List<ForwardSensitivity> listForward = new ArrayList<>();
listForward.add(new SimplyCompoundedForwardSensitivity(coupon.getIborIndexFixingPeriodStartTime(), coupon
.getIborIndexFixingPeriodEndTime(), coupon.getIborIndexFixingAccrualFactor(), forwardBar));
mapFwd.put(multicurves.getName(coupon.getIndex()), listForward);
result = result.plus(ccyPayment, MulticurveSensitivity.ofForward(mapFwd));
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 CouponIborFxReset coupon,
final MulticurveProviderInterface multicurves) {
ArgumentChecker.notNull(coupon, "coupon");
ArgumentChecker.notNull(multicurves, "multicurves");
double forward = multicurves.getSimplyCompoundForwardRate(coupon.getIndex(),
coupon.getIborIndexFixingPeriodStartTime(), coupon.getIborIndexFixingPeriodEndTime(),
coupon.getIborIndexFixingAccrualFactor());
double tp = coupon.getPaymentTime();
double t0 = coupon.getFxDeliveryTime();
Currency ccyPayment = coupon.getCurrency();
Currency ccyReference = coupon.getReferenceCurrency();
double dfCcyPaymentAtPayment = multicurves.getDiscountFactor(ccyPayment, tp);
double dfCcyReferenceAtDelivery = multicurves.getDiscountFactor(ccyReference, t0);
double dfCcyPaymentAtDelivery = multicurves.getDiscountFactor(ccyPayment, t0);
double notionalRef = coupon.getNotional();
double pvRef = (forward + coupon.getSpread()) * coupon.getPaymentYearFraction() * notionalRef *
dfCcyPaymentAtPayment * dfCcyReferenceAtDelivery / dfCcyPaymentAtDelivery;
return MultipleCurrencyAmount.of(ccyReference, pvRef);
}
}