/**
* Copyright (C) 2011 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.analytics.financial.interestrate.cash.provider;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.opengamma.analytics.financial.interestrate.cash.derivative.Cash;
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.MultipleCurrencyAmount;
import com.opengamma.util.tuple.DoublesPair;
/**
* The methods associated to the pricing of cash deposit by discounting.
*/
public final class CashDiscountingMethod {
/**
* The method unique instance.
*/
private static final CashDiscountingMethod INSTANCE = new CashDiscountingMethod();
/**
* Return the unique instance of the class.
* @return The instance.
*/
public static CashDiscountingMethod getInstance() {
return INSTANCE;
}
/**
* Private constructor.
*/
private CashDiscountingMethod() {
}
/**
* Compute the present value by discounting the final cash flow (nominal + interest) and the initial payment (initial amount).
* @param deposit The deposit.
* @param curves The curves.
* @return The present value.
*/
public MultipleCurrencyAmount presentValue(final Cash deposit, final MulticurveProviderInterface curves) {
ArgumentChecker.notNull(deposit, "Deposit");
ArgumentChecker.notNull(curves, "Multicurves");
final double dfStart = curves.getDiscountFactor(deposit.getCurrency(), deposit.getStartTime());
final double dfEnd = curves.getDiscountFactor(deposit.getCurrency(), deposit.getEndTime());
final double pv = (deposit.getNotional() + deposit.getInterestAmount()) * dfEnd - deposit.getInitialAmount() * dfStart;
return MultipleCurrencyAmount.of(deposit.getCurrency(), pv);
}
/**
* Compute the present value by discounting the final cash flow (nominal + interest) and the initial payment (initial amount).
* @param deposit The deposit.
* @param curves The curves.
* @return The present value.
*/
public MultipleCurrencyMulticurveSensitivity presentValueCurveSensitivity(final Cash deposit, final MulticurveProviderInterface curves) {
ArgumentChecker.notNull(deposit, "Deposit");
ArgumentChecker.notNull(curves, "Multicurves");
final double dfStart = curves.getDiscountFactor(deposit.getCurrency(), deposit.getStartTime());
final double dfEnd = curves.getDiscountFactor(deposit.getCurrency(), deposit.getEndTime());
// Backward sweep
final double pvBar = 1.0;
final double dfEndBar = deposit.getNotional() + deposit.getInterestAmount() * pvBar;
final double dfStartBar = -deposit.getInitialAmount() * pvBar;
final Map<String, List<DoublesPair>> mapDsc = new HashMap<>();
final List<DoublesPair> listDiscounting = new ArrayList<>();
listDiscounting.add(DoublesPair.of(deposit.getStartTime(), -deposit.getStartTime() * dfStart * dfStartBar));
listDiscounting.add(DoublesPair.of(deposit.getEndTime(), -deposit.getEndTime() * dfEnd * dfEndBar));
mapDsc.put(curves.getName(deposit.getCurrency()), listDiscounting);
MultipleCurrencyMulticurveSensitivity result = new MultipleCurrencyMulticurveSensitivity();
result = result.plus(deposit.getCurrency(), MulticurveSensitivity.ofYieldDiscounting(mapDsc));
return result;
}
/**
* Computes the deposit fair rate given the start and end time and the accrual factor.
* When deposit has already start the number may not be meaning full as the remaining period is not in line with the accrual factor.
* @param deposit The deposit.
* @param curves The curves.
* @return The rate.
*/
public double parRate(final Cash deposit, final MulticurveProviderInterface curves) {
final double af = deposit.getAccrualFactor();
return (curves.getDiscountFactor(deposit.getCurrency(), deposit.getStartTime()) / curves.getDiscountFactor(deposit.getCurrency(), deposit.getEndTime()) - 1) / af;
}
/**
* Computes the spread to be added to the deposit rate to have a zero present value.
* When deposit has already start the number may not be meaning full as only the final payment remains (no initial payment).
* @param deposit The deposit.
* @param curves The curves.
* @return The spread.
*/
public double parSpread(final Cash deposit, final MulticurveProviderInterface curves) {
ArgumentChecker.notNull(deposit, "Deposit");
ArgumentChecker.notNull(curves, "Multicurves");
ArgumentChecker.isTrue(deposit.getNotional() != 0.0, "Notional is 0");
final double dfStart = curves.getDiscountFactor(deposit.getCurrency(), deposit.getStartTime());
final double dfEnd = curves.getDiscountFactor(deposit.getCurrency(), deposit.getEndTime());
return (deposit.getInitialAmount() * dfStart - (deposit.getNotional() + deposit.getInterestAmount()) * dfEnd) / (deposit.getNotional() * deposit.getAccrualFactor() * dfEnd);
}
/**
* Computes the par spread curve sensitivity.
* When deposit has already start the number may not be meaning full as only the final payment remains (no initial payment).
* @param deposit The deposit.
* @param curves The curves.
* @return The spread curve sensitivity.
*/
public MulticurveSensitivity parSpreadCurveSensitivity(final Cash deposit, final MulticurveProviderInterface curves) {
ArgumentChecker.notNull(deposit, "Deposit");
ArgumentChecker.notNull(curves, "Multicurves");
ArgumentChecker.isTrue(deposit.getNotional() != 0.0, "Notional is 0");
final double dfStart = curves.getDiscountFactor(deposit.getCurrency(), deposit.getStartTime());
final double dfEnd = curves.getDiscountFactor(deposit.getCurrency(), deposit.getEndTime());
// Backward sweep
final double parSpreadBar = 1.0;
final double dfEndBar = -(deposit.getInitialAmount() * dfStart / (dfEnd * dfEnd)) / (deposit.getNotional() * deposit.getAccrualFactor()) * parSpreadBar;
final double dfStartBar = (deposit.getInitialAmount() / dfEnd) / (deposit.getNotional() * deposit.getAccrualFactor()) * parSpreadBar;
final Map<String, List<DoublesPair>> mapDsc = new HashMap<>();
final List<DoublesPair> listDiscounting = new ArrayList<>();
listDiscounting.add(DoublesPair.of(deposit.getStartTime(), -deposit.getStartTime() * dfStart * dfStartBar));
listDiscounting.add(DoublesPair.of(deposit.getEndTime(), -deposit.getEndTime() * dfEnd * dfEndBar));
mapDsc.put(curves.getName(deposit.getCurrency()), listDiscounting);
return MulticurveSensitivity.ofYieldDiscounting(mapDsc);
}
}