private double dscSensitivity(ResolvedFra fra, double forwardRate, double discountFactor, double paymentTime, double eps)
	  {

		RatesProvider provNew = mock(typeof(RatesProvider));
		when(provNew.ValuationDate).thenReturn(VAL_DATE);
		RateComputationFn<RateComputation> obsFuncNew = mock(typeof(RateComputationFn));
		when(obsFuncNew.rate(fra.FloatingRate, fra.StartDate, fra.EndDate, provNew)).thenReturn(forwardRate);
		when(provNew.discountFactor(fra.Currency, fra.PaymentDate)).thenReturn(discountFactor * Math.Exp(-eps * paymentTime));
		CurrencyAmount upDscValue = (new DiscountingFraProductPricer(obsFuncNew)).presentValue(fra, provNew);
		when(provNew.discountFactor(fra.Currency, fra.PaymentDate)).thenReturn(discountFactor * Math.Exp(eps * paymentTime));
		CurrencyAmount downDscValue = (new DiscountingFraProductPricer(obsFuncNew)).presentValue(fra, provNew);
		return upDscValue.minus(downDscValue).multipliedBy(0.5 / eps).Amount;
	  }
コード例 #2
0
        //-------------------------------------------------------------------------
        /// <summary>
        /// Calculates the price of the foreign exchange vanilla 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>
        /// </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(ResolvedFxVanillaOption option, RatesProvider ratesProvider, BlackFxOptionSmileVolatilities volatilities)
        {
            validate(ratesProvider, volatilities);
            double timeToExpiry = volatilities.relativeTime(option.Expiry);

            if (timeToExpiry <= 0d)
            {
                return(0d);
            }
            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);

            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);
            }
            return(df * priceFwd);
        }
コード例 #3
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)));
        }
コード例 #4
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)));
        }
コード例 #5
0
        //-------------------------------------------------------------------------
        /// <summary>
        /// Calculates the present value of the Ibor caplet/floorlet period.
        /// <para>
        /// The result is expressed using the currency of the period.
        ///
        /// </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 </returns>
        public virtual CurrencyAmount presentValue(IborCapletFloorletPeriod period, RatesProvider ratesProvider, IborCapletFloorletVolatilities volatilities)
        {
            validate(volatilities);
            Currency currency = period.Currency;

            if (ratesProvider.ValuationDate.isAfter(period.PaymentDate))
            {
                return(CurrencyAmount.of(currency, 0d));
            }
            double  expiry    = volatilities.relativeTime(period.FixingDateTime);
            double  df        = ratesProvider.discountFactor(currency, period.PaymentDate);
            PutCall putCall   = period.PutCall;
            double  strike    = period.Strike;
            double  indexRate = ratesProvider.iborIndexRates(period.Index).rate(period.IborRate.Observation);

            if (expiry < 0d)
            {     // Option has expired already
                double sign   = putCall.Call ? 1d : -1d;
                double payoff = Math.Max(sign * (indexRate - strike), 0d);
                return(CurrencyAmount.of(currency, df * payoff * period.YearFraction * period.Notional));
            }
            double volatility = volatilities.volatility(expiry, strike, indexRate);
            double price      = df * period.YearFraction * volatilities.price(expiry, putCall, strike, indexRate, volatility);

            return(CurrencyAmount.of(currency, price * period.Notional));
        }
        //-------------------------------------------------------------------------
        /// <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)));
        }
コード例 #7
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)));
        }
        //-------------------------------------------------------------------------
        /// <summary>
        /// Calculates the price of the foreign exchange vanilla 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>
        /// </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(ResolvedFxVanillaOption option, RatesProvider ratesProvider, BlackFxOptionVolatilities volatilities)
        {
            ResolvedFxSingle underlying     = option.Underlying;
            double           forwardPrice   = undiscountedPrice(option, ratesProvider, volatilities);
            double           discountFactor = ratesProvider.discountFactor(option.CounterCurrency, underlying.PaymentDate);

            return(discountFactor * forwardPrice);
        }
        //-------------------------------------------------------------------------
        /// <summary>
        /// Calculates the numeraire, used to multiply the results.
        /// </summary>
        /// <param name="swaption">  the swap </param>
        /// <param name="fixedLeg">  the fixed leg </param>
        /// <param name="forward">  the forward rate </param>
        /// <param name="ratesProvider">  the rates provider </param>
        /// <returns> the numeraire </returns>
        protected internal virtual double calculateNumeraire(ResolvedSwaption swaption, ResolvedSwapLeg fixedLeg, double forward, RatesProvider ratesProvider)
        {
            double annuityCash = swapPricer.LegPricer.annuityCash(fixedLeg, forward);
            CashSwaptionSettlement cashSettlement = (CashSwaptionSettlement)swaption.SwaptionSettlement;
            double discountSettle = ratesProvider.discountFactor(fixedLeg.Currency, cashSettlement.SettlementDate);

            return(Math.Abs(annuityCash * discountSettle));
        }
