com.opengamma.strata.pricer.impl.swap.DiscountingFxResetNotionalExchangePricer Maven / Gradle / Ivy
/*
* Copyright (C) 2015 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.strata.pricer.impl.swap;
import java.time.LocalDate;
import com.opengamma.strata.basics.currency.Currency;
import com.opengamma.strata.basics.currency.CurrencyAmount;
import com.opengamma.strata.basics.currency.MultiCurrencyAmount;
import com.opengamma.strata.market.explain.ExplainKey;
import com.opengamma.strata.market.explain.ExplainMapBuilder;
import com.opengamma.strata.market.sensitivity.PointSensitivityBuilder;
import com.opengamma.strata.pricer.DiscountFactors;
import com.opengamma.strata.pricer.fx.FxIndexRates;
import com.opengamma.strata.pricer.rate.RatesProvider;
import com.opengamma.strata.pricer.swap.SwapPaymentEventPricer;
import com.opengamma.strata.product.swap.FxResetNotionalExchange;
/**
* Pricer implementation for the exchange of FX reset notionals.
*
* The FX reset notional exchange is priced by discounting the value of the exchange.
* The value of the exchange is calculated by performing an FX conversion on the amount.
*/
public class DiscountingFxResetNotionalExchangePricer
implements SwapPaymentEventPricer {
/**
* Default implementation.
*/
public static final DiscountingFxResetNotionalExchangePricer DEFAULT =
new DiscountingFxResetNotionalExchangePricer();
/**
* Creates an instance.
*/
public DiscountingFxResetNotionalExchangePricer() {
}
//-------------------------------------------------------------------------
@Override
public double presentValue(FxResetNotionalExchange event, RatesProvider provider) {
// forecastValue * discountFactor
double df = provider.discountFactor(event.getCurrency(), event.getPaymentDate());
return forecastValue(event, provider) * df;
}
@Override
public PointSensitivityBuilder presentValueSensitivity(FxResetNotionalExchange event, RatesProvider provider) {
DiscountFactors discountFactors = provider.discountFactors(event.getCurrency());
PointSensitivityBuilder sensiDsc = discountFactors.zeroRatePointSensitivity(event.getPaymentDate());
sensiDsc = sensiDsc.multipliedBy(forecastValue(event, provider));
PointSensitivityBuilder sensiFx = forecastValueSensitivity(event, provider);
sensiFx = sensiFx.multipliedBy(discountFactors.discountFactor(event.getPaymentDate()));
return sensiDsc.combinedWith(sensiFx);
}
//-------------------------------------------------------------------------
@Override
public double forecastValue(FxResetNotionalExchange event, RatesProvider provider) {
// notional * fxRate
return event.getNotional() * fxRate(event, provider);
}
// obtains the FX rate
private double fxRate(FxResetNotionalExchange event, RatesProvider provider) {
FxIndexRates rates = provider.fxIndexRates(event.getObservation().getIndex());
return rates.rate(event.getObservation(), event.getReferenceCurrency());
}
@Override
public PointSensitivityBuilder forecastValueSensitivity(FxResetNotionalExchange event, RatesProvider provider) {
FxIndexRates rates = provider.fxIndexRates(event.getObservation().getIndex());
return rates.ratePointSensitivity(event.getObservation(), event.getReferenceCurrency())
.multipliedBy(event.getNotional());
}
//-------------------------------------------------------------------------
@Override
public void explainPresentValue(FxResetNotionalExchange event, RatesProvider provider, ExplainMapBuilder builder) {
Currency currency = event.getCurrency();
LocalDate paymentDate = event.getPaymentDate();
builder.put(ExplainKey.ENTRY_TYPE, "FxResetNotionalExchange");
builder.put(ExplainKey.PAYMENT_DATE, paymentDate);
builder.put(ExplainKey.PAYMENT_CURRENCY, currency);
builder.put(ExplainKey.TRADE_NOTIONAL, event.getNotionalAmount());
if (paymentDate.isBefore(provider.getValuationDate())) {
builder.put(ExplainKey.COMPLETED, Boolean.TRUE);
builder.put(ExplainKey.FORECAST_VALUE, CurrencyAmount.zero(currency));
builder.put(ExplainKey.PRESENT_VALUE, CurrencyAmount.zero(currency));
} else {
builder.addListEntry(ExplainKey.OBSERVATIONS, child -> {
child.put(ExplainKey.ENTRY_TYPE, "FxObservation");
child.put(ExplainKey.INDEX, event.getObservation().getIndex());
child.put(ExplainKey.FIXING_DATE, event.getObservation().getFixingDate());
child.put(ExplainKey.INDEX_VALUE, fxRate(event, provider));
});
builder.put(ExplainKey.DISCOUNT_FACTOR, provider.discountFactor(currency, paymentDate));
builder.put(ExplainKey.FORECAST_VALUE, CurrencyAmount.of(currency, forecastValue(event, provider)));
builder.put(ExplainKey.PRESENT_VALUE, CurrencyAmount.of(currency, presentValue(event, provider)));
}
}
//-------------------------------------------------------------------------
@Override
public MultiCurrencyAmount currencyExposure(FxResetNotionalExchange event, RatesProvider provider) {
LocalDate fixingDate = event.getObservation().getFixingDate();
FxIndexRates rates = provider.fxIndexRates(event.getObservation().getIndex());
double df = provider.discountFactor(event.getCurrency(), event.getPaymentDate());
if (!fixingDate.isAfter(provider.getValuationDate()) &&
rates.getFixings().get(fixingDate).isPresent()) {
double fxRate = rates.rate(event.getObservation(), event.getReferenceCurrency());
return MultiCurrencyAmount.of(CurrencyAmount.of(event.getCurrency(), event.getNotional() * df * fxRate));
}
LocalDate maturityDate = event.getObservation().getMaturityDate();
double fxRateSpotSensitivity =
rates.getFxForwardRates().rateFxSpotSensitivity(event.getReferenceCurrency(), maturityDate);
return MultiCurrencyAmount.of(
CurrencyAmount.of(event.getReferenceCurrency(), event.getNotional() * df * fxRateSpotSensitivity));
}
@Override
public double currentCash(FxResetNotionalExchange event, RatesProvider provider) {
if (provider.getValuationDate().isEqual(event.getPaymentDate())) {
return forecastValue(event, provider);
}
return 0d;
}
}