예제 #1
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)));
        }
예제 #2
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)));
        }
예제 #3
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)));
        }
        //-------------------------------------------------------------------------
        /// <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);
            double  pvbp       = SwapPricer.LegPricer.pvbp(fixedLeg, ratesProvider);
            double  strike     = SwapPricer.LegPricer.couponEquivalent(fixedLeg, ratesProvider, pvbp);
            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 pvbpDr    = SwapPricer.LegPricer.pvbpSensitivity(fixedLeg, ratesProvider);
            PointSensitivityBuilder forwardDr = SwapPricer.parRateSensitivity(underlying, ratesProvider);
            double sign = swaption.LongShort.sign();

            return(pvbpDr.multipliedBy(price * sign * Math.Sign(pvbp)).combinedWith(forwardDr.multipliedBy(delta * Math.Abs(pvbp) * sign)));
        }
        //-------------------------------------------------------------------------
        /// <summary>
        /// Calculates the present value sensitivity of the swaption product to the rate curves.
        /// <para>
        /// The present value sensitivity is computed in a "sticky model parameter" style, i.e. the sensitivity to the
        /// curve nodes with the SABR model parameters unchanged. This sensitivity does not include a potential
        /// re-calibration of the model parameters to the raw market data.
        ///
        /// </para>
        /// </summary>
        /// <param name="swaption">  the swaption product </param>
        /// <param name="ratesProvider">  the rates provider </param>
        /// <param name="swaptionVolatilities">  the volatilities </param>
        /// <returns> the point sensitivity to the rate curves </returns>
        public virtual PointSensitivityBuilder presentValueSensitivityRatesStickyModel(ResolvedSwaption swaption, RatesProvider ratesProvider, SabrSwaptionVolatilities swaptionVolatilities)
        {
            validate(swaption, ratesProvider, swaptionVolatilities);
            ZonedDateTime   expiryDateTime = swaption.Expiry;
            double          expiry         = swaptionVolatilities.relativeTime(expiryDateTime);
            ResolvedSwap    underlying     = swaption.Underlying;
            ResolvedSwapLeg fixedLeg       = this.fixedLeg(underlying);

            if (expiry < 0d)
            {     // Option has expired already
                return(PointSensitivityBuilder.none());
            }
            double           forward       = SwapPricer.parRate(underlying, ratesProvider);
            double           pvbp          = SwapPricer.LegPricer.pvbp(fixedLeg, ratesProvider);
            double           strike        = SwapPricer.LegPricer.couponEquivalent(fixedLeg, ratesProvider, pvbp);
            double           tenor         = swaptionVolatilities.tenor(fixedLeg.StartDate, fixedLeg.EndDate);
            double           shift         = swaptionVolatilities.shift(expiry, tenor);
            ValueDerivatives volatilityAdj = swaptionVolatilities.volatilityAdjoint(expiry, tenor, strike, forward);
            bool             isCall        = fixedLeg.PayReceive.Pay;
            // Payer at strike is exercise when rate > strike, i.e. call on rate
            // Backward sweep
            PointSensitivityBuilder pvbpDr    = SwapPricer.LegPricer.pvbpSensitivity(fixedLeg, ratesProvider);
            PointSensitivityBuilder forwardDr = SwapPricer.parRateSensitivity(underlying, ratesProvider);
            double shiftedForward             = forward + shift;
            double shiftedStrike = strike + shift;
            double price         = BlackFormulaRepository.price(shiftedForward, shiftedStrike, expiry, volatilityAdj.Value, isCall);
            double delta         = BlackFormulaRepository.delta(shiftedForward, shiftedStrike, expiry, volatilityAdj.Value, isCall);
            double vega          = BlackFormulaRepository.vega(shiftedForward, shiftedStrike, expiry, volatilityAdj.Value);
            double sign          = swaption.LongShort.sign();

            return(pvbpDr.multipliedBy(price * sign * Math.Sign(pvbp)).combinedWith(forwardDr.multipliedBy((delta + vega * volatilityAdj.getDerivative(0)) * Math.Abs(pvbp) * sign)));
        }
        //-------------------------------------------------------------------------
        /// <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)));
        }
        // Compute the accrued interest sensitivity on a given period by approximation
        private static PointSensitivityBuilder approximatedInterestSensitivity(OvernightIndexObservation observation, LocalDate endDate, OvernightIndexRates rates)
        {
            DayCount dayCount = observation.Index.DayCount;
            double   remainingFixingAccrualFactor = dayCount.yearFraction(observation.EffectiveDate, endDate);
            double   forwardRate = rates.periodRate(observation, endDate);
            PointSensitivityBuilder forwardRateSensitivity = rates.periodRatePointSensitivity(observation, endDate);
            double rateExp = 1.0 + forwardRate * remainingFixingAccrualFactor;

            forwardRateSensitivity = forwardRateSensitivity.multipliedBy(remainingFixingAccrualFactor / rateExp);
            return(forwardRateSensitivity);
        }
        //-------------------------------------------------------------------------
        /// <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));
        }
            // Calculate the total rate sensitivity.
            internal PointSensitivityBuilder calculateRateSensitivity()
            {
                // call these methods to ensure mutable fixedPeriod variable is updated
                pastAccumulation();
                valuationDateAccumulation();
                // calculate sensitivity
                PointSensitivityBuilder combinedPointSensitivity      = approximatedForwardAccumulationSensitivity();
                PointSensitivityBuilder cutOffAccumulationSensitivity = this.cutOffAccumulationSensitivity();

                combinedPointSensitivity = combinedPointSensitivity.combinedWith(cutOffAccumulationSensitivity);
                combinedPointSensitivity = combinedPointSensitivity.multipliedBy(1.0d / accrualFactorTotal);
                return(combinedPointSensitivity);
            }
 // Composition - forward part in non-cutoff period; past/valuation date case dealt with in previous methods
 internal ObjDoublePair <PointSensitivityBuilder> compositionFactorAndSensitivityNonCutoff()
 {
     if (!nextFixing.isAfter(lastFixingNonCutoff))
     {
         OvernightIndexObservation obs = computation.observeOn(nextFixing);
         LocalDate startDate           = obs.EffectiveDate;
         LocalDate endDate             = computation.calculateMaturityFromFixing(lastFixingNonCutoff);
         double    accrualFactor       = dayCount.yearFraction(startDate, endDate);
         double    rate = rates.periodRate(obs, endDate);
         PointSensitivityBuilder rateSensitivity = rates.periodRatePointSensitivity(obs, endDate);
         rateSensitivity = rateSensitivity.multipliedBy(accrualFactor);
         return(ObjDoublePair.of(rateSensitivity, 1.0d + accrualFactor * rate));
     }
     return(ObjDoublePair.of(PointSensitivityBuilder.none(), 1.0d));
 }
        private PointSensitivityBuilder rateForwardSensitivity(OvernightAveragedRateComputation computation, OvernightIndexRates rates)
        {
            OvernightIndex          index                           = computation.Index;
            HolidayCalendar         calendar                        = computation.FixingCalendar;
            LocalDate               startFixingDate                 = computation.StartDate;
            LocalDate               endFixingDateP1                 = computation.EndDate;
            LocalDate               endFixingDate                   = calendar.previous(endFixingDateP1);
            LocalDate               onRateEndDate                   = computation.calculateMaturityFromFixing(endFixingDate);
            LocalDate               onRateStartDate                 = computation.calculateEffectiveFromFixing(startFixingDate);
            LocalDate               lastNonCutOffMatDate            = onRateEndDate;
            int                     cutoffOffset                    = computation.RateCutOffDays > 1 ? computation.RateCutOffDays : 1;
            PointSensitivityBuilder combinedPointSensitivityBuilder = PointSensitivityBuilder.none();
            double                  accrualFactorTotal              = index.DayCount.yearFraction(onRateStartDate, onRateEndDate);

            if (cutoffOffset > 1)
            {     // Cut-off period
                IList <double> noCutOffAccrualFactorList = new List <double>();
                LocalDate      currentFixingDate         = endFixingDateP1;
                LocalDate      cutOffEffectiveDate;
                for (int i = 0; i < cutoffOffset; i++)
                {
                    currentFixingDate    = calendar.previous(currentFixingDate);
                    cutOffEffectiveDate  = computation.calculateEffectiveFromFixing(currentFixingDate);
                    lastNonCutOffMatDate = computation.calculateMaturityFromEffective(cutOffEffectiveDate);
                    double accrualFactor = index.DayCount.yearFraction(cutOffEffectiveDate, lastNonCutOffMatDate);
                    noCutOffAccrualFactorList.Add(accrualFactor);
                }
                OvernightIndexObservation lastIndexObs = computation.observeOn(currentFixingDate);
                PointSensitivityBuilder   forwardRateCutOffSensitivity = rates.ratePointSensitivity(lastIndexObs);
                double totalAccrualFactor = 0.0;
                for (int i = 0; i < cutoffOffset - 1; i++)
                {
                    totalAccrualFactor += noCutOffAccrualFactorList[i];
                }
                forwardRateCutOffSensitivity    = forwardRateCutOffSensitivity.multipliedBy(totalAccrualFactor);
                combinedPointSensitivityBuilder = combinedPointSensitivityBuilder.combinedWith(forwardRateCutOffSensitivity);
            }
            // Approximated part
            OvernightIndexObservation indexObs = computation.observeOn(onRateStartDate);
            PointSensitivityBuilder   approximatedInterestAndSensitivity = approximatedInterestSensitivity(indexObs, lastNonCutOffMatDate, rates);

            combinedPointSensitivityBuilder = combinedPointSensitivityBuilder.combinedWith(approximatedInterestAndSensitivity);
            combinedPointSensitivityBuilder = combinedPointSensitivityBuilder.multipliedBy(1.0 / accrualFactorTotal);
            // final rate
            return(combinedPointSensitivityBuilder);
        }
            // Composition - forward part in the cutoff period; past/valuation date case dealt with in previous methods
            internal ObjDoublePair <PointSensitivityBuilder> compositionFactorAndSensitivityCutoff()
            {
                OvernightIndexObservation obs = computation.observeOn(lastFixingNonCutoff);

                if (!nextFixing.isAfter(lastFixingNonCutoff))
                {
                    double rate = rates.rate(obs);
                    double compositionFactor           = 1.0d;
                    double compositionFactorDerivative = 0.0;
                    for (int i = 0; i < cutoffOffset - 1; i++)
                    {
                        compositionFactor           *= 1.0d + accrualFactorCutoff[i] * rate;
                        compositionFactorDerivative += accrualFactorCutoff[i] / (1.0d + accrualFactorCutoff[i] * rate);
                    }
                    compositionFactorDerivative *= compositionFactor;
                    PointSensitivityBuilder rateSensitivity = cutoffOffset <= 1 ? PointSensitivityBuilder.none() : rates.ratePointSensitivity(obs);
                    rateSensitivity = rateSensitivity.multipliedBy(compositionFactorDerivative);
                    return(ObjDoublePair.of(rateSensitivity, compositionFactor));
                }
                return(ObjDoublePair.of(PointSensitivityBuilder.none(), 1.0d));
            }
        public virtual void test_presentValueSensitivityRatesStickyStrike_parity()
        {
            CurrencyParameterSensitivities pvSensiRecLong  = RATE_PROVIDER.parameterSensitivity(PRICER_SWAPTION.presentValueSensitivityRatesStickyStrike(SWAPTION_REC_LONG, RATE_PROVIDER, VOLS).build());
            CurrencyParameterSensitivities pvSensiRecShort = RATE_PROVIDER.parameterSensitivity(PRICER_SWAPTION.presentValueSensitivityRatesStickyStrike(SWAPTION_REC_SHORT, RATE_PROVIDER, VOLS).build());
            CurrencyParameterSensitivities pvSensiPayLong  = RATE_PROVIDER.parameterSensitivity(PRICER_SWAPTION.presentValueSensitivityRatesStickyStrike(SWAPTION_PAY_LONG, RATE_PROVIDER, VOLS).build());
            CurrencyParameterSensitivities pvSensiPayShort = RATE_PROVIDER.parameterSensitivity(PRICER_SWAPTION.presentValueSensitivityRatesStickyStrike(SWAPTION_PAY_SHORT, RATE_PROVIDER, VOLS).build());

            assertTrue(pvSensiRecLong.equalWithTolerance(pvSensiRecShort.multipliedBy(-1d), NOTIONAL * TOL));
            assertTrue(pvSensiPayLong.equalWithTolerance(pvSensiPayShort.multipliedBy(-1d), NOTIONAL * TOL));

            double forward = PRICER_SWAP.parRate(RSWAP_REC, RATE_PROVIDER);
            PointSensitivityBuilder forwardSensi = PRICER_SWAP.parRateSensitivity(RSWAP_REC, RATE_PROVIDER);
            double annuityCash      = PRICER_SWAP.LegPricer.annuityCash(RSWAP_REC.getLegs(SwapLegType.FIXED).get(0), forward);
            double annuityCashDeriv = PRICER_SWAP.LegPricer.annuityCashDerivative(RSWAP_REC.getLegs(SwapLegType.FIXED).get(0), forward).getDerivative(0);
            double discount         = RATE_PROVIDER.discountFactor(USD, SETTLE_DATE);
            PointSensitivityBuilder        discountSensi = RATE_PROVIDER.discountFactors(USD).zeroRatePointSensitivity(SETTLE_DATE);
            PointSensitivities             expecedPoint  = discountSensi.multipliedBy(annuityCash * (forward - STRIKE)).combinedWith(forwardSensi.multipliedBy(discount * annuityCash + discount * annuityCashDeriv * (forward - STRIKE))).build();
            CurrencyParameterSensitivities expected      = RATE_PROVIDER.parameterSensitivity(expecedPoint);

            assertTrue(expected.equalWithTolerance(pvSensiPayLong.combinedWith(pvSensiRecLong.multipliedBy(-1d)), NOTIONAL * TOL));
            assertTrue(expected.equalWithTolerance(pvSensiRecShort.combinedWith(pvSensiPayShort.multipliedBy(-1d)), NOTIONAL * TOL));
        }
        /// <summary>
        /// Calculates the present value sensitivity of the product.
        /// <para>
        /// The present value sensitivity of the product is the sensitivity of present value to the underlying curves.
        ///
        /// </para>
        /// </summary>
        /// <param name="cdsIndex">  the product </param>
        /// <param name="ratesProvider">  the rates provider </param>
        /// <param name="referenceDate">  the reference date </param>
        /// <param name="refData">  the reference data </param>
        /// <returns> the present value sensitivity </returns>
        public virtual PointSensitivityBuilder presentValueSensitivity(ResolvedCdsIndex cdsIndex, CreditRatesProvider ratesProvider, LocalDate referenceDate, ReferenceData refData)
        {
            if (isExpired(cdsIndex, ratesProvider))
            {
                return(PointSensitivityBuilder.none());
            }
            ResolvedCds cds                = cdsIndex.toSingleNameCds();
            LocalDate   stepinDate         = cds.StepinDateOffset.adjust(ratesProvider.ValuationDate, refData);
            LocalDate   effectiveStartDate = cds.calculateEffectiveStartDate(stepinDate);
            double      recoveryRate       = underlyingPricer.recoveryRate(cds, ratesProvider);
            Triple <CreditDiscountFactors, LegalEntitySurvivalProbabilities, double> rates = reduceDiscountFactors(cds, ratesProvider);

            double signedNotional = cds.BuySell.normalize(cds.Notional);
            PointSensitivityBuilder protectionLegSensi = underlyingPricer.protectionLegSensitivity(cds, rates.First, rates.Second, referenceDate, effectiveStartDate, recoveryRate);

            protectionLegSensi = protectionLegSensi.multipliedBy(signedNotional * rates.Third);
            PointSensitivityBuilder riskyAnnuitySensi = underlyingPricer.riskyAnnuitySensitivity(cds, rates.First, rates.Second, referenceDate, stepinDate, effectiveStartDate);

            riskyAnnuitySensi = riskyAnnuitySensi.multipliedBy(-cds.FixedRate * signedNotional * rates.Third);

            return(protectionLegSensi.combinedWith(riskyAnnuitySensi));
        }
