//-------------------------------------------------------------------------
        private ValueDerivatives priceDerivatives(ResolvedFxSingleBarrierOption option, RatesProvider ratesProvider, BlackFxOptionVolatilities volatilities, RecombiningTrinomialTreeData data)
        {
            validate(option, ratesProvider, volatilities);
            validateData(option, ratesProvider, volatilities, data);
            int nSteps = data.NumberOfSteps;
            ResolvedFxVanillaOption underlyingOption = option.UnderlyingOption;
            double           timeToExpiry            = data.getTime(nSteps);
            ResolvedFxSingle underlyingFx            = underlyingOption.Underlying;
            Currency         ccyBase                  = underlyingFx.CounterCurrencyPayment.Currency;
            Currency         ccyCounter               = underlyingFx.CounterCurrencyPayment.Currency;
            DiscountFactors  baseDiscountFactors      = ratesProvider.discountFactors(ccyBase);
            DiscountFactors  counterDiscountFactors   = ratesProvider.discountFactors(ccyCounter);
            double           rebateAtExpiry           = 0d; // used to price knock-in option
            double           rebateAtExpiryDerivative = 0d; // used to price knock-in option
            double           notional                 = Math.Abs(underlyingFx.BaseCurrencyPayment.Amount);

            double[] rebateArray = new double[nSteps + 1];
            SimpleConstantContinuousBarrier barrier = (SimpleConstantContinuousBarrier)option.Barrier;

            if (option.Rebate.Present)
            {
                CurrencyAmount rebateCurrencyAmount = option.Rebate.get();
                double         rebatePerUnit        = rebateCurrencyAmount.Amount / notional;
                bool           isCounter            = rebateCurrencyAmount.Currency.Equals(ccyCounter);
                double         rebate = isCounter ? rebatePerUnit : rebatePerUnit * barrier.BarrierLevel;
                if (barrier.KnockType.KnockIn)
                {   // use in-out parity
                    double dfCounterAtExpiry = counterDiscountFactors.discountFactor(timeToExpiry);
                    double dfBaseAtExpiry    = baseDiscountFactors.discountFactor(timeToExpiry);
                    for (int i = 0; i < nSteps + 1; ++i)
                    {
                        rebateArray[i] = isCounter ? rebate * dfCounterAtExpiry / counterDiscountFactors.discountFactor(data.getTime(i)) : rebate * dfBaseAtExpiry / baseDiscountFactors.discountFactor(data.getTime(i));
                    }
                    if (isCounter)
                    {
                        rebateAtExpiry = rebatePerUnit * dfCounterAtExpiry;
                    }
                    else
                    {
                        rebateAtExpiry           = rebatePerUnit * data.Spot * dfBaseAtExpiry;
                        rebateAtExpiryDerivative = rebatePerUnit * dfBaseAtExpiry;
                    }
                }
                else
                {
                    Arrays.fill(rebateArray, rebate);
                }
            }
            ConstantContinuousSingleBarrierKnockoutFunction barrierFunction = ConstantContinuousSingleBarrierKnockoutFunction.of(underlyingOption.Strike, timeToExpiry, underlyingOption.PutCall, nSteps, barrier.BarrierType, barrier.BarrierLevel, DoubleArray.ofUnsafe(rebateArray));
            ValueDerivatives barrierPrice = TREE.optionPriceAdjoint(barrierFunction, data);

            if (barrier.KnockType.KnockIn)
            {     // use in-out parity
                EuropeanVanillaOptionFunction vanillaFunction = EuropeanVanillaOptionFunction.of(underlyingOption.Strike, timeToExpiry, underlyingOption.PutCall, nSteps);
                ValueDerivatives vanillaPrice = TREE.optionPriceAdjoint(vanillaFunction, data);
                return(ValueDerivatives.of(vanillaPrice.Value + rebateAtExpiry - barrierPrice.Value, DoubleArray.of(vanillaPrice.getDerivative(0) + rebateAtExpiryDerivative - barrierPrice.getDerivative(0))));
            }
            return(barrierPrice);
        }
        //-------------------------------------------------------------------------
        /// <summary>
        /// Computes the present value curve sensitivity by simple forward rate estimation.
        /// </summary>
        /// <param name="cmsPeriod">  the CMS </param>
        /// <param name="provider">  the rates provider </param>
        /// <returns> the present value sensitivity </returns>
        public virtual PointSensitivityBuilder presentValueSensitivity(CmsPeriod cmsPeriod, RatesProvider provider)
        {
            Currency  ccy           = cmsPeriod.Currency;
            LocalDate valuationDate = provider.ValuationDate;

            if (valuationDate.isAfter(cmsPeriod.PaymentDate))
            {
                return(PointSensitivityBuilder.none());
            }
            LocalDate fixingDate = cmsPeriod.FixingDate;
            double    dfPayment  = provider.discountFactor(ccy, cmsPeriod.PaymentDate);

            if (!fixingDate.isAfter(valuationDate))
            {     // Using fixing
                double?fixedRate = provider.timeSeries(cmsPeriod.Index).get(fixingDate);
                if (fixedRate.HasValue)
                {
                    double payoff = 0d;
                    switch (cmsPeriod.CmsPeriodType)
                    {
                    case CAPLET:
                        payoff = Math.Max(fixedRate.Value - cmsPeriod.Strike, 0d);
                        break;

                    case FLOORLET:
                        payoff = Math.Max(cmsPeriod.Strike - fixedRate.Value, 0d);
                        break;

                    case COUPON:
                        payoff = fixedRate.Value;
                        break;

                    default:
                        throw new System.ArgumentException("unsupported CMS type");
                    }
                    return(provider.discountFactors(ccy).zeroRatePointSensitivity(cmsPeriod.PaymentDate).multipliedBy(payoff * cmsPeriod.Notional * cmsPeriod.YearFraction));
                }
                else if (fixingDate.isBefore(valuationDate))
                {
                    throw new System.ArgumentException(Messages.format("Unable to get fixing for {} on date {}, no time-series supplied", cmsPeriod.Index, fixingDate));
                }
            }
            if (!cmsPeriod.CmsPeriodType.Equals(CmsPeriodType.COUPON))
            {
                throw new System.ArgumentException("Unable to price cap or floor in this pricer");
            }
            // Using forward
            ResolvedSwap        swap        = cmsPeriod.UnderlyingSwap;
            ZeroRateSensitivity dfPaymentdr = provider.discountFactors(ccy).zeroRatePointSensitivity(cmsPeriod.PaymentDate);
            double forward = swapPricer.parRate(swap, provider);
            PointSensitivityBuilder forwardSensi = swapPricer.parRateSensitivity(swap, provider);

            return(forwardSensi.multipliedBy(dfPayment).combinedWith(dfPaymentdr.multipliedBy(forward)).multipliedBy(cmsPeriod.Notional * cmsPeriod.YearFraction));
        }
        //-------------------------------------------------------------------------
        /// <summary>
        /// Calculates the present value sensitivity of the swaption to the rate curves.
        /// <para>
        /// The present value sensitivity is computed in a "sticky strike" style, i.e. the sensitivity to the
        /// curve nodes with the volatility at the swaption strike unchanged. This sensitivity does not include a potential
        /// change of volatility due to the implicit change of forward rate or moneyness.
        ///
        /// </para>
        /// </summary>
        /// <param name="swaption">  the swaption </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 presentValueSensitivityRatesStickyStrike(ResolvedSwaption swaption, RatesProvider ratesProvider, SwaptionVolatilities swaptionVolatilities)
        {
            validate(swaption, ratesProvider, swaptionVolatilities);
            double          expiry     = swaptionVolatilities.relativeTime(swaption.Expiry);
            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           volatility        = swaptionVolatilities.volatility(expiry, tenor, strike, forward);
            PutCall          putCall           = PutCall.ofPut(fixedLeg.PayReceive.Receive);
            double           price             = swaptionVolatilities.price(expiry, tenor, putCall, strike, forward, volatility);
            double           delta             = swaptionVolatilities.priceDelta(expiry, tenor, putCall, strike, forward, volatility);
            // Backward sweep
            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 + annuityCashDr * price)).combinedWith(discountSettleSensi.multipliedBy(sign * annuityCash * price)));
        }
