/** * Calculates the delta of the Ibor future option product * based on the price of the underlying future. * <p> * The delta of the product is the sensitivity of the option price to the future price. * The volatility is unchanged for a fixed strike in the sensitivity computation, hence the "StickyStrike" name. * * @param futureOption the option product * @param ratesProvider the rates provider * @param volatilities the volatilities * @param futurePrice the price of the underlying future, in decimal form * @return the price curve sensitivity of the product */ public double deltaStickyStrike( ResolvedIborFutureOption futureOption, RatesProvider ratesProvider, NormalIborFutureOptionVolatilities volatilities, double futurePrice) { ArgChecker.isTrue(futureOption.getPremiumStyle().equals(FutureOptionPremiumStyle.DAILY_MARGIN), "Premium style should be DAILY_MARGIN"); double timeToExpiry = volatilities.relativeTime(futureOption.getExpiry()); double strike = futureOption.getStrikePrice(); ResolvedIborFuture future = futureOption.getUnderlyingFuture(); double volatility = volatilities.volatility(timeToExpiry, future.getLastTradeDate(), strike, futurePrice); return NormalFormulaRepository.delta(futurePrice, strike, timeToExpiry, volatility, futureOption.getPutCall()); }
/** * Restricted copy constructor. * @param beanToCopy the bean to copy from, not null */ private Builder(ResolvedIborFutureOption beanToCopy) { this.securityId = beanToCopy.getSecurityId(); this.putCall = beanToCopy.getPutCall(); this.strikePrice = beanToCopy.getStrikePrice(); this.expiry = beanToCopy.getExpiry(); this.premiumStyle = beanToCopy.getPremiumStyle(); this.rounding = beanToCopy.getRounding(); this.underlyingFuture = beanToCopy.getUnderlyingFuture(); }
public void test_builder() { ResolvedIborFutureOption test = sut(); assertEquals(test.getSecurityId(), PRODUCT.getSecurityId()); assertEquals(test.getPutCall(), PRODUCT.getPutCall()); assertEquals(test.getStrikePrice(), PRODUCT.getStrikePrice()); assertEquals(test.getPremiumStyle(), PRODUCT.getPremiumStyle()); assertEquals(test.getExpiry(), PRODUCT.getExpiry()); assertEquals(test.getExpiryDate(), PRODUCT.getExpiryDate()); assertEquals(test.getRounding(), PRODUCT.getRounding()); assertEquals(test.getUnderlyingFuture(), PRODUCT.getUnderlyingFuture().resolve(REF_DATA)); assertEquals(test.getIndex(), PRODUCT.getUnderlyingFuture().getIndex()); }
public void price_from_future_price() { IborIndexRates mockIbor = mock(IborIndexRates.class); SimpleRatesProvider prov = new SimpleRatesProvider(); prov.setIborRates(mockIbor); when(mockIbor.rate(OPTION.getUnderlyingFuture().getIborRate().getObservation())).thenReturn(RATE); double futurePrice = 0.9875; double strike = OPTION.getStrikePrice(); double timeToExpiry = ACT_365F.relativeYearFraction(VAL_DATE, OPTION.getExpiryDate()); double priceSimpleMoneyness = strike - futurePrice; double normalVol = PARAMETERS_PRICE.zValue(timeToExpiry, priceSimpleMoneyness); EuropeanVanillaOption option = EuropeanVanillaOption.of(strike, timeToExpiry, OPTION.getPutCall()); NormalFunctionData normalPoint = NormalFunctionData.of(futurePrice, 1.0, normalVol); double optionPriceExpected = NORMAL_FUNCTION.getPriceFunction(option).apply(normalPoint); double optionPriceComputed = OPTION_PRICER.price(OPTION, prov, VOL_SIMPLE_MONEY_PRICE, futurePrice); assertEquals(optionPriceComputed, optionPriceExpected, TOLERANCE_PRICE); }
private double futurePrice(ResolvedIborFutureOption futureOption, RatesProvider ratesProvider) { ResolvedIborFuture future = futureOption.getUnderlyingFuture(); return futurePricer.price(future, ratesProvider); }
/** * Calculates the price sensitivity of the Ibor future option product based on curves. * <p> * The price sensitivity of the product is the sensitivity of the price to the underlying curves. * The volatility is unchanged for a fixed strike in the sensitivity computation, hence the "StickyStrike" name. * <p> * This calculates the underlying future price using the future pricer. * * @param futureOption the option product * @param ratesProvider the rates provider * @param volatilities the volatilities * @return the price curve sensitivity of the product */ public PointSensitivities priceSensitivityRatesStickyStrike( ResolvedIborFutureOption futureOption, RatesProvider ratesProvider, NormalIborFutureOptionVolatilities volatilities) { ArgChecker.isTrue(futureOption.getPremiumStyle().equals(FutureOptionPremiumStyle.DAILY_MARGIN), "Premium style should be DAILY_MARGIN"); double futurePrice = futurePrice(futureOption, ratesProvider); return priceSensitivityRatesStickyStrike(futureOption, ratesProvider, volatilities, futurePrice); }
public void delta_from_future_price() { IborIndexRates mockIbor = mock(IborIndexRates.class); SimpleRatesProvider prov = new SimpleRatesProvider(); prov.setIborRates(mockIbor); when(mockIbor.rate(OPTION.getUnderlyingFuture().getIborRate().getObservation())).thenReturn(RATE); double futurePrice = 0.9875; double strike = OPTION.getStrikePrice(); double timeToExpiry = ACT_365F.relativeYearFraction(VAL_DATE, OPTION.getExpiryDate()); double priceSimpleMoneyness = strike - futurePrice; double normalVol = PARAMETERS_PRICE.zValue(timeToExpiry, priceSimpleMoneyness); EuropeanVanillaOption option = EuropeanVanillaOption.of(strike, timeToExpiry, OPTION.getPutCall()); NormalFunctionData normalPoint = NormalFunctionData.of(futurePrice, 1.0, normalVol); double optionDeltaExpected = NORMAL_FUNCTION.getDelta(option, normalPoint); double optionDeltaComputed = OPTION_PRICER.deltaStickyStrike(OPTION, prov, VOL_SIMPLE_MONEY_PRICE, futurePrice); assertEquals(optionDeltaComputed, optionDeltaExpected, TOLERANCE_PRICE); }
/** * Calculates the number related to Ibor futures product on which the daily margin is computed. * <p> * For two consecutive settlement prices C1 and C2, the daily margin is computed as * {@code marginIndex(future, C2) - marginIndex(future, C1)}. * * @param option the option product * @param price the price of the product, in decimal form * @return the index */ double marginIndex(ResolvedIborFutureOption option, double price) { double notional = option.getUnderlyingFuture().getNotional(); double accrualFactor = option.getUnderlyingFuture().getAccrualFactor(); return price * notional * accrualFactor; }
/** * Calculates the price of the Ibor future option product * based on the price of the underlying future. * <p> * The price of the option is the price on the valuation date. * * @param futureOption the option product * @param ratesProvider the rates provider * @param volatilities the volatilities * @param futurePrice the price of the underlying future, in decimal form * @return the price of the product, in decimal form */ public double price( ResolvedIborFutureOption futureOption, RatesProvider ratesProvider, NormalIborFutureOptionVolatilities volatilities, double futurePrice) { ArgChecker.isTrue(futureOption.getPremiumStyle().equals(FutureOptionPremiumStyle.DAILY_MARGIN), "Premium style should be DAILY_MARGIN"); ArgChecker.isTrue(futureOption.getUnderlyingFuture().getIndex().equals(volatilities.getIndex()), "Future index should be the same as data index"); double timeToExpiry = volatilities.relativeTime(futureOption.getExpiry()); double strike = futureOption.getStrikePrice(); ResolvedIborFuture future = futureOption.getUnderlyingFuture(); double volatility = volatilities.volatility(timeToExpiry, future.getLastTradeDate(), strike, futurePrice); return NormalFormulaRepository.price(futurePrice, strike, timeToExpiry, volatility, futureOption.getPutCall()); }
@Override protected Object propertyGet(Bean bean, String propertyName, boolean quiet) { switch (propertyName.hashCode()) { case 1574023291: // securityId return ((ResolvedIborFutureOption) bean).getSecurityId(); case -219971059: // putCall return ((ResolvedIborFutureOption) bean).getPutCall(); case 50946231: // strikePrice return ((ResolvedIborFutureOption) bean).getStrikePrice(); case -1289159373: // expiry return ((ResolvedIborFutureOption) bean).getExpiry(); case -1257652838: // premiumStyle return ((ResolvedIborFutureOption) bean).getPremiumStyle(); case -142444: // rounding return ((ResolvedIborFutureOption) bean).getRounding(); case -165476480: // underlyingFuture return ((ResolvedIborFutureOption) bean).getUnderlyingFuture(); } return super.propertyGet(bean, propertyName, quiet); }
public void priceSensitivityNormalVolatility_from_future_price() { IborIndexRates mockIbor = mock(IborIndexRates.class); SimpleRatesProvider prov = new SimpleRatesProvider(); prov.setIborRates(mockIbor); when(mockIbor.rate(OPTION.getUnderlyingFuture().getIborRate().getObservation())).thenReturn(RATE); double futurePrice = 0.9875; double strike = OPTION.getStrikePrice(); double timeToExpiry = ACT_365F.relativeYearFraction(VAL_DATE, OPTION.getExpiryDate()); double priceSimpleMoneyness = strike - futurePrice; double normalVol = PARAMETERS_PRICE.zValue(timeToExpiry, priceSimpleMoneyness); EuropeanVanillaOption option = EuropeanVanillaOption.of(strike, timeToExpiry, OPTION.getPutCall()); NormalFunctionData normalPoint = NormalFunctionData.of(futurePrice, 1.0, normalVol); double optionVegaExpected = NORMAL_FUNCTION.getVega(option, normalPoint); IborFutureOptionSensitivity optionVegaComputed = OPTION_PRICER.priceSensitivityModelParamsVolatility( OPTION, prov, VOL_SIMPLE_MONEY_PRICE, futurePrice); assertEquals(optionVegaComputed.getSensitivity(), optionVegaExpected, TOLERANCE_PRICE); assertEquals(optionVegaComputed.getExpiry(), timeToExpiry); assertEquals(optionVegaComputed.getFixingDate(), OPTION.getUnderlyingFuture().getIborRate().getObservation().getFixingDate()); assertEquals(optionVegaComputed.getStrikePrice(), OPTION.getStrikePrice()); assertEquals(optionVegaComputed.getFuturePrice(), futurePrice); }
/** * Calculates the margin index sensitivity of the Ibor future product. * <p> * The margin index sensitivity if the sensitivity of the margin index to the underlying curves. * For two consecutive settlement prices C1 and C2, the daily margin is computed as * {@code marginIndex(future, C2) - marginIndex(future, C1)}. * * @param option the option product * @param priceSensitivity the price sensitivity of the product * @return the index sensitivity */ PointSensitivities marginIndexSensitivity( ResolvedIborFutureOption option, PointSensitivities priceSensitivity) { double notional = option.getUnderlyingFuture().getNotional(); double accrualFactor = option.getUnderlyingFuture().getAccrualFactor(); return priceSensitivity.multipliedBy(notional * accrualFactor); }
/** * Calculates the price sensitivity to the normal volatility used for the pricing of the Ibor future option * based on the price of the underlying future. * <p> * This sensitivity is also called the <i>price normal vega</i>. * * @param futureOption the option product * @param ratesProvider the rates provider * @param volatilities the volatilities * @param futurePrice the underlying future price, in decimal form * @return the sensitivity */ public IborFutureOptionSensitivity priceSensitivityModelParamsVolatility( ResolvedIborFutureOption futureOption, RatesProvider ratesProvider, NormalIborFutureOptionVolatilities volatilities, double futurePrice) { ArgChecker.isTrue(futureOption.getPremiumStyle().equals(FutureOptionPremiumStyle.DAILY_MARGIN), "Premium style should be DAILY_MARGIN"); double timeToExpiry = volatilities.relativeTime(futureOption.getExpiry()); double strike = futureOption.getStrikePrice(); ResolvedIborFuture future = futureOption.getUnderlyingFuture(); double volatility = volatilities.volatility(timeToExpiry, future.getLastTradeDate(), strike, futurePrice); double vega = NormalFormulaRepository.vega(futurePrice, strike, timeToExpiry, volatility, futureOption.getPutCall()); return IborFutureOptionSensitivity.of( volatilities.getName(), timeToExpiry, future.getLastTradeDate(), strike, futurePrice, future.getCurrency(), vega); }
/** * Calculates the price sensitivity of the Ibor future option product * based on the price of the underlying future. * <p> * The price sensitivity of the product is the sensitivity of the price to the underlying curves. * The volatility is unchanged for a fixed strike in the sensitivity computation, hence the "StickyStrike" name. * * @param futureOption the option product * @param ratesProvider the rates provider * @param volatilities the volatilities * @param futurePrice the price of the underlying future, in decimal form * @return the price curve sensitivity of the product */ public PointSensitivities priceSensitivityRatesStickyStrike( ResolvedIborFutureOption futureOption, RatesProvider ratesProvider, NormalIborFutureOptionVolatilities volatilities, double futurePrice) { double delta = deltaStickyStrike(futureOption, ratesProvider, volatilities, futurePrice); PointSensitivities futurePriceSensitivity = futurePricer.priceSensitivity(futureOption.getUnderlyingFuture(), ratesProvider); return futurePriceSensitivity.multipliedBy(delta); }
/** * Computes the present value sensitivity to the normal volatility used in the pricing. * <p> * The result is a single sensitivity to the volatility used. * The volatility is associated with the expiry/delay/strike/future price key combination. * <p> * This calculates the underlying future price using the future pricer. * * @param futureOptionTrade the trade * @param ratesProvider the rates provider * @param volatilities the volatilities * @return the price sensitivity */ public IborFutureOptionSensitivity presentValueSensitivityModelParamsVolatility( ResolvedIborFutureOptionTrade futureOptionTrade, RatesProvider ratesProvider, NormalIborFutureOptionVolatilities volatilities) { ResolvedIborFuture future = futureOptionTrade.getProduct().getUnderlyingFuture(); double futurePrice = futureOptionPricer.getFuturePricer().price(future, ratesProvider); return presentValueSensitivityModelParamsVolatility(futureOptionTrade, ratesProvider, volatilities, futurePrice); }
public void price_from_env() { IborIndexRates mockIbor = mock(IborIndexRates.class); SimpleRatesProvider prov = new SimpleRatesProvider(); prov.setIborRates(mockIbor); when(mockIbor.rate(OPTION.getUnderlyingFuture().getIborRate().getObservation())).thenReturn(RATE); double futurePrice = 1.0 - RATE; double optionPriceExpected = OPTION_PRICER.price(OPTION, prov, VOL_SIMPLE_MONEY_PRICE, futurePrice); double optionPriceComputed = OPTION_PRICER.price(OPTION, prov, VOL_SIMPLE_MONEY_PRICE); assertEquals(optionPriceComputed, optionPriceExpected, TOLERANCE_PRICE); }
public void delta_from_env() { IborIndexRates mockIbor = mock(IborIndexRates.class); SimpleRatesProvider prov = new SimpleRatesProvider(); prov.setIborRates(mockIbor); when(mockIbor.rate(OPTION.getUnderlyingFuture().getIborRate().getObservation())).thenReturn(RATE); double futurePrice = 1.0 - RATE; double optionDeltaExpected = OPTION_PRICER.deltaStickyStrike(OPTION, prov, VOL_SIMPLE_MONEY_PRICE, futurePrice); double optionDeltaComputed = OPTION_PRICER.deltaStickyStrike(OPTION, prov, VOL_SIMPLE_MONEY_PRICE); assertEquals(optionDeltaComputed, optionDeltaExpected, TOLERANCE_PRICE); }
public void priceSensitivityStickyStrike_from_future_price() { IborIndexRates mockIbor = mock(IborIndexRates.class); SimpleRatesProvider prov = new SimpleRatesProvider(); prov.setIborRates(mockIbor); when(mockIbor.rate(OPTION.getUnderlyingFuture().getIborRate().getObservation())).thenReturn(RATE); double futurePrice = 0.9875; PointSensitivities futurePriceSensitivity = FUTURE_PRICER.priceSensitivity(OPTION.getUnderlyingFuture(), prov); double delta = OPTION_PRICER.deltaStickyStrike(OPTION, prov, VOL_SIMPLE_MONEY_PRICE, futurePrice); PointSensitivities optionPriceSensitivityExpected = futurePriceSensitivity.multipliedBy(delta); PointSensitivities optionPriceSensitivityComputed = OPTION_PRICER.priceSensitivityRatesStickyStrike(OPTION, prov, VOL_SIMPLE_MONEY_PRICE, futurePrice); assertTrue(optionPriceSensitivityExpected.equalWithTolerance(optionPriceSensitivityComputed, TOLERANCE_PRICE_DELTA)); }
public void priceSensitivityStickyStrike_from_env() { IborIndexRates mockIbor = mock(IborIndexRates.class); SimpleRatesProvider prov = new SimpleRatesProvider(); prov.setIborRates(mockIbor); when(mockIbor.rate(OPTION.getUnderlyingFuture().getIborRate().getObservation())).thenReturn(RATE); PointSensitivities futurePriceSensitivity = OPTION_PRICER.getFuturePricer() .priceSensitivity(OPTION.getUnderlyingFuture(), prov); double delta = OPTION_PRICER.deltaStickyStrike(OPTION, prov, VOL_SIMPLE_MONEY_PRICE); PointSensitivities optionPriceSensitivityExpected = futurePriceSensitivity.multipliedBy(delta); PointSensitivities optionPriceSensitivityComputed = OPTION_PRICER.priceSensitivityRatesStickyStrike(OPTION, prov, VOL_SIMPLE_MONEY_PRICE); assertTrue(optionPriceSensitivityExpected.equalWithTolerance(optionPriceSensitivityComputed, TOLERANCE_PRICE_DELTA)); }
public void priceSensitivityNormalVolatility_from_env() { IborIndexRates mockIbor = mock(IborIndexRates.class); SimpleRatesProvider prov = new SimpleRatesProvider(); prov.setIborRates(mockIbor); when(mockIbor.rate(OPTION.getUnderlyingFuture().getIborRate().getObservation())).thenReturn(RATE); double futurePrice = 1.0 - RATE; IborFutureOptionSensitivity optionVegaExpected = OPTION_PRICER.priceSensitivityModelParamsVolatility( OPTION, prov, VOL_SIMPLE_MONEY_PRICE, futurePrice); IborFutureOptionSensitivity optionVegaComputed = OPTION_PRICER.priceSensitivityModelParamsVolatility( OPTION, prov, VOL_SIMPLE_MONEY_PRICE); assertTrue(optionVegaExpected.compareKey(optionVegaComputed) == 0); assertEquals(optionVegaComputed.getSensitivity(), optionVegaExpected.getSensitivity(), TOLERANCE_PRICE_DELTA); }