Ejemplo n.º 1
0
 //-------------------------------------------------------------------------
 public virtual void test_presentValueSensitivity()
 {
     for (int i = 0; i < NB_STRIKES; ++i)
     {
         ResolvedFxVanillaOption        option        = CALLS[i];
         PointSensitivityBuilder        point         = PRICER.presentValueSensitivityRatesStickyStrike(option, RATES_PROVIDER, VOLS);
         CurrencyParameterSensitivities sensiComputed = RATES_PROVIDER.parameterSensitivity(point.build());
         double timeToExpiry = VOLS.relativeTime(EXPIRY);
         double forwardRate  = FX_PRICER.forwardFxRate(UNDERLYING[i], RATES_PROVIDER).fxRate(CURRENCY_PAIR);
         double strikeRate   = option.Strike;
         SmileDeltaParameters smileAtTime = VOLS.Smile.smileForExpiry(timeToExpiry);
         double[]             vols        = smileAtTime.Volatility.toArray();
         double df = RATES_PROVIDER.discountFactor(USD, PAY);
         CurrencyParameterSensitivities sensiExpected = FD_CAL.sensitivity(RATES_PROVIDER, p => PRICER.presentValue(option, p, VOLS));
         CurrencyParameterSensitivities sensiRes      = FD_CAL.sensitivity(RATES_PROVIDER, (ImmutableRatesProvider p) =>
         {
             double fwd     = FX_PRICER.forwardFxRate(option.Underlying, p).fxRate(CURRENCY_PAIR);
             double[] strs  = smileAtTime.strike(fwd).toArray();
             double[] wghts = weights(fwd, strikeRate, strs, timeToExpiry, vols[1]);
             double res     = 0d;
             for (int j = 0; j < 3; ++j)
             {
                 res += wghts[j] * (BlackFormulaRepository.price(forwardRate, strs[j], timeToExpiry, vols[j], true) - BlackFormulaRepository.price(forwardRate, strs[j], timeToExpiry, vols[1], true));
             }
             return(CurrencyAmount.of(USD, -res * df * NOTIONAL));
         });
         assertTrue(sensiComputed.equalWithTolerance(sensiExpected.combinedWith(sensiRes), FD_EPS * NOTIONAL * 10d));
     }
 }
        //-------------------------------------------------------------------------
        /// <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)));
        }