示例#4
0
        //-------------------------------------------------------------------------
        /// <summary>
        /// Calculates the present value sensitivity of the Ibor caplet/floorlet 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="period">  the Ibor caplet/floorlet period </param>
        /// <param name="ratesProvider">  the rates provider </param>
        /// <param name="volatilities">  the volatilities </param>
        /// <returns> the point sensitivity to the rate curves </returns>
        public virtual PointSensitivityBuilder presentValueSensitivityRatesStickyModel(IborCapletFloorletPeriod period, RatesProvider ratesProvider, SabrIborCapletFloorletVolatilities volatilities)
        {
            Currency currency = period.Currency;

            if (ratesProvider.ValuationDate.isAfter(period.PaymentDate))
            {
                return(PointSensitivityBuilder.none());
            }
            double  expiry    = volatilities.relativeTime(period.FixingDateTime);
            PutCall putCall   = period.PutCall;
            double  strike    = period.Strike;
            double  indexRate = ratesProvider.iborIndexRates(period.Index).rate(period.IborRate.Observation);
            PointSensitivityBuilder dfSensi = ratesProvider.discountFactors(currency).zeroRatePointSensitivity(period.PaymentDate);
            double factor = period.Notional * period.YearFraction;

            if (expiry < 0d)
            {     // option expired already, but not yet paid
                double sign   = putCall.Call ? 1d : -1d;
                double payoff = Math.Max(sign * (indexRate - strike), 0d);
                return(dfSensi.multipliedBy(payoff * factor));
            }
            ValueDerivatives        volatilityAdj       = volatilities.volatilityAdjoint(expiry, strike, indexRate);
            PointSensitivityBuilder indexRateSensiSensi = ratesProvider.iborIndexRates(period.Index).ratePointSensitivity(period.IborRate.Observation);
            double df       = ratesProvider.discountFactor(currency, period.PaymentDate);
            double fwdPv    = factor * volatilities.price(expiry, putCall, strike, indexRate, volatilityAdj.Value);
            double fwdDelta = factor * volatilities.priceDelta(expiry, putCall, strike, indexRate, volatilityAdj.Value);
            double fwdVega  = factor * volatilities.priceVega(expiry, putCall, strike, indexRate, volatilityAdj.Value);

            return(dfSensi.multipliedBy(fwdPv).combinedWith(indexRateSensiSensi.multipliedBy(fwdDelta * df + fwdVega * volatilityAdj.getDerivative(0) * df)));
        }
        //-------------------------------------------------------------------------
        public virtual void calibration_test()
        {
            RatesProvider result2 = CALIBRATOR.calibrate(CURVE_GROUP_DEFN, ALL_QUOTES, REF_DATA);

            // pv test
            CurveNode[]           fwd3Nodes  = CURVES_NODES[0][0];
            IList <ResolvedTrade> fwd3Trades = new List <ResolvedTrade>();

            for (int i = 0; i < fwd3Nodes.Length; i++)
            {
                fwd3Trades.Add(fwd3Nodes[i].resolvedTrade(1d, ALL_QUOTES, REF_DATA));
            }
            for (int i = 0; i < FWD6_NB_NODES; i++)
            {
                MultiCurrencyAmount pvIrs2 = SWAP_PRICER.presentValue(((ResolvedSwapTrade)fwd3Trades[i]).Product, result2);
                assertEquals(pvIrs2.getAmount(GBP).Amount, 0.0, TOLERANCE_PV);
            }
            // regression test for curve
            DiscountFactors dsc     = result2.discountFactors(GBP);
            double          prevDsc = 0d;

            for (int i = 0; i < 121; ++i)
            {
                double time   = ((double)i);
                double curDsc = dsc.discountFactor(time);
                if (i > 59)
                {
                    double fwd = prevDsc / curDsc - 1d;
                    assertEquals(fwd, 0.042, 2d * ONE_BP);
                }
                assertEquals(curDsc, DSC_EXP.get(i), ONE_PC);
                prevDsc = curDsc;
            }
        }