コード例 #10
0
        /// <summary>
        /// Computes the adjusted forward rate for a CMS coupon.
        /// <para>
        /// The adjusted forward rate, is the number such that, multiplied by the notional, the year fraction and the payment
        /// date discount factor, it produces the present value. In other terms, it is the number which used in the same
        /// formula used for Ibor coupon pricing will provide the correct present value.
        /// </para>
        /// <para>
        /// For period already fixed, this number will be equal to the swap index fixing.
        /// </para>
        /// <para>
        /// For cap or floor the result is the adjusted forward rate for the coupon equivalent to the cap/floor,
        /// i.e. the coupon with the same dates and index but with no cap or floor strike.
        ///
        /// </para>
        /// </summary>
        /// <param name="cmsPeriod">  the CMS period, which should be of the type <seealso cref="CmsPeriodType#COUPON"/> </param>
        /// <param name="provider">  the rates provider </param>
        /// <param name="swaptionVolatilities">  the swaption volatilities </param>
        /// <returns> the adjusted forward rate </returns>
        public double adjustedForwardRate(CmsPeriod cmsPeriod, RatesProvider provider, SabrSwaptionVolatilities swaptionVolatilities)
        {
            CmsPeriod coupon    = cmsPeriod.toCouponEquivalent();
            Currency  ccy       = cmsPeriod.Currency;
            double    dfPayment = provider.discountFactor(ccy, coupon.PaymentDate);
            double    pv        = presentValue(coupon, provider, swaptionVolatilities).Amount;

            return(pv / (coupon.Notional * coupon.YearFraction * dfPayment));
        }
        //-------------------------------------------------------------------------
        /// <summary>
        /// Calculates the delta of the foreign exchange vanilla option product.
        /// <para>
        /// The delta is the first derivative of <seealso cref="#price"/> with respect to spot.
        ///
        /// </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 delta of the product </returns>
        public virtual double delta(ResolvedFxVanillaOption option, RatesProvider ratesProvider, BlackFxOptionVolatilities volatilities)
        {
            ResolvedFxSingle underlying             = option.Underlying;
            double           fwdDelta               = undiscountedDelta(option, ratesProvider, volatilities);
            double           discountFactor         = ratesProvider.discountFactor(option.CounterCurrency, underlying.PaymentDate);
            double           fwdRateSpotSensitivity = fxPricer.forwardFxRateSpotSensitivity(option.PutCall.Call ? underlying : underlying.inverse(), ratesProvider);

            return(fwdDelta * discountFactor * fwdRateSpotSensitivity);
        }
コード例 #12
0
        //-------------------------------------------------------------------------
        /// <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>
        /// Computes the present value sensitivity to the black volatility used in the pricing.
        /// <para>
        /// The result is a single sensitivity to the volatility used. This is also called Black vega.
        ///
        /// </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 sensitivity </returns>
        public virtual PointSensitivityBuilder presentValueSensitivityModelParamsVolatility(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;
            Currency         ccyBase          = currencyPair.Base;
            Currency         ccyCounter       = currencyPair.Counter;
            double           dfBase           = ratesProvider.discountFactor(ccyBase, underlyingFx.PaymentDate);
            double           dfCounter        = ratesProvider.discountFactor(ccyCounter, underlyingFx.PaymentDate);
            double           todayFx          = ratesProvider.fxRate(currencyPair);
            double           forward          = todayFx * dfBase / dfCounter;

            return(FxOptionSensitivity.of(volatilities.Name, currencyPair, volatilities.relativeTime(underlyingOption.Expiry), underlyingOption.Strike, forward, ccyCounter, priceDerivatives.getDerivative(4) * signedNotional(underlyingOption)));
        }
コード例 #14
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));
        }
