/**
* Copyright (C) 2014 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.sesame.fra;
import java.security.InvalidParameterException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.threeten.bp.ZonedDateTime;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.opengamma.analytics.financial.instrument.InstrumentDefinition;
import com.opengamma.analytics.financial.instrument.fra.ForwardRateAgreementDefinition;
import com.opengamma.analytics.financial.interestrate.InstrumentDerivative;
import com.opengamma.analytics.financial.interestrate.InstrumentDerivativeVisitor;
import com.opengamma.analytics.financial.provider.calculator.discounting.CrossGammaMultiCurveCalculator;
import com.opengamma.analytics.financial.provider.calculator.discounting.CrossGammaSingleCurveCalculator;
import com.opengamma.analytics.financial.provider.calculator.discounting.PV01CurveParametersCalculator;
import com.opengamma.analytics.financial.provider.calculator.discounting.ParRateDiscountingCalculator;
import com.opengamma.analytics.financial.provider.calculator.discounting.PresentValueCurveSensitivityDiscountingCalculator;
import com.opengamma.analytics.financial.provider.calculator.discounting.PresentValueDiscountingCalculator;
import com.opengamma.analytics.financial.provider.calculator.generic.MarketQuoteSensitivityBlockCalculator;
import com.opengamma.analytics.financial.provider.curve.CurveBuildingBlockBundle;
import com.opengamma.analytics.financial.provider.description.interestrate.MulticurveProviderDiscount;
import com.opengamma.analytics.financial.provider.description.interestrate.MulticurveProviderInterface;
import com.opengamma.analytics.financial.provider.description.interestrate.ParameterProviderInterface;
import com.opengamma.analytics.financial.provider.sensitivity.multicurve.MultipleCurrencyMulticurveSensitivity;
import com.opengamma.analytics.financial.provider.sensitivity.multicurve.MultipleCurrencyParameterSensitivity;
import com.opengamma.analytics.financial.provider.sensitivity.parameter.ParameterSensitivityParameterCalculator;
import com.opengamma.analytics.math.matrix.CommonsMatrixAlgebra;
import com.opengamma.analytics.math.matrix.DoubleMatrix1D;
import com.opengamma.analytics.math.matrix.DoubleMatrix2D;
import com.opengamma.analytics.util.amount.ReferenceAmount;
import com.opengamma.financial.analytics.DoubleLabelledMatrix1D;
import com.opengamma.financial.analytics.DoubleLabelledMatrix2D;
import com.opengamma.financial.analytics.conversion.FRASecurityConverter;
import com.opengamma.financial.analytics.conversion.FixedIncomeConverterDataProvider;
import com.opengamma.financial.analytics.model.fixedincome.BucketedCrossSensitivities;
import com.opengamma.financial.analytics.model.fixedincome.BucketedCurveSensitivities;
import com.opengamma.financial.analytics.model.fixedincome.FraCashFlowDetailsCalculator;
import com.opengamma.financial.analytics.model.fixedincome.SwapLegCashFlows;
import com.opengamma.financial.analytics.timeseries.HistoricalTimeSeriesBundle;
import com.opengamma.financial.security.fra.FRASecurity;
import com.opengamma.financial.security.fra.ForwardRateAgreementSecurity;
import com.opengamma.financial.security.irs.PayReceiveType;
import com.opengamma.sesame.CurveMatrixLabeller;
import com.opengamma.util.ArgumentChecker;
import com.opengamma.util.money.Currency;
import com.opengamma.util.money.MultipleCurrencyAmount;
import com.opengamma.util.result.FailureStatus;
import com.opengamma.util.result.Result;
import com.opengamma.util.tuple.Pair;
import com.opengamma.util.tuple.Pairs;
/**
* Calculator for Discounting FRAs.
*/
public class DiscountingFRACalculator implements FRACalculator {
/**
* Calculator for present value.
*/
private static final PresentValueDiscountingCalculator PVDC = PresentValueDiscountingCalculator.getInstance();
/**
* Calculator for par rate.
*/
private static final ParRateDiscountingCalculator PRDC = ParRateDiscountingCalculator.getInstance();
/**
* Calculator for PV01
*/
private static final PV01CurveParametersCalculator<ParameterProviderInterface> PV01C =
new PV01CurveParametersCalculator<>(PresentValueCurveSensitivityDiscountingCalculator.getInstance());
/** The curve sensitivity calculator */
private static final InstrumentDerivativeVisitor<ParameterProviderInterface, MultipleCurrencyMulticurveSensitivity> PVCSDC =
PresentValueCurveSensitivityDiscountingCalculator.getInstance();
/** The parameter sensitivity calculator */
private static final ParameterSensitivityParameterCalculator<ParameterProviderInterface> PSC =
new ParameterSensitivityParameterCalculator<>(PVCSDC);
/** The market quote sensitivity calculator */
private static final MarketQuoteSensitivityBlockCalculator<ParameterProviderInterface> BUCKETED_PV01_CALCULATOR =
new MarketQuoteSensitivityBlockCalculator<>(PSC);
/** The calculator which will compute intra-curve gammas */
private static final CrossGammaMultiCurveCalculator CGC = new CrossGammaMultiCurveCalculator(PVCSDC);
/** The calculator which will compute the sum of columns gammas */
private static final CrossGammaSingleCurveCalculator SUM_OF_COLUMNS_GAMMA = new CrossGammaSingleCurveCalculator(PVCSDC);
/** Matrix algebra tooling to permit matrix manipulation */
private static final CommonsMatrixAlgebra MA = new CommonsMatrixAlgebra();
/**
* Provides scaling to/from basis points.
*/
private static final double BASIS_POINT_FACTOR = 1.0E-4;
/**
* Derivative form of the security.
*/
private final InstrumentDerivative _derivative;
/**
* The multicurve bundle.
*/
private final MulticurveProviderDiscount _bundle;
/**
* The curve building block bundle.
*/
private final CurveBuildingBlockBundle _curveBuildingBlockBundle;
/**
* The curve labellers.
*/
private final Map<String, CurveMatrixLabeller> _curveLabellers;
/**
* The FRA definition.
*/
private ForwardRateAgreementDefinition _definition;
/**
* Creates a calculator for a FRA.
* @param security the fra to calculate values for, not null
* @param bundle the multicurve bundle, including the curves, not null
* @param fraConverter converter for transforming a fra into its InstrumentDefinition form, not null
* @param valuationTime the ZonedDateTime, not null
* @param curveBuildingBlockBundle the curve block building bundle, not null
* @param curveLabellers the curve labellers, not null
*/
public DiscountingFRACalculator(FRASecurity security,
MulticurveProviderDiscount bundle,
FRASecurityConverter fraConverter,
ZonedDateTime valuationTime,
CurveBuildingBlockBundle curveBuildingBlockBundle,
Map<String, CurveMatrixLabeller> curveLabellers) {
ArgumentChecker.notNull(security, "security");
ArgumentChecker.notNull(fraConverter, "fraConverter");
ArgumentChecker.notNull(valuationTime, "valuationTime");
_derivative = createInstrumentDerivative(security, fraConverter, valuationTime);
_bundle = ArgumentChecker.notNull(bundle, "bundle");
_curveBuildingBlockBundle = ArgumentChecker.notNull(curveBuildingBlockBundle, "curveBuildingBlockBundle");
_curveLabellers = ArgumentChecker.notNull(curveLabellers, "curveLabellers");
}
/**
* Creates a calculator for a FRA.
*
* @param security the fra to calculate values for, not null
* @param bundle the multicurve bundle, including the curves, not null
* @param fraConverter converter for transforming a fra into its InstrumentDefinition form, not null
* @param valuationTime the ZonedDateTime, not null
* @param definitionConverter converter for transforming the instrumentDefinition into the Derivative, not null
* @param fixings the HistoricalTimeSeriesBundle, a collection of historical time-series objects
* @param curveBuildingBlockBundle the curve block building bundle, not null
* @param curveLabellers the curve labellers, not null
*/
public DiscountingFRACalculator(ForwardRateAgreementSecurity security,
MulticurveProviderDiscount bundle,
FRASecurityConverter fraConverter,
ZonedDateTime valuationTime,
FixedIncomeConverterDataProvider definitionConverter,
HistoricalTimeSeriesBundle fixings,
CurveBuildingBlockBundle curveBuildingBlockBundle,
Map<String, CurveMatrixLabeller> curveLabellers) {
ArgumentChecker.notNull(security, "security");
ArgumentChecker.notNull(fraConverter, "fraConverter");
ArgumentChecker.notNull(valuationTime, "valuationTime");
ArgumentChecker.notNull(definitionConverter, "definitionConverter");
ArgumentChecker.notNull(fixings, "fixings");
_definition = (ForwardRateAgreementDefinition) security.accept(fraConverter);
_derivative = _definition.toDerivative(valuationTime);
_bundle = ArgumentChecker.notNull(bundle, "bundle");
_curveBuildingBlockBundle = ArgumentChecker.notNull(curveBuildingBlockBundle, "curveBuildingBlockBundle");
_curveLabellers = ArgumentChecker.notNull(curveLabellers, "curveLabellers");
}
@Override
public Result<MultipleCurrencyAmount> calculatePV() {
return Result.success(calculateResult(PVDC));
}
@Override
public Result<MultipleCurrencyAmount> calculatePv(MulticurveProviderInterface bundle) {
ArgumentChecker.notNull(bundle, "curve bundle");
return Result.success(_derivative.accept(PVDC, bundle));
}
@Override
public Result<Double> calculateRate() {
return Result.success(calculateResult(PRDC));
}
private <T> T calculateResult(InstrumentDerivativeVisitor<ParameterProviderInterface, T> calculator) {
return _derivative.accept(calculator, _bundle);
}
private InstrumentDerivative createInstrumentDerivative(FRASecurity security,
FRASecurityConverter fraConverter,
ZonedDateTime valuationTime) {
InstrumentDefinition<?> definition = security.accept(fraConverter);
return definition.toDerivative(valuationTime);
}
@Override
public Result<ReferenceAmount<Pair<String, Currency>>> calculatePV01() {
return Result.success(calculateResult(PV01C));
}
@Override
public Result<BucketedCurveSensitivities> calculateBucketedPV01() {
MultipleCurrencyParameterSensitivity sensitivity = BUCKETED_PV01_CALCULATOR
.fromInstrument(_derivative, _bundle, _curveBuildingBlockBundle)
.multipliedBy(BASIS_POINT_FACTOR);
Map<Pair<String, Currency>, DoubleLabelledMatrix1D> labelledMatrix1DMap = new HashMap<>();
for (Map.Entry<Pair<String, Currency>, DoubleMatrix1D> entry : sensitivity.getSensitivities().entrySet()) {
CurveMatrixLabeller labeller = _curveLabellers.get(entry.getKey().getFirst());
DoubleLabelledMatrix1D matrix = labeller.labelMatrix(entry.getValue());
labelledMatrix1DMap.put(entry.getKey(), matrix);
}
return Result.success(BucketedCurveSensitivities.of(labelledMatrix1DMap));
}
@Override
public Result<BucketedCrossSensitivities> calculateBucketedCrossGamma() {
HashMap<String, DoubleMatrix2D> crossGammas = CGC.calculateCrossGammaIntraCurve(_derivative, _bundle);
Map<String, DoubleLabelledMatrix2D> labelledMatrix2DMap = new HashMap<>();
for (Map.Entry<String, DoubleMatrix2D> entry : crossGammas.entrySet()) {
CurveMatrixLabeller labeller = _curveLabellers.get(entry.getKey());
//Values returned from analytics need to be scaled appropriately: multiplied by 1 bp ^ 1bp
DoubleMatrix2D scaledValues = (DoubleMatrix2D) MA.scale(entry.getValue(), BASIS_POINT_FACTOR * BASIS_POINT_FACTOR);
DoubleLabelledMatrix2D matrix = labeller.labelMatrix(scaledValues);
labelledMatrix2DMap.put(entry.getKey(), matrix);
}
return Result.success(BucketedCrossSensitivities.of(labelledMatrix2DMap));
}
@Override
public Result<BucketedCurveSensitivities> calculateBucketedGamma() {
MulticurveProviderDiscount singleCurveBundle = (MulticurveProviderDiscount) _bundle;
Set<String> curveNames = singleCurveBundle.getAllCurveNames();
if (curveNames.size() != 1) {
return Result.failure(
new InvalidParameterException("Only bucketed gamma on single-curve multicurve is currently supported"));
}
Set<Currency> currencies = singleCurveBundle.getCurrencies();
double[] rawGamma = SUM_OF_COLUMNS_GAMMA.calculateSumOfColumnsGamma(_derivative, singleCurveBundle);
for (int i = 0; i < rawGamma.length; ++i) {
rawGamma[i] *= BASIS_POINT_FACTOR * BASIS_POINT_FACTOR;
}
DoubleMatrix1D gamma = new DoubleMatrix1D(rawGamma);
Pair<String, Currency> sensitivityKey = Pairs.of(curveNames.iterator().next(), currencies.iterator().next());
CurveMatrixLabeller curveMatrixLabeller = _curveLabellers.get(sensitivityKey.getFirst());
DoubleLabelledMatrix1D matrix = curveMatrixLabeller.labelMatrix(gamma);
Map<Pair<String, Currency>, DoubleLabelledMatrix1D> labelledMatrix1DMap = ImmutableMap.of(sensitivityKey, matrix);
return Result.success(BucketedCurveSensitivities.of(labelledMatrix1DMap));
}
@Override
public Result<SwapLegCashFlows> calculateReceiveCashFlows() {
SwapLegCashFlows flows = _derivative.accept(new FraCashFlowDetailsCalculator(_bundle, PayReceiveType.RECEIVE), _definition);
return Result.success(flows);
}
@Override
public Result<SwapLegCashFlows> calculatePayCashFlows() {
SwapLegCashFlows flows = _derivative.accept(new FraCashFlowDetailsCalculator(_bundle, PayReceiveType.PAY), _definition);
return Result.success(flows);
}
}