示例#6
0
        /// <summary>
        /// Calculates the par spread curve sensitivity for a swap.
        /// <para>
        /// The par spread is the common spread on all payments of the first leg for which the total swap present value is 0.
        /// </para>
        /// <para>
        /// The par spread is computed with respect to the first leg. For that leg, all the payments have a unique
        /// accrual period (no compounding) and no FX reset.
        ///
        /// </para>
        /// </summary>
        /// <param name="swap">  the product </param>
        /// <param name="provider">  the rates provider </param>
        /// <returns> the par spread curve sensitivity of the swap product </returns>
        public virtual PointSensitivityBuilder parSpreadSensitivity(ResolvedSwap swap, RatesProvider provider)
        {
            ResolvedSwapLeg         referenceLeg    = swap.Legs.get(0);
            Currency                ccyReferenceLeg = referenceLeg.Currency;
            double                  convertedPv     = presentValue(swap, ccyReferenceLeg, provider).Amount;
            PointSensitivityBuilder convertedPvDr   = presentValueSensitivity(swap, ccyReferenceLeg, provider);
            // try one payment compounding, typically for inflation swaps
            Triple <bool, int, double> fixedCompounded = checkFixedCompounded(referenceLeg);

            if (fixedCompounded.First)
            {
                double df = provider.discountFactor(ccyReferenceLeg, referenceLeg.PaymentPeriods.get(0).PaymentDate);
                PointSensitivityBuilder dfDr = provider.discountFactors(ccyReferenceLeg).zeroRatePointSensitivity(referenceLeg.PaymentPeriods.get(0).PaymentDate);
                double referenceConvertedPv  = legPricer.presentValue(referenceLeg, provider).Amount;
                PointSensitivityBuilder referenceConvertedPvDr = legPricer.presentValueSensitivity(referenceLeg, provider);
                double notional = ((RatePaymentPeriod)referenceLeg.PaymentPeriods.get(0)).Notional;
                PointSensitivityBuilder dParSpreadDr = convertedPvDr.combinedWith(referenceConvertedPvDr.multipliedBy(-1)).multipliedBy(-1.0d / (df * notional)).combinedWith(dfDr.multipliedBy((convertedPv - referenceConvertedPv) / (df * df * notional))).multipliedBy(1.0d / fixedCompounded.Second * Math.Pow(-(convertedPv - referenceConvertedPv) / (df * notional) + 1.0d, 1.0d / fixedCompounded.Second - 1.0d));
                return(dParSpreadDr);
            }
            double pvbp = legPricer.pvbp(referenceLeg, provider);
            // Backward sweep
            double convertedPvBar          = -1d / pvbp;
            double pvbpBar                 = convertedPv / (pvbp * pvbp);
            PointSensitivityBuilder pvbpDr = legPricer.pvbpSensitivity(referenceLeg, provider);

            return(convertedPvDr.multipliedBy(convertedPvBar).combinedWith(pvbpDr.multipliedBy(pvbpBar)));
        }
