/** * Computes the option security price curve sensitivity. The future price is computed without * convexity adjustment. * * @param security The future option security. * @param sabrData The SABR data bundle. * @return The security price curve sensitivity. */ public PresentValueSABRSensitivityDataBundle priceSABRSensitivity( final InterestRateFutureOptionMarginSecurity security, final SABRInterestRateDataBundle sabrData) { final PresentValueSABRSensitivityDataBundle sensi = new PresentValueSABRSensitivityDataBundle(); // Forward sweep final double priceFuture = METHOD_FUTURE.price(security.getUnderlyingFuture(), sabrData); final double rateStrike = 1.0 - security.getStrike(); final EuropeanVanillaOption option = new EuropeanVanillaOption(rateStrike, security.getExpirationTime(), !security.isCall()); final double forward = 1 - priceFuture; final double delay = security.getUnderlyingFuture().getLastTradingTime() - security.getExpirationTime(); final double[] volatilityAdjoint = sabrData .getSABRParameter() .getVolatilityAdjoint(security.getExpirationTime(), delay, rateStrike, forward); final BlackFunctionData dataBlack = new BlackFunctionData(forward, 1.0, volatilityAdjoint[0]); final double[] priceAdjoint = BLACK_FUNCTION.getPriceAdjoint(option, dataBlack); // Backward sweep final double priceBar = 1.0; final double volatilityBar = priceAdjoint[2] * priceBar; final DoublesPair expiryDelay = new DoublesPair(security.getExpirationTime(), delay); sensi.addAlpha(expiryDelay, volatilityAdjoint[3] * volatilityBar); sensi.addBeta(expiryDelay, volatilityAdjoint[4] * volatilityBar); sensi.addRho(expiryDelay, volatilityAdjoint[5] * volatilityBar); sensi.addNu(expiryDelay, volatilityAdjoint[6] * volatilityBar); return sensi; }
/** * Computes the option security price curve sensitivity. The future price is computed without * convexity adjustment. * * @param security The future option security. * @param sabrData The SABR data bundle. * @return The security price curve sensitivity. */ public InterestRateCurveSensitivity priceCurveSensitivity( final InterestRateFutureOptionMarginSecurity security, final SABRInterestRateDataBundle sabrData) { // Forward sweep final double priceFuture = METHOD_FUTURE.price(security.getUnderlyingFuture(), sabrData); final double rateStrike = 1.0 - security.getStrike(); final EuropeanVanillaOption option = new EuropeanVanillaOption(rateStrike, security.getExpirationTime(), !security.isCall()); final double forward = 1 - priceFuture; final double delay = security.getUnderlyingFuture().getLastTradingTime() - security.getExpirationTime(); final double[] volatilityAdjoint = sabrData .getSABRParameter() .getVolatilityAdjoint(security.getExpirationTime(), delay, rateStrike, forward); final BlackFunctionData dataBlack = new BlackFunctionData(forward, 1.0, volatilityAdjoint[0]); final double[] priceAdjoint = BLACK_FUNCTION.getPriceAdjoint(option, dataBlack); // Backward sweep final double priceBar = 1.0; final double volatilityBar = priceAdjoint[2] * priceBar; final double forwardBar = priceAdjoint[1] * priceBar + volatilityAdjoint[1] * volatilityBar; final double priceFutureBar = -forwardBar; final InterestRateCurveSensitivity priceFutureDerivative = METHOD_FUTURE.priceCurveSensitivity(security.getUnderlyingFuture(), sabrData); return priceFutureDerivative.multipliedBy(priceFutureBar); }
@Test /** Tests the present value. */ public void presentValueNoNotional() { final MultipleCurrencyAmount pv = METHOD.presentValue(ZERO_COUPON_CAP, BLACK_INFLATION); final double timeToMaturity = ZERO_COUPON_CAP.getReferenceEndTime() - ZERO_COUPON_CAP.getLastKnownFixingTime(); final double df = MARKET .getCurve(ZERO_COUPON_CAP.getCurrency()) .getDiscountFactor(ZERO_COUPON_CAP.getPaymentTime()); final double finalIndex = MARKET.getCurve(PRICE_INDEX_EUR).getPriceIndex(ZERO_COUPON_CAP.getReferenceEndTime()); final double forward = finalIndex / INDEX_1MAY_2008; final EuropeanVanillaOption option = new EuropeanVanillaOption( Math.pow(1 + ZERO_COUPON_CAP.getStrike(), ZERO_COUPON_CAP.getMaturity()), timeToMaturity, ZERO_COUPON_CAP.isCap()); final double volatility = BLACK_INFLATION .getBlackParameters() .getVolatility(ZERO_COUPON_CAP.getReferenceEndTime(), ZERO_COUPON_CAP.getStrike()); final BlackFunctionData dataBlack = new BlackFunctionData(forward, 1.0, volatility); final Function1D<BlackFunctionData, Double> func = BLACK_FUNCTION.getPriceFunction(option); final double pvExpected = df * func.evaluate(dataBlack) * ZERO_COUPON_CAP.getNotional() * ZERO_COUPON_CAP.getPaymentYearFraction(); assertEquals( "Zero-coupon inflation DiscountingMethod: Present value", pvExpected, pv.getAmount(ZERO_COUPON_CAP.getCurrency()), TOLERANCE_PV); }
public void delta() { final double priceFutures = METHOD_FUTURE.price(CALL_JB_147.getUnderlyingFuture(), ISSUER_SPECIFIC_MULTICURVES); final EuropeanVanillaOption option = new EuropeanVanillaOption( STRIKE_147, CALL_JB_147.getExpirationTime(), CALL_JB_147.isCall()); final double expiry = CALL_JB_147.getExpirationTime(); final double volatility = BLACK_SURFACE_EXP_STRIKE.getZValue(expiry, STRIKE_147); double df = ISSUER_SPECIFIC_MULTICURVES .getMulticurveProvider() .getDiscountFactor(JBM5_DEFINITION.getCurrency(), CALL_JB_147.getExpirationTime()); final BlackFunctionData dataBlack = new BlackFunctionData(priceFutures, df, volatility); final double[] priceAD = BLACK_FUNCTION.getPriceAdjoint(option, dataBlack); final double deltaCallExpected = priceAD[1]; final double deltaCallComputed = METHOD_OPT.delta(CALL_JB_147, BLACK_EXP_STRIKE_BNDFUT); assertEquals( "BondFuturesOptionPremiumSecurityBlackBondFuturesMethod: delta", deltaCallExpected, deltaCallComputed, TOLERANCE_DELTA); final double deltaPutComputed = METHOD_OPT.delta(PUT_JB_147, BLACK_EXP_STRIKE_BNDFUT); assertEquals( "BondFuturesOptionPremiumSecurityBlackBondFuturesMethod: delta", deltaCallExpected - deltaPutComputed, df, TOLERANCE_DELTA); }
@Test public void presentValue() { final MultipleCurrencyAmount pvMethod = METHOD_BLACK.presentValue(SWAPTION_LONG_REC, BLACK_MULTICURVES); final double forward = SWAPTION_LONG_REC.getUnderlyingSwap().accept(PRDC, MULTICURVES); final double pvbp = METHOD_SWAP.presentValueBasisPoint(SWAPTION_LONG_REC.getUnderlyingSwap(), MULTICURVES); final double volatility = BLACK.getVolatility( SWAPTION_LONG_REC.getTimeToExpiry(), SWAPTION_LONG_REC.getMaturityTime()); final BlackPriceFunction blackFunction = new BlackPriceFunction(); final BlackFunctionData dataBlack = new BlackFunctionData(forward, pvbp, volatility); final Function1D<BlackFunctionData, Double> func = blackFunction.getPriceFunction(SWAPTION_LONG_REC); final double pvExpected = func.evaluate(dataBlack); assertEquals( "Swaption Black method: present value", pvExpected, pvMethod.getAmount(EUR), TOLERANCE_PV); }
/** * Computes the option security price from future price. * * @param security The future option security. * @param sabrData The SABR data bundle. * @param priceFuture The price of the underlying future. * @return The security price. */ public double optionPriceFromFuturePrice( final InterestRateFutureOptionMarginSecurity security, final SABRInterestRateDataBundle sabrData, final double priceFuture) { final double rateStrike = 1.0 - security.getStrike(); final EuropeanVanillaOption option = new EuropeanVanillaOption(rateStrike, security.getExpirationTime(), !security.isCall()); final double forward = 1 - priceFuture; final double delay = security.getUnderlyingFuture().getLastTradingTime() - security.getExpirationTime(); final double volatility = sabrData .getSABRParameter() .getVolatility(new double[] {security.getExpirationTime(), delay, rateStrike, forward}); final BlackFunctionData dataBlack = new BlackFunctionData(forward, 1.0, volatility); final double priceSecurity = BLACK_FUNCTION.getPriceFunction(option).evaluate(dataBlack); return priceSecurity; }
public void priceFromFuturesPrice() { final double price = 1.465; final EuropeanVanillaOption option = new EuropeanVanillaOption( STRIKE_147, CALL_JB_147.getExpirationTime(), CALL_JB_147.isCall()); final double logmoney = Math.log(STRIKE_147 / price); final double expiry = CALL_JB_147.getExpirationTime(); final double volatility = BLACK_SURFACE_EXP_STRIKE.getZValue(expiry, logmoney); double df = ISSUER_SPECIFIC_MULTICURVES .getMulticurveProvider() .getDiscountFactor(JBM5_DEFINITION.getCurrency(), expiry); final BlackFunctionData dataBlack = new BlackFunctionData(price, df, volatility); final double priceExpected = BLACK_FUNCTION.getPriceFunction(option).evaluate(dataBlack); final double priceComputed = METHOD_OPT.priceFromUnderlyingPrice(CALL_JB_147, BLACK_EXP_STRIKE_BNDFUT, price); assertEquals( "BondFuturesOptionPremiumSecurityBlackBondFuturesMethod: underlying futures price", priceExpected, priceComputed, TOLERANCE_RATE); }
/** * Computes the present value of the Physical delivery swaption through approximation.. * * @param swaption The swaption. * @param cfe The swaption cash flow equiovalent. * @param g2Data The G2++ parameters and the curves. * @return The present value. */ public CurrencyAmount presentValue( final SwaptionPhysicalFixedIbor swaption, final AnnuityPaymentFixed cfe, final G2ppPiecewiseConstantDataBundle g2Data) { YieldAndDiscountCurve dsc = g2Data.getCurve(swaption.getUnderlyingSwap().getFixedLeg().getDiscountCurve()); int nbCf = cfe.getNumberOfPayments(); double[] cfa = new double[nbCf]; double[] t = new double[nbCf]; for (int loopcf = 0; loopcf < nbCf; loopcf++) { cfa[loopcf] = -Math.signum(cfe.getNthPayment(0).getAmount()) * cfe.getNthPayment(loopcf).getAmount(); t[loopcf] = cfe.getNthPayment(loopcf).getPaymentTime(); } double rhog2pp = g2Data.getG2ppParameter().getCorrelation(); double[][] ht0 = MODEL_G2PP.volatilityMaturityPart(g2Data.getG2ppParameter(), t[0], t); double[] dfswap = new double[nbCf]; double[] p0 = new double[nbCf]; double[] cP = new double[nbCf]; for (int loopcf = 0; loopcf < nbCf; loopcf++) { dfswap[loopcf] = dsc.getDiscountFactor(t[loopcf]); p0[loopcf] = dfswap[loopcf] / dfswap[0]; cP[loopcf] = cfa[loopcf] * p0[loopcf]; } double k = -cfa[0]; double b0 = 0.0; for (int loopcf = 1; loopcf < nbCf; loopcf++) { b0 += cP[loopcf]; } double[] alpha0 = new double[nbCf - 1]; double[] beta0 = new double[2]; for (int loopcf = 0; loopcf < nbCf - 1; loopcf++) { alpha0[loopcf] = cfa[loopcf + 1] * p0[loopcf + 1] / b0; beta0[0] += alpha0[loopcf] * ht0[0][loopcf + 1]; beta0[1] += alpha0[loopcf] * ht0[1][loopcf + 1]; } double[][] gamma = MODEL_G2PP.gamma(g2Data.getG2ppParameter(), 0, swaption.getTimeToExpiry()); double[] tau = new double[nbCf]; for (int loopcf = 0; loopcf < nbCf; loopcf++) { tau[loopcf] = gamma[0][0] * ht0[0][loopcf] * ht0[0][loopcf] + gamma[1][1] * ht0[1][loopcf] * ht0[1][loopcf] + 2 * rhog2pp * gamma[0][1] * ht0[0][loopcf] * ht0[1][loopcf]; } double xbarnum = 0.0; double xbarde = 0.0; for (int loopcf = 0; loopcf < nbCf; loopcf++) { xbarnum += cP[loopcf] - cP[loopcf] * tau[loopcf] * tau[loopcf] / 2.0; xbarde += cP[loopcf] * tau[loopcf]; } double xbar = xbarnum / xbarde; double[] pK = new double[nbCf]; for (int loopcf = 0; loopcf < nbCf; loopcf++) { pK[loopcf] = p0[loopcf] * (1.0 - tau[loopcf] * xbar - tau[loopcf] * tau[loopcf] / 2.0); } double[] alphaK = new double[nbCf - 1]; double[] betaK = new double[2]; for (int loopcf = 0; loopcf < nbCf - 1; loopcf++) { alphaK[loopcf] = cfa[loopcf + 1] * pK[loopcf + 1] / k; betaK[0] += alphaK[loopcf] * ht0[0][loopcf + 1]; betaK[1] += alphaK[loopcf] * ht0[1][loopcf + 1]; } double[] betaBar = new double[] {(beta0[0] + betaK[0]) / 2.0, (beta0[1] + betaK[1]) / 2.0}; double sigmaBar2 = gamma[0][0] * betaBar[0] * betaBar[0] + gamma[1][1] * betaBar[1] * betaBar[1] + 2 * rhog2pp * gamma[0][1] * betaBar[0] * betaBar[1]; double sigmaBar = Math.sqrt(sigmaBar2); EuropeanVanillaOption option = new EuropeanVanillaOption(k, 1, !swaption.isCall()); final BlackPriceFunction blackFunction = new BlackPriceFunction(); final BlackFunctionData dataBlack = new BlackFunctionData(b0, dfswap[0], sigmaBar); final Function1D<BlackFunctionData, Double> func = blackFunction.getPriceFunction(option); final double price = func.evaluate(dataBlack) * (swaption.isLong() ? 1.0 : -1.0); return CurrencyAmount.of(swaption.getCurrency(), price); }