/**
* Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.analytics.financial.interestrate.future.calculator;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.opengamma.analytics.financial.instrument.index.IndexON;
import com.opengamma.analytics.financial.interestrate.InstrumentDerivativeVisitorAdapter;
import com.opengamma.analytics.financial.interestrate.future.derivative.FederalFundsFutureSecurity;
import com.opengamma.analytics.financial.interestrate.future.derivative.InterestRateFutureSecurity;
import com.opengamma.analytics.financial.interestrate.future.derivative.SwapFuturesPriceDeliverableSecurity;
import com.opengamma.analytics.financial.provider.calculator.discounting.PresentValueCurveSensitivityDiscountingCalculator;
import com.opengamma.analytics.financial.provider.calculator.discounting.PresentValueDiscountingCalculator;
import com.opengamma.analytics.financial.provider.description.interestrate.ParameterProviderInterface;
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.SimplyCompoundedForwardSensitivity;
import com.opengamma.util.ArgumentChecker;
import com.opengamma.util.tuple.DoublesPair;
/**
* Computes the price curve sensitivity for different types of futures. Calculator using a multi-curve provider.
*/
public final class FuturesPriceCurveSensitivityMulticurveCalculator extends InstrumentDerivativeVisitorAdapter<ParameterProviderInterface, MulticurveSensitivity> {
/**
* The unique instance of the calculator.
*/
private static final FuturesPriceCurveSensitivityMulticurveCalculator INSTANCE = new FuturesPriceCurveSensitivityMulticurveCalculator();
/**
* Gets the calculator instance.
* @return The calculator.
*/
public static FuturesPriceCurveSensitivityMulticurveCalculator getInstance() {
return INSTANCE;
}
/**
* Constructor.
*/
private FuturesPriceCurveSensitivityMulticurveCalculator() {
}
/** Implementation note: The pricing of some futures is done by calling the PresentValueCurveSensitivityDiscountingCalculator on the underlying.
* The present value curve sensitivity calculator refers to the futures calculator, that creates a circular reference of static methods. */
private static final PresentValueCurveSensitivityDiscountingCalculator PVCSDC = PresentValueCurveSensitivityDiscountingCalculator.getInstance();
// ----- Futures -----
@Override
public MulticurveSensitivity visitInterestRateFutureSecurity(final InterestRateFutureSecurity futures, final ParameterProviderInterface multicurve) {
ArgumentChecker.notNull(futures, "Futures");
ArgumentChecker.notNull(multicurve, "Multi-curves provider");
final double priceBar = 1.0;
final double forwardBar = -priceBar;
final Map<String, List<ForwardSensitivity>> mapFwd = new HashMap<>();
final List<ForwardSensitivity> listForward = new ArrayList<>();
listForward.add(new SimplyCompoundedForwardSensitivity(futures.getFixingPeriodStartTime(), futures.getFixingPeriodEndTime(), futures.getFixingPeriodAccrualFactor(), forwardBar));
mapFwd.put(multicurve.getMulticurveProvider().getName(futures.getIborIndex()), listForward);
return MulticurveSensitivity.ofForward(mapFwd);
}
@Override
public MulticurveSensitivity visitFederalFundsFutureSecurity(final FederalFundsFutureSecurity futures, final ParameterProviderInterface multicurve) {
ArgumentChecker.notNull(futures, "Futures");
ArgumentChecker.notNull(multicurve, "Multi-curves provider");
final IndexON index = futures.getIndex();
final int nbFixing = futures.getFixingPeriodAccrualFactor().length;
final double[] rates = new double[nbFixing];
for (int loopfix = 0; loopfix < nbFixing; loopfix++) {
rates[loopfix] = multicurve.getMulticurveProvider().getSimplyCompoundForwardRate(index, futures.getFixingPeriodTime()[loopfix], futures.getFixingPeriodTime()[loopfix + 1],
futures.getFixingPeriodAccrualFactor()[loopfix]);
}
// Backward sweep
final double priceBar = 1.0;
final double interestBar = -1.0 / futures.getFixingTotalAccrualFactor() * priceBar;
final double[] ratesBar = new double[nbFixing];
for (int loopfix = 0; loopfix < nbFixing; loopfix++) {
ratesBar[loopfix] = futures.getFixingPeriodAccrualFactor()[loopfix] * interestBar;
}
final Map<String, List<ForwardSensitivity>> resultMap = new HashMap<>();
final List<ForwardSensitivity> listON = new ArrayList<>();
for (int loopfix = 0; loopfix < nbFixing; loopfix++) {
listON.add(new SimplyCompoundedForwardSensitivity(futures.getFixingPeriodTime()[loopfix], futures.getFixingPeriodTime()[loopfix + 1], futures.getFixingPeriodAccrualFactor()[loopfix],
ratesBar[loopfix]));
}
resultMap.put(multicurve.getMulticurveProvider().getName(index), listON);
return MulticurveSensitivity.ofForward(resultMap);
}
@Override
public MulticurveSensitivity visitSwapFuturesPriceDeliverableSecurity(final SwapFuturesPriceDeliverableSecurity futures, final ParameterProviderInterface multicurve) {
ArgumentChecker.notNull(futures, "futures");
ArgumentChecker.notNull(multicurve, "multi-curve provider");
double dfInv = 1.0 / multicurve.getMulticurveProvider().getDiscountFactor(futures.getCurrency(), futures.getDeliveryTime());
MulticurveSensitivity pvcs = futures.getUnderlyingSwap().accept(PVCSDC, multicurve.getMulticurveProvider()).getSensitivity(futures.getCurrency()).multipliedBy(dfInv);
final PresentValueDiscountingCalculator pvCalc = PresentValueDiscountingCalculator.getInstance();
double pv = futures.getUnderlyingSwap().accept(pvCalc, multicurve.getMulticurveProvider()).getAmount(futures.getCurrency());
final Map<String, List<DoublesPair>> resultMap = new HashMap<>();
final List<DoublesPair> listDf = new ArrayList<>();
listDf.add(DoublesPair.of(futures.getDeliveryTime(), futures.getDeliveryTime() * pv * dfInv));
resultMap.put(multicurve.getMulticurveProvider().getName(futures.getCurrency()), listDf);
MulticurveSensitivity result = MulticurveSensitivity.ofYieldDiscounting(resultMap);
return result.plus(pvcs);
}
}