示例#7
0
        //-------------------------------------------------------------------------
        /// <summary>
        /// Calculates the present value rates sensitivity of the Ibor caplet/floorlet.
        /// <para>
        /// The present value rates sensitivity of the caplet/floorlet is the sensitivity
        /// of the present value to the underlying curves.
        ///
        /// </para>
        /// </summary>
        /// <param name="period">  the Ibor caplet/floorlet period </param>
        /// <param name="ratesProvider">  the rates provider </param>
        /// <param name="volatilities">  the volatilities </param>
        /// <returns> the present value curve sensitivity </returns>
        public virtual PointSensitivityBuilder presentValueSensitivityRates(IborCapletFloorletPeriod period, RatesProvider ratesProvider, IborCapletFloorletVolatilities volatilities)
        {
            validate(volatilities);
            Currency currency = period.Currency;

            if (ratesProvider.ValuationDate.isAfter(period.PaymentDate))
            {
                return(PointSensitivityBuilder.none());
            }
            double  expiry    = volatilities.relativeTime(period.FixingDateTime);
            PutCall putCall   = period.PutCall;
            double  strike    = period.Strike;
            double  indexRate = ratesProvider.iborIndexRates(period.Index).rate(period.IborRate.Observation);
            PointSensitivityBuilder dfSensi = ratesProvider.discountFactors(currency).zeroRatePointSensitivity(period.PaymentDate);

            if (expiry < 0d)
            {     // Option has expired already
                double sign   = putCall.Call ? 1d : -1d;
                double payoff = Math.Max(sign * (indexRate - strike), 0d);
                return(dfSensi.multipliedBy(payoff * period.YearFraction * period.Notional));
            }
            PointSensitivityBuilder indexRateSensiSensi = ratesProvider.iborIndexRates(period.Index).ratePointSensitivity(period.IborRate.Observation);
            double volatility = volatilities.volatility(expiry, strike, indexRate);
            double df         = ratesProvider.discountFactor(currency, period.PaymentDate);
            double factor     = period.Notional * period.YearFraction;
            double fwdPv      = factor * volatilities.price(expiry, putCall, strike, indexRate, volatility);
            double fwdDelta   = factor * volatilities.priceDelta(expiry, putCall, strike, indexRate, volatility);

            return(dfSensi.multipliedBy(fwdPv).combinedWith(indexRateSensiSensi.multipliedBy(fwdDelta * df)));
        }
        //-------------------------------------------------------------------------
        //  The derivatives are [0] spot, [1] strike, [2] rate, [3] cost-of-carry, [4] volatility, [5] timeToExpiry, [6] spot twice
        private ValueDerivatives priceDerivatives(ResolvedFxSingleBarrierOption option, RatesProvider ratesProvider, BlackFxOptionVolatilities volatilities)
        {
            validate(option, ratesProvider, volatilities);
            SimpleConstantContinuousBarrier barrier          = (SimpleConstantContinuousBarrier)option.Barrier;
            ResolvedFxVanillaOption         underlyingOption = option.UnderlyingOption;

            double[] derivatives = new double[7];
            if (volatilities.relativeTime(underlyingOption.Expiry) < 0d)
            {
                return(ValueDerivatives.of(0d, DoubleArray.ofUnsafe(derivatives)));
            }
            ResolvedFxSingle underlyingFx           = underlyingOption.Underlying;
            CurrencyPair     currencyPair           = underlyingFx.CurrencyPair;
            Currency         ccyBase                = currencyPair.Base;
            Currency         ccyCounter             = currencyPair.Counter;
            DiscountFactors  baseDiscountFactors    = ratesProvider.discountFactors(ccyBase);
            DiscountFactors  counterDiscountFactors = ratesProvider.discountFactors(ccyCounter);

            double           rateBase         = baseDiscountFactors.zeroRate(underlyingFx.PaymentDate);
            double           rateCounter      = counterDiscountFactors.zeroRate(underlyingFx.PaymentDate);
            double           costOfCarry      = rateCounter - rateBase;
            double           dfBase           = baseDiscountFactors.discountFactor(underlyingFx.PaymentDate);
            double           dfCounter        = counterDiscountFactors.discountFactor(underlyingFx.PaymentDate);
            double           todayFx          = ratesProvider.fxRate(currencyPair);
            double           strike           = underlyingOption.Strike;
            double           forward          = todayFx * dfBase / dfCounter;
            double           volatility       = volatilities.volatility(currencyPair, underlyingOption.Expiry, strike, forward);
            double           timeToExpiry     = volatilities.relativeTime(underlyingOption.Expiry);
            ValueDerivatives valueDerivatives = BARRIER_PRICER.priceAdjoint(todayFx, strike, timeToExpiry, costOfCarry, rateCounter, volatility, underlyingOption.PutCall.Call, barrier);

            if (!option.Rebate.Present)
            {
                return(valueDerivatives);
            }
            CurrencyAmount   rebate = option.Rebate.get();
            ValueDerivatives valueDerivativesRebate = rebate.Currency.Equals(ccyCounter) ? CASH_REBATE_PRICER.priceAdjoint(todayFx, timeToExpiry, costOfCarry, rateCounter, volatility, barrier.inverseKnockType()) : ASSET_REBATE_PRICER.priceAdjoint(todayFx, timeToExpiry, costOfCarry, rateCounter, volatility, barrier.inverseKnockType());
            double           rebateRate             = rebate.Amount / Math.Abs(underlyingFx.BaseCurrencyPayment.Amount);
            double           price = valueDerivatives.Value + rebateRate * valueDerivativesRebate.Value;

            derivatives[0] = valueDerivatives.getDerivative(0) + rebateRate * valueDerivativesRebate.getDerivative(0);
            derivatives[1] = valueDerivatives.getDerivative(1);
            for (int i = 2; i < 7; ++i)
            {
                derivatives[i] = valueDerivatives.getDerivative(i) + rebateRate * valueDerivativesRebate.getDerivative(i - 1);
            }
            return(ValueDerivatives.of(price, DoubleArray.ofUnsafe(derivatives)));
        }
        public virtual void test_ratesProvider()
        {
            ImmutableMap <Currency, CurveId> discounts = ImmutableMap.of(USD, CURVE_ID_DSC);
            ImmutableMap <Index, CurveId>    forwards  = ImmutableMap.of(USD_FED_FUND, CURVE_ID_DSC, USD_LIBOR_3M, CURVE_ID_FWD, US_CPI_U, CURVE_ID_FWD);
            RatesMarketDataLookup            test      = RatesMarketDataLookup.of(discounts, forwards);
            LocalDate     valDate       = date(2015, 6, 30);
            Curve         dscCurve      = ConstantCurve.of(Curves.discountFactors(CURVE_ID_DSC.CurveName, ACT_360), 1d);
            Curve         fwdCurve      = ConstantCurve.of(Curves.discountFactors(CURVE_ID_FWD.CurveName, ACT_360), 2d);
            MarketData    md            = ImmutableMarketData.of(valDate, ImmutableMap.of(CURVE_ID_DSC, dscCurve, CURVE_ID_FWD, fwdCurve));
            RatesProvider ratesProvider = test.ratesProvider(md);

            assertEquals(ratesProvider.ValuationDate, valDate);
            assertEquals(ratesProvider.findData(CURVE_ID_DSC.CurveName), dscCurve);
            assertEquals(ratesProvider.findData(CURVE_ID_FWD.CurveName), fwdCurve);
            assertEquals(ratesProvider.findData(CurveName.of("Rubbish")), null);
            assertEquals(ratesProvider.IborIndices, ImmutableSet.of(USD_LIBOR_3M));
            assertEquals(ratesProvider.OvernightIndices, ImmutableSet.of(USD_FED_FUND));
            assertEquals(ratesProvider.PriceIndices, ImmutableSet.of(US_CPI_U));
            assertEquals(ratesProvider.TimeSeriesIndices, ImmutableSet.of());
            // check discount factors
            SimpleDiscountFactors df = (SimpleDiscountFactors)ratesProvider.discountFactors(USD);

            assertEquals(df.Curve.Name, dscCurve.Name);
            assertThrowsIllegalArg(() => ratesProvider.discountFactors(GBP));
            // check Ibor
            DiscountIborIndexRates ibor   = (DiscountIborIndexRates)ratesProvider.iborIndexRates(USD_LIBOR_3M);
            SimpleDiscountFactors  iborDf = (SimpleDiscountFactors)ibor.DiscountFactors;

            assertEquals(iborDf.Curve.Name, fwdCurve.Name);
            assertThrowsIllegalArg(() => ratesProvider.iborIndexRates(GBP_LIBOR_3M));
            // check Overnight
            DiscountOvernightIndexRates on   = (DiscountOvernightIndexRates)ratesProvider.overnightIndexRates(USD_FED_FUND);
            SimpleDiscountFactors       onDf = (SimpleDiscountFactors)on.DiscountFactors;

            assertEquals(onDf.Curve.Name, dscCurve.Name);
            assertThrowsIllegalArg(() => ratesProvider.overnightIndexRates(GBP_SONIA));
            // check price curve must be interpolated
            assertThrowsIllegalArg(() => ratesProvider.priceIndexValues(US_CPI_U));
            // to immutable
            ImmutableRatesProvider expectedImmutable = ImmutableRatesProvider.builder(valDate).fxRateProvider(MarketDataFxRateProvider.of(md)).discountCurve(USD, dscCurve).indexCurve(USD_FED_FUND, dscCurve).indexCurve(USD_LIBOR_3M, fwdCurve).indexCurve(US_CPI_U, fwdCurve).build();

            assertEquals(ratesProvider.toImmutableRatesProvider(), expectedImmutable);
        }
        //-------------------------------------------------------------------------
        /// <summary>
        /// Calculates the present value sensitivity of the FX barrier option product.
        /// <para>
        /// The present value sensitivity of the product is the sensitivity of <seealso cref="#presentValue"/> to
        /// the underlying curves.
        /// </para>
        /// <para>
        /// The volatility is fixed in this sensitivity computation, i.e., sticky-strike.
        ///
        /// </para>
        /// </summary>
        /// <param name="option">  the option product </param>
        /// <param name="ratesProvider">  the rates provider </param>
        /// <param name="volatilities">  the Black volatility provider </param>
        /// <returns> the present value curve sensitivity of the product </returns>
        public virtual PointSensitivityBuilder presentValueSensitivityRatesStickyStrike(ResolvedFxSingleBarrierOption option, RatesProvider ratesProvider, BlackFxOptionVolatilities volatilities)
        {
            ResolvedFxVanillaOption underlyingOption = option.UnderlyingOption;

            if (volatilities.relativeTime(underlyingOption.Expiry) <= 0d)
            {
                return(PointSensitivityBuilder.none());
            }
            ValueDerivatives    priceDerivatives    = this.priceDerivatives(option, ratesProvider, volatilities);
            ResolvedFxSingle    underlyingFx        = underlyingOption.Underlying;
            CurrencyPair        currencyPair        = underlyingFx.CurrencyPair;
            double              signedNotional      = this.signedNotional(underlyingOption);
            double              counterYearFraction = ratesProvider.discountFactors(currencyPair.Counter).relativeYearFraction(underlyingFx.PaymentDate);
            ZeroRateSensitivity counterSensi        = ZeroRateSensitivity.of(currencyPair.Counter, counterYearFraction, signedNotional * (priceDerivatives.getDerivative(2) + priceDerivatives.getDerivative(3)));
            double              baseYearFraction    = ratesProvider.discountFactors(currencyPair.Base).relativeYearFraction(underlyingFx.PaymentDate);
            ZeroRateSensitivity baseSensi           = ZeroRateSensitivity.of(currencyPair.Base, baseYearFraction, currencyPair.Counter, -priceDerivatives.getDerivative(3) * signedNotional);

            return(counterSensi.combinedWith(baseSensi));
        }
        /// <summary>
        /// Calculates the price of the FX barrier option product.
        /// <para>
        /// 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 <seealso cref="#presentValue"/> for scaling and currency.
        /// </para>
        /// <para>
        /// The volatility used in this computation is the Black implied volatility at expiry time and strike.
        ///
        /// </para>
        /// </summary>
        /// <param name="option">  the option product </param>
        /// <param name="ratesProvider">  the rates provider </param>
        /// <param name="volatilities">  the Black volatility provider </param>
        /// <returns> the price of the product </returns>
        public virtual double price(ResolvedFxSingleBarrierOption option, RatesProvider ratesProvider, BlackFxOptionVolatilities volatilities)
        {
            validate(option, ratesProvider, volatilities);
            SimpleConstantContinuousBarrier barrier          = (SimpleConstantContinuousBarrier)option.Barrier;
            ResolvedFxVanillaOption         underlyingOption = option.UnderlyingOption;

            if (volatilities.relativeTime(underlyingOption.Expiry) < 0d)
            {
                return(0d);
            }
            ResolvedFxSingle underlyingFx           = underlyingOption.Underlying;
            Currency         ccyBase                = underlyingFx.BaseCurrencyPayment.Currency;
            Currency         ccyCounter             = underlyingFx.CounterCurrencyPayment.Currency;
            CurrencyPair     currencyPair           = underlyingFx.CurrencyPair;
            DiscountFactors  baseDiscountFactors    = ratesProvider.discountFactors(ccyBase);
            DiscountFactors  counterDiscountFactors = ratesProvider.discountFactors(ccyCounter);

            double rateBase     = baseDiscountFactors.zeroRate(underlyingFx.PaymentDate);
            double rateCounter  = counterDiscountFactors.zeroRate(underlyingFx.PaymentDate);
            double costOfCarry  = rateCounter - rateBase;
            double dfBase       = baseDiscountFactors.discountFactor(underlyingFx.PaymentDate);
            double dfCounter    = counterDiscountFactors.discountFactor(underlyingFx.PaymentDate);
            double todayFx      = ratesProvider.fxRate(currencyPair);
            double strike       = underlyingOption.Strike;
            double forward      = todayFx * dfBase / dfCounter;
            double volatility   = volatilities.volatility(currencyPair, underlyingOption.Expiry, strike, forward);
            double timeToExpiry = volatilities.relativeTime(underlyingOption.Expiry);
            double price        = BARRIER_PRICER.price(todayFx, strike, timeToExpiry, costOfCarry, rateCounter, volatility, underlyingOption.PutCall.Call, barrier);

            if (option.Rebate.Present)
            {
                CurrencyAmount rebate      = option.Rebate.get();
                double         priceRebate = rebate.Currency.Equals(ccyCounter) ? CASH_REBATE_PRICER.price(todayFx, timeToExpiry, costOfCarry, rateCounter, volatility, barrier.inverseKnockType()) : ASSET_REBATE_PRICER.price(todayFx, timeToExpiry, costOfCarry, rateCounter, volatility, barrier.inverseKnockType());
                price += priceRebate * rebate.Amount / Math.Abs(underlyingFx.BaseCurrencyPayment.Amount);
            }
            return(price);
        }