コード例 #16
0
        //-------------------------------------------------------------------------
        /// <summary>
        /// Computes the par rate for swaps with a fixed leg.
        /// <para>
        /// The par rate is the common rate on all payments of the fixed leg for which the total swap present value is 0.
        /// </para>
        /// <para>
        /// At least one leg must be a fixed leg. The par rate will be computed with respect to the first fixed leg
        /// in which all the payments are fixed payments with a unique accrual period (no compounding) and no FX reset.
        /// If the fixed leg is compounding, the par rate is computed only when the number of fixed coupon payments is 1 and
        /// accrual factor of each sub-period is 1
        ///
        /// </para>
        /// </summary>
        /// <param name="swap">  the product </param>
        /// <param name="provider">  the rates provider </param>
        /// <returns> the par rate </returns>
        public virtual double parRate(ResolvedSwap swap, RatesProvider provider)
        {
            // find fixed leg
            ResolvedSwapLeg fixedLeg    = this.fixedLeg(swap);
            Currency        ccyFixedLeg = fixedLeg.Currency;
            // other payments (not fixed leg coupons) converted in fixed leg currency
            double otherLegsConvertedPv = 0.0;

            foreach (ResolvedSwapLeg leg in swap.Legs)
            {
                if (leg != fixedLeg)
                {
                    double pvLocal = legPricer.presentValueInternal(leg, provider);
                    otherLegsConvertedPv += (pvLocal * provider.fxRate(leg.Currency, ccyFixedLeg));
                }
            }
            double fixedLegEventsPv = legPricer.presentValueEventsInternal(fixedLeg, provider);

            if (fixedLeg.PaymentPeriods.size() > 1)
            {     // try multiperiod par-rate
                  // PVBP
                double pvbpFixedLeg = legPricer.pvbp(fixedLeg, provider);
                // Par rate
                return(-(otherLegsConvertedPv + fixedLegEventsPv) / pvbpFixedLeg);
            }
            SwapPaymentPeriod firstPeriod = fixedLeg.PaymentPeriods.get(0);

            ArgChecker.isTrue(firstPeriod is RatePaymentPeriod, "PaymentPeriod must be instance of RatePaymentPeriod");
            RatePaymentPeriod payment = (RatePaymentPeriod)firstPeriod;

            if (payment.AccrualPeriods.size() == 1)
            {     // no compounding
                  // PVBP
                double pvbpFixedLeg = legPricer.pvbp(fixedLeg, provider);
                // Par rate
                return(-(otherLegsConvertedPv + fixedLegEventsPv) / pvbpFixedLeg);
            }
            // try Compounding
            Triple <bool, int, double> fixedCompounded = checkFixedCompounded(fixedLeg);

            ArgChecker.isTrue(fixedCompounded.First, "Swap should have a fixed leg and for one payment it should be based on compunding witout spread.");
            double notional = payment.Notional;
            double df       = provider.discountFactor(ccyFixedLeg, payment.PaymentDate);

            return(Math.Pow(-(otherLegsConvertedPv + fixedLegEventsPv) / (notional * df) + 1.0d, 1.0 / fixedCompounded.Second) - 1.0d);
        }
コード例 #17
0
        /// <summary>
        /// Calculates the currency exposure of the foreign exchange vanilla option product.
        /// </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 currency exposure </returns>
        public virtual MultiCurrencyAmount currencyExposure(ResolvedFxVanillaOption option, RatesProvider ratesProvider, BlackFxOptionSmileVolatilities volatilities)
        {
            validate(ratesProvider, volatilities);
            double timeToExpiry = volatilities.relativeTime(option.Expiry);

            if (timeToExpiry <= 0d)
            {
                return(MultiCurrencyAmount.empty());
            }
            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               spot                   = ratesProvider.fxRate(currencyPair);
            double               forwardRate            = forward.fxRate(currencyPair);
            double               fwdRateSpotSensitivity = fxPricer.forwardFxRateSpotSensitivity(option.PutCall.Call ? underlyingFx : underlyingFx.inverse(), ratesProvider);
            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         price          = df * priceFwd;
            double         delta          = df * deltaFwd * fwdRateSpotSensitivity;
            double         signedNotional = this.signedNotional(option);
            CurrencyAmount domestic       = CurrencyAmount.of(currencyPair.Counter, (price - delta * spot) * signedNotional);
            CurrencyAmount foreign        = CurrencyAmount.of(currencyPair.Base, delta * signedNotional);

            return(MultiCurrencyAmount.of(domestic, foreign));
        }
        //-------------------------------------------------------------------------
        /// <summary>
        /// Calculates the Black theta of the foreign exchange vanilla option product.
        /// <para>
        /// The theta is the negative of the first derivative of <seealso cref="#price"/> with respect to time parameter
        /// in Black formula (the discounted driftless theta).
        ///
        /// </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 theta of the product </returns>
        public virtual double theta(ResolvedFxVanillaOption option, RatesProvider ratesProvider, BlackFxOptionVolatilities volatilities)
        {
            double timeToExpiry = volatilities.relativeTime(option.Expiry);

            if (timeToExpiry <= 0d)
            {
                return(0d);
            }
            ResolvedFxSingle underlying     = option.Underlying;
            FxRate           forward        = fxPricer.forwardFxRate(underlying, ratesProvider);
            CurrencyPair     strikePair     = underlying.CurrencyPair;
            double           forwardRate    = forward.fxRate(strikePair);
            double           strikeRate     = option.Strike;
            double           volatility     = volatilities.volatility(strikePair, option.Expiry, strikeRate, forwardRate);
            double           fwdTheta       = BlackFormulaRepository.driftlessTheta(forwardRate, strikeRate, timeToExpiry, volatility);
            double           discountFactor = ratesProvider.discountFactor(option.CounterCurrency, underlying.PaymentDate);

            return(discountFactor * fwdTheta);
        }
