/** * Copyright (C) 2014 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.analytics.financial.interestrate.bond.calculator; /** * Calculates the PV01s for a bond total return swap. */ /** A singleton instance */ /** The PV01 calculator */ /** * Gets the singleton instance. * @return The singleton instance */ /** * Private constructor. */ /** * Copyright (C) 2014 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ import java.util.Map; import com.opengamma.analytics.ShiftType; import com.opengamma.analytics.financial.instrument.index.IborIndex; import com.opengamma.analytics.financial.instrument.index.IndexON; import com.opengamma.analytics.financial.interestrate.InstrumentDerivativeVisitor; import com.opengamma.analytics.financial.interestrate.InstrumentDerivativeVisitorAdapter; import com.opengamma.analytics.financial.interestrate.bond.definition.BillTotalReturnSwap; import com.opengamma.analytics.financial.interestrate.bond.definition.BondTotalReturnSwap; import com.opengamma.analytics.financial.legalentity.LegalEntity; import com.opengamma.analytics.financial.legalentity.LegalEntityFilter; import com.opengamma.analytics.financial.model.interestrate.curve.YieldAndDiscountCurve; import com.opengamma.analytics.financial.model.interestrate.curve.YieldCurve; import com.opengamma.analytics.financial.model.interestrate.curve.YieldCurveUtils; import com.opengamma.analytics.financial.provider.calculator.discounting.PV01CurveParametersCalculator; import com.opengamma.analytics.financial.provider.calculator.issuer.PresentValueCurveSensitivityIssuerCalculator; import com.opengamma.analytics.financial.provider.description.interestrate.IssuerProviderDiscount; import com.opengamma.analytics.financial.provider.description.interestrate.MulticurveProviderDiscount; import com.opengamma.analytics.financial.provider.description.interestrate.ParameterIssuerProviderInterface; import com.opengamma.analytics.util.amount.ReferenceAmount; import com.opengamma.util.ArgumentChecker; import com.opengamma.util.money.Currency; import com.opengamma.util.tuple.Pair; import com.opengamma.util.tuple.Pairs; /** * Returns the change in PV01 of an instrument due to a parallel 1bp move of <b>all</b> the curves to which the bond total * return swap is sensitive. The value is returned in the currency of the asset. */ public final class BondBillTrsGammaPV01Calculator extends InstrumentDerivativeVisitorAdapter<ParameterIssuerProviderInterface, Double> { /** The singleton instance */ private static final InstrumentDerivativeVisitor<ParameterIssuerProviderInterface, Double> INSTANCE = new BondBillTrsGammaPV01Calculator(); /** The PV01 calculator */ private static final InstrumentDerivativeVisitor <ParameterIssuerProviderInterface, ReferenceAmount<Pair<String, Currency>>> PV01_CALCULATOR = new PV01CurveParametersCalculator<>(PresentValueCurveSensitivityIssuerCalculator.getInstance()); /** * The size of the scaling: 1 basis point. */ private static final double BP1 = 1.0E-4; /** * Gets the singleton instance. * @return The instance */ public static InstrumentDerivativeVisitor<ParameterIssuerProviderInterface, Double> getInstance() { return INSTANCE; } /** * Private constructor */ private BondBillTrsGammaPV01Calculator() { } /** * Calculates the change in PV01 of an instrument due to a parallel move of each yield curve the instrument is sensitive to, scaled so that the move is 1bp. * @param bondTrs The instrument, not null * @param data The curve data provider, not null * @return The scaled sensitivity for each curve/currency. */ @Override public Double visitBondTotalReturnSwap(final BondTotalReturnSwap bondTrs, final ParameterIssuerProviderInterface data) { ArgumentChecker.notNull(bondTrs, "bondTrs"); ArgumentChecker.notNull(data, "data"); final ParameterIssuerProviderInterface bumped = getBumpedProvider(data); final ReferenceAmount<Pair<String, Currency>> pv01 = bondTrs.accept(PV01_CALCULATOR, data); final ReferenceAmount<Pair<String, Currency>> up = bondTrs.accept(PV01_CALCULATOR, bumped); final Currency assetCurrency = bondTrs.getAsset().getCurrency(); double gammaPV01 = 0; for (final Map.Entry<Pair<String, Currency>, Double> entry : pv01.getMap().entrySet()) { final Pair<String, Currency> bumpedNameCurrency = Pairs.of(entry.getKey().getFirst() + YieldCurveUtils.PARALLEL_SHIFT_NAME, entry.getKey().getSecond()); if (!(up.getMap().containsKey(bumpedNameCurrency))) { throw new IllegalStateException("Have bumped PV01 for curve / currency pair " + entry.getKey() + " but no PV01"); } final Currency pv01Currency = entry.getKey().getSecond(); final double fxRate = data.getMulticurveProvider().getFxRate(pv01Currency, assetCurrency); gammaPV01 += fxRate * (up.getMap().get(bumpedNameCurrency) - entry.getValue()) / BP1; } return gammaPV01; } /** * Calculates the change in PV01 of an instrument due to a parallel move of each yield curve the instrument is sensitive to, scaled so that the move is 1bp. * @param billTrs The instrument, not null * @param data The curve data provider, not null * @return The scaled sensitivity for each curve/currency. */ @Override public Double visitBillTotalReturnSwap(final BillTotalReturnSwap billTrs, final ParameterIssuerProviderInterface data) { ArgumentChecker.notNull(billTrs, "billTrs"); ArgumentChecker.notNull(data, "data"); final ParameterIssuerProviderInterface bumped = getBumpedProvider(data); final ReferenceAmount<Pair<String, Currency>> pv01 = billTrs.accept(PV01_CALCULATOR, data); final ReferenceAmount<Pair<String, Currency>> up = billTrs.accept(PV01_CALCULATOR, bumped); final Currency assetCurrency = billTrs.getAsset().getCurrency(); double gammaPV01 = 0; for (final Map.Entry<Pair<String, Currency>, Double> entry : pv01.getMap().entrySet()) { final Pair<String, Currency> bumpedNameCurrency = Pairs.of(entry.getKey().getFirst() + YieldCurveUtils.PARALLEL_SHIFT_NAME, entry.getKey().getSecond()); if (!(up.getMap().containsKey(bumpedNameCurrency))) { throw new IllegalStateException("Have bumped PV01 for curve / currency pair " + entry.getKey() + " but no PV01"); } final Currency pv01Currency = entry.getKey().getSecond(); final double fxRate = data.getMulticurveProvider().getFxRate(pv01Currency, assetCurrency); gammaPV01 += fxRate * (up.getMap().get(bumpedNameCurrency) - entry.getValue()) / BP1; } return gammaPV01; } /** * Bumps every curve in a provider. This method will be replaced when the curve providers * have been refactored. * @param data The curves * @return A provider with each curve bumped by +1 bp */ private static ParameterIssuerProviderInterface getBumpedProvider(final ParameterIssuerProviderInterface data) { if (data instanceof IssuerProviderDiscount) { final IssuerProviderDiscount discount = ((IssuerProviderDiscount) data); final MulticurveProviderDiscount multicurveProvider = discount.getMulticurveProvider(); final IssuerProviderDiscount bumped = new IssuerProviderDiscount(new MulticurveProviderDiscount(multicurveProvider.getFxRates())); for (final Map.Entry<Currency, YieldAndDiscountCurve> entry : multicurveProvider.getDiscountingCurves().entrySet()) { if (!(entry.getValue() instanceof YieldCurve)) { throw new IllegalArgumentException("Can only bump YieldCurves"); } bumped.getMulticurveProvider().setCurve(entry.getKey(), YieldCurveUtils.withParallelShift((YieldCurve) entry.getValue(), BP1, ShiftType.ABSOLUTE)); } for (final Map.Entry<IborIndex, YieldAndDiscountCurve> entry : multicurveProvider.getForwardIborCurves().entrySet()) { if (!(entry.getValue() instanceof YieldCurve)) { throw new IllegalArgumentException("Can only bump YieldCurves"); } bumped.getMulticurveProvider().setCurve(entry.getKey(), YieldCurveUtils.withParallelShift((YieldCurve) entry.getValue(), BP1, ShiftType.ABSOLUTE)); } for (final Map.Entry<IndexON, YieldAndDiscountCurve> entry : multicurveProvider.getForwardONCurves().entrySet()) { if (!(entry.getValue() instanceof YieldCurve)) { throw new IllegalArgumentException("Can only bump YieldCurves"); } bumped.getMulticurveProvider().setCurve(entry.getKey(), YieldCurveUtils.withParallelShift((YieldCurve) entry.getValue(), BP1, ShiftType.ABSOLUTE)); } for (final Map.Entry<Pair<Object, LegalEntityFilter<LegalEntity>>, YieldAndDiscountCurve> entry : discount.getIssuerCurves().entrySet()) { if (!(entry.getValue() instanceof YieldCurve)) { throw new IllegalArgumentException("Can only bump YieldCurves"); } bumped.setCurve(entry.getKey(), YieldCurveUtils.withParallelShift((YieldCurve) entry.getValue(), BP1, ShiftType.ABSOLUTE)); } return bumped; } throw new UnsupportedOperationException("Cannot bump curves of type " + data.getClass()); } }