//------------------------------------------------------------------------- /// <summary> /// Calculates the present value sensitivity of the swaption product to the rate curves. /// <para> /// The present value sensitivity is computed in a "sticky model parameter" style, i.e. the sensitivity to the /// curve nodes with the SABR model parameters unchanged. This sensitivity does not include a potential /// re-calibration of the model parameters to the raw market data. /// /// </para> /// </summary> /// <param name="swaption"> the swaption product </param> /// <param name="ratesProvider"> the rates provider </param> /// <param name="swaptionVolatilities"> the volatilities </param> /// <returns> the point sensitivity to the rate curves </returns> public virtual PointSensitivityBuilder presentValueSensitivityRatesStickyModel(ResolvedSwaption swaption, RatesProvider ratesProvider, SabrSwaptionVolatilities swaptionVolatilities) { validate(swaption, ratesProvider, swaptionVolatilities); ZonedDateTime expiryDateTime = swaption.Expiry; double expiry = swaptionVolatilities.relativeTime(expiryDateTime); ResolvedSwap underlying = swaption.Underlying; ResolvedSwapLeg fixedLeg = this.fixedLeg(underlying); if (expiry < 0d) { // Option has expired already return(PointSensitivityBuilder.none()); } double forward = SwapPricer.parRate(underlying, ratesProvider); ValueDerivatives annuityDerivative = SwapPricer.LegPricer.annuityCashDerivative(fixedLeg, forward); double annuityCash = annuityDerivative.Value; double annuityCashDr = annuityDerivative.getDerivative(0); LocalDate settlementDate = ((CashSwaptionSettlement)swaption.SwaptionSettlement).SettlementDate; double discountSettle = ratesProvider.discountFactor(fixedLeg.Currency, settlementDate); double strike = calculateStrike(fixedLeg); double tenor = swaptionVolatilities.tenor(fixedLeg.StartDate, fixedLeg.EndDate); double shift = swaptionVolatilities.shift(expiry, tenor); ValueDerivatives volatilityAdj = swaptionVolatilities.volatilityAdjoint(expiry, tenor, strike, forward); bool isCall = fixedLeg.PayReceive.Pay; double shiftedForward = forward + shift; double shiftedStrike = strike + shift; double price = BlackFormulaRepository.price(shiftedForward, shiftedStrike, expiry, volatilityAdj.Value, isCall); double delta = BlackFormulaRepository.delta(shiftedForward, shiftedStrike, expiry, volatilityAdj.Value, isCall); double vega = BlackFormulaRepository.vega(shiftedForward, shiftedStrike, expiry, volatilityAdj.Value); PointSensitivityBuilder forwardSensi = SwapPricer.parRateSensitivity(underlying, ratesProvider); PointSensitivityBuilder discountSettleSensi = ratesProvider.discountFactors(fixedLeg.Currency).zeroRatePointSensitivity(settlementDate); double sign = swaption.LongShort.sign(); return(forwardSensi.multipliedBy(sign * discountSettle * (annuityCash * (delta + vega * volatilityAdj.getDerivative(0)) + annuityCashDr * price)).combinedWith(discountSettleSensi.multipliedBy(sign * annuityCash * price))); }
/// <summary> /// Calculates the delta of the bond future option product based on the price of the underlying future. /// <para> /// 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. /// /// </para> /// </summary> /// <param name="futureOption"> the option product </param> /// <param name="discountingProvider"> the discounting provider </param> /// <param name="volatilities"> the volatilities </param> /// <param name="futurePrice"> the price of the underlying future </param> /// <returns> the price curve sensitivity of the product </returns> public double deltaStickyStrike(ResolvedBondFutureOption futureOption, LegalEntityDiscountingProvider discountingProvider, BlackBondFutureVolatilities volatilities, double futurePrice) { ArgChecker.isTrue(futureOption.PremiumStyle.Equals(FutureOptionPremiumStyle.DAILY_MARGIN), "Premium style should be DAILY_MARGIN"); double strike = futureOption.StrikePrice; ResolvedBondFuture future = futureOption.UnderlyingFuture; double volatility = volatilities.volatility(futureOption.Expiry, future.LastTradeDate, strike, futurePrice); double timeToExpiry = volatilities.relativeTime(futureOption.Expiry); double delta = BlackFormulaRepository.delta(futurePrice, strike, timeToExpiry, volatility, futureOption.PutCall.Call); return(delta); }
//------------------------------------------------------------------------- public virtual void test_delta_presentValueDelta() { double deltaCall = PRICER.delta(CALL_OTM, RATES_PROVIDER, VOLS); CurrencyAmount pvDeltaCall = PRICER.presentValueDelta(CALL_OTM, RATES_PROVIDER, VOLS); double deltaPut = PRICER.delta(PUT_ITM, RATES_PROVIDER, VOLS); CurrencyAmount pvDeltaPut = PRICER.presentValueDelta(PUT_ITM, RATES_PROVIDER, VOLS); double timeToExpiry = VOLS.relativeTime(EXPIRY); double dfFor = RATES_PROVIDER.discountFactor(EUR, PAYMENT_DATE); double forward = PRICER.DiscountingFxSingleProductPricer.forwardFxRate(FX_PRODUCT_HIGH, RATES_PROVIDER).fxRate(CURRENCY_PAIR); double vol = SMILE_TERM.volatility(timeToExpiry, STRIKE_RATE_HIGH, forward); double expectedDeltaCall = dfFor * BlackFormulaRepository.delta(forward, STRIKE_RATE_HIGH, timeToExpiry, vol, true); double expectedDeltaPut = dfFor * BlackFormulaRepository.delta(forward, STRIKE_RATE_HIGH, timeToExpiry, vol, false); double expectedPvDeltaCall = -NOTIONAL *dfFor *BlackFormulaRepository.delta(forward, STRIKE_RATE_HIGH, timeToExpiry, vol, true); double expectedPvDeltaPut = NOTIONAL * dfFor * BlackFormulaRepository.delta(forward, STRIKE_RATE_HIGH, timeToExpiry, vol, false); assertEquals(deltaCall, expectedDeltaCall, TOL); assertEquals(pvDeltaCall.Currency, USD); assertEquals(pvDeltaCall.Amount, expectedPvDeltaCall, NOTIONAL * TOL); assertEquals(deltaPut, expectedDeltaPut, TOL); assertEquals(pvDeltaPut.Currency, USD); assertEquals(pvDeltaPut.Amount, expectedPvDeltaPut, NOTIONAL * TOL); }
public virtual void test_presentValueDelta_formula_shift() { CurrencyAmount computedCaplet = PRICER.presentValueDelta(CAPLET_LONG, RATES, SHIFTED_VOLS); CurrencyAmount computedFloorlet = PRICER.presentValueDelta(FLOORLET_SHORT, RATES, SHIFTED_VOLS); double forward = RATES.iborIndexRates(EUR_EURIBOR_3M).rate(RATE_COMP.Observation); double expiry = SHIFTED_VOLS.relativeTime(CAPLET_LONG.FixingDateTime); double volatility = SHIFTED_VOLS.volatility(expiry, STRIKE, forward); double df = RATES.discountFactor(EUR, CAPLET_LONG.PaymentDate); double shift = IborCapletFloorletDataSet.SHIFT; double expectedCaplet = NOTIONAL * df * CAPLET_LONG.YearFraction * BlackFormulaRepository.delta(forward + shift, STRIKE + shift, expiry, volatility, true); double expectedFloorlet = -NOTIONAL *df *FLOORLET_SHORT.YearFraction *BlackFormulaRepository.delta(forward + shift, STRIKE + shift, expiry, volatility, false); assertEquals(computedCaplet.Currency, EUR); assertEquals(computedCaplet.Amount, expectedCaplet, NOTIONAL * TOL); assertEquals(computedFloorlet.Currency, EUR); assertEquals(computedFloorlet.Amount, expectedFloorlet, NOTIONAL * TOL); }