Ejemplo n.º 3
0
 //-------------------------------------------------------------------------
 public virtual void test_price_presentValue()
 {
     for (int i = 0; i < NB_STRIKES; ++i)
     {
         ResolvedFxVanillaOption      call      = CALLS[i];
         ResolvedFxVanillaOptionTrade callTrade = ResolvedFxVanillaOptionTrade.builder().product(call).premium(Payment.of(EUR, 0, VAL_DATE)).build();
         double               computedPriceCall = PRICER.price(call, RATES_PROVIDER, VOLS);
         CurrencyAmount       computedCall      = PRICER.presentValue(call, RATES_PROVIDER, VOLS);
         double               timeToExpiry      = VOLS.relativeTime(EXPIRY);
         FxRate               forward           = FX_PRICER.forwardFxRate(UNDERLYING[i], RATES_PROVIDER);
         double               forwardRate       = forward.fxRate(CURRENCY_PAIR);
         double               strikeRate        = call.Strike;
         SmileDeltaParameters smileAtTime       = VOLS.Smile.smileForExpiry(timeToExpiry);
         double[]             strikes           = smileAtTime.strike(forwardRate).toArray();
         double[]             vols              = smileAtTime.Volatility.toArray();
         double               df                = RATES_PROVIDER.discountFactor(USD, PAY);
         double[]             weights           = this.weights(forwardRate, strikeRate, strikes, timeToExpiry, vols[1]);
         double               expectedPriceCall = BlackFormulaRepository.price(forwardRate, strikeRate, timeToExpiry, vols[1], true);
         for (int j = 0; j < 3; ++j)
         {
             expectedPriceCall += weights[j] * (BlackFormulaRepository.price(forwardRate, strikes[j], timeToExpiry, vols[j], true) - BlackFormulaRepository.price(forwardRate, strikes[j], timeToExpiry, vols[1], true));
         }
         expectedPriceCall *= df;
         assertEquals(computedPriceCall, expectedPriceCall, TOL);
         assertEquals(computedCall.Amount, expectedPriceCall * NOTIONAL, TOL * NOTIONAL);
         // test against trade pricer
         assertEquals(computedCall, TRADE_PRICER.presentValue(callTrade, RATES_PROVIDER, VOLS).getAmount(USD));
     }
 }
        /// <summary>
        /// Calculates the price of the bond future option product
        /// based on the price of the underlying future.
        /// <para>
        /// The price of the option is the price on the valuation date.
        /// </para>
        /// <para>
        /// Strata uses <i>decimal prices</i> for bond futures. This is coherent with the pricing of <seealso cref="BondFuture"/>.
        /// For example, a price of 1.32% is represented in Strata by 0.0132.
        ///
        /// </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 of the product, in decimal form </returns>
        public double price(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             price        = BlackFormulaRepository.price(futurePrice, strike, timeToExpiry, volatility, futureOption.PutCall.Call);

            return(price);
        }
        //-------------------------------------------------------------------------
        public virtual void test_price_presentValue()
        {
            double         priceCallOtm         = PRICER.price(CALL_OTM, RATES_PROVIDER, VOLS);
            CurrencyAmount pvCallOtm            = PRICER.presentValue(CALL_OTM, RATES_PROVIDER, VOLS);
            double         pricePutOtm          = PRICER.price(PUT_OTM, RATES_PROVIDER, VOLS);
            CurrencyAmount pvPutOtm             = PRICER.presentValue(PUT_OTM, RATES_PROVIDER, VOLS);
            double         timeToExpiry         = VOLS.relativeTime(EXPIRY);
            double         df                   = RATES_PROVIDER.discountFactor(USD, PAYMENT_DATE);
            double         forward              = PRICER.DiscountingFxSingleProductPricer.forwardFxRate(FX_PRODUCT_HIGH, RATES_PROVIDER).fxRate(CURRENCY_PAIR);
            double         volHigh              = SMILE_TERM.volatility(timeToExpiry, STRIKE_RATE_HIGH, forward);
            double         volLow               = SMILE_TERM.volatility(timeToExpiry, STRIKE_RATE_LOW, forward);
            double         expectedPriceCallOtm = df * BlackFormulaRepository.price(forward, STRIKE_RATE_HIGH, timeToExpiry, volHigh, true);
            double         expectedPricePutOtm  = df * BlackFormulaRepository.price(forward, STRIKE_RATE_LOW, timeToExpiry, volLow, false);
            double         expectedPvCallOtm    = -NOTIONAL *df *BlackFormulaRepository.price(forward, STRIKE_RATE_HIGH, timeToExpiry, volHigh, true);

            double expectedPvPutOtm = -NOTIONAL *df *BlackFormulaRepository.price(forward, STRIKE_RATE_LOW, timeToExpiry, volLow, false);

            assertEquals(priceCallOtm, expectedPriceCallOtm, TOL);
            assertEquals(pvCallOtm.Currency, USD);
            assertEquals(pvCallOtm.Amount, expectedPvCallOtm, NOTIONAL * TOL);
            assertEquals(pricePutOtm, expectedPricePutOtm, TOL);
            assertEquals(pvPutOtm.Currency, USD);
            assertEquals(pvPutOtm.Amount, expectedPvPutOtm, NOTIONAL * TOL);
        }
        public virtual void flatVolPriceTest()
        {
            double          tol               = 2.0e-2;
            double          constantVol       = 0.15;
            double          spot              = 100d;
            double          maxTime           = 1d;
            int             nSteps            = 9;
            ConstantSurface impliedVolSurface = ConstantSurface.of("impliedVol", constantVol);

            System.Func <double, double> zeroRate = (double?x) =>
            {
                return(0d);
            };
            System.Func <DoublesPair, ValueDerivatives> func = (DoublesPair x) =>
            {
                double price = BlackFormulaRepository.price(spot, x.Second, x.First, constantVol, true);
                return(ValueDerivatives.of(price, DoubleArray.EMPTY));
            };
            DeformedSurface priceSurface = DeformedSurface.of(DefaultSurfaceMetadata.of("price"), impliedVolSurface, func);
            ImpliedTrinomialTreeLocalVolatilityCalculator calc = new ImpliedTrinomialTreeLocalVolatilityCalculator(nSteps, maxTime, INTERP_TIMESQ_LINEAR);
            InterpolatedNodalSurface localVolSurface           = calc.localVolatilityFromPrice(priceSurface, spot, zeroRate, zeroRate);

            assertEquals(localVolSurface.ZValues.Where(d => !DoubleMath.fuzzyEquals(d, constantVol, tol)).Count(), 0);
        }
        //-------------------------------------------------------------------------
        public virtual void test_presentValue_formula()
        {
            CurrencyAmount computedCaplet   = PRICER.presentValue(CAPLET_LONG, RATES, VOLS);
            CurrencyAmount computedFloorlet = PRICER.presentValue(FLOORLET_SHORT, RATES, VOLS);
            double         forward          = RATES.iborIndexRates(EUR_EURIBOR_3M).rate(RATE_COMP.Observation);
            double         expiry           = VOLS.relativeTime(CAPLET_LONG.FixingDateTime);
            double         volatility       = VOLS.volatility(expiry, STRIKE, forward);
            double         df               = RATES.discountFactor(EUR, CAPLET_LONG.PaymentDate);
            double         expectedCaplet   = NOTIONAL * df * CAPLET_LONG.YearFraction * BlackFormulaRepository.price(forward, STRIKE, expiry, volatility, true);
            double         expectedFloorlet = -NOTIONAL *df *FLOORLET_SHORT.YearFraction *BlackFormulaRepository.price(forward, STRIKE, expiry, volatility, false);

            assertEquals(computedCaplet.Currency, EUR);
            assertEquals(computedCaplet.Amount, expectedCaplet, NOTIONAL * TOL);
            assertEquals(computedFloorlet.Currency, EUR);
            assertEquals(computedFloorlet.Amount, expectedFloorlet, NOTIONAL * TOL);
        }
        //-------------------------------------------------------------------------
        public virtual void test_presentValue_formula()
        {
            CurrencyAmount computedCaplet   = PRICER.presentValue(CAPLET_LONG, RATES, VOLS);
            CurrencyAmount computedFloorlet = PRICER.presentValue(FLOORLET_SHORT, RATES, VOLS);
            double         forward          = RATES.iborIndexRates(EUR_EURIBOR_3M).rate(RATE_COMP.Observation);
            double         expiry           = VOLS.relativeTime(CAPLET_LONG.FixingDateTime);
            double         volatility       = VOLS.volatility(expiry, STRIKE, forward);
            double         df               = RATES.discountFactor(EUR, CAPLET_LONG.PaymentDate);
            double         expectedCaplet   = NOTIONAL * df * CAPLET_LONG.YearFraction * BlackFormulaRepository.price(forward + SHIFT, STRIKE + SHIFT, expiry, volatility, CALL.Call);
            double         expectedFloorlet = -NOTIONAL *df *FLOORLET_SHORT.YearFraction *BlackFormulaRepository.price(forward + SHIFT, STRIKE + SHIFT, expiry, volatility, PUT.Call);

            assertEquals(computedCaplet.Currency, EUR);
            assertEquals(computedCaplet.Amount, expectedCaplet, NOTIONAL * TOL);
            assertEquals(computedFloorlet.Currency, EUR);
            assertEquals(computedFloorlet.Amount, expectedFloorlet, NOTIONAL * TOL);
            // consistency with shifted Black
            ShiftedBlackIborCapletFloorletExpiryStrikeVolatilities vols = ShiftedBlackIborCapletFloorletExpiryStrikeVolatilities.of(EUR_EURIBOR_3M, VALUATION, ConstantSurface.of("constVol", volatility).withMetadata(Surfaces.blackVolatilityByExpiryStrike("costVol", DayCounts.ACT_ACT_ISDA)), IborCapletFloorletSabrRateVolatilityDataSet.CURVE_CONST_SHIFT);
            CurrencyAmount computedCapletBlack   = PRICER_BASE.presentValue(CAPLET_LONG, RATES, vols);
            CurrencyAmount computedFloorletBlack = PRICER_BASE.presentValue(FLOORLET_SHORT, RATES, vols);

            assertEquals(computedCaplet.Amount, computedCapletBlack.Amount, NOTIONAL * TOL);
            assertEquals(computedFloorlet.Amount, computedFloorletBlack.Amount, NOTIONAL * TOL);
        }