示例#12
0
        /// <summary>
        /// Computes cash flow equivalent and sensitivity of Ibor leg.
        /// <para>
        /// The return type is a map of {@code NotionalExchange} and {@code PointSensitivityBuilder}.
        ///
        /// </para>
        /// </summary>
        /// <param name="iborLeg">  the Ibor leg </param>
        /// <param name="ratesProvider">  the rates provider </param>
        /// <returns> the cash flow equivalent and sensitivity </returns>
        public static ImmutableMap <Payment, PointSensitivityBuilder> cashFlowEquivalentAndSensitivityIborLeg(ResolvedSwapLeg iborLeg, RatesProvider ratesProvider)
        {
            ArgChecker.isTrue(iborLeg.Type.Equals(SwapLegType.IBOR), "Leg type should be IBOR");
            ArgChecker.isTrue(iborLeg.PaymentEvents.Empty, "PaymentEvent should be empty");
            IDictionary <Payment, PointSensitivityBuilder> res = new Dictionary <Payment, PointSensitivityBuilder>();

            foreach (SwapPaymentPeriod paymentPeriod in iborLeg.PaymentPeriods)
            {
                ArgChecker.isTrue(paymentPeriod is RatePaymentPeriod, "rate payment should be RatePaymentPeriod");
                RatePaymentPeriod ratePaymentPeriod = (RatePaymentPeriod)paymentPeriod;
                ArgChecker.isTrue(ratePaymentPeriod.AccrualPeriods.size() == 1, "rate payment should not be compounding");
                RateAccrualPeriod    rateAccrualPeriod = ratePaymentPeriod.AccrualPeriods.get(0);
                CurrencyAmount       notional          = ratePaymentPeriod.NotionalAmount;
                LocalDate            paymentDate       = ratePaymentPeriod.PaymentDate;
                IborIndexObservation obs             = ((IborRateComputation)rateAccrualPeriod.RateComputation).Observation;
                IborIndex            index           = obs.Index;
                LocalDate            fixingStartDate = obs.EffectiveDate;
                double fixingYearFraction            = obs.YearFraction;

                double  factorIndex = (1d + fixingYearFraction * ratesProvider.iborIndexRates(index).rate(obs));
                double  dfPayment   = ratesProvider.discountFactor(paymentPeriod.Currency, paymentPeriod.PaymentDate);
                double  dfStart     = ratesProvider.discountFactor(paymentPeriod.Currency, fixingStartDate);
                double  beta        = factorIndex * dfPayment / dfStart;
                double  ycRatio     = rateAccrualPeriod.YearFraction / fixingYearFraction;
                Payment payStart    = Payment.of(notional.multipliedBy(beta * ycRatio), fixingStartDate);
                Payment payEnd      = Payment.of(notional.multipliedBy(-ycRatio), paymentDate);
                double  factor      = ycRatio * notional.Amount / dfStart;

                PointSensitivityBuilder factorIndexSensi     = ratesProvider.iborIndexRates(index).ratePointSensitivity(obs).multipliedBy(fixingYearFraction * dfPayment * factor);
                PointSensitivityBuilder dfPaymentSensitivity = ratesProvider.discountFactors(paymentPeriod.Currency).zeroRatePointSensitivity(paymentPeriod.PaymentDate).multipliedBy(factorIndex * factor);
                PointSensitivityBuilder dfStartSensitivity   = ratesProvider.discountFactors(paymentPeriod.Currency).zeroRatePointSensitivity(fixingStartDate).multipliedBy(-factorIndex * dfPayment * factor / dfStart);
                res[payStart] = factorIndexSensi.combinedWith(dfPaymentSensitivity).combinedWith(dfStartSensitivity);
                res[payEnd]   = PointSensitivityBuilder.none();
            }
            return(ImmutableMap.copyOf(res));
        }
        /// <summary>
        /// Calculates the present value sensitivity of the foreign exchange vanilla option product.
        /// <para>
        /// The present value sensitivity of the product is the sensitivity of <seealso cref="#presentValue"/> to
        /// the underlying curves.
        /// </para>
        /// <para>
        /// The volatility is fixed in this sensitivity computation.
        ///
        /// </para>
        /// </summary>
        /// <param name="option">  the option product </param>
        /// <param name="ratesProvider">  the rates provider </param>
        /// <param name="volatilities">  the Black volatility provider </param>
        /// <returns> the present value curve sensitivity of the product </returns>
        public virtual PointSensitivities presentValueSensitivityRatesStickyStrike(ResolvedFxVanillaOption option, RatesProvider ratesProvider, BlackFxOptionVolatilities volatilities)
        {
            if (volatilities.relativeTime(option.Expiry) < 0d)
            {
                return(PointSensitivities.empty());
            }
            ResolvedFxSingle        underlying     = option.Underlying;
            double                  fwdDelta       = undiscountedDelta(option, ratesProvider, volatilities);
            double                  discountFactor = ratesProvider.discountFactor(option.CounterCurrency, underlying.PaymentDate);
            double                  notional       = signedNotional(option);
            PointSensitivityBuilder fwdSensi       = fxPricer.forwardFxRatePointSensitivity(option.PutCall.Call ? underlying : underlying.inverse(), ratesProvider).multipliedBy(notional * discountFactor * fwdDelta);
            double                  fwdPrice       = undiscountedPrice(option, ratesProvider, volatilities);
            PointSensitivityBuilder dscSensi       = ratesProvider.discountFactors(option.CounterCurrency).zeroRatePointSensitivity(underlying.PaymentDate).multipliedBy(notional * fwdPrice);

            return(fwdSensi.combinedWith(dscSensi).build().convertedTo(option.CounterCurrency, ratesProvider));
        }