コード例 #19
0
        /// <summary>
        /// Explains the present value of the CMS period.
        /// <para>
        /// This returns explanatory information about the calculation.
        ///
        /// </para>
        /// </summary>
        /// <param name="period">  the product </param>
        /// <param name="ratesProvider">  the rates provider </param>
        /// <param name="swaptionVolatilities">  the volatilities </param>
        /// <param name="builder">  the builder to populate </param>
        public void explainPresentValue(CmsPeriod period, RatesProvider ratesProvider, SabrSwaptionVolatilities swaptionVolatilities, ExplainMapBuilder builder)
        {
            string    type        = period.CmsPeriodType.ToString();
            Currency  ccy         = period.Currency;
            LocalDate paymentDate = period.PaymentDate;

            builder.put(ExplainKey.ENTRY_TYPE, "Cms" + type + "Period");
            builder.put(ExplainKey.STRIKE_VALUE, period.Strike);
            builder.put(ExplainKey.NOTIONAL, CurrencyAmount.of(ccy, period.Notional));
            builder.put(ExplainKey.PAYMENT_DATE, period.PaymentDate);
            builder.put(ExplainKey.DISCOUNT_FACTOR, ratesProvider.discountFactor(ccy, paymentDate));
            builder.put(ExplainKey.START_DATE, period.StartDate);
            builder.put(ExplainKey.END_DATE, period.EndDate);
            builder.put(ExplainKey.FIXING_DATE, period.FixingDate);
            builder.put(ExplainKey.ACCRUAL_YEAR_FRACTION, period.YearFraction);
            builder.put(ExplainKey.PRESENT_VALUE, presentValue(period, ratesProvider, swaptionVolatilities));
            builder.put(ExplainKey.FORWARD_RATE, swapPricer.parRate(period.UnderlyingSwap, ratesProvider));
            builder.put(ExplainKey.CONVEXITY_ADJUSTED_RATE, adjustedForwardRate(period, ratesProvider, swaptionVolatilities));
        }
コード例 #20
0
        //-------------------------------------------------------------------------
        /// <summary>
        /// Calculates the present value volatility sensitivity of the Ibor caplet/floorlet.
        /// <para>
        /// The present value volatility sensitivity of the caplet/floorlet is the sensitivity
        /// of the present value to the implied volatility.
        /// </para>
        /// <para>
        /// The sensitivity to the implied volatility is also called vega.
        ///
        /// </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 volatility </returns>
        public virtual PointSensitivityBuilder presentValueSensitivityModelParamsVolatility(IborCapletFloorletPeriod period, RatesProvider ratesProvider, IborCapletFloorletVolatilities volatilities)
        {
            validate(volatilities);
            double   expiry   = volatilities.relativeTime(period.FixingDateTime);
            double   strike   = period.Strike;
            Currency currency = period.Currency;

            if (expiry <= 0d)
            {     // Option has expired already or at expiry
                return(PointSensitivityBuilder.none());
            }
            double  forward    = ratesProvider.iborIndexRates(period.Index).rate(period.IborRate.Observation);
            double  volatility = volatilities.volatility(expiry, strike, forward);
            PutCall putCall    = period.PutCall;
            double  df         = ratesProvider.discountFactor(currency, period.PaymentDate);
            double  vega       = df * period.YearFraction * volatilities.priceVega(expiry, putCall, strike, forward, volatility);

            return(IborCapletFloorletSensitivity.of(volatilities.Name, expiry, strike, forward, currency, vega * period.Notional));
        }
