/**
* Copyright (C) 2015 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.analytics.financial.interestrate.future.provider;
import static org.testng.AssertJUnit.assertEquals;
import java.util.Arrays;
import java.util.LinkedHashMap;
import org.testng.annotations.Test;
import org.threeten.bp.ZonedDateTime;
import com.opengamma.analytics.financial.instrument.future.InterestRateFutureOptionMarginSecurityDefinition;
import com.opengamma.analytics.financial.instrument.future.InterestRateFutureOptionMarginTransactionDefinition;
import com.opengamma.analytics.financial.instrument.future.InterestRateFutureSecurityDefinition;
import com.opengamma.analytics.financial.instrument.index.IborIndex;
import com.opengamma.analytics.financial.instrument.index.IndexIborMaster;
import com.opengamma.analytics.financial.interestrate.future.calculator.FuturesPriceMulticurveCalculator;
import com.opengamma.analytics.financial.interestrate.future.calculator.FuturesPriceNormalSTIRFuturesCalculator;
import com.opengamma.analytics.financial.interestrate.future.derivative.InterestRateFutureOptionMarginSecurity;
import com.opengamma.analytics.financial.interestrate.future.derivative.InterestRateFutureOptionMarginTransaction;
import com.opengamma.analytics.financial.interestrate.future.derivative.InterestRateFutureSecurity;
import com.opengamma.analytics.financial.model.interestrate.curve.YieldAndDiscountCurve;
import com.opengamma.analytics.financial.model.interestrate.curve.YieldPeriodicCurve;
import com.opengamma.analytics.financial.provider.calculator.discounting.PV01CurveParametersCalculator;
import com.opengamma.analytics.financial.provider.calculator.normalstirfutures.DeltaNormalSTIRFutureOptionCalculator;
import com.opengamma.analytics.financial.provider.calculator.normalstirfutures.GammaNormalSTIRFutureOptionCalculator;
import com.opengamma.analytics.financial.provider.calculator.normalstirfutures.PositionDeltaNormalSTIRFutureOptionCalculator;
import com.opengamma.analytics.financial.provider.calculator.normalstirfutures.PositionGammaNormalSTIRFutureOptionCalculator;
import com.opengamma.analytics.financial.provider.calculator.normalstirfutures.PositionThetaNormalSTIRFutureOptionCalculator;
import com.opengamma.analytics.financial.provider.calculator.normalstirfutures.PositionVegaNormalSTIRFutureOptionCalculator;
import com.opengamma.analytics.financial.provider.calculator.normalstirfutures.PresentValueCurveSensitivityNormalSTIRFuturesCalculator;
import com.opengamma.analytics.financial.provider.calculator.normalstirfutures.PresentValueNormalSTIRFuturesCalculator;
import com.opengamma.analytics.financial.provider.calculator.normalstirfutures.ThetaNormalSTIRFutureOptionCalculator;
import com.opengamma.analytics.financial.provider.calculator.normalstirfutures.VegaNormalSTIRFutureOptionCalculator;
import com.opengamma.analytics.financial.provider.description.interestrate.MulticurveProviderDiscount;
import com.opengamma.analytics.financial.provider.description.interestrate.NormalSTIRFuturesExpSimpleMoneynessProviderDiscount;
import com.opengamma.analytics.financial.provider.description.interestrate.NormalSTIRFuturesProviderInterface;
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.financial.util.AssertSensitivityObjects;
import com.opengamma.analytics.math.curve.InterpolatedDoublesCurve;
import com.opengamma.analytics.math.interpolation.CombinedInterpolatorExtrapolatorFactory;
import com.opengamma.analytics.math.interpolation.GridInterpolator2D;
import com.opengamma.analytics.math.interpolation.Interpolator1D;
import com.opengamma.analytics.math.interpolation.Interpolator1DFactory;
import com.opengamma.analytics.math.matrix.DoubleMatrix1D;
import com.opengamma.analytics.math.surface.InterpolatedDoublesSurface;
import com.opengamma.analytics.util.amount.ReferenceAmount;
import com.opengamma.financial.convention.calendar.Calendar;
import com.opengamma.util.money.Currency;
import com.opengamma.util.money.MultipleCurrencyAmount;
import com.opengamma.util.time.DateUtils;
import com.opengamma.util.tuple.ObjectsPair;
import com.opengamma.util.tuple.Pair;
import com.opengamma.util.tuple.Pairs;
/**
*
*/
public class STIRFuturesOptionNormalExpSimpleMoneynessGBPE2ETest {
private static final IndexIborMaster INDEX_MASTER = IndexIborMaster.getInstance();
private static final ZonedDateTime VALUATION_DATE = DateUtils.getUTCDate(2014, 2, 17, 9, 0);
private static final BondAndSTIRFuturesE2EExamplesData DATA = new BondAndSTIRFuturesE2EExamplesData();
/* curve and surface */
private static final IborIndex GBPLIBOR3M = INDEX_MASTER.getIndex("GBPLIBOR3M");
private static final Currency GBP = GBPLIBOR3M.getCurrency();
private static final MulticurveProviderDiscount MULTICURVES;
static {
Interpolator1D interpolator = CombinedInterpolatorExtrapolatorFactory.getInterpolator(Interpolator1DFactory.LINEAR,
Interpolator1DFactory.FLAT_EXTRAPOLATOR, Interpolator1DFactory.LINEAR_EXTRAPOLATOR);
String curveName = "GBP curve";
InterpolatedDoublesCurve rawCurve = InterpolatedDoublesCurve.from(DATA.getTimeGBP(), DATA.getRateGBP(),
interpolator, curveName);
int compoundPeriodsPerYear = 1;
YieldAndDiscountCurve singleCurve = YieldPeriodicCurve.from(compoundPeriodsPerYear, rawCurve);
MULTICURVES = new MulticurveProviderDiscount();
MULTICURVES.setCurve(GBPLIBOR3M, singleCurve);
}
private static final Interpolator1D VALUESSQUARE_FLAT = CombinedInterpolatorExtrapolatorFactory.getInterpolator(
Interpolator1DFactory.SQUARE_LINEAR, Interpolator1DFactory.FLAT_EXTRAPOLATOR,
Interpolator1DFactory.FLAT_EXTRAPOLATOR);
private static final Interpolator1D TIME_VALUESSQUARE_FLAT = CombinedInterpolatorExtrapolatorFactory.getInterpolator(
Interpolator1DFactory.TIME_SQUARE, Interpolator1DFactory.FLAT_EXTRAPOLATOR,
Interpolator1DFactory.FLAT_EXTRAPOLATOR);
private static final GridInterpolator2D INTERPOLATOR_2D = new GridInterpolator2D(TIME_VALUESSQUARE_FLAT, VALUESSQUARE_FLAT);
private static final InterpolatedDoublesSurface VOL_SURFACE_SIMPLEMONEY;
static {
VOL_SURFACE_SIMPLEMONEY = InterpolatedDoublesSurface.from(DATA.getExpiry(), DATA.getSimpleMoneyness(),
DATA.getVolatility(), INTERPOLATOR_2D);
}
private static final NormalSTIRFuturesExpSimpleMoneynessProviderDiscount NORMAL_MULTICURVES =
new NormalSTIRFuturesExpSimpleMoneynessProviderDiscount(MULTICURVES, VOL_SURFACE_SIMPLEMONEY, GBPLIBOR3M, false);
/* Rate futures */
private static final InterestRateFutureSecurityDefinition RATE_FUTURE_Q; // Quarterly
private static final InterestRateFutureSecurityDefinition RATE_FUTURE_S; // Serial
private static final InterestRateFutureSecurityDefinition RATE_FUTURE_M; // Mid-curve
private static final ZonedDateTime LAST_TRADING_DATE_Q = DateUtils.getUTCDate(2014, 6, 19, 0, 0);
private static final ZonedDateTime LAST_TRADING_DATE_S = DateUtils.getUTCDate(2014, 6, 19, 0, 0);
private static final ZonedDateTime LAST_TRADING_DATE_M = DateUtils.getUTCDate(2015, 6, 17, 0, 0);
private static final double NOTIONAL = 5000.0;
private static final String FUTURE_NAME = "20140300";
private static final Calendar CALENDAR = DATA.getGBPCalendar();
private static final double PAYMENT_ACCRUAL_FACTOR = 0.25;
static {
RATE_FUTURE_Q = new InterestRateFutureSecurityDefinition(LAST_TRADING_DATE_Q, GBPLIBOR3M, NOTIONAL,
PAYMENT_ACCRUAL_FACTOR, FUTURE_NAME, CALENDAR);
RATE_FUTURE_S = new InterestRateFutureSecurityDefinition(LAST_TRADING_DATE_S, GBPLIBOR3M, NOTIONAL,
PAYMENT_ACCRUAL_FACTOR, FUTURE_NAME, CALENDAR);
RATE_FUTURE_M = new InterestRateFutureSecurityDefinition(LAST_TRADING_DATE_M, GBPLIBOR3M, NOTIONAL,
PAYMENT_ACCRUAL_FACTOR, FUTURE_NAME, CALENDAR);
}
/* Rate futures option */
private static final ZonedDateTime EXPIRATION_DATE = DateUtils.getUTCDate(2014, 6, 19, 0, 0);
private static final ZonedDateTime EXPIRATION_DATE_S = DateUtils.getUTCDate(2014, 5, 21, 0, 0);
private static final double STRIKE = 0.995;
private static final boolean IS_CALL = false;
private static final double STRIKE_S = 0.925;
private static final boolean IS_CALL_S = true;
private static final InterestRateFutureOptionMarginSecurityDefinition RATE_FUTURE_OPTION_Q =
new InterestRateFutureOptionMarginSecurityDefinition(RATE_FUTURE_Q, EXPIRATION_DATE, STRIKE, IS_CALL);
private static final InterestRateFutureOptionMarginSecurityDefinition RATE_FUTURE_OPTION_S =
new InterestRateFutureOptionMarginSecurityDefinition(RATE_FUTURE_S, EXPIRATION_DATE_S, STRIKE_S, IS_CALL_S);
private static final InterestRateFutureOptionMarginSecurityDefinition RATE_FUTURE_OPTION_M =
new InterestRateFutureOptionMarginSecurityDefinition(RATE_FUTURE_M, EXPIRATION_DATE, STRIKE, IS_CALL);
/* Rate futures option transaction */
private static final ZonedDateTime TRADE_DATE = DateUtils.getUTCDate(2008, 8, 27, 1, 0);
private static final long QUANTITY = 1;
private static final double TRADE_PRICE = 0.0;
private static final InterestRateFutureOptionMarginTransactionDefinition TRANSACTION_DEFINITION_Q =
new InterestRateFutureOptionMarginTransactionDefinition(RATE_FUTURE_OPTION_Q, QUANTITY, TRADE_DATE, TRADE_PRICE);
private static final InterestRateFutureOptionMarginTransactionDefinition TRANSACTION_DEFINITION_S =
new InterestRateFutureOptionMarginTransactionDefinition(RATE_FUTURE_OPTION_S, QUANTITY, TRADE_DATE, TRADE_PRICE);
private static final InterestRateFutureOptionMarginTransactionDefinition TRANSACTION_DEFINITION_M =
new InterestRateFutureOptionMarginTransactionDefinition(RATE_FUTURE_OPTION_M, QUANTITY, TRADE_DATE, TRADE_PRICE);
private static final Double LAST_MARGIN_PRICE = 0.004;
private static final InterestRateFutureOptionMarginTransaction TRANSACTION_Q = TRANSACTION_DEFINITION_Q.toDerivative(
VALUATION_DATE, LAST_MARGIN_PRICE);
private static final InterestRateFutureOptionMarginTransaction TRANSACTION_S = TRANSACTION_DEFINITION_S.toDerivative(
VALUATION_DATE, LAST_MARGIN_PRICE);
private static final InterestRateFutureOptionMarginTransaction TRANSACTION_M = TRANSACTION_DEFINITION_M.toDerivative(
VALUATION_DATE, LAST_MARGIN_PRICE);
private static final FuturesPriceNormalSTIRFuturesCalculator POC =
FuturesPriceNormalSTIRFuturesCalculator.getInstance();
private static final PresentValueNormalSTIRFuturesCalculator PVC =
PresentValueNormalSTIRFuturesCalculator.getInstance();
private static final PresentValueCurveSensitivityNormalSTIRFuturesCalculator PVSC =
PresentValueCurveSensitivityNormalSTIRFuturesCalculator.getInstance();
private static final ParameterSensitivityParameterCalculator<NormalSTIRFuturesProviderInterface> PSSFC =
new ParameterSensitivityParameterCalculator<>(PVSC);
private static final PV01CurveParametersCalculator<NormalSTIRFuturesProviderInterface> PV01PC =
new PV01CurveParametersCalculator<>(PVSC);
private static final PositionDeltaNormalSTIRFutureOptionCalculator PDEC =
PositionDeltaNormalSTIRFutureOptionCalculator.getInstance();
private static final PositionGammaNormalSTIRFutureOptionCalculator PGAC =
PositionGammaNormalSTIRFutureOptionCalculator.getInstance();
private static final PositionThetaNormalSTIRFutureOptionCalculator PTHC =
PositionThetaNormalSTIRFutureOptionCalculator.getInstance();
private static final PositionVegaNormalSTIRFutureOptionCalculator PVEC =
PositionVegaNormalSTIRFutureOptionCalculator.getInstance();
private static final FuturesPriceMulticurveCalculator FPC = FuturesPriceMulticurveCalculator.getInstance();
private static final double TOL = 1.0e-10;
private static final double TOLERANCE_PRICE = 1.0e-8;
private static final double BP1 = 1.0E-4;
/**
* Options on GBPLIBOR3M futures
*/
@Test
public void testGBP() {
double optionPriceQ = TRANSACTION_Q.accept(POC, NORMAL_MULTICURVES) * 100.0;
MultipleCurrencyAmount pvQ = TRANSACTION_Q.accept(PVC, NORMAL_MULTICURVES);
MultipleCurrencyParameterSensitivity bucketedPv01Q = PSSFC.calculateSensitivity(TRANSACTION_Q, NORMAL_MULTICURVES)
.multipliedBy(BP1);
ReferenceAmount<Pair<String, Currency>> pv01Q = TRANSACTION_Q.accept(PV01PC, NORMAL_MULTICURVES);
double deltaQ = TRANSACTION_Q.accept(PDEC, NORMAL_MULTICURVES);
double gammaQ = TRANSACTION_Q.accept(PGAC, NORMAL_MULTICURVES);
double thetaQ = TRANSACTION_Q.accept(PTHC, NORMAL_MULTICURVES);
double vegaQ = TRANSACTION_Q.accept(PVEC, NORMAL_MULTICURVES);
double optionPriceS = TRANSACTION_S.accept(POC, NORMAL_MULTICURVES) * 100.0;
MultipleCurrencyAmount pvS = TRANSACTION_S.accept(PVC, NORMAL_MULTICURVES);
MultipleCurrencyParameterSensitivity bucketedPv01S = PSSFC.calculateSensitivity(TRANSACTION_S, NORMAL_MULTICURVES)
.multipliedBy(BP1);
ReferenceAmount<Pair<String, Currency>> pv01S = TRANSACTION_S.accept(PV01PC, NORMAL_MULTICURVES);
double deltaS = TRANSACTION_S.accept(PDEC, NORMAL_MULTICURVES);
double gammaS = TRANSACTION_S.accept(PGAC, NORMAL_MULTICURVES);
double thetaS = TRANSACTION_S.accept(PTHC, NORMAL_MULTICURVES);
double vegaS = TRANSACTION_S.accept(PVEC, NORMAL_MULTICURVES);
double optionPriceM = TRANSACTION_M.accept(POC, NORMAL_MULTICURVES) * 100.0;
MultipleCurrencyAmount pvM = TRANSACTION_M.accept(PVC, NORMAL_MULTICURVES);
MultipleCurrencyParameterSensitivity bucketedPv01M = PSSFC.calculateSensitivity(TRANSACTION_M, NORMAL_MULTICURVES)
.multipliedBy(BP1);
ReferenceAmount<Pair<String, Currency>> pv01M = TRANSACTION_M.accept(PV01PC, NORMAL_MULTICURVES);
double deltaM = TRANSACTION_M.accept(PDEC, NORMAL_MULTICURVES);
double gammaM = TRANSACTION_M.accept(PGAC, NORMAL_MULTICURVES);
double thetaM = TRANSACTION_M.accept(PTHC, NORMAL_MULTICURVES);
double vegaM = TRANSACTION_M.accept(PVEC, NORMAL_MULTICURVES);
double[] bucketedPv01ExpectedQ = new double[] {-0.054806430508358664, 0.06707132607404294, 0.05004545341589028,
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
LinkedHashMap<Pair<String, Currency>, DoubleMatrix1D> sensitivityQ = new LinkedHashMap<>();
sensitivityQ.put(ObjectsPair.of(MULTICURVES.getName(GBPLIBOR3M), GBP), new DoubleMatrix1D(bucketedPv01ExpectedQ));
MultipleCurrencyParameterSensitivity expectedbucketQ = new MultipleCurrencyParameterSensitivity(sensitivityQ);
double[] bucketedPv01ExpectedS = new double[] {0.0629242351204289, -0.07700577929588694, -0.057458072861900376,
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
LinkedHashMap<Pair<String, Currency>, DoubleMatrix1D> sensitivityS = new LinkedHashMap<>();
sensitivityS.put(ObjectsPair.of(MULTICURVES.getName(GBPLIBOR3M), GBP), new DoubleMatrix1D(bucketedPv01ExpectedS));
MultipleCurrencyParameterSensitivity expectedbucketS = new MultipleCurrencyParameterSensitivity(sensitivityS);
double[] bucketedPv01ExpectedM = new double[] {0.0, 0.0, 0.0, 0.0, -0.22709713168560872, 0.16225955718689586,
0.12742291520626903, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
LinkedHashMap<Pair<String, Currency>, DoubleMatrix1D> sensitivityM = new LinkedHashMap<>();
sensitivityM.put(ObjectsPair.of(MULTICURVES.getName(GBPLIBOR3M), GBP), new DoubleMatrix1D(bucketedPv01ExpectedM));
MultipleCurrencyParameterSensitivity expectedbucketM = new MultipleCurrencyParameterSensitivity(sensitivityM);
assertRelative("testGBP, Quarterly, option price", 17.54034187127257, optionPriceQ, TOL);
assertRelative("testGBP, Quarterly, PV", 214.25427339090714, pvQ.getAmount(GBP), TOL);
AssertSensitivityObjects.assertEquals("testGBP, Quarterly, bucketed pv01", expectedbucketQ, bucketedPv01Q, TOL);
assertRelative("testGBP, Quarterly, pv01", 0.062310348981574545,
pv01Q.getMap().get(Pairs.of(MULTICURVES.getName(GBPLIBOR3M), GBP)), TOL);
assertRelative("testGBP, Quarterly, delta", -625.7416121580532, deltaQ, TOL);
assertRelative("testGBP, Quarterly, gamma", 1136.3204100189546, gammaQ, TOL);
assertRelative("testGBP, Quarterly, theta", -327.37192184568823, thetaQ, TOL);
assertRelative("testGBP, Quarterly, vega", 288.3056023589055, vegaQ, TOL);
assertRelative("testGBP, Serial, option price", 18.407490643468012, optionPriceS, TOL);
assertRelative("testGBP, Serial, PV", 225.09363304335017, pvS.getAmount(GBP), TOL);
AssertSensitivityObjects.assertEquals("testGBP, Serial, bucketed pv01", expectedbucketS, bucketedPv01S, TOL);
assertRelative("testGBP, Serial, pv01", -0.07153961703735841,
pv01S.getMap().get(Pairs.of(MULTICURVES.getName(GBPLIBOR3M), GBP)), TOL);
assertRelative("testGBP, Serial, delta", 718.4250454344859, deltaS, TOL);
assertRelative("testGBP, Serial, gamma", 1331.3307281718564, gammaS, TOL);
assertRelative("testGBP, Serial, theta", -353.7610514224842, thetaS, TOL);
assertRelative("testGBP, Serial, vega", 247.2880146963564, vegaS, TOL);
assertRelative("testGBP, Mid-curve, option price", 21.609363997913587, optionPriceM, TOL);
assertRelative("testGBP, Mid-curve, PV", 265.11704997391985, pvM.getAmount(GBP), TOL);
AssertSensitivityObjects.assertEquals("testGBP, Mid-curve, bucketed pv01", expectedbucketM, bucketedPv01M, TOL);
assertRelative("testGBP, Mid-curve, pv01", 0.06258534070755618,
pv01M.getMap().get(Pairs.of(MULTICURVES.getName(GBPLIBOR3M), GBP)), TOL);
assertRelative("testGBP, Mid-curve, delta", -631.4378001022222, deltaM, TOL);
assertRelative("testGBP, Mid-curve, gamma", 935.5314630568365, gammaM, TOL);
assertRelative("testGBP, Mid-curve, theta", -397.5689087443393, thetaM, TOL);
assertRelative("testGBP, Mid-curve, vega", 288.2818961163769, vegaM, TOL);
}
/* Tests options on futures with 0 volatility. */
@Test
public void volatility0() {
InterpolatedDoublesSurface vol0 = InterpolatedDoublesSurface.from(new double[]{0.25, 5.0, 0.25, 5.0},
new double[] {-0.10, -0.10, 0.10, 0.10}, new double[] {0.0, 0.0, 0.0, 0.0}, INTERPOLATOR_2D);
NormalSTIRFuturesExpSimpleMoneynessProviderDiscount multicurveNormal0 =
new NormalSTIRFuturesExpSimpleMoneynessProviderDiscount(MULTICURVES, vol0, GBPLIBOR3M, false);
double optionPriceVol0 = TRANSACTION_Q.accept(POC, multicurveNormal0);
double futuresPrice = TRANSACTION_Q.getUnderlyingSecurity().getUnderlyingFuture().accept(FPC, MULTICURVES);
double optionPriceIntrinsic = STRIKE - futuresPrice; // Put
assertEquals("Option price for a volatilituy of 0", optionPriceIntrinsic, optionPriceVol0, TOLERANCE_PRICE);
}
/**
* Underlying price and option value are rounded
*/
@Test
public void withRoundingTest() {
InterestRateFutureOptionMarginSecurity futureOptionQ = TRANSACTION_Q.getUnderlyingSecurity();
InterestRateFutureSecurity futureQ = futureOptionQ.getUnderlyingFuture();
double futurePriceQ = rounding(METHOD_FUTURE.price(futureQ, NORMAL_MULTICURVES.getMulticurveProvider()));
double optionPriceQ = rounding(METHOD_OPTION.priceFromFuturePrice(futureOptionQ, NORMAL_MULTICURVES, futurePriceQ) * 100.0);
MultipleCurrencyAmount pvQ = METHOD_OPTION_MARGIN_TRANSA.presentValueFromFuturePrice(TRANSACTION_Q,
NORMAL_MULTICURVES, futurePriceQ);
double pvQRounded = rounding(pvQ.getAmount(GBP));
MultipleCurrencyMulticurveSensitivity pvSenseQ = METHOD_OPTION_MARGIN_TRANSA
.presentValueCurveSensitivityFromPrice(TRANSACTION_Q, NORMAL_MULTICURVES, futurePriceQ);
MultipleCurrencyParameterSensitivity bucketedPv01QUnscaled = PSSFC.pointToParameterSensitivity(pvSenseQ,
NORMAL_MULTICURVES);
String curveName = NORMAL_MULTICURVES.getMulticurveProvider().getName(GBPLIBOR3M);
double[] bucketedPv01QRounded = rounding(bucketedPv01QUnscaled.multipliedBy(BP1)
.getSensitivity(NORMAL_MULTICURVES.getMulticurveProvider().getName(GBPLIBOR3M), GBP).getData());
double pv01QRounded = rounding(PV01PC.pv01CurveParameters(bucketedPv01QUnscaled).getMap()
.get(Pairs.of(curveName, GBP)));
double deltaQ = rounding(METHOD_OPTION_MARGIN.priceDeltaFromFuturePrice(futureOptionQ, NORMAL_MULTICURVES,
futurePriceQ));
double gammaQ = rounding(METHOD_OPTION_MARGIN.priceGammaFromFuturePrice(futureOptionQ, NORMAL_MULTICURVES,
futurePriceQ));
double thetaQ = rounding(METHOD_OPTION_MARGIN.priceThetaFromFuturePrice(futureOptionQ, NORMAL_MULTICURVES,
futurePriceQ));
double vegaQ = rounding(METHOD_OPTION_MARGIN.priceVegaFromFuturePrice(futureOptionQ, NORMAL_MULTICURVES,
futurePriceQ));
InterestRateFutureOptionMarginSecurity futureOptionS = TRANSACTION_S.getUnderlyingSecurity();
InterestRateFutureSecurity futureS = futureOptionS.getUnderlyingFuture();
double futurePriceS = rounding(METHOD_FUTURE.price(futureS, NORMAL_MULTICURVES.getMulticurveProvider()));
double optionPriceS = rounding(METHOD_OPTION.priceFromFuturePrice(futureOptionS, NORMAL_MULTICURVES, futurePriceS) * 100.0);
MultipleCurrencyAmount pvS = METHOD_OPTION_MARGIN_TRANSA.presentValueFromFuturePrice(TRANSACTION_S,
NORMAL_MULTICURVES, futurePriceS);
double pvSRounded = rounding(pvS.getAmount(GBP));
MultipleCurrencyMulticurveSensitivity pvSenseS = METHOD_OPTION_MARGIN_TRANSA
.presentValueCurveSensitivityFromPrice(TRANSACTION_S, NORMAL_MULTICURVES, futurePriceS);
MultipleCurrencyParameterSensitivity bucketedPv01SUnscaled = PSSFC.pointToParameterSensitivity(pvSenseS,
NORMAL_MULTICURVES);
double[] bucketedPv01SRounded = rounding(bucketedPv01SUnscaled.multipliedBy(BP1)
.getSensitivity(NORMAL_MULTICURVES.getMulticurveProvider().getName(GBPLIBOR3M), GBP).getData());
double pv01SRounded = rounding(PV01PC.pv01CurveParameters(bucketedPv01SUnscaled).getMap()
.get(Pairs.of(curveName, GBP)));
double deltaS = rounding(METHOD_OPTION_MARGIN.priceDeltaFromFuturePrice(futureOptionS, NORMAL_MULTICURVES,
futurePriceS));
double gammaS = rounding(METHOD_OPTION_MARGIN.priceGammaFromFuturePrice(futureOptionS, NORMAL_MULTICURVES,
futurePriceS));
double thetaS = rounding(METHOD_OPTION_MARGIN.priceThetaFromFuturePrice(futureOptionS, NORMAL_MULTICURVES,
futurePriceS));
double vegaS = rounding(METHOD_OPTION_MARGIN.priceVegaFromFuturePrice(futureOptionS, NORMAL_MULTICURVES,
futurePriceS));
InterestRateFutureOptionMarginSecurity futureOptionM = TRANSACTION_M.getUnderlyingSecurity();
InterestRateFutureSecurity futureM = futureOptionM.getUnderlyingFuture();
double futurePriceM = rounding(METHOD_FUTURE.price(futureM, NORMAL_MULTICURVES.getMulticurveProvider()));
double optionPriceM = rounding(METHOD_OPTION.priceFromFuturePrice(futureOptionM, NORMAL_MULTICURVES, futurePriceM) * 100.0);
MultipleCurrencyAmount pvM = METHOD_OPTION_MARGIN_TRANSA.presentValueFromFuturePrice(TRANSACTION_M,
NORMAL_MULTICURVES, futurePriceM);
double pvMRounded = rounding(pvM.getAmount(GBP));
MultipleCurrencyMulticurveSensitivity pvSenseM = METHOD_OPTION_MARGIN_TRANSA
.presentValueCurveSensitivityFromPrice(TRANSACTION_M, NORMAL_MULTICURVES, futurePriceM);
MultipleCurrencyParameterSensitivity bucketedPv01MUnscaled = PSSFC.pointToParameterSensitivity(pvSenseM,
NORMAL_MULTICURVES);
double[] bucketedPv01MRounded = rounding(bucketedPv01MUnscaled.multipliedBy(BP1)
.getSensitivity(NORMAL_MULTICURVES.getMulticurveProvider().getName(GBPLIBOR3M), GBP).getData());
double pv01MRounded = rounding(PV01PC.pv01CurveParameters(bucketedPv01MUnscaled).getMap()
.get(Pairs.of(curveName, GBP)));
double deltaM = rounding(METHOD_OPTION_MARGIN.priceDeltaFromFuturePrice(futureOptionM, NORMAL_MULTICURVES,
futurePriceM));
double gammaM = rounding(METHOD_OPTION_MARGIN.priceGammaFromFuturePrice(futureOptionM, NORMAL_MULTICURVES,
futurePriceM));
double thetaM = rounding(METHOD_OPTION_MARGIN.priceThetaFromFuturePrice(futureOptionM, NORMAL_MULTICURVES,
futurePriceM));
double vegaM = rounding(METHOD_OPTION_MARGIN.priceVegaFromFuturePrice(futureOptionM, NORMAL_MULTICURVES,
futurePriceM));
double[] bucketedPv01ExpectedQ = new double[] {-0.0548, 0.06705, 0.05005, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
double[] bucketedPv01ExpectedS = new double[] {0.0629, -0.077, -0.05745, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
double[] bucketedPv01ExpectedM = new double[] {0.0, 0.0, 0.0, 0.0, -0.2271, 0.16225, 0.12745, 0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
assertRelative("testGBP, Quarterly, option price", 17.5392, optionPriceQ, TOL);
assertRelative("testGBP, Quarterly, PV", 214.2398, pvQRounded, TOL);
assertArrayRelative("testGBP, Quarterly, bucketed pv01", bucketedPv01ExpectedQ, bucketedPv01QRounded, TOL);
assertRelative("testGBP, Quarterly, pv01", 0.0623, pv01QRounded, TOL);
assertRelative("testGBP, Quarterly, delta", -0.5006, deltaQ, TOL);
assertRelative("testGBP, Quarterly, gamma", 0.9091, gammaQ, TOL);
assertRelative("testGBP, Quarterly, theta", -0.2619, thetaQ, TOL);
assertRelative("testGBP, Quarterly, vega", 0.23065, vegaQ, TOL);
assertRelative("testGBP, Serial, option price", 18.40765, optionPriceS, TOL);
assertRelative("testGBP, Serial, PV", 225.09555, pvSRounded, TOL);
assertArrayRelative("testGBP, Serial, bucketed pv01", bucketedPv01ExpectedS, bucketedPv01SRounded, TOL);
assertRelative("testGBP, Serial, pv01", -0.07155, pv01SRounded, TOL);
assertRelative("testGBP, Serial, delta", 0.57475, deltaS, TOL);
assertRelative("testGBP, Serial, gamma", 1.06505, gammaS, TOL);
assertRelative("testGBP, Serial, theta", -0.283, thetaS, TOL);
assertRelative("testGBP, Serial, vega", 0.19785, vegaS, TOL);
assertRelative("testGBP, Mid-curve, option price", 21.6245, optionPriceM, TOL);
assertRelative("testGBP, Mid-curve, PV", 265.30635, pvMRounded, TOL);
assertArrayRelative("testGBP, Mid-curve, bucketed pv01", bucketedPv01ExpectedM, bucketedPv01MRounded, TOL);
assertRelative("testGBP, Mid-curve, pv01", 0.0626, pv01MRounded, TOL);
assertRelative("testGBP, Mid-curve, delta", -0.50515, deltaM, TOL);
assertRelative("testGBP, Mid-curve, gamma", 0.74795, gammaM, TOL);
assertRelative("testGBP, Mid-curve, theta", -0.31825, thetaM, TOL);
assertRelative("testGBP, Mid-curve, vega", 0.23065, vegaM, TOL);
}
private double[] rounding(double[] values) {
int n = values.length;
double[] res = new double[n];
for (int i = 0; i < n; ++i) {
res[i] = rounding(values[i]);
}
return res;
}
private double rounding(double value) {
double rounding = 0.5 * BP1;
return Math.round(value / rounding) * rounding;
}
/**
* Test volatility surface interpolation.
*/
@Test
public void volatilitySurfaceSamplingTest() {
double expiry1 = 17.0 / 365.0;
double moneyness1 = -0.0063;
double interpolatedVol1 = VOL_SURFACE_SIMPLEMONEY.getZValue(expiry1, moneyness1);
assertRelative("volatilitySurfaceSamplingPrintTest", 1.0623, interpolatedVol1, TOL);
double expiry2 = 72.0 / 365.0;
double moneyness2 = 0.0036;
double interpolatedVol2 = VOL_SURFACE_SIMPLEMONEY.getZValue(expiry2, moneyness2);
assertRelative("volatilitySurfaceSamplingPrintTest", 0.7228061226912788, interpolatedVol2, TOL);
double expiry3 = 25.0 / 365.0;
double moneyness3 = 0.005;
double interpolatedVol3 = VOL_SURFACE_SIMPLEMONEY.getZValue(expiry3, moneyness3);
assertRelative("volatilitySurfaceSamplingPrintTest", 0.8395130870530448, interpolatedVol3, TOL);
}
/**
* Test negative strike rate, strike > 1.0
*/
@Test
public void negativeRateStrikeTest() {
/*
* Put with negative strike rate.
*/
double strikePut = 1.01; // greater than 1
InterestRateFutureOptionMarginSecurityDefinition optionNegativeStrikeQ =
new InterestRateFutureOptionMarginSecurityDefinition(RATE_FUTURE_Q, EXPIRATION_DATE, strikePut, IS_CALL);
InterestRateFutureOptionMarginTransactionDefinition transacQrtNegativeDfnQ = new InterestRateFutureOptionMarginTransactionDefinition(
optionNegativeStrikeQ, QUANTITY, TRADE_DATE, TRADE_PRICE);
InterestRateFutureOptionMarginTransaction transacQrtNegativeQ = transacQrtNegativeDfnQ.toDerivative(VALUATION_DATE,
LAST_MARGIN_PRICE);
InterestRateFutureOptionMarginSecurity futureOptionQ = transacQrtNegativeQ.getUnderlyingSecurity();
InterestRateFutureSecurity futureQ = futureOptionQ.getUnderlyingFuture();
double futurePriceQ = METHOD_FUTURE.price(futureQ, NORMAL_MULTICURVES.getMulticurveProvider());
// Option price
double optionPriceQ = METHOD_OPTION.priceFromFuturePrice(futureOptionQ, NORMAL_MULTICURVES, futurePriceQ) * 100.0;
assertRelative("negativeRateStrikeTest", 22.948758005868182, optionPriceQ, TOL);
// PV
MultipleCurrencyAmount pvQ = METHOD_OPTION_MARGIN_TRANSA.presentValueFromFuturePrice(transacQrtNegativeQ,
NORMAL_MULTICURVES, futurePriceQ);
assertRelative("negativeRateStrikeTest", 281.8594750733523, pvQ.getAmount(GBP), TOL);
// Option Greeks
Double deltaQ = METHOD_OPTION_MARGIN.priceDeltaFromFuturePrice(futureOptionQ, NORMAL_MULTICURVES, futurePriceQ);
assertRelative("negativeRateStrikeTest", -0.5112417249707829, deltaQ, TOL);
Double gammaQ = METHOD_OPTION_MARGIN.priceGammaFromFuturePrice(futureOptionQ, NORMAL_MULTICURVES, futurePriceQ);
assertRelative("negativeRateStrikeTest", 0.7180096667060368, gammaQ, TOL);
Double thetaQ = METHOD_OPTION_MARGIN.priceThetaFromFuturePrice(futureOptionQ, NORMAL_MULTICURVES, futurePriceQ);
assertRelative("negativeRateStrikeTest", -0.33132021712054266, thetaQ, TOL);
Double vegaQ = METHOD_OPTION_MARGIN.priceVegaFromFuturePrice(futureOptionQ, NORMAL_MULTICURVES, futurePriceQ);
assertRelative("negativeRateStrikeTest", 0.2305531595874542, vegaQ, TOL);
// bucketed PV01
MultipleCurrencyMulticurveSensitivity pvSenseQ = METHOD_OPTION_MARGIN_TRANSA
.presentValueCurveSensitivityFromPrice(transacQrtNegativeQ, NORMAL_MULTICURVES, futurePriceQ);
MultipleCurrencyParameterSensitivity bucketedPv01Q = PSSFC
.pointToParameterSensitivity(pvSenseQ, NORMAL_MULTICURVES);
MultipleCurrencyParameterSensitivity bucketedPv01RescaledQ = bucketedPv01Q.multipliedBy(BP1);
double[] bucketedPv01ExpectedQ = new double[] {-0.055972252620278336, 0.06849804250654201, 0.05111000178461486,
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
LinkedHashMap<Pair<String, Currency>, DoubleMatrix1D> sensitivityQ = new LinkedHashMap<>();
sensitivityQ.put(ObjectsPair.of(MULTICURVES.getName(GBPLIBOR3M), GBP), new DoubleMatrix1D(bucketedPv01ExpectedQ));
MultipleCurrencyParameterSensitivity expectedbucketQ = new MultipleCurrencyParameterSensitivity(sensitivityQ);
AssertSensitivityObjects.assertEquals("negativeRateStrikeTest", expectedbucketQ, bucketedPv01RescaledQ, TOL);
// PV01
ReferenceAmount<Pair<String, Currency>> pv01Q = PV01PC.pv01CurveParameters(bucketedPv01Q);
assertRelative("negativeRateStrikeTest", 0.06363579167087854,
pv01Q.getMap().get(Pairs.of(MULTICURVES.getName(GBPLIBOR3M), GBP)), TOL);
/*
* Call with negative strike rate.
*/
double strikeCall = 1.015; // greater than 1
InterestRateFutureOptionMarginSecurityDefinition optionNegativeStrikeS =
new InterestRateFutureOptionMarginSecurityDefinition(RATE_FUTURE_S, EXPIRATION_DATE, strikeCall, IS_CALL_S);
InterestRateFutureOptionMarginTransactionDefinition transacSrtNegativeDfnS = new InterestRateFutureOptionMarginTransactionDefinition(
optionNegativeStrikeS, QUANTITY, TRADE_DATE, TRADE_PRICE);
InterestRateFutureOptionMarginTransaction transacSrtNegativeS = transacSrtNegativeDfnS.toDerivative(VALUATION_DATE,
LAST_MARGIN_PRICE);
InterestRateFutureOptionMarginSecurity futureOptionS = transacSrtNegativeS.getUnderlyingSecurity();
InterestRateFutureSecurity futureS = futureOptionS.getUnderlyingFuture();
double futurePriceS = METHOD_FUTURE.price(futureS, NORMAL_MULTICURVES.getMulticurveProvider());
// Option price
double optionPriceS = METHOD_OPTION.priceFromFuturePrice(futureOptionS, NORMAL_MULTICURVES, futurePriceS) * 100.0;
assertRelative("negativeRateStrikeTest", 21.140011994079945, optionPriceS, TOL);
// PV
MultipleCurrencyAmount pvS = METHOD_OPTION_MARGIN_TRANSA.presentValueFromFuturePrice(transacSrtNegativeS,
NORMAL_MULTICURVES, futurePriceS);
assertRelative("negativeRateStrikeTest", 259.25014992599927, pvS.getAmount(GBP), TOL);
// Option Greeks
Double deltaS = METHOD_OPTION_MARGIN.priceDeltaFromFuturePrice(futureOptionS, NORMAL_MULTICURVES, futurePriceS);
assertRelative("negativeRateStrikeTest", 0.4851687305611848, deltaS, TOL);
Double gammaS = METHOD_OPTION_MARGIN.priceGammaFromFuturePrice(futureOptionS, NORMAL_MULTICURVES, futurePriceS);
assertRelative("negativeRateStrikeTest", 0.7177984337559097, gammaS, TOL);
Double thetaS = METHOD_OPTION_MARGIN.priceThetaFromFuturePrice(futureOptionS, NORMAL_MULTICURVES, futurePriceS);
assertRelative("negativeRateStrikeTest", -0.3312227452477471, thetaS, TOL);
Double vegaS = METHOD_OPTION_MARGIN.priceVegaFromFuturePrice(futureOptionS, NORMAL_MULTICURVES, futurePriceS);
assertRelative("negativeRateStrikeTest", 0.23048533261197038, vegaS, TOL);
// bucketed PV01
MultipleCurrencyMulticurveSensitivity pvSenseS = METHOD_OPTION_MARGIN_TRANSA
.presentValueCurveSensitivityFromPrice(transacSrtNegativeS, NORMAL_MULTICURVES, futurePriceS);
MultipleCurrencyParameterSensitivity bucketedPv01S = PSSFC
.pointToParameterSensitivity(pvSenseS, NORMAL_MULTICURVES);
MultipleCurrencyParameterSensitivity bucketedPv01RescaledS = bucketedPv01S.multipliedBy(BP1);
double[] bucketedPv01ExpectedS = new double[] {0.053117704256205496, -0.06500468703082543, -0.048503425040744896,
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
LinkedHashMap<Pair<String, Currency>, DoubleMatrix1D> sensitivityS = new LinkedHashMap<>();
sensitivityS.put(ObjectsPair.of(MULTICURVES.getName(GBPLIBOR3M), GBP), new DoubleMatrix1D(bucketedPv01ExpectedS));
MultipleCurrencyParameterSensitivity expectedbucketS = new MultipleCurrencyParameterSensitivity(sensitivityS);
AssertSensitivityObjects.assertEquals("negativeRateStrikeTest", expectedbucketS, bucketedPv01RescaledS, TOL);
// PV01
ReferenceAmount<Pair<String, Currency>> pv01S = PV01PC.pv01CurveParameters(bucketedPv01S);
assertRelative("negativeRateStrikeTest", -0.060390407815364824,
pv01S.getMap().get(Pairs.of(MULTICURVES.getName(GBPLIBOR3M), GBP)), TOL);
}
/**
* Test negative forward rate, fwd > 1.0
*/
@Test
public void negativeRateFutureTest() {
// new curve producing negative forward rate
int nRates = DATA.getRateGBP().length;
double[] bumpedRates = Arrays.copyOf(DATA.getRateGBP(), nRates);
bumpedRates[0] = 0.00121959;
bumpedRates[1] = -0.00332545;
bumpedRates[2] = -0.00263185;
bumpedRates[3] = 0.00163185;
final MulticurveProviderDiscount multiCurve;
Interpolator1D interpolator = CombinedInterpolatorExtrapolatorFactory.getInterpolator(Interpolator1DFactory.LINEAR,
Interpolator1DFactory.FLAT_EXTRAPOLATOR, Interpolator1DFactory.LINEAR_EXTRAPOLATOR);
String curveName = "GBP curve";
InterpolatedDoublesCurve rawCurve = InterpolatedDoublesCurve.from(DATA.getTimeGBP(), bumpedRates,
interpolator, curveName);
int compoundPeriodsPerYear = 1;
YieldAndDiscountCurve singleCurve = YieldPeriodicCurve.from(compoundPeriodsPerYear, rawCurve);
multiCurve = new MulticurveProviderDiscount();
multiCurve.setCurve(GBPLIBOR3M, singleCurve);
NormalSTIRFuturesExpSimpleMoneynessProviderDiscount normalMulticurve =
new NormalSTIRFuturesExpSimpleMoneynessProviderDiscount(multiCurve, VOL_SURFACE_SIMPLEMONEY, GBPLIBOR3M, false);
/*
* put option
*/
InterestRateFutureOptionMarginSecurity futureOptionQ = TRANSACTION_Q.getUnderlyingSecurity();
InterestRateFutureSecurity futureQ = futureOptionQ.getUnderlyingFuture();
double futurePriceQ = METHOD_FUTURE.price(futureQ, normalMulticurve.getMulticurveProvider()); // greater than 1
// Option price
double optionPriceQ = METHOD_OPTION.priceFromFuturePrice(futureOptionQ, normalMulticurve, futurePriceQ) * 100.0;
assertRelative("negativeRateFutureTest", 15.781077242671984, optionPriceQ, TOL);
// PV
MultipleCurrencyAmount pvQ = METHOD_OPTION_MARGIN_TRANSA.presentValueFromFuturePrice(TRANSACTION_Q,
normalMulticurve, futurePriceQ);
assertRelative("negativeRateStrikeTest", 192.2634655333998, pvQ.getAmount(GBP), TOL);
// Option Greeks
Double deltaQ = METHOD_OPTION_MARGIN.priceDeltaFromFuturePrice(futureOptionQ, normalMulticurve, futurePriceQ);
assertRelative("negativeRateFutureTest", -0.488553523088012, deltaQ, TOL);
Double gammaQ = METHOD_OPTION_MARGIN.priceGammaFromFuturePrice(futureOptionQ, normalMulticurve, futurePriceQ);
assertRelative("negativeRateFutureTest", 0.972260987489144, gammaQ, TOL);
Double thetaQ = METHOD_OPTION_MARGIN.priceThetaFromFuturePrice(futureOptionQ, normalMulticurve, futurePriceQ);
assertRelative("negativeRateFutureTest", -0.2446711062778777, thetaQ, TOL);
Double vegaQ = METHOD_OPTION_MARGIN.priceVegaFromFuturePrice(futureOptionQ, normalMulticurve, futurePriceQ);
assertRelative("negativeRateFutureTest", 0.23054979307619397, vegaQ, TOL);
// bucketed PV01
MultipleCurrencyMulticurveSensitivity pvSenseQ = METHOD_OPTION_MARGIN_TRANSA
.presentValueCurveSensitivityFromPrice(TRANSACTION_Q, normalMulticurve, futurePriceQ);
MultipleCurrencyParameterSensitivity bucketedPv01UnscaledQ = PSSFC.pointToParameterSensitivity(pvSenseQ,
normalMulticurve);
MultipleCurrencyParameterSensitivity bucketedPv01Q = bucketedPv01UnscaledQ.multipliedBy(BP1);
double[] bucketedPv01ExpectedQ = new double[] {-0.05361798658810737, 0.06589164141372715, 0.04910507773660669, 0.0,
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
LinkedHashMap<Pair<String, Currency>, DoubleMatrix1D> sensitivityQ = new LinkedHashMap<>();
sensitivityQ.put(ObjectsPair.of(multiCurve.getName(GBPLIBOR3M), GBP), new DoubleMatrix1D(bucketedPv01ExpectedQ));
MultipleCurrencyParameterSensitivity expectedbucketQ = new MultipleCurrencyParameterSensitivity(sensitivityQ);
AssertSensitivityObjects.assertEquals("negativeRateStrikeTest", expectedbucketQ, bucketedPv01Q, TOL);
// PV01
ReferenceAmount<Pair<String, Currency>> pv01Q = PV01PC.pv01CurveParameters(bucketedPv01UnscaledQ);
assertRelative("negativeRateFutureTest", 0.06137873256222647,
pv01Q.getMap().get(Pairs.of(multiCurve.getName(GBPLIBOR3M), GBP)), TOL);
/*
* call option
*/
InterestRateFutureOptionMarginSecurity futureOptionS = TRANSACTION_S.getUnderlyingSecurity();
InterestRateFutureSecurity futureS = futureOptionS.getUnderlyingFuture();
double futurePriceS = METHOD_FUTURE.price(futureS, normalMulticurve.getMulticurveProvider()); // greater than 1
// Option price
double optionPriceS = METHOD_OPTION.priceFromFuturePrice(futureOptionS, normalMulticurve, futurePriceS) * 100.0;
assertRelative("negativeRateFutureTest", 19.129658973690766, optionPriceS, TOL);
// PV
MultipleCurrencyAmount pvS = METHOD_OPTION_MARGIN_TRANSA.presentValueFromFuturePrice(TRANSACTION_S,
normalMulticurve, futurePriceS);
assertRelative("negativeRateStrikeTest", 234.12073717113458, pvS.getAmount(GBP), TOL);
// Option Greeks
Double deltaS = METHOD_OPTION_MARGIN.priceDeltaFromFuturePrice(futureOptionS, normalMulticurve, futurePriceS);
assertRelative("negativeRateFutureTest", 0.5879262616822158, deltaS, TOL);
Double gammaS = METHOD_OPTION_MARGIN.priceGammaFromFuturePrice(futureOptionS, normalMulticurve, futurePriceS);
assertRelative("negativeRateFutureTest", 1.05770727450262, gammaS, TOL);
Double thetaS = METHOD_OPTION_MARGIN.priceThetaFromFuturePrice(futureOptionS, normalMulticurve, futurePriceS);
assertRelative("negativeRateFutureTest", -0.2810538580740668, thetaS, TOL);
Double vegaS = METHOD_OPTION_MARGIN.priceVegaFromFuturePrice(futureOptionS, normalMulticurve, futurePriceS);
assertRelative("negativeRateFutureTest", 0.19646382863919248, vegaS, TOL);
// bucketed PV01
MultipleCurrencyMulticurveSensitivity pvSenseS = METHOD_OPTION_MARGIN_TRANSA
.presentValueCurveSensitivityFromPrice(TRANSACTION_S, normalMulticurve, futurePriceS);
MultipleCurrencyParameterSensitivity bucketedPv01UnscaledS = PSSFC.pointToParameterSensitivity(pvSenseS,
normalMulticurve);
MultipleCurrencyParameterSensitivity bucketedPv01S = bucketedPv01UnscaledS.multipliedBy(BP1);
double[] bucketedPv01ExpectedS = new double[] {0.06452398954043419, -0.07929412967409682, -0.059093146234659076,
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
LinkedHashMap<Pair<String, Currency>, DoubleMatrix1D> sensitivityS = new LinkedHashMap<>();
sensitivityS.put(ObjectsPair.of(multiCurve.getName(GBPLIBOR3M), GBP), new DoubleMatrix1D(bucketedPv01ExpectedS));
MultipleCurrencyParameterSensitivity expectedbucketS = new MultipleCurrencyParameterSensitivity(sensitivityS);
AssertSensitivityObjects.assertEquals("negativeRateStrikeTest", expectedbucketS, bucketedPv01S, TOL);
// PV01
ReferenceAmount<Pair<String, Currency>> pv01S = PV01PC.pv01CurveParameters(bucketedPv01UnscaledS);
assertRelative("negativeRateFutureTest", -0.07386328636832172,
pv01S.getMap().get(Pairs.of(multiCurve.getName(GBPLIBOR3M), GBP)), TOL);
}
private static final InterestRateFutureSecurityDiscountingMethod METHOD_FUTURE = InterestRateFutureSecurityDiscountingMethod
.getInstance();
private static final InterestRateFutureOptionMarginSecurityNormalSmileMethod METHOD_OPTION = InterestRateFutureOptionMarginSecurityNormalSmileMethod
.getInstance();
private static final InterestRateFutureOptionMarginSecurityNormalSmileMethod METHOD_OPTION_MARGIN = InterestRateFutureOptionMarginSecurityNormalSmileMethod
.getInstance();
private static final InterestRateFutureOptionMarginTransactionNormalSmileMethod METHOD_OPTION_MARGIN_TRANSA = InterestRateFutureOptionMarginTransactionNormalSmileMethod
.getInstance();
private static final DeltaNormalSTIRFutureOptionCalculator DEC = DeltaNormalSTIRFutureOptionCalculator.getInstance();
private static final GammaNormalSTIRFutureOptionCalculator GAC = GammaNormalSTIRFutureOptionCalculator.getInstance();
private static final ThetaNormalSTIRFutureOptionCalculator THC = ThetaNormalSTIRFutureOptionCalculator.getInstance();
private static final VegaNormalSTIRFutureOptionCalculator VEC = VegaNormalSTIRFutureOptionCalculator.getInstance();
/**
* Replicating the calculators by the underlying methods in which futures price is taken as an input.
*/
@Test
public void underlyingMethodTest() {
double localTol = 1.0e-14;
InterestRateFutureOptionMarginSecurity futureOption = TRANSACTION_Q.getUnderlyingSecurity();
InterestRateFutureSecurity future = futureOption.getUnderlyingFuture();
double futurePrice = METHOD_FUTURE.price(future, NORMAL_MULTICURVES.getMulticurveProvider());
// Option price and PV
double optionPriceQ = TRANSACTION_Q.accept(POC, NORMAL_MULTICURVES);
double optionPriceQRe = METHOD_OPTION.priceFromFuturePrice(futureOption, NORMAL_MULTICURVES, futurePrice);
assertRelative("underlyingMethodTest", optionPriceQ, optionPriceQRe, localTol);
MultipleCurrencyAmount pvQ = TRANSACTION_Q.accept(PVC, NORMAL_MULTICURVES);
MultipleCurrencyAmount pvQRe = METHOD_OPTION_MARGIN_TRANSA.presentValueFromFuturePrice(TRANSACTION_Q,
NORMAL_MULTICURVES, futurePrice);
assertRelative("underlyingMethodTest", pvQ.getAmount(GBP), pvQRe.getAmount(GBP), localTol);
// Option Greeks
Double delta = TRANSACTION_Q.accept(DEC, NORMAL_MULTICURVES);
Double deltaRe = METHOD_OPTION_MARGIN.priceDeltaFromFuturePrice(futureOption, NORMAL_MULTICURVES, futurePrice);
assertRelative("underlyingMethodTest", delta, deltaRe, localTol);
Double gamma = TRANSACTION_Q.accept(GAC, NORMAL_MULTICURVES);
Double gammaRe = METHOD_OPTION_MARGIN.priceGammaFromFuturePrice(futureOption, NORMAL_MULTICURVES, futurePrice);
assertRelative("underlyingMethodTest", gamma, gammaRe, localTol);
Double theta = TRANSACTION_Q.accept(THC, NORMAL_MULTICURVES);
Double thetaRe = METHOD_OPTION_MARGIN.priceThetaFromFuturePrice(futureOption, NORMAL_MULTICURVES, futurePrice);
assertRelative("underlyingMethodTest", theta, thetaRe, localTol);
Double vega = TRANSACTION_Q.accept(VEC, NORMAL_MULTICURVES);
Double vegaRe = METHOD_OPTION_MARGIN.priceVegaFromFuturePrice(futureOption, NORMAL_MULTICURVES, futurePrice);
assertRelative("underlyingMethodTest", vega, vegaRe, localTol);
// PV01
MultipleCurrencyParameterSensitivity bucketedPv01Q = PSSFC.calculateSensitivity(TRANSACTION_Q, NORMAL_MULTICURVES);
MultipleCurrencyMulticurveSensitivity pvSense = METHOD_OPTION_MARGIN_TRANSA
.presentValueCurveSensitivityFromPrice(TRANSACTION_Q, NORMAL_MULTICURVES, futurePrice);
MultipleCurrencyParameterSensitivity bucketedPv01QRe = PSSFC.pointToParameterSensitivity(pvSense,
NORMAL_MULTICURVES);
AssertSensitivityObjects.assertEquals("underlyingMethodTest", bucketedPv01Q, bucketedPv01QRe, localTol);
ReferenceAmount<Pair<String, Currency>> pv01Q = TRANSACTION_Q.accept(PV01PC, NORMAL_MULTICURVES);
ReferenceAmount<Pair<String, Currency>> pv01QRe = PV01PC.pv01CurveParameters(bucketedPv01QRe);
assertRelative("underlyingMethodTest", pv01Q.getMap().get(Pairs.of(MULTICURVES.getName(GBPLIBOR3M), GBP)), pv01QRe
.getMap().get(Pairs.of(MULTICURVES.getName(GBPLIBOR3M), GBP)), localTol);
}
private void assertArrayRelative(String message, double[] expected, double[] obtained, double relativeTol) {
int nData = expected.length;
assertEquals(message, nData, obtained.length);
for (int i = 0; i < nData; ++i) {
assertRelative(message, expected[i], obtained[i], relativeTol);
}
}
private void assertRelative(String message, double expected, double obtained, double relativeTol) {
double ref = Math.max(Math.abs(expected), 1.0);
assertEquals(message, expected, obtained, ref * relativeTol);
}
}