예제 #15
0
        //-------------------------------------------------------------------------
        /// <summary>
        /// Calculates the present value sensitivity of the swaption product.
        /// <para>
        /// The present value sensitivity of the product is the sensitivity of the present value to
        /// the underlying curves.
        ///
        /// </para>
        /// </summary>
        /// <param name="swaption">  the product </param>
        /// <param name="ratesProvider">  the rates provider </param>
        /// <param name="hwProvider">  the Hull-White model parameter provider </param>
        /// <returns> the point sensitivity to the rate curves </returns>
        public virtual PointSensitivityBuilder presentValueSensitivityRates(ResolvedSwaption swaption, RatesProvider ratesProvider, HullWhiteOneFactorPiecewiseConstantParametersProvider hwProvider)
        {
            validate(swaption, ratesProvider, hwProvider);
            ResolvedSwap swap       = swaption.Underlying;
            LocalDate    expiryDate = swaption.ExpiryDate;

            if (expiryDate.isBefore(ratesProvider.ValuationDate))
            {     // Option has expired already
                return(PointSensitivityBuilder.none());
            }
            ImmutableMap <Payment, PointSensitivityBuilder> cashFlowEquivSensi = CashFlowEquivalentCalculator.cashFlowEquivalentAndSensitivitySwap(swap, ratesProvider);
            ImmutableList <Payment> list = cashFlowEquivSensi.Keys.asList();
            ImmutableList <PointSensitivityBuilder> listSensi = cashFlowEquivSensi.values().asList();
            int nPayments = list.size();

            double[] alpha = new double[nPayments];
            double[] discountedCashFlow = new double[nPayments];
            for (int loopcf = 0; loopcf < nPayments; loopcf++)
            {
                Payment payment = list.get(loopcf);
                alpha[loopcf] = hwProvider.alpha(ratesProvider.ValuationDate, expiryDate, expiryDate, payment.Date);
                discountedCashFlow[loopcf] = paymentPricer.presentValueAmount(payment, ratesProvider);
            }
            double omega = (swap.getLegs(SwapLegType.FIXED).get(0).PayReceive.Pay ? -1d : 1d);
            double kappa = computeKappa(hwProvider, discountedCashFlow, alpha, omega);
            PointSensitivityBuilder point = PointSensitivityBuilder.none();

            for (int loopcf = 0; loopcf < nPayments; loopcf++)
            {
                Payment payment = list.get(loopcf);
                double  cdf     = NORMAL.getCDF(omega * (kappa + alpha[loopcf]));
                point = point.combinedWith(paymentPricer.presentValueSensitivity(payment, ratesProvider).multipliedBy(cdf));
                if (!listSensi.get(loopcf).Equals(PointSensitivityBuilder.none()))
                {
                    point = point.combinedWith(listSensi.get(loopcf).multipliedBy(cdf * ratesProvider.discountFactor(payment.Currency, payment.Date)));
                }
            }
            return(swaption.LongShort.Long ? point : point.multipliedBy(-1d));
        }
