/**
* Copyright (C) 2014 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.analytics.financial.interestrate.payments.provider;
import static org.testng.AssertJUnit.assertEquals;
import static org.testng.AssertJUnit.assertTrue;
import org.testng.annotations.Test;
import org.threeten.bp.Period;
import org.threeten.bp.ZonedDateTime;
import com.opengamma.analytics.financial.instrument.index.IborIndex;
import com.opengamma.analytics.financial.instrument.payment.CapFloorIborDefinition;
import com.opengamma.analytics.financial.instrument.payment.CouponIborDefinition;
import com.opengamma.analytics.financial.interestrate.payments.derivative.CapFloorIbor;
import com.opengamma.analytics.financial.interestrate.payments.derivative.CouponIbor;
import com.opengamma.analytics.financial.model.option.definition.SABRInterestRateParameters;
import com.opengamma.analytics.financial.model.volatility.BlackFormulaRepository;
import com.opengamma.analytics.financial.model.volatility.smile.fitting.interpolation.BenaimDodgsonKainthExtrapolationFunctionProvider;
import com.opengamma.analytics.financial.model.volatility.smile.fitting.interpolation.InterpolatedSmileFunction;
import com.opengamma.analytics.financial.model.volatility.smile.fitting.interpolation.ShiftedLogNormalExtrapolationFunctionProvider;
import com.opengamma.analytics.financial.model.volatility.smile.fitting.interpolation.SmileExtrapolationFunctionSABRProvider;
import com.opengamma.analytics.financial.model.volatility.smile.fitting.interpolation.SmileInterpolatorSABRWithExtrapolation;
import com.opengamma.analytics.financial.model.volatility.smile.fitting.interpolation.SmileInterpolatorSpline;
import com.opengamma.analytics.financial.provider.description.MulticurveProviderDiscountDataSets;
import com.opengamma.analytics.financial.provider.description.SABRDataSets;
import com.opengamma.analytics.financial.provider.description.interestrate.MulticurveProviderDiscount;
import com.opengamma.analytics.financial.provider.description.interestrate.SABRCapProviderDiscount;
import com.opengamma.analytics.financial.schedule.ScheduleCalculator;
import com.opengamma.analytics.math.interpolation.Interpolator1DFactory;
import com.opengamma.financial.convention.calendar.Calendar;
import com.opengamma.util.money.Currency;
import com.opengamma.util.money.MultipleCurrencyAmount;
import com.opengamma.util.test.TestGroup;
import com.opengamma.util.time.DateUtils;
/**
* Test class for {@link CapFloorIborInArrearsSmileModelCapGenericReplicationMethod} and
* {@link CouponIborInArrearsSmileModelReplicationMethod}
*/
@Test(groups = TestGroup.UNIT)
public class CapFloorIborInArrearsSmileModelCapGenericReplicationMethodTest {
private static final MulticurveProviderDiscount MULTICURVES = MulticurveProviderDiscountDataSets
.createMulticurveEurUsd();
private static final IborIndex EURIBOR6M = MulticurveProviderDiscountDataSets.getIndexesIborMulticurveEurUsd()[1];
private static final Currency EUR = EURIBOR6M.getCurrency();
private static final Calendar CALENDAR = MulticurveProviderDiscountDataSets.getEURCalendar();
private static final SABRInterestRateParameters SABR_PARAMETER = SABRDataSets.createSABR1();
private static final SABRCapProviderDiscount SABR_MULTICURVES = new SABRCapProviderDiscount(MULTICURVES,
SABR_PARAMETER, EURIBOR6M);
// Dates
private static final ZonedDateTime REFERENCE_DATE = DateUtils.getUTCDate(2011, 6, 7);
private static final ZonedDateTime START_ACCRUAL_DATE = ScheduleCalculator.getAdjustedDate(REFERENCE_DATE,
Period.ofYears(9), EURIBOR6M, CALENDAR);
private static final ZonedDateTime END_ACCRUAL_DATE = ScheduleCalculator.getAdjustedDate(START_ACCRUAL_DATE,
EURIBOR6M, CALENDAR);
private static final double ACCRUAL_FACTOR = EURIBOR6M.getDayCount().getDayCountFraction(START_ACCRUAL_DATE,
END_ACCRUAL_DATE, CALENDAR);
private static final ZonedDateTime FIXING_DATE = ScheduleCalculator.getAdjustedDate(END_ACCRUAL_DATE,
-EURIBOR6M.getSpotLag(), CALENDAR);
private static final double NOTIONAL = 100000000; //100m
private static final double STRIKE = 0.03;
private static final boolean IS_CAP = true;
// Definition description: In arrears
private static final CapFloorIborDefinition CAP_IA_LONG_DEFINITION = new CapFloorIborDefinition(EUR,
FIXING_DATE, START_ACCRUAL_DATE, END_ACCRUAL_DATE, ACCRUAL_FACTOR, NOTIONAL, FIXING_DATE,
EURIBOR6M, STRIKE, IS_CAP, CALENDAR);
private static final CouponIborDefinition COUPON_IBOR_IA_DEFINITION = new CouponIborDefinition(EUR, FIXING_DATE,
START_ACCRUAL_DATE, END_ACCRUAL_DATE, ACCRUAL_FACTOR, NOTIONAL, FIXING_DATE,
EURIBOR6M, CALENDAR);
private static final CapFloorIborDefinition CAP_IA_SHORT_DEFINITION = new CapFloorIborDefinition(EUR,
FIXING_DATE, START_ACCRUAL_DATE, END_ACCRUAL_DATE, ACCRUAL_FACTOR, -NOTIONAL, FIXING_DATE,
EURIBOR6M, STRIKE, IS_CAP, CALENDAR);
private static final CapFloorIborDefinition FLOOR_IA_SHORT_DEFINITION = new CapFloorIborDefinition(EUR,
FIXING_DATE, START_ACCRUAL_DATE, END_ACCRUAL_DATE, ACCRUAL_FACTOR, -NOTIONAL,
FIXING_DATE, EURIBOR6M, STRIKE, !IS_CAP, CALENDAR);
// To derivative
private static final CapFloorIbor CAP_LONG = (CapFloorIbor) CAP_IA_LONG_DEFINITION.toDerivative(REFERENCE_DATE);
private static final CouponIbor COUPON_IBOR = (CouponIbor) COUPON_IBOR_IA_DEFINITION.toDerivative(REFERENCE_DATE);
private static final CapFloorIbor CAP_SHORT = (CapFloorIbor) CAP_IA_SHORT_DEFINITION.toDerivative(REFERENCE_DATE);
private static final CapFloorIbor FLOOR_SHORT = (CapFloorIbor) FLOOR_IA_SHORT_DEFINITION.toDerivative(REFERENCE_DATE);
// Methods
private static final double MU = 8.00;
// Extracted Sample data
private static final double[] STRIKES = new double[] {0.005, 0.01, 0.014844615790478254, 0.015, 0.02, 0.025, 0.03,
0.035, 0.04, 0.045, 0.05, 0.055, 0.06, 0.07, 0.08, 0.09, 0.1, 0.11, 0.12 };
private static final double[] VOLS = new double[] {0.7358548700933457, 0.5523841305358348, 0.4657877918377955,
0.4638783367475177, 0.4224312896268929, 0.40717031545963184, 0.4045852433505948,
0.40746426050271956, 0.41252053623278173, 0.4183168373948183, 0.42422257685856807, 0.4299622516488387,
0.4354215920678454, 0.4453783030412607, 0.45410005682243837, 0.4617460214027164,
0.4684858081353601, 0.4744669985423348, 0.47981106357536796 };
private static final double FORWARD = 0.014844615790478254;
/**
* Consistency with {@link CapFloorIborInArrearsSABRCapGenericReplicationMethod} using SABR interpolation and extrapolation
* Note that SmileInterpolatorSABR and SmileInterpolatorSABRWithRightExtrapolation uses weighted sum of SABR's as interpolation.
* Thus they do not exactly match (especially for the no extrapolation case).
*
* Due to an update of the integration range, the resulting numbers are not close in some cases.
* Still one can confirm the agreement if we use the same upper cutoff
* in {@link CapFloorIborInArrearsSmileModelCapGenericReplicationMethod}
*/
@Test
public void consistencyTest() {
/**
* Cap/Floor Ibor
*/
CapFloorIbor[] derivatives = new CapFloorIbor[] {CAP_LONG, CAP_SHORT, FLOOR_SHORT };
for (final CapFloorIbor derivative : derivatives) {
double forward = SABR_MULTICURVES.getMulticurveProvider().getSimplyCompoundForwardRate(derivative.getIndex(),
derivative.getFixingPeriodStartTime(), derivative.getFixingPeriodEndTime(),
derivative.getFixingAccrualFactor());
double maturity = derivative.getFixingPeriodEndTime() - derivative.getFixingPeriodStartTime();
int nSample = 50;
double[] sampleStrikes = new double[nSample];
double[] sampleVolatilities = new double[nSample];
for (int i = 0; i < nSample; ++i) {
sampleStrikes[i] = forward * (i * 0.04 + 0.001);
sampleVolatilities[i] = SABR_PARAMETER.getVolatility(derivative.getFixingTime(), maturity, sampleStrikes[i],
forward);
}
/*
* With extrapolation
*/
CapFloorIborSABRCapExtrapolationRightMethod oldMethod = new CapFloorIborSABRCapExtrapolationRightMethod(
sampleStrikes[nSample - 1], MU);
CapFloorIborInArrearsSABRCapGenericReplicationMethod methodSabrExtrap = new CapFloorIborInArrearsSABRCapGenericReplicationMethod(
oldMethod);
MultipleCurrencyAmount res1Extrap = methodSabrExtrap.presentValue(derivative, SABR_MULTICURVES);
BenaimDodgsonKainthExtrapolationFunctionProvider provider = new BenaimDodgsonKainthExtrapolationFunctionProvider(
MU, MU);
SmileInterpolatorSABRWithExtrapolation sabrExtrap = new SmileInterpolatorSABRWithExtrapolation(provider);
InterpolatedSmileFunction smileFunctionExtrap = new InterpolatedSmileFunction(sabrExtrap, forward, sampleStrikes,
derivative.getFixingTime(), sampleVolatilities);
CapFloorIborInArrearsSmileModelCapGenericReplicationMethod methodSabrGeneralExtrap = new CapFloorIborInArrearsSmileModelCapGenericReplicationMethod(
smileFunctionExtrap);
MultipleCurrencyAmount res2Extrap = methodSabrGeneralExtrap.presentValue(derivative, MULTICURVES);
double refExtrap = res1Extrap.getAmount(derivative.getCurrency());
assertEquals(refExtrap, res2Extrap.getAmount(derivative.getCurrency()), Math.abs(refExtrap) * 1.e-6);
}
/**
* Coupon Ibor
*/
double forward = SABR_MULTICURVES.getMulticurveProvider().getSimplyCompoundForwardRate(COUPON_IBOR.getIndex(),
COUPON_IBOR.getFixingPeriodStartTime(), COUPON_IBOR.getFixingPeriodEndTime(),
COUPON_IBOR.getFixingAccrualFactor());
double maturity = COUPON_IBOR.getFixingPeriodEndTime() - COUPON_IBOR.getFixingPeriodStartTime();
int nSample = 50;
double[] sampleStrikes = new double[nSample];
double[] sampleVolatilities = new double[nSample];
for (int i = 0; i < nSample; ++i) {
sampleStrikes[i] = forward * (i * 0.04 + 0.001);
sampleVolatilities[i] = SABR_PARAMETER.getVolatility(COUPON_IBOR.getFixingTime(), maturity, sampleStrikes[i],
forward);
}
/*
* With extrapolation
*/
CapFloorIborSABRCapExtrapolationRightMethod oldMethod = new CapFloorIborSABRCapExtrapolationRightMethod(
sampleStrikes[nSample - 1], MU);
CouponIborInArrearsReplicationMethod methodSabrExtrap = new CouponIborInArrearsReplicationMethod(oldMethod);
MultipleCurrencyAmount res1Extrap = methodSabrExtrap.presentValue(COUPON_IBOR, SABR_MULTICURVES);
BenaimDodgsonKainthExtrapolationFunctionProvider provider = new BenaimDodgsonKainthExtrapolationFunctionProvider(
MU, MU);
SmileInterpolatorSABRWithExtrapolation sabrExtrap = new SmileInterpolatorSABRWithExtrapolation(provider);
InterpolatedSmileFunction smileFunctionExtrap = new InterpolatedSmileFunction(sabrExtrap, forward, sampleStrikes,
COUPON_IBOR.getFixingTime(), sampleVolatilities);
CouponIborInArrearsSmileModelReplicationMethod methodSabrGeneralExtrap = new CouponIborInArrearsSmileModelReplicationMethod(
smileFunctionExtrap);
MultipleCurrencyAmount res2Extrap = methodSabrGeneralExtrap.presentValue(COUPON_IBOR, MULTICURVES);
double refExtrap = res1Extrap.getAmount(COUPON_IBOR.getCurrency());
assertEquals(refExtrap, res2Extrap.getAmount(COUPON_IBOR.getCurrency()), Math.abs(refExtrap) * 1.e-6);
}
/**
* Comparing two ways of extrapolation, {@link SmileExtrapolationFunctionSABRProvider}
* The two extrapolation methods produce similar result only for a specific choice of mu.
*/
@Test
public void ComparisonTest() {
CapFloorIbor[] derivatives = new CapFloorIbor[] {CAP_LONG, CAP_SHORT, FLOOR_SHORT };
for (final CapFloorIbor derivative : derivatives) {
double muLow = 18.0;
double muHigh = 1.217;
BenaimDodgsonKainthExtrapolationFunctionProvider provider = new BenaimDodgsonKainthExtrapolationFunctionProvider(
muLow, muHigh);
SmileInterpolatorSABRWithExtrapolation sabrExtrap2 = new SmileInterpolatorSABRWithExtrapolation(provider);
InterpolatedSmileFunction smileFunctionExtrap2 = new InterpolatedSmileFunction(sabrExtrap2, FORWARD, STRIKES,
derivative.getFixingTime(), VOLS);
CapFloorIborInArrearsSmileModelCapGenericReplicationMethod methodSabrGeneralExtrap2 = new CapFloorIborInArrearsSmileModelCapGenericReplicationMethod(
smileFunctionExtrap2);
MultipleCurrencyAmount res2Extrap2 = methodSabrGeneralExtrap2.presentValue(derivative, MULTICURVES);
ShiftedLogNormalExtrapolationFunctionProvider providerLog = new ShiftedLogNormalExtrapolationFunctionProvider(
"Quiet");
SmileInterpolatorSABRWithExtrapolation sabrExtrap2Log = new SmileInterpolatorSABRWithExtrapolation(providerLog);
InterpolatedSmileFunction smileFunctionExtrap2Log = new InterpolatedSmileFunction(sabrExtrap2Log, FORWARD,
STRIKES, derivative.getFixingTime(), VOLS);
CapFloorIborInArrearsSmileModelCapGenericReplicationMethod methodSabrGeneralExtrap2Log = new CapFloorIborInArrearsSmileModelCapGenericReplicationMethod(
smileFunctionExtrap2Log);
MultipleCurrencyAmount res2Extrap2Log = methodSabrGeneralExtrap2Log.presentValue(derivative, MULTICURVES);
SmileInterpolatorSpline spline = new SmileInterpolatorSpline(Interpolator1DFactory.PCHIP_INSTANCE, "Quiet");
InterpolatedSmileFunction smileFunctionSpline = new InterpolatedSmileFunction(spline, FORWARD, STRIKES,
derivative.getFixingTime(), VOLS);
CapFloorIborInArrearsSmileModelCapGenericReplicationMethod methodSpline = new CapFloorIborInArrearsSmileModelCapGenericReplicationMethod(
smileFunctionSpline);
MultipleCurrencyAmount resSpline = methodSpline.presentValue(derivative, MULTICURVES);
double ref = res2Extrap2.getAmount(EUR);
assertEquals(ref, res2Extrap2Log.getAmount(EUR), Math.abs(ref) * 1.e-3);
assertEquals(ref, resSpline.getAmount(EUR), Math.abs(ref) * 1.e-3);
}
/**
* Coupon Ibor
*/
double muLow = 14.05;
double muHigh = 1.217;
BenaimDodgsonKainthExtrapolationFunctionProvider provider = new BenaimDodgsonKainthExtrapolationFunctionProvider(
muLow, muHigh);
SmileInterpolatorSABRWithExtrapolation sabrExtrap2 = new SmileInterpolatorSABRWithExtrapolation(provider);
InterpolatedSmileFunction smileFunctionExtrap2 = new InterpolatedSmileFunction(sabrExtrap2, FORWARD, STRIKES,
COUPON_IBOR.getFixingTime(), VOLS);
CouponIborInArrearsSmileModelReplicationMethod methodSabrGeneralExtrap2 = new CouponIborInArrearsSmileModelReplicationMethod(
smileFunctionExtrap2);
MultipleCurrencyAmount res2Extrap2 = methodSabrGeneralExtrap2.presentValue(COUPON_IBOR, MULTICURVES);
ShiftedLogNormalExtrapolationFunctionProvider providerLog = new ShiftedLogNormalExtrapolationFunctionProvider(
"Quiet");
SmileInterpolatorSABRWithExtrapolation sabrExtrap2Log = new SmileInterpolatorSABRWithExtrapolation(providerLog);
InterpolatedSmileFunction smileFunctionExtrap2Log = new InterpolatedSmileFunction(sabrExtrap2Log, FORWARD, STRIKES,
COUPON_IBOR.getFixingTime(), VOLS);
CouponIborInArrearsSmileModelReplicationMethod methodSabrGeneralExtrap2Log = new CouponIborInArrearsSmileModelReplicationMethod(
smileFunctionExtrap2Log);
MultipleCurrencyAmount res2Extrap2Log = methodSabrGeneralExtrap2Log.presentValue(COUPON_IBOR, MULTICURVES);
SmileInterpolatorSpline spline = new SmileInterpolatorSpline(Interpolator1DFactory.PCHIP_INSTANCE, "Quiet");
InterpolatedSmileFunction smileFunctionSpline = new InterpolatedSmileFunction(spline, FORWARD, STRIKES,
COUPON_IBOR.getFixingTime(), VOLS);
CouponIborInArrearsSmileModelReplicationMethod methodSpline = new CouponIborInArrearsSmileModelReplicationMethod(
smileFunctionSpline);
MultipleCurrencyAmount resSpline = methodSpline.presentValue(COUPON_IBOR, MULTICURVES);
double ref = res2Extrap2.getAmount(EUR);
assertEquals(ref, res2Extrap2Log.getAmount(EUR), Math.abs(ref) * 1.e-2);
assertEquals(ref, resSpline.getAmount(EUR), Math.abs(ref) * 1.e-2);
}
/**
* Check parity relationship for the present value
*/
@Test
public void persentValueSABRExtrapolationParity() {
double[] musCap = muCalculator(STRIKES, VOLS, FORWARD, CAP_LONG.getFixingTime());
SmileExtrapolationFunctionSABRProvider provider1 = new BenaimDodgsonKainthExtrapolationFunctionProvider(musCap[0],
musCap[1]);
double[] musIbor = muCalculator(STRIKES, VOLS, FORWARD, COUPON_IBOR.getFixingTime());
SmileExtrapolationFunctionSABRProvider provider2 = new BenaimDodgsonKainthExtrapolationFunctionProvider(musIbor[0],
musIbor[1]);
SmileExtrapolationFunctionSABRProvider provider = new ShiftedLogNormalExtrapolationFunctionProvider("Quiet");
SmileExtrapolationFunctionSABRProvider[] providers1 = new SmileExtrapolationFunctionSABRProvider[] {provider1,
provider };
SmileExtrapolationFunctionSABRProvider[] providers2 = new SmileExtrapolationFunctionSABRProvider[] {provider2,
provider };
for (int i = 0; i < 2; ++i) {
SmileInterpolatorSABRWithExtrapolation sabrExtrap = new SmileInterpolatorSABRWithExtrapolation(providers1[i]);
InterpolatedSmileFunction smileFunctionExtrap = new InterpolatedSmileFunction(sabrExtrap, FORWARD, STRIKES,
CAP_LONG.getFixingTime(), VOLS);
CapFloorIborInArrearsSmileModelCapGenericReplicationMethod methodSabrGeneralExtrap = new CapFloorIborInArrearsSmileModelCapGenericReplicationMethod(
smileFunctionExtrap);
MultipleCurrencyAmount priceCapLong = methodSabrGeneralExtrap.presentValue(CAP_LONG, MULTICURVES);
MultipleCurrencyAmount priceCapShort = methodSabrGeneralExtrap.presentValue(CAP_SHORT, MULTICURVES);
assertEquals(priceCapLong.getAmount(EUR), -priceCapShort.getAmount(EUR),
Math.abs(priceCapLong.getAmount(EUR)) * 1.0e-10);
SmileInterpolatorSABRWithExtrapolation sabrExtrap2 = new SmileInterpolatorSABRWithExtrapolation(providers2[i]);
InterpolatedSmileFunction smileFunctionExtrap2 = new InterpolatedSmileFunction(sabrExtrap2, FORWARD, STRIKES,
COUPON_IBOR.getFixingTime(), VOLS);
CouponIborInArrearsSmileModelReplicationMethod methodSabrGeneralExtrap2 = new CouponIborInArrearsSmileModelReplicationMethod(
smileFunctionExtrap2);
MultipleCurrencyAmount priceIbor = methodSabrGeneralExtrap2.presentValue(COUPON_IBOR, MULTICURVES);
final CapFloorIborDefinition cap0Definition = new CapFloorIborDefinition(EUR, END_ACCRUAL_DATE,
START_ACCRUAL_DATE, END_ACCRUAL_DATE, ACCRUAL_FACTOR, NOTIONAL, FIXING_DATE, EURIBOR6M, 0.0,
IS_CAP, CALENDAR);
final CapFloorIbor cap0 = (CapFloorIbor) cap0Definition.toDerivative(REFERENCE_DATE);
final MultipleCurrencyAmount priceCap0 = methodSabrGeneralExtrap.presentValue(cap0, MULTICURVES);
assertEquals(priceCap0.getAmount(EUR), priceIbor.getAmount(EUR), Math.abs(priceCap0.getAmount(EUR)) * 1.0e-10);
}
}
/**
* faster decay for larger mu, thus smaller pv
*/
@Test
public void muDependenceTest() {
double[] mu = new double[] {25.0, 18.0, 5.0, 1.5 };
int nMu = mu.length;
CapFloorIbor[] derivatives = new CapFloorIbor[] {CAP_LONG, CAP_SHORT, FLOOR_SHORT };
for (final CapFloorIbor derivative : derivatives) {
double prev = 0.0;
double pres = 0.0;
for (int i = 0; i < nMu; ++i) {
BenaimDodgsonKainthExtrapolationFunctionProvider provider = new BenaimDodgsonKainthExtrapolationFunctionProvider(
mu[i], mu[i]);
SmileInterpolatorSABRWithExtrapolation sabrExtrap2 = new SmileInterpolatorSABRWithExtrapolation(provider);
InterpolatedSmileFunction smileFunctionExtrap2 = new InterpolatedSmileFunction(sabrExtrap2, FORWARD, STRIKES,
derivative.getFixingTime(), VOLS);
CapFloorIborInArrearsSmileModelCapGenericReplicationMethod methodSabrGeneralExtrap2 = new CapFloorIborInArrearsSmileModelCapGenericReplicationMethod(
smileFunctionExtrap2);
MultipleCurrencyAmount res2Extrap2 = methodSabrGeneralExtrap2.presentValue(derivative, MULTICURVES);
pres = Math.abs(res2Extrap2.getAmount(EUR));
assertTrue(pres > prev);
prev = pres;
}
}
double prev = 0.0;
double pres = 0.0;
for (int i = 0; i < nMu; ++i) {
BenaimDodgsonKainthExtrapolationFunctionProvider provider = new BenaimDodgsonKainthExtrapolationFunctionProvider(
mu[i], mu[i]);
SmileInterpolatorSABRWithExtrapolation sabrExtrap2 = new SmileInterpolatorSABRWithExtrapolation(provider);
InterpolatedSmileFunction smileFunctionExtrap2 = new InterpolatedSmileFunction(sabrExtrap2, FORWARD, STRIKES,
COUPON_IBOR.getFixingTime(), VOLS);
CouponIborInArrearsSmileModelReplicationMethod methodSabrGeneralExtrap2 = new CouponIborInArrearsSmileModelReplicationMethod(
smileFunctionExtrap2);
MultipleCurrencyAmount res2Extrap2 = methodSabrGeneralExtrap2.presentValue(COUPON_IBOR, MULTICURVES);
pres = Math.abs(res2Extrap2.getAmount(EUR));
assertTrue(pres > prev);
prev = pres;
}
}
private double[] muCalculator(final double[] strikes, final double[] vols, final double forward, final double expiry) {
double[] res = new double[2];
int nSample = strikes.length;
res[0] = strikes[0] * BlackFormulaRepository.dualDelta(forward, strikes[0], expiry, vols[0], false) /
BlackFormulaRepository.price(forward, strikes[0], expiry, vols[0], false);
res[1] = -strikes[nSample - 1] *
BlackFormulaRepository.dualDelta(forward, strikes[nSample - 1], expiry, vols[nSample - 1], true) /
BlackFormulaRepository.price(forward, strikes[nSample - 1], expiry, vols[nSample - 1], true);
return res;
}
}