コード例 #21
0
        //-------------------------------------------------------------------------
        /// <summary>
        /// Calculates the present value theta of the Ibor caplet/floorlet period.
        /// <para>
        /// The present value theta is given by the minus of the present value sensitivity to the {@code timeToExpiry}
        /// parameter of the model.
        ///
        /// </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 theta </returns>
        public virtual CurrencyAmount presentValueTheta(IborCapletFloorletPeriod period, RatesProvider ratesProvider, IborCapletFloorletVolatilities volatilities)
        {
            validate(volatilities);
            double   expiry   = volatilities.relativeTime(period.FixingDateTime);
            Currency currency = period.Currency;

            if (expiry < 0d)
            {     // Option has expired already
                return(CurrencyAmount.of(currency, 0d));
            }
            double  forward    = ratesProvider.iborIndexRates(period.Index).rate(period.IborRate.Observation);
            double  strike     = period.Strike;
            double  volatility = volatilities.volatility(expiry, strike, forward);
            PutCall putCall    = period.PutCall;
            double  df         = ratesProvider.discountFactor(currency, period.PaymentDate);
            double  priceTheta = df * period.YearFraction * volatilities.priceTheta(expiry, putCall, strike, forward, volatility);

            return(CurrencyAmount.of(currency, priceTheta * period.Notional));
        }
コード例 #22
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));
        }
コード例 #23
0
 // calculates the cash flow of the events composing the leg in the currency of the swap leg
 internal virtual CashFlows cashFlowEventsInternal(ResolvedSwapLeg leg, RatesProvider provider)
 {
     ImmutableList.Builder <CashFlow> builder = ImmutableList.builder();
     foreach (SwapPaymentEvent @event in leg.PaymentEvents)
     {
         if ([email protected](provider.ValuationDate))
         {
             double forecastValue = paymentEventPricer.forecastValue(@event, provider);
             if (forecastValue != 0d)
             {
                 Currency  currency       = @event.Currency;
                 LocalDate paymentDate    = @event.PaymentDate;
                 double    discountFactor = provider.discountFactor(currency, paymentDate);
                 CashFlow  singleCashFlow = CashFlow.ofForecastValue(paymentDate, currency, forecastValue, discountFactor);
                 builder.add(singleCashFlow);
             }
         }
     }
     return(CashFlows.of(builder.build()));
 }
コード例 #24
0
        //-------------------------------------------------------------------------
        /// <summary>
        /// Calculates the present value sensitivity to the SABR model parameters of the Ibor caplet/floorlet.
        /// <para>
        /// The sensitivity of the present value to the SABR model parameters, alpha, beta, rho and nu.
        ///
        /// </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 SABR model parameters </returns>
        public virtual PointSensitivityBuilder presentValueSensitivityModelParamsSabr(IborCapletFloorletPeriod period, RatesProvider ratesProvider, SabrIborCapletFloorletVolatilities volatilities)
        {
            double expiry = volatilities.relativeTime(period.FixingDateTime);

            if (expiry < 0d)
            {     // option expired already
                return(PointSensitivityBuilder.none());
            }
            Currency         currency               = period.Currency;
            PutCall          putCall                = period.PutCall;
            double           strike                 = period.Strike;
            double           indexRate              = ratesProvider.iborIndexRates(period.Index).rate(period.IborRate.Observation);
            double           factor                 = period.Notional * period.YearFraction;
            ValueDerivatives volatilityAdj          = volatilities.volatilityAdjoint(expiry, strike, indexRate);
            DoubleArray      derivative             = volatilityAdj.Derivatives;
            double           df                     = ratesProvider.discountFactor(currency, period.PaymentDate);
            double           vega                   = df * factor * volatilities.priceVega(expiry, putCall, strike, indexRate, volatilityAdj.Value);
            IborCapletFloorletVolatilitiesName name = volatilities.Name;

            return(PointSensitivityBuilder.of(IborCapletFloorletSabrSensitivity.of(name, expiry, ALPHA, currency, vega * derivative.get(2)), IborCapletFloorletSabrSensitivity.of(name, expiry, BETA, currency, vega * derivative.get(3)), IborCapletFloorletSabrSensitivity.of(name, expiry, RHO, currency, vega * derivative.get(4)), IborCapletFloorletSabrSensitivity.of(name, expiry, NU, currency, vega * derivative.get(5))));
        }