示例#14
0
        //-------------------------------------------------------------------------
        /// <summary>
        /// Calculates the present value sensitivity of the foreign exchange vanilla option product.
        /// <para>
        /// The present value sensitivity of the product is the sensitivity of <seealso cref="#presentValue"/> to
        /// the underlying curves.
        /// </para>
        /// <para>
        /// The implied strikes and weights are fixed in this sensitivity computation.
        ///
        /// </para>
        /// </summary>
        /// <param name="option">  the option product </param>
        /// <param name="ratesProvider">  the rates provider </param>
        /// <param name="volatilities">  the Black volatility provider </param>
        /// <returns> the present value curve sensitivity of the product </returns>
        public virtual PointSensitivityBuilder presentValueSensitivityRatesStickyStrike(ResolvedFxVanillaOption option, RatesProvider ratesProvider, BlackFxOptionSmileVolatilities volatilities)
        {
            validate(ratesProvider, volatilities);
            double timeToExpiry = volatilities.relativeTime(option.Expiry);

            if (timeToExpiry <= 0d)
            {
                return(PointSensitivityBuilder.none());
            }
            ResolvedFxSingle     underlyingFx = option.Underlying;
            Currency             ccyCounter   = option.CounterCurrency;
            double               df           = ratesProvider.discountFactor(ccyCounter, underlyingFx.PaymentDate);
            FxRate               forward      = fxPricer.forwardFxRate(underlyingFx, ratesProvider);
            CurrencyPair         currencyPair = underlyingFx.CurrencyPair;
            double               forwardRate  = forward.fxRate(currencyPair);
            double               strikeRate   = option.Strike;
            bool                 isCall       = option.PutCall.Call;
            SmileDeltaParameters smileAtTime  = volatilities.Smile.smileForExpiry(timeToExpiry);

            double[] strikes = smileAtTime.strike(forwardRate).toArray();
            double[] vols    = smileAtTime.Volatility.toArray();
            double   volAtm  = vols[1];

            double[] x        = vannaVolgaWeights(forwardRate, strikeRate, timeToExpiry, volAtm, strikes);
            double   priceFwd = BlackFormulaRepository.price(forwardRate, strikeRate, timeToExpiry, volAtm, isCall);
            double   deltaFwd = BlackFormulaRepository.delta(forwardRate, strikeRate, timeToExpiry, volAtm, isCall);

            for (int i = 0; i < 3; i += 2)
            {
                double priceFwdAtm   = BlackFormulaRepository.price(forwardRate, strikes[i], timeToExpiry, volAtm, isCall);
                double priceFwdSmile = BlackFormulaRepository.price(forwardRate, strikes[i], timeToExpiry, vols[i], isCall);
                priceFwd += x[i] * (priceFwdSmile - priceFwdAtm);
                double deltaFwdAtm   = BlackFormulaRepository.delta(forwardRate, strikes[i], timeToExpiry, volAtm, isCall);
                double deltaFwdSmile = BlackFormulaRepository.delta(forwardRate, strikes[i], timeToExpiry, vols[i], isCall);
                deltaFwd += x[i] * (deltaFwdSmile - deltaFwdAtm);
            }
            double signedNotional            = this.signedNotional(option);
            PointSensitivityBuilder dfSensi  = ratesProvider.discountFactors(ccyCounter).zeroRatePointSensitivity(underlyingFx.PaymentDate).multipliedBy(priceFwd * signedNotional);
            PointSensitivityBuilder fwdSensi = fxPricer.forwardFxRatePointSensitivity(option.PutCall.Call ? underlyingFx : underlyingFx.inverse(), ratesProvider).multipliedBy(df * deltaFwd * signedNotional);

            return(dfSensi.combinedWith(fwdSensi));
        }
示例#15
0
        //-------------------------------------------------------------------------
        /// <summary>
        /// Computes the present value curve sensitivity by replication in SABR framework with extrapolation on the right.
        /// </summary>
        /// <param name="cmsPeriod">  the CMS </param>
        /// <param name="provider">  the rates provider </param>
        /// <param name="swaptionVolatilities">  the swaption volatilities </param>
        /// <returns> the present value sensitivity </returns>
        public PointSensitivityBuilder presentValueSensitivityRates(CmsPeriod cmsPeriod, RatesProvider provider, SabrSwaptionVolatilities swaptionVolatilities)
        {
            Currency ccy = cmsPeriod.Currency;

            if (provider.ValuationDate.isAfter(cmsPeriod.PaymentDate))
            {
                return(PointSensitivityBuilder.none());
            }
            SwapIndex     index         = cmsPeriod.Index;
            ResolvedSwap  swap          = cmsPeriod.UnderlyingSwap;
            double        dfPayment     = provider.discountFactor(ccy, cmsPeriod.PaymentDate);
            ZonedDateTime valuationDate = swaptionVolatilities.ValuationDateTime;
            LocalDate     fixingDate    = cmsPeriod.FixingDate;
            double        expiryTime    = swaptionVolatilities.relativeTime(fixingDate.atTime(index.FixingTime).atZone(index.FixingZone));
            double        tenor         = swaptionVolatilities.tenor(swap.StartDate, swap.EndDate);
            double        shift         = swaptionVolatilities.shift(expiryTime, tenor);
            double        strikeCpn     = cmsPeriod.CmsPeriodType.Equals(CmsPeriodType.COUPON) ? -shift : cmsPeriod.Strike;

            if (!fixingDate.isAfter(valuationDate.toLocalDate()))
            {
                double?fixedRate = provider.timeSeries(cmsPeriod.Index).get(fixingDate);
                if (fixedRate.HasValue)
                {
                    double payoff = payOff(cmsPeriod.CmsPeriodType, strikeCpn, fixedRate.Value);
                    return(provider.discountFactors(ccy).zeroRatePointSensitivity(cmsPeriod.PaymentDate).multipliedBy(payoff * cmsPeriod.Notional * cmsPeriod.YearFraction));
                }
                else if (fixingDate.isBefore(valuationDate.toLocalDate()))
                {
                    throw new System.ArgumentException(Messages.format("Unable to get fixing for {} on date {}, no time-series supplied", cmsPeriod.Index, fixingDate));
                }
            }
            double forward = swapPricer.parRate(swap, provider);
            double eta     = index.Template.Convention.FixedLeg.DayCount.relativeYearFraction(cmsPeriod.PaymentDate, swap.StartDate);
            CmsDeltaIntegrantProvider intProv    = new CmsDeltaIntegrantProvider(this, cmsPeriod, swap, swaptionVolatilities, forward, strikeCpn, expiryTime, tenor, cutOffStrike, eta);
            RungeKuttaIntegrator1D    integrator = new RungeKuttaIntegrator1D(ABS_TOL, REL_TOL, NUM_ITER);

            double[] bs = intProv.bsbsp(strikeCpn);
            double[] n  = intProv.Nnp;
            double   strikePartPrice   = intProv.k(strikeCpn) * n[0] * bs[0];
            double   integralPartPrice = 0d;
            double   integralPart      = 0d;

            System.Func <double, double> integrant      = intProv.integrant();
            System.Func <double, double> integrantDelta = intProv.integrantDelta();
            try
            {
                if (intProv.PutCall.Call)
                {
                    integralPartPrice = integrateCall(integrator, integrant, swaptionVolatilities, forward, strikeCpn, expiryTime, tenor);
                    integralPart      = dfPayment * integrateCall(integrator, integrantDelta, swaptionVolatilities, forward, strikeCpn, expiryTime, tenor);
                }
                else
                {
                    integralPartPrice = -integrator.integrate(integrant, -shift + ZERO_SHIFT, strikeCpn).Value;
                    integralPart      = -dfPayment *integrator.integrate(integrantDelta, -shift, strikeCpn);
                }
            }
            catch (Exception e)
            {
                throw new MathException(e);
            }
            double deltaPD = strikePartPrice + integralPartPrice;

            if (cmsPeriod.CmsPeriodType.Equals(CmsPeriodType.COUPON))
            {
                deltaPD -= shift;
            }
            deltaPD *= cmsPeriod.Notional * cmsPeriod.YearFraction;
            double strikePart = dfPayment * intProv.k(strikeCpn) * (n[1] * bs[0] + n[0] * bs[1]);
            double deltaFwd   = (strikePart + integralPart) * cmsPeriod.Notional * cmsPeriod.YearFraction;
            PointSensitivityBuilder sensiFwd = swapPricer.parRateSensitivity(swap, provider).multipliedBy(deltaFwd);
            PointSensitivityBuilder sensiDf  = provider.discountFactors(ccy).zeroRatePointSensitivity(cmsPeriod.PaymentDate).multipliedBy(deltaPD);

            return(sensiFwd.combinedWith(sensiDf));
        }