예제 #16
0
        internal virtual PointSensitivityBuilder riskyAnnuitySensitivity(ResolvedCds cds, CreditDiscountFactors discountFactors, LegalEntitySurvivalProbabilities survivalProbabilities, LocalDate referenceDate, LocalDate stepinDate, LocalDate effectiveStartDate)
        {
            double pv = 0d;
            PointSensitivityBuilder pvSensi = PointSensitivityBuilder.none();

            foreach (CreditCouponPaymentPeriod coupon in cds.PaymentPeriods)
            {
                if (stepinDate.isBefore(coupon.EndDate))
                {
                    double q = survivalProbabilities.survivalProbability(coupon.EffectiveEndDate);
                    PointSensitivityBuilder qSensi = survivalProbabilities.zeroRatePointSensitivity(coupon.EffectiveEndDate);
                    double p = discountFactors.discountFactor(coupon.PaymentDate);
                    PointSensitivityBuilder pSensi = discountFactors.zeroRatePointSensitivity(coupon.PaymentDate);
                    pv     += coupon.YearFraction * p * q;
                    pvSensi = pvSensi.combinedWith(pSensi.multipliedBy(coupon.YearFraction * q).combinedWith(qSensi.multipliedBy(coupon.YearFraction * p)));
                }
            }

            if (cds.PaymentOnDefault.AccruedInterest)
            {
                // This is needed so that the code is consistent with ISDA C when the Markit `fix' is used.
                LocalDate   start = cds.PaymentPeriods.size() == 1 ? effectiveStartDate : cds.AccrualStartDate;
                DoubleArray integrationSchedule = DoublesScheduleGenerator.getIntegrationsPoints(discountFactors.relativeYearFraction(start), discountFactors.relativeYearFraction(cds.ProtectionEndDate), discountFactors.ParameterKeys, survivalProbabilities.ParameterKeys);
                foreach (CreditCouponPaymentPeriod coupon in cds.PaymentPeriods)
                {
                    Pair <double, PointSensitivityBuilder> pvAndSensi = singlePeriodAccrualOnDefaultSensitivity(coupon, effectiveStartDate, integrationSchedule, discountFactors, survivalProbabilities);
                    pv     += pvAndSensi.First;
                    pvSensi = pvSensi.combinedWith(pvAndSensi.Second);
                }
            }

            double df = discountFactors.discountFactor(referenceDate);
            PointSensitivityBuilder dfSensi = discountFactors.zeroRatePointSensitivity(referenceDate).multipliedBy(-pv / (df * df));

            pvSensi = pvSensi.multipliedBy(1d / df);

            return(dfSensi.combinedWith(pvSensi));
        }