コード例 #25
0
        private IList <ZeroRateSensitivity> dscSensitivityFD(RatesProvider provider, NotionalExchange @event, double eps)
        {
            Currency      currency       = @event.Currency;
            LocalDate     paymentDate    = @event.PaymentDate;
            double        discountFactor = provider.discountFactor(currency, paymentDate);
            double        paymentTime    = DAY_COUNT.relativeYearFraction(VAL_DATE, paymentDate);
            RatesProvider provUp         = mock(typeof(RatesProvider));
            RatesProvider provDw         = mock(typeof(RatesProvider));

            when(provUp.ValuationDate).thenReturn(VAL_DATE);
            when(provUp.discountFactor(currency, paymentDate)).thenReturn(discountFactor * Math.Exp(-eps * paymentTime));
            when(provDw.ValuationDate).thenReturn(VAL_DATE);
            when(provDw.discountFactor(currency, paymentDate)).thenReturn(discountFactor * Math.Exp(eps * paymentTime));
            DiscountingNotionalExchangePricer pricer = DiscountingNotionalExchangePricer.DEFAULT;
            double pvUp = pricer.presentValue(@event, provUp);
            double pvDw = pricer.presentValue(@event, provDw);
            double res  = 0.5 * (pvUp - pvDw) / eps;
            IList <ZeroRateSensitivity> zeroRateSensi = new List <ZeroRateSensitivity>();

            zeroRateSensi.Add(ZeroRateSensitivity.of(currency, paymentTime, res));
            return(zeroRateSensi);
        }
コード例 #26
0
        /// <summary>
        /// Computes the par spread for swaps.
        /// <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 will be computed with respect to the first leg. For that leg, all the payments have a unique
        /// accrual period or multiple accrual periods with Flat compounding and no FX reset.
        ///
        /// </para>
        /// </summary>
        /// <param name="swap">  the product </param>
        /// <param name="provider">  the rates provider </param>
        /// <returns> the par rate </returns>
        public virtual double parSpread(ResolvedSwap swap, RatesProvider provider)
        {
            ResolvedSwapLeg referenceLeg    = swap.Legs.get(0);
            Currency        ccyReferenceLeg = referenceLeg.Currency;
            // 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);
                double convertedPv          = presentValue(swap, ccyReferenceLeg, provider).Amount;
                double referenceConvertedPv = legPricer.presentValue(referenceLeg, provider).Amount;
                double notional             = ((RatePaymentPeriod)referenceLeg.PaymentPeriods.get(0)).Notional;
                double parSpread            = Math.Pow(-(convertedPv - referenceConvertedPv) / (df * notional) + 1.0d, 1.0d / fixedCompounded.Second) - (1.0d + fixedCompounded.Third);
                return(parSpread);
            }
            // In other cases, try the standard multiperiod par spread
            double convertedPv = presentValue(swap, ccyReferenceLeg, provider).Amount;
            double pvbp        = legPricer.pvbp(referenceLeg, provider);

            return(-convertedPv / pvbp);
        }
コード例 #27
0
        /// <summary>
        /// Computes the present value sensitivity to the black volatilities used in the pricing.
        /// <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 sensitivity </returns>
        public virtual PointSensitivityBuilder presentValueSensitivityModelParamsVolatility(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;
            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   vegaAtm                   = BlackFormulaRepository.vega(forwardRate, strikeRate, timeToExpiry, volAtm);
            double   signedNotional            = this.signedNotional(option);
            PointSensitivityBuilder sensiSmile = PointSensitivityBuilder.none();

            for (int i = 0; i < 3; i += 2)
            {
                double vegaFwdAtm = BlackFormulaRepository.vega(forwardRate, strikes[i], timeToExpiry, volAtm);
                vegaAtm -= x[i] * vegaFwdAtm;
                double vegaFwdSmile = BlackFormulaRepository.vega(forwardRate, strikes[i], timeToExpiry, vols[i]);
                sensiSmile = sensiSmile.combinedWith(FxOptionSensitivity.of(volatilities.Name, currencyPair, timeToExpiry, strikes[i], forwardRate, ccyCounter, df * signedNotional * x[i] * vegaFwdSmile));
            }
            FxOptionSensitivity sensiAtm = FxOptionSensitivity.of(volatilities.Name, currencyPair, timeToExpiry, strikes[1], forwardRate, ccyCounter, df * signedNotional * vegaAtm);

            return(sensiAtm.combinedWith(sensiSmile));
        }
