@Override public double zValue(double x, double y) { return deformationFunction.apply(DoublesPair.of(x, y)).getValue(); }
/** * Calculates the price of the FX barrier option product. * <p> * The price of the product is the value on the valuation date for one unit of the base currency * and is expressed in the counter currency. The price does not take into account the long/short flag. * See {@linkplain #presentValue(ResolvedFxSingleBarrierOption, RatesProvider, BlackFxOptionVolatilities, RecombiningTrinomialTreeData) presnetValue} * for scaling and currency. * <p> * This assumes the tree is already calibrated and the tree data is stored as {@code RecombiningTrinomialTreeData}. * The tree data should be consistent with the pricer and other inputs, see {@link #validateData}. * * @param option the option product * @param ratesProvider the rates provider * @param volatilities the Black volatility provider * @param treeData the trinomial tree data * @return the price of the product */ public double price( ResolvedFxSingleBarrierOption option, RatesProvider ratesProvider, BlackFxOptionVolatilities volatilities, RecombiningTrinomialTreeData treeData) { return priceDerivatives(option, ratesProvider, volatilities, treeData).getValue(); }
@Override protected double doFirstDerivative(double xValue) { ArgChecker.isTrue(Math.abs(xValue) > SMALL, "magnitude of xValue must not be small"); ValueDerivatives resValue = FUNCTION.evaluateAndDifferentiate(poly, xValue); return -resValue.getValue() / (xValue * xValue) + resValue.getDerivative(0) / xValue; }
@Override protected double doFirstDerivative(double xValue) { ArgChecker.isTrue(Math.abs(xValue) > SMALL, "magnitude of xValue must not be small"); ValueDerivatives resValue = FUNCTION.evaluateAndDifferentiate(poly, xValue); return -resValue.getValue() / (xValue * xValue) + resValue.getDerivative(0) / xValue; }
@Override protected double doFirstDerivative(double xValue) { ArgChecker.isTrue(Math.abs(xValue) > SMALL, "magnitude of xValue must not be small"); ValueDerivatives resValue = FUNCTION.evaluateAndDifferentiate(poly, xValue); return -resValue.getValue() / (xValue * xValue) + resValue.getDerivative(0) / xValue; }
private double[] toArray(ValueDerivatives valueDerivatives) { double[] derivatives = valueDerivatives.getDerivatives().toArray(); double[] res = new double[derivatives.length + 1]; res[0] = valueDerivatives.getValue(); System.arraycopy(derivatives, 0, res, 1, derivatives.length); return res; }
/** * Computes the derivative of the conventional cash annuity with respect to the yield from a swap leg. * <p> * The computation is relevant only for standard swaps with constant notional and regular payments. * The swap leg must be a fixed leg. However, this is not checked internally. * * @param fixedLeg the fixed leg of the swap * @param yield the yield * @return the cash annuity */ public ValueDerivatives annuityCashDerivative(ResolvedSwapLeg fixedLeg, double yield) { int nbFixedPeriod = fixedLeg.getPaymentPeriods().size(); SwapPaymentPeriod paymentPeriod = fixedLeg.getPaymentPeriods().get(0); ArgChecker.isTrue(paymentPeriod instanceof RatePaymentPeriod, "payment period should be RatePaymentPeriod"); RatePaymentPeriod ratePaymentPeriod = (RatePaymentPeriod) paymentPeriod; int nbFixedPaymentYear = (int) Math.round(1d / ratePaymentPeriod.getDayCount().yearFraction(ratePaymentPeriod.getStartDate(), ratePaymentPeriod.getEndDate())); double notional = Math.abs(ratePaymentPeriod.getNotional()); ValueDerivatives annuityUnit = annuityCash1(nbFixedPaymentYear, nbFixedPeriod, yield); return ValueDerivatives.of(annuityUnit.getValue() * notional, annuityUnit.getDerivatives().multipliedBy(notional)); }
public void annuity_cash_1() { double shift = 1.0E-7; for (int looprate = 0; looprate < RATES.length; looprate++) { double annuityExpected = PRICER_LEG.annuityCash(NB_PERIODS_PER_YEAR, NB_PERIODS, RATES[looprate]); ValueDerivatives annuityComputed = PRICER_LEG.annuityCash1(NB_PERIODS_PER_YEAR, NB_PERIODS, RATES[looprate]); assertEquals(annuityComputed.getValue(), annuityExpected, TOLERANCE_ANNUITY); double annuityP = PRICER_LEG.annuityCash(NB_PERIODS_PER_YEAR, NB_PERIODS, RATES[looprate] + shift); double annuityM = PRICER_LEG.annuityCash(NB_PERIODS_PER_YEAR, NB_PERIODS, RATES[looprate] - shift); double derivative1Expected = (annuityP - annuityM) / (2.0d * shift); assertEquals(annuityComputed.getDerivative(0), derivative1Expected, TOLERANCE_ANNUITY_1, "Rate: " + looprate); } }
public void test_of() { ValueDerivatives test = ValueDerivatives.of(VALUE, DERIVATIVES); assertEquals(test.getValue(), VALUE, 0); assertEquals(test.getDerivatives(), DERIVATIVES); assertEquals(test.getDerivative(0), DERIVATIVES.get(0)); assertEquals(test.getDerivative(1), DERIVATIVES.get(1)); assertEquals(test.getDerivative(2), DERIVATIVES.get(2)); }
public void annuity_cash_2() { double shift = 1.0E-7; for (int looprate = 0; looprate < RATES.length; looprate++) { ValueDerivatives annuityExpected = PRICER_LEG.annuityCash1(NB_PERIODS_PER_YEAR, NB_PERIODS, RATES[looprate]); ValueDerivatives annuityComputed = PRICER_LEG.annuityCash2(NB_PERIODS_PER_YEAR, NB_PERIODS, RATES[looprate]); ValueDerivatives annuityP = PRICER_LEG.annuityCash1(NB_PERIODS_PER_YEAR, NB_PERIODS, RATES[looprate] + shift); ValueDerivatives annuityM = PRICER_LEG.annuityCash1(NB_PERIODS_PER_YEAR, NB_PERIODS, RATES[looprate] - shift); double derivative2Expected = (annuityP.getDerivative(0) - annuityM.getDerivative(0)) / (2.0d * shift); assertEquals(annuityComputed.getValue(), annuityExpected.getValue(), TOLERANCE_ANNUITY_1); assertEquals(annuityComputed.getDerivative(0), annuityExpected.getDerivative(0), TOLERANCE_ANNUITY_1); assertEquals(annuityComputed.getDerivative(1), derivative2Expected, TOLERANCE_ANNUITY_2); } }
public void annuity_cash_3() { double shift = 1.0E-7; for (int looprate = 0; looprate < RATES.length; looprate++) { ValueDerivatives annuityExpected = PRICER_LEG.annuityCash2(NB_PERIODS_PER_YEAR, NB_PERIODS, RATES[looprate]); ValueDerivatives annuityComputed = PRICER_LEG.annuityCash3(NB_PERIODS_PER_YEAR, NB_PERIODS, RATES[looprate]); ValueDerivatives annuityP = PRICER_LEG.annuityCash2(NB_PERIODS_PER_YEAR, NB_PERIODS, RATES[looprate] + shift); ValueDerivatives annuityM = PRICER_LEG.annuityCash2(NB_PERIODS_PER_YEAR, NB_PERIODS, RATES[looprate] - shift); double derivative3Expected = (annuityP.getDerivative(1) - annuityM.getDerivative(1)) / (2.0d * shift); assertEquals(annuityComputed.getValue(), annuityExpected.getValue(), TOLERANCE_ANNUITY_1); assertEquals(annuityComputed.getDerivative(0), annuityExpected.getDerivative(0), TOLERANCE_ANNUITY_1); assertEquals(annuityComputed.getDerivative(1), annuityExpected.getDerivative(1), TOLERANCE_ANNUITY_2); assertEquals(annuityComputed.getDerivative(2), derivative3Expected, TOLERANCE_ANNUITY_3, "rate: " + looprate); } }
/** *Test the alpha = 0 edge case. Implied vol is zero for alpha = 0, and except in the ATM case, the alpha sensitivity is infinite. We *choose to (arbitrarily) return 1e7 in this case. */ @Test public void testVolatilityAdjointAlpha0() { double eps = 1e-5; double tol = 1e-6; SabrFormulaData data = DATA.withAlpha(0.0); testVolatilityAdjoint(F, CALL_ATM, data, eps, tol); double volatility = FUNCTION.volatility(F, STRIKE_ITM, T, data); ValueDerivatives volatilityAdjoint = FUNCTION.volatilityAdjoint(F, STRIKE_ITM, T, data); assertEquals(volatility, volatilityAdjoint.getValue(), tol); assertEquals(0.0, volatilityAdjoint.getDerivative(0), tol); assertEquals(0.0, volatilityAdjoint.getDerivative(1), tol); assertEquals(1e7, volatilityAdjoint.getDerivative(2), tol); assertEquals(0.0, volatilityAdjoint.getDerivative(3), tol); assertEquals(0.0, volatilityAdjoint.getDerivative(4), tol); assertEquals(0.0, volatilityAdjoint.getDerivative(5), tol); }
public void implied_volatility_from_normal_adjoint() { double shiftFd = 1.0E-6; for (int i = 0; i < N; i++) { double ivBlackComputed = BlackFormulaRepository .impliedVolatilityFromNormalApproximated(FORWARD, STRIKES[i], TIME_TO_EXPIRY, SIGMA_NORMAL[i]); ValueDerivatives ivBlackAdj = BlackFormulaRepository .impliedVolatilityFromNormalApproximatedAdjoint(FORWARD, STRIKES[i], TIME_TO_EXPIRY, SIGMA_NORMAL[i]); assertEquals(ivBlackComputed, ivBlackAdj.getValue(), TOLERANCE_1); assertEquals(1, ivBlackAdj.getDerivatives().size()); double ivBlackComputedP = BlackFormulaRepository .impliedVolatilityFromNormalApproximated(FORWARD, STRIKES[i], TIME_TO_EXPIRY, SIGMA_NORMAL[i] + shiftFd); double ivBlackComputedM = BlackFormulaRepository .impliedVolatilityFromNormalApproximated(FORWARD, STRIKES[i], TIME_TO_EXPIRY, SIGMA_NORMAL[i] - shiftFd); double derivativeApproximated = (ivBlackComputedP - ivBlackComputedM) / (2 * shiftFd); assertEquals(derivativeApproximated, ivBlackAdj.getDerivative(0), TOLERANCE_VOL_DELTA); } }
public void implied_volatility_adjoint() { double shiftFd = 1.0E-6; for (int i = 0; i < N; i++) { double impliedVol = NormalFormulaRepository.impliedVolatilityFromBlackApproximated(FORWARD, STRIKES[i], T, SIGMA_BLACK[i]); ValueDerivatives impliedVolAdj = NormalFormulaRepository.impliedVolatilityFromBlackApproximatedAdjoint(FORWARD, STRIKES[i], T, SIGMA_BLACK[i]); assertEquals(impliedVolAdj.getValue(), impliedVol, TOLERANCE_VOL); double impliedVolP = NormalFormulaRepository.impliedVolatilityFromBlackApproximated(FORWARD, STRIKES[i], T, SIGMA_BLACK[i] + shiftFd); double impliedVolM = NormalFormulaRepository.impliedVolatilityFromBlackApproximated(FORWARD, STRIKES[i], T, SIGMA_BLACK[i] - shiftFd); double derivativeApproximated = (impliedVolP - impliedVolM) / (2 * shiftFd); assertEquals(impliedVolAdj.getDerivatives().size(), 1); assertEquals(impliedVolAdj.getDerivative(0), derivativeApproximated, TOLERANCE_VOL); } }
/** * Computes the option price derivative with respect to the strike. * <p> * The price is SABR below the cut-off strike and extrapolated beyond. * * @param strike the strike of the option * @param putCall whether the option is put or call * @return the option price derivative */ public double priceDerivativeStrike(double strike, PutCall putCall) { // Uses Hagan et al SABR function. if (strike <= cutOffStrike) { ValueDerivatives volatilityAdjoint = sabrFunction.volatilityAdjoint(forward, strike, timeToExpiry, sabrData); ValueDerivatives bsAdjoint = BlackFormulaRepository.priceAdjoint( forward, strike, timeToExpiry, volatilityAdjoint.getValue(), putCall.equals(PutCall.CALL)); return bsAdjoint.getDerivative(1) + bsAdjoint.getDerivative(3) * volatilityAdjoint.getDerivative(1); } // Uses extrapolation for call. double pDK = extrapolationDerivative(strike); if (putCall.isPut()) { // Put by call/put parity pDK += 1.0; } return pDK; }
public void test_zValue() { double tol = 1.0e-14; double x = 2.5; double y = 1.44; DeformedSurface test = DeformedSurface.of(METADATA, SURFACE_ORG, FUNCTION); double computedValue1 = test.zValue(x, y); double computedValue2 = test.zValue(DoublesPair.of(x, y)); UnitParameterSensitivity computedSensi1 = test.zValueParameterSensitivity(x, y); UnitParameterSensitivity computedSensi2 = test.zValueParameterSensitivity(DoublesPair.of(x, y)); ValueDerivatives expected = FUNCTION.apply(DoublesPair.of(x, y)); assertEquals(computedValue1, expected.getValue()); assertEquals(computedValue2, expected.getValue()); assertTrue(DoubleArrayMath.fuzzyEquals( computedSensi1.getSensitivity().toArray(), expected.getDerivatives().toArray(), tol)); assertTrue(DoubleArrayMath.fuzzyEquals( computedSensi2.getSensitivity().toArray(), expected.getDerivatives().toArray(), tol)); }
/** * smoothly connected to limiting cases. */ public void smallsigmaTTest() { for (SimpleConstantContinuousBarrier barrier : BARRIERS) { double volUp = 2.0e-3; double volDw = 1.0e-3; double time = 1.0e-2; double optUp = PRICER.price(SPOT, time, COST_OF_CARRY, RATE_DOM, volUp, barrier); double optDw = PRICER.price(SPOT, time, COST_OF_CARRY, RATE_DOM, volDw, barrier); assertRelative(optUp, optDw); ValueDerivatives optUpAdj = PRICER.priceAdjoint(SPOT, time, COST_OF_CARRY, RATE_DOM, volUp, barrier); ValueDerivatives optDwAdj = PRICER.priceAdjoint(SPOT, time, COST_OF_CARRY, RATE_DOM, volDw, barrier); assertRelative(optUpAdj.getValue(), optDwAdj.getValue()); for (int i = 0; i < 6; ++i) { assertRelative(optUpAdj.getDerivative(i), optDwAdj.getDerivative(i)); } } }
/** * smoothly connected to limiting cases. */ public void smallsigmaTTest() { for (SimpleConstantContinuousBarrier barrier : BARRIERS) { double volUp = 2.0e-3; double volDw = 1.0e-3; double time = 1.0e-2; double optUp = PRICER.price(SPOT, time, COST_OF_CARRY, RATE_DOM, volUp, barrier); double optDw = PRICER.price(SPOT, time, COST_OF_CARRY, RATE_DOM, volDw, barrier); assertRelative(optUp, optDw, 1.0e-3); ValueDerivatives optUpAdj = PRICER.priceAdjoint(SPOT, time, COST_OF_CARRY, RATE_DOM, volUp, barrier); ValueDerivatives optDwAdj = PRICER.priceAdjoint(SPOT, time, COST_OF_CARRY, RATE_DOM, volDw, barrier); assertRelative(optUpAdj.getValue(), optDwAdj.getValue(), 1.0e-3); for (int i = 0; i < 6; ++i) { assertRelative(optUpAdj.getDerivative(i), optDwAdj.getDerivative(i), TOL); } } }
private void testSmallValues(double strike, boolean isCall, SimpleConstantContinuousBarrier barrier) { // small parameters double volUp = 2.0e-3; double volDw = 1.0e-3; double time = 1.0e-2; // price double optUp = BARRIER_PRICER.price(SPOT, strike, time, COST_OF_CARRY, RATE_DOM, volUp, isCall, barrier); double optDw = BARRIER_PRICER.price(SPOT, strike, time, COST_OF_CARRY, RATE_DOM, volDw, isCall, barrier); assertRelative(optUp, optDw); // price adjoint ValueDerivatives optUpAdj = BARRIER_PRICER.priceAdjoint(SPOT, strike, time, COST_OF_CARRY, RATE_DOM, volUp, isCall, barrier); ValueDerivatives optDwAdj = BARRIER_PRICER.priceAdjoint(SPOT, strike, time, COST_OF_CARRY, RATE_DOM, volDw, isCall, barrier); assertRelative(optUpAdj.getValue(), optDwAdj.getValue()); for (int i = 0; i < 6; ++i) { assertRelative(optUpAdj.getDerivative(i), optDwAdj.getDerivative(i)); } }
public void test_volatility() { SabrParametersIborCapletFloorletVolatilities prov = SabrParametersIborCapletFloorletVolatilities.of(NAME, EUR_EURIBOR_3M, DATE_TIME, PARAM); for (int i = 0; i < NB_TEST; i++) { for (int j = 0; j < NB_STRIKE; ++j) { double expiryTime = prov.relativeTime(TEST_OPTION_EXPIRY[i]); double volExpected = PARAM.volatility(expiryTime, TEST_STRIKE[j], TEST_FORWARD); double volComputed = prov.volatility(TEST_OPTION_EXPIRY[i], TEST_STRIKE[j], TEST_FORWARD); assertEquals(volComputed, volExpected, TOLERANCE_VOL); ValueDerivatives volAdjExpected = PARAM.volatilityAdjoint(expiryTime, TEST_STRIKE[j], TEST_FORWARD); ValueDerivatives volAdjComputed = prov.volatilityAdjoint(expiryTime, TEST_STRIKE[j], TEST_FORWARD); assertEquals(volAdjComputed.getValue(), volExpected, TOLERANCE_VOL); assertTrue(DoubleArrayMath.fuzzyEquals( volAdjComputed.getDerivatives().toArray(), volAdjExpected.getDerivatives().toArray(), TOLERANCE_VOL)); } } }