예제 #17
0
        /// <summary>
        /// Calculates the par rate curve sensitivity for a swap 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.
        /// All the payments in that leg should be fixed payments with 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 rate curve sensitivity of the swap product </returns>
        public virtual PointSensitivityBuilder parRateSensitivity(ResolvedSwap swap, RatesProvider provider)
        {
            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);
            double pvbpFixedLeg     = legPricer.pvbp(fixedLeg, provider);
            // Backward sweep
            double otherLegsConvertedPvBar                 = -1.0d / pvbpFixedLeg;
            double fixedLegEventsPvBar                     = -1.0d / pvbpFixedLeg;
            double pvbpFixedLegBar                         = (otherLegsConvertedPv + fixedLegEventsPv) / (pvbpFixedLeg * pvbpFixedLeg);
            PointSensitivityBuilder pvbpFixedLegDr         = legPricer.pvbpSensitivity(fixedLeg, provider);
            PointSensitivityBuilder fixedLegEventsPvDr     = legPricer.presentValueSensitivityEventsInternal(fixedLeg, provider);
            PointSensitivityBuilder otherLegsConvertedPvDr = PointSensitivityBuilder.none();

            foreach (ResolvedSwapLeg leg in swap.Legs)
            {
                if (leg != fixedLeg)
                {
                    PointSensitivityBuilder pvLegDr = legPricer.presentValueSensitivity(leg, provider).multipliedBy(provider.fxRate(leg.Currency, ccyFixedLeg));
                    otherLegsConvertedPvDr = otherLegsConvertedPvDr.combinedWith(pvLegDr);
                }
            }
            otherLegsConvertedPvDr = otherLegsConvertedPvDr.withCurrency(ccyFixedLeg);
            return(pvbpFixedLegDr.multipliedBy(pvbpFixedLegBar).combinedWith(fixedLegEventsPvDr.multipliedBy(fixedLegEventsPvBar)).combinedWith(otherLegsConvertedPvDr.multipliedBy(otherLegsConvertedPvBar)));
        }
예제 #18
0
        //-------------------------------------------------------------------------
        public virtual void test_multipliedBy()
        {
            PointSensitivityBuilder @base = PointSensitivityBuilder.none();

            assertSame(@base.multipliedBy(2.0), @base);     // no effect
        }