コード例 #28
0
        /// <summary>
        /// Computes cash flow equivalent of Ibor leg.
        /// <para>
        /// The return type is {@code ResolvedSwapLeg} in which individual payments are
        /// represented in terms of {@code NotionalExchange}.
        ///
        /// </para>
        /// </summary>
        /// <param name="iborLeg">  the Ibor leg </param>
        /// <param name="ratesProvider">  the rates provider </param>
        /// <returns> the cash flow equivalent </returns>
        public static ResolvedSwapLeg cashFlowEquivalentIborLeg(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");
            IList <NotionalExchange> paymentEvents = new List <NotionalExchange>();

            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           beta     = (1d + fixingYearFraction * ratesProvider.iborIndexRates(index).rate(obs)) * ratesProvider.discountFactor(paymentPeriod.Currency, paymentPeriod.PaymentDate) / ratesProvider.discountFactor(paymentPeriod.Currency, fixingStartDate);
                double           ycRatio  = rateAccrualPeriod.YearFraction / fixingYearFraction;
                NotionalExchange payStart = NotionalExchange.of(notional.multipliedBy(beta * ycRatio), fixingStartDate);
                NotionalExchange payEnd   = NotionalExchange.of(notional.multipliedBy(-ycRatio), paymentDate);
                paymentEvents.Add(payStart);
                paymentEvents.Add(payEnd);
            }
            ResolvedSwapLeg leg = ResolvedSwapLeg.builder().paymentEvents(paymentEvents).payReceive(PayReceive.RECEIVE).type(SwapLegType.OTHER).build();

            return(leg);
        }
コード例 #29
0
        /// <summary>
        /// Computes the present value sensitivity to SABR parameters 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 presentValueSensitivityModelParamsSabr(CmsPeriod cmsPeriod, RatesProvider provider, SabrSwaptionVolatilities swaptionVolatilities)
        {
            Currency      ccy           = cmsPeriod.Currency;
            SwapIndex     index         = cmsPeriod.Index;
            ResolvedSwap  swap          = cmsPeriod.UnderlyingSwap;
            double        dfPayment     = provider.discountFactor(ccy, cmsPeriod.PaymentDate);
            ZonedDateTime valuationDate = swaptionVolatilities.ValuationDateTime;
            LocalDate     fixingDate    = cmsPeriod.FixingDate;
            ZonedDateTime expiryDate    = fixingDate.atTime(index.FixingTime).atZone(index.FixingZone);
            double        tenor         = swaptionVolatilities.tenor(swap.StartDate, swap.EndDate);

            if (provider.ValuationDate.isAfter(cmsPeriod.PaymentDate))
            {
                return(PointSensitivityBuilder.none());
            }
            if (!fixingDate.isAfter(valuationDate.toLocalDate()))
            {
                double?fixedRate = provider.timeSeries(cmsPeriod.Index).get(fixingDate);
                if (fixedRate.HasValue)
                {
                    return(PointSensitivityBuilder.none());
                }
                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 expiryTime            = swaptionVolatilities.relativeTime(expiryDate);
            double shift                 = swaptionVolatilities.shift(expiryTime, tenor);
            double strikeCpn             = cmsPeriod.CmsPeriodType.Equals(CmsPeriodType.COUPON) ? -shift : cmsPeriod.Strike;
            double forward               = swapPricer.parRate(swap, provider);
            double eta                   = index.Template.Convention.FixedLeg.DayCount.relativeYearFraction(cmsPeriod.PaymentDate, swap.StartDate);
            CmsIntegrantProvider intProv = new CmsIntegrantProvider(this, cmsPeriod, swap, swaptionVolatilities, forward, strikeCpn, expiryTime, tenor, cutOffStrike, eta);
            double factor                = dfPayment / intProv.h(forward) * intProv.g(forward);
            double factor2               = factor * intProv.k(strikeCpn);

            double[] strikePartPrice          = intProv.SabrExtrapolation.priceAdjointSabr(Math.Max(0d, strikeCpn + shift), intProv.PutCall).Derivatives.multipliedBy(factor2).toArray();
            RungeKuttaIntegrator1D integrator = new RungeKuttaIntegrator1D(ABS_TOL, REL_TOL_VEGA, NUM_ITER);

            double[] totalSensi = new double[4];
            for (int loopparameter = 0; loopparameter < 4; loopparameter++)
            {
                double integralPart = 0d;
                System.Func <double, double> integrant = intProv.integrantVega(loopparameter);
                try
                {
                    if (intProv.PutCall.Call)
                    {
                        integralPart = dfPayment * integrateCall(integrator, integrant, swaptionVolatilities, forward, strikeCpn, expiryTime, tenor);
                    }
                    else
                    {
                        integralPart = -dfPayment *integrator.integrate(integrant, -shift + ZERO_SHIFT, strikeCpn);
                    }
                }
                catch (Exception e)
                {
                    throw new Exception(e);
                }
                totalSensi[loopparameter] = (strikePartPrice[loopparameter] + integralPart) * cmsPeriod.Notional * cmsPeriod.YearFraction;
            }
            SwaptionVolatilitiesName name = swaptionVolatilities.Name;

            return(PointSensitivityBuilder.of(SwaptionSabrSensitivity.of(name, expiryTime, tenor, ALPHA, ccy, totalSensi[0]), SwaptionSabrSensitivity.of(name, expiryTime, tenor, BETA, ccy, totalSensi[1]), SwaptionSabrSensitivity.of(name, expiryTime, tenor, RHO, ccy, totalSensi[2]), SwaptionSabrSensitivity.of(name, expiryTime, tenor, NU, ccy, totalSensi[3])));
        }
コード例 #30
0
        /// <summary>
        /// Computes the present value sensitivity to strike 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 double presentValueSensitivityStrike(CmsPeriod cmsPeriod, RatesProvider provider, SabrSwaptionVolatilities swaptionVolatilities)
        {
            ArgChecker.isFalse(cmsPeriod.CmsPeriodType.Equals(CmsPeriodType.COUPON), "presentValueSensitivityStrike is not relevant for CMS coupon");
            Currency  ccy   = cmsPeriod.Currency;
            SwapIndex index = cmsPeriod.Index;

            if (provider.ValuationDate.isAfter(cmsPeriod.PaymentDate))
            {
                return(0d);
            }
            ResolvedSwap  swap          = cmsPeriod.UnderlyingSwap;
            double        dfPayment     = provider.discountFactor(ccy, cmsPeriod.PaymentDate);
            ZonedDateTime valuationDate = swaptionVolatilities.ValuationDateTime;
            LocalDate     fixingDate    = cmsPeriod.FixingDate;
            double        tenor         = swaptionVolatilities.tenor(swap.StartDate, swap.EndDate);
            ZonedDateTime expiryDate    = fixingDate.atTime(index.FixingTime).atZone(index.FixingZone);
            double        expiryTime    = swaptionVolatilities.relativeTime(expiryDate);
            double        strike        = cmsPeriod.Strike;
            double        shift         = swaptionVolatilities.shift(expiryTime, tenor);

            if (!fixingDate.isAfter(valuationDate.toLocalDate()))
            {
                double?fixedRate = provider.timeSeries(cmsPeriod.Index).get(fixingDate);
                if (fixedRate.HasValue)
                {
                    double payoff = 0d;
                    switch (cmsPeriod.CmsPeriodType)
                    {
                    case CAPLET:
                        payoff = fixedRate.Value >= strike ? -1d : 0d;
                        break;

                    case FLOORLET:
                        payoff = fixedRate.Value < strike ? 1d : 0d;
                        break;

                    default:
                        throw new System.ArgumentException("unsupported CMS type");
                    }
                    return(payoff * cmsPeriod.Notional * cmsPeriod.YearFraction * dfPayment);
                }
                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);
            CmsIntegrantProvider intProv = new CmsIntegrantProvider(this, cmsPeriod, swap, swaptionVolatilities, forward, strike, expiryTime, tenor, cutOffStrike, eta);
            double factor = dfPayment * intProv.g(forward) / intProv.h(forward);
            RungeKuttaIntegrator1D integrator = new RungeKuttaIntegrator1D(ABS_TOL, REL_TOL_STRIKE, NUM_ITER);

            double[] kpkpp = intProv.kpkpp(strike);
            double   firstPart;
            double   thirdPart;

            System.Func <double, double> integrant = intProv.integrantDualDelta();
            if (intProv.PutCall.Call)
            {
                firstPart = -kpkpp[0] * intProv.bs(strike);
                thirdPart = integrateCall(integrator, integrant, swaptionVolatilities, forward, strike, expiryTime, tenor);
            }
            else
            {
                firstPart = -kpkpp[0] * intProv.bs(strike);
                thirdPart = -integrator.integrate(integrant, -shift + ZERO_SHIFT, strike).Value;
            }
            double secondPart = intProv.k(strike) * intProv.SabrExtrapolation.priceDerivativeStrike(strike + shift, intProv.PutCall);

            return(cmsPeriod.Notional * cmsPeriod.YearFraction * factor * (firstPart + secondPart + thirdPart));
        }