/// <summary>
        /// Calibrate trinomial tree to Black volatilities.
        /// <para>
        /// {@code timeToExpiry} determines the coverage of the resulting trinomial tree.
        /// Thus this should match the time to expiry of the target instrument to price using the calibrated tree.
        ///
        /// </para>
        /// </summary>
        /// <param name="timeToExpiry">  the time to expiry </param>
        /// <param name="currencyPair">  the currency pair </param>
        /// <param name="ratesProvider">  the rates provider </param>
        /// <param name="volatilities">  the Black volatility provider </param>
        /// <returns> the trinomial tree data </returns>
        public virtual RecombiningTrinomialTreeData calibrateTrinomialTree(double timeToExpiry, CurrencyPair currencyPair, RatesProvider ratesProvider, BlackFxOptionVolatilities volatilities)
        {
            validate(ratesProvider, volatilities);
            if (timeToExpiry <= 0d)
            {
                throw new System.ArgumentException("option expired");
            }
            Currency        ccyBase                = currencyPair.Base;
            Currency        ccyCounter             = currencyPair.Counter;
            double          todayFx                = ratesProvider.fxRate(currencyPair);
            DiscountFactors baseDiscountFactors    = ratesProvider.discountFactors(ccyBase);
            DiscountFactors counterDiscountFactors = ratesProvider.discountFactors(ccyCounter);

            System.Func <double, double> interestRate = (double?t) =>
            {
                return(counterDiscountFactors.zeroRate(t.Value));
            };
            System.Func <double, double> dividendRate = (double?t) =>
            {
                return(baseDiscountFactors.zeroRate(t.Value));
            };
            System.Func <DoublesPair, double> impliedVolSurface = (DoublesPair tk) =>
            {
                double dfBase    = baseDiscountFactors.discountFactor(tk.First);
                double dfCounter = counterDiscountFactors.discountFactor(tk.First);
                double forward   = todayFx * dfBase / dfCounter;
                return(volatilities.volatility(currencyPair, tk.First, tk.Second, forward));
            };
            ImpliedTrinomialTreeLocalVolatilityCalculator localVol = new ImpliedTrinomialTreeLocalVolatilityCalculator(nSteps, timeToExpiry);

            return(localVol.calibrateImpliedVolatility(impliedVolSurface, todayFx, interestRate, dividendRate));
        }
Exemplo n.º 2
0
        public virtual PointSensitivityBuilder pvbpSensitivity(RatePaymentPeriod paymentPeriod, RatesProvider provider)
        {
            ArgChecker.isTrue(!paymentPeriod.FxReset.Present, "FX reset is not supported");
            int accPeriodCount = paymentPeriod.AccrualPeriods.size();

            ArgChecker.isTrue(accPeriodCount == 1 || paymentPeriod.CompoundingMethod.Equals(CompoundingMethod.FLAT), "Only one accrued period or Flat compounding supported");
            // no compounding
            if (accPeriodCount == 1)
            {
                RateAccrualPeriod accrualPeriod   = paymentPeriod.AccrualPeriods.get(0);
                DiscountFactors   discountFactors = provider.discountFactors(paymentPeriod.Currency);
                return(discountFactors.zeroRatePointSensitivity(paymentPeriod.PaymentDate).multipliedBy(accrualPeriod.YearFraction * paymentPeriod.Notional));
            }
            else
            {
                // Flat compounding
                switch (paymentPeriod.CompoundingMethod)
                {
                case FLAT:
                    return(pvbpSensitivtyCompoundedFlat(paymentPeriod, provider));

                default:
                    throw new System.NotSupportedException("PVBP not implemented yet for non FLAT compounding");
                }
            }
        }
        //-------------------------------------------------------------------------
        /// <summary>
        /// Calculates the present value sensitivity of the swaption product to the rate curves.
        /// <para>
        /// The present value sensitivity is computed in a "sticky model parameter" style, i.e. the sensitivity to the
        /// curve nodes with the SABR model parameters unchanged. This sensitivity does not include a potential
        /// re-calibration of the model parameters to the raw market data.
        ///
        /// </para>
        /// </summary>
        /// <param name="swaption">  the swaption product </param>
        /// <param name="ratesProvider">  the rates provider </param>
        /// <param name="swaptionVolatilities">  the volatilities </param>
        /// <returns> the point sensitivity to the rate curves </returns>
        public virtual PointSensitivityBuilder presentValueSensitivityRatesStickyModel(ResolvedSwaption swaption, RatesProvider ratesProvider, SabrSwaptionVolatilities swaptionVolatilities)
        {
            validate(swaption, ratesProvider, swaptionVolatilities);
            ZonedDateTime   expiryDateTime = swaption.Expiry;
            double          expiry         = swaptionVolatilities.relativeTime(expiryDateTime);
            ResolvedSwap    underlying     = swaption.Underlying;
            ResolvedSwapLeg fixedLeg       = this.fixedLeg(underlying);

            if (expiry < 0d)
            {     // Option has expired already
                return(PointSensitivityBuilder.none());
            }
            double                  forward           = SwapPricer.parRate(underlying, ratesProvider);
            ValueDerivatives        annuityDerivative = SwapPricer.LegPricer.annuityCashDerivative(fixedLeg, forward);
            double                  annuityCash       = annuityDerivative.Value;
            double                  annuityCashDr     = annuityDerivative.getDerivative(0);
            LocalDate               settlementDate    = ((CashSwaptionSettlement)swaption.SwaptionSettlement).SettlementDate;
            double                  discountSettle    = ratesProvider.discountFactor(fixedLeg.Currency, settlementDate);
            double                  strike            = calculateStrike(fixedLeg);
            double                  tenor             = swaptionVolatilities.tenor(fixedLeg.StartDate, fixedLeg.EndDate);
            double                  shift             = swaptionVolatilities.shift(expiry, tenor);
            ValueDerivatives        volatilityAdj     = swaptionVolatilities.volatilityAdjoint(expiry, tenor, strike, forward);
            bool                    isCall            = fixedLeg.PayReceive.Pay;
            double                  shiftedForward    = forward + shift;
            double                  shiftedStrike     = strike + shift;
            double                  price             = BlackFormulaRepository.price(shiftedForward, shiftedStrike, expiry, volatilityAdj.Value, isCall);
            double                  delta             = BlackFormulaRepository.delta(shiftedForward, shiftedStrike, expiry, volatilityAdj.Value, isCall);
            double                  vega                = BlackFormulaRepository.vega(shiftedForward, shiftedStrike, expiry, volatilityAdj.Value);
            PointSensitivityBuilder forwardSensi        = SwapPricer.parRateSensitivity(underlying, ratesProvider);
            PointSensitivityBuilder discountSettleSensi = ratesProvider.discountFactors(fixedLeg.Currency).zeroRatePointSensitivity(settlementDate);
            double                  sign                = swaption.LongShort.sign();

            return(forwardSensi.multipliedBy(sign * discountSettle * (annuityCash * (delta + vega * volatilityAdj.getDerivative(0)) + annuityCashDr * price)).combinedWith(discountSettleSensi.multipliedBy(sign * annuityCash * price)));
        }
        //-------------------------------------------------------------------------
        /// <summary>
        /// Calculates the deposit fair rate given the start and end time and the accrual factor.
        /// <para>
        /// When the deposit has already started the number may not be meaningful as the remaining period
        /// is not in line with the accrual factor.
        ///
        /// </para>
        /// </summary>
        /// <param name="deposit">  the product </param>
        /// <param name="provider">  the rates provider </param>
        /// <returns> the par rate </returns>
        public virtual double parRate(ResolvedTermDeposit deposit, RatesProvider provider)
        {
            Currency        currency        = deposit.Currency;
            DiscountFactors discountFactors = provider.discountFactors(currency);
            double          dfStart         = discountFactors.discountFactor(deposit.StartDate);
            double          dfEnd           = discountFactors.discountFactor(deposit.EndDate);
            double          accrualFactor   = deposit.YearFraction;

            return((dfStart / dfEnd - 1d) / accrualFactor);
        }
        /// <summary>
        /// Calculates the present value sensitivity of the Ibor fixing product.
        /// <para>
        /// The present value sensitivity of the product is the sensitivity of the present value to
        /// the underlying curves.
        ///
        /// </para>
        /// </summary>
        /// <param name="deposit">  the product </param>
        /// <param name="provider">  the rates provider </param>
        /// <returns> the point sensitivity of the present value </returns>
        public virtual PointSensitivities presentValueSensitivity(ResolvedIborFixingDeposit deposit, RatesProvider provider)
        {
            double          forwardRate     = this.forwardRate(deposit, provider);
            DiscountFactors discountFactors = provider.discountFactors(deposit.Currency);
            double          discountFactor  = discountFactors.discountFactor(deposit.EndDate);
            // sensitivity
            PointSensitivityBuilder sensiFwd = forwardRateSensitivity(deposit, provider).multipliedBy(-discountFactor * deposit.Notional * deposit.YearFraction);
            PointSensitivityBuilder sensiDsc = discountFactors.zeroRatePointSensitivity(deposit.EndDate).multipliedBy(deposit.Notional * deposit.YearFraction * (deposit.FixedRate - forwardRate));

            return(sensiFwd.combinedWith(sensiDsc).build());
        }
        public virtual PointSensitivityBuilder presentValueSensitivity(FxResetNotionalExchange @event, RatesProvider provider)
        {
            DiscountFactors         discountFactors = provider.discountFactors(@event.Currency);
            PointSensitivityBuilder sensiDsc        = discountFactors.zeroRatePointSensitivity(@event.PaymentDate);

            sensiDsc = sensiDsc.multipliedBy(forecastValue(@event, provider));
            PointSensitivityBuilder sensiFx = forecastValueSensitivity(@event, provider);

            sensiFx = sensiFx.multipliedBy(discountFactors.discountFactor(@event.PaymentDate));
            return(sensiDsc.combinedWith(sensiFx));
        }
        //-------------------------------------------------------------------------
        /// <summary>
        /// Calculates the price sensitivity of the deliverable swap futures product.
        /// <para>
        /// The price sensitivity of the product is the sensitivity of the price to the underlying curves.
        ///
        /// </para>
        /// </summary>
        /// <param name="future">  the future </param>
        /// <param name="ratesProvider">  the rates provider </param>
        /// <returns> the price curve sensitivity of the product </returns>
        public PointSensitivities priceSensitivity(ResolvedDsf future, RatesProvider ratesProvider)
        {
            ResolvedSwap            swap        = future.UnderlyingSwap;
            Currency                currency    = future.Currency;
            double                  pvSwap      = swapPricer.presentValue(swap, currency, ratesProvider).Amount;
            double                  dfInv       = 1d / ratesProvider.discountFactor(currency, future.DeliveryDate);
            PointSensitivityBuilder sensiSwapPv = swapPricer.presentValueSensitivity(swap, ratesProvider).multipliedBy(dfInv);
            PointSensitivityBuilder sensiDf     = ratesProvider.discountFactors(currency).zeroRatePointSensitivity(future.DeliveryDate).multipliedBy(-pvSwap * dfInv * dfInv);

            return(sensiSwapPv.combinedWith(sensiDf).build());
        }
        /// <summary>
        /// Calculates the par spread curve sensitivity.
        /// <para>
        /// The calculation is based on both of initial and final payments.
        /// Thus the number resulting may not be meaningful when deposit has already started and only the final
        /// payment remains (no initial payment).
        ///
        /// </para>
        /// </summary>
        /// <param name="deposit">  the product </param>
        /// <param name="provider">  the rates provider </param>
        /// <returns> the par spread curve sensitivity </returns>
        public virtual PointSensitivities parSpreadSensitivity(ResolvedTermDeposit deposit, RatesProvider provider)
        {
            Currency                currency         = deposit.Currency;
            double                  accrualFactorInv = 1d / deposit.YearFraction;
            double                  dfStart          = provider.discountFactor(currency, deposit.StartDate);
            double                  dfEndInv         = 1d / provider.discountFactor(currency, deposit.EndDate);
            DiscountFactors         discountFactors  = provider.discountFactors(currency);
            PointSensitivityBuilder sensStart        = discountFactors.zeroRatePointSensitivity(deposit.StartDate).multipliedBy(dfEndInv * accrualFactorInv);
            PointSensitivityBuilder sensEnd          = discountFactors.zeroRatePointSensitivity(deposit.EndDate).multipliedBy(-dfStart * dfEndInv * dfEndInv * accrualFactorInv);

            return(sensStart.combinedWith(sensEnd).build());
        }
        /// <summary>
        /// Calculates the present value sensitivity of the FRA product.
        /// <para>
        /// The present value sensitivity of the product is the sensitivity of the present value to
        /// the underlying curves.
        ///
        /// </para>
        /// </summary>
        /// <param name="fra">  the product </param>
        /// <param name="provider">  the rates provider </param>
        /// <returns> the point sensitivity of the present value </returns>
        public virtual PointSensitivities presentValueSensitivity(ResolvedFra fra, RatesProvider provider)
        {
            DiscountFactors         discountFactors = provider.discountFactors(fra.Currency);
            double                  df         = discountFactors.discountFactor(fra.PaymentDate);
            double                  notional   = fra.Notional;
            double                  unitAmount = this.unitAmount(fra, provider);
            double                  derivative = this.derivative(fra, provider);
            PointSensitivityBuilder iborSens   = forwardRateSensitivity(fra, provider).multipliedBy(derivative * df * notional);
            PointSensitivityBuilder discSens   = discountFactors.zeroRatePointSensitivity(fra.PaymentDate).multipliedBy(unitAmount * notional);

            return(iborSens.withCurrency(fra.Currency).combinedWith(discSens).build());
        }
        /// <summary>
        /// Calculates the present value sensitivity by discounting the final cash flow (nominal + interest)
        /// and the initial payment (initial amount).
        /// </summary>
        /// <param name="deposit">  the product </param>
        /// <param name="provider">  the rates provider </param>
        /// <returns> the point sensitivity of the present value </returns>
        public virtual PointSensitivities presentValueSensitivity(ResolvedTermDeposit deposit, RatesProvider provider)
        {
            Currency currency = deposit.Currency;
            // backward sweep
            double dfEndBar   = deposit.Notional + deposit.Interest;
            double dfStartBar = -initialAmount(deposit, provider);
            // sensitivity
            DiscountFactors         discountFactors = provider.discountFactors(currency);
            PointSensitivityBuilder sensStart       = discountFactors.zeroRatePointSensitivity(deposit.StartDate).multipliedBy(dfStartBar);
            PointSensitivityBuilder sensEnd         = discountFactors.zeroRatePointSensitivity(deposit.EndDate).multipliedBy(dfEndBar);

            return(sensStart.combinedWith(sensEnd).build());
        }
Exemplo n.º 11
0
        //-------------------------------------------------------------------------
        public virtual PointSensitivityBuilder presentValueSensitivity(RatePaymentPeriod period, RatesProvider provider)
        {
            Currency                ccy             = period.Currency;
            DiscountFactors         discountFactors = provider.discountFactors(ccy);
            LocalDate               paymentDate     = period.PaymentDate;
            double                  df = discountFactors.discountFactor(paymentDate);
            PointSensitivityBuilder forecastSensitivity = forecastValueSensitivity(period, provider);

            forecastSensitivity = forecastSensitivity.multipliedBy(df);
            double forecastValue = this.forecastValue(period, provider);
            PointSensitivityBuilder dscSensitivity = discountFactors.zeroRatePointSensitivity(paymentDate);

            dscSensitivity = dscSensitivity.multipliedBy(forecastValue);
            return(forecastSensitivity.combinedWith(dscSensitivity));
        }
        //-------------------------------------------------------------------------
        /// <summary>
        /// Calculates the present value by discounting the final cash flow (nominal + interest)
        /// and the initial payment (initial amount).
        /// <para>
        /// The present value of the product is the value on the valuation date.
        ///
        /// </para>
        /// </summary>
        /// <param name="deposit">  the product </param>
        /// <param name="provider">  the rates provider </param>
        /// <returns> the present value of the product </returns>
        public virtual CurrencyAmount presentValue(ResolvedTermDeposit deposit, RatesProvider provider)
        {
            Currency currency = deposit.Currency;

            if (provider.ValuationDate.isAfter(deposit.EndDate))
            {
                return(CurrencyAmount.of(currency, 0.0d));
            }
            DiscountFactors discountFactors = provider.discountFactors(currency);
            double          dfStart         = discountFactors.discountFactor(deposit.StartDate);
            double          dfEnd           = discountFactors.discountFactor(deposit.EndDate);
            double          pvStart         = initialAmount(deposit, provider) * dfStart;
            double          pvEnd           = (deposit.Notional + deposit.Interest) * dfEnd;
            double          pv = pvEnd - pvStart;

            return(CurrencyAmount.of(currency, pv));
        }
Exemplo n.º 13
0
        /// <summary>
        /// Calculates the par spread sensitivity to the curves.
        /// <para>
        /// The sensitivity is reported in the counter currency of the product, but is actually dimensionless.
        ///
        /// </para>
        /// </summary>
        /// <param name="swap">  the product </param>
        /// <param name="provider">  the rates provider </param>
        /// <returns> the spread curve sensitivity </returns>
        public virtual PointSensitivities parSpreadSensitivity(ResolvedFxSwap swap, RatesProvider provider)
        {
            Payment             counterPaymentNear = swap.NearLeg.CounterCurrencyPayment;
            MultiCurrencyAmount pv = presentValue(swap, provider);
            double pvCounterCcy    = pv.convertedTo(counterPaymentNear.Currency, provider).Amount;
            double dfEnd           = provider.discountFactor(counterPaymentNear.Currency, swap.FarLeg.PaymentDate);
            double notionalBaseCcy = swap.NearLeg.BaseCurrencyPayment.Amount;
            double ps = -pvCounterCcy / (notionalBaseCcy * dfEnd);
            // backward sweep
            double psBar                       = 1d;
            double pvCounterCcyBar             = -1d / (notionalBaseCcy * dfEnd) * psBar;
            double dfEndBar                    = -ps / dfEnd * psBar;
            ZeroRateSensitivity ddfEnddr       = provider.discountFactors(counterPaymentNear.Currency).zeroRatePointSensitivity(swap.FarLeg.PaymentDate);
            PointSensitivities  result         = ddfEnddr.multipliedBy(dfEndBar).build();
            PointSensitivities  dpvdr          = presentValueSensitivity(swap, provider);
            PointSensitivities  dpvdrConverted = dpvdr.convertedTo(counterPaymentNear.Currency, provider);

            return(result.combinedWith(dpvdrConverted.multipliedBy(pvCounterCcyBar)));
        }
        /// <summary>
        /// Calculates the present value curve sensitivity of the NDF product.
        /// <para>
        /// The present value sensitivity of the product is the sensitivity of the present value to
        /// the underlying curves.
        ///
        /// </para>
        /// </summary>
        /// <param name="ndf">  the product </param>
        /// <param name="provider">  the rates provider </param>
        /// <returns> the point sensitivity of the present value </returns>
        public virtual PointSensitivities presentValueSensitivity(ResolvedFxNdf ndf, RatesProvider provider)
        {
            if (provider.ValuationDate.isAfter(ndf.PaymentDate))
            {
                return(PointSensitivities.empty());
            }
            Currency ccySettle               = ndf.SettlementCurrency;
            Currency ccyOther                = ndf.NonDeliverableCurrency;
            double   notionalSettle          = ndf.SettlementNotional;
            double   agreedRate              = ndf.AgreedFxRate.fxRate(ccySettle, ccyOther);
            double   forwardRate             = provider.fxIndexRates(ndf.Index).rate(ndf.Observation, ccySettle);
            double   dfSettle                = provider.discountFactor(ccySettle, ndf.PaymentDate);
            double   ratio                   = agreedRate / forwardRate;
            double   dscBar                  = (1d - ratio) * notionalSettle;
            PointSensitivityBuilder sensiDsc = provider.discountFactors(ccySettle).zeroRatePointSensitivity(ndf.PaymentDate).multipliedBy(dscBar);
            double forwardRateBar            = dfSettle * notionalSettle * ratio / forwardRate;
            PointSensitivityBuilder sensiFx  = provider.fxIndexRates(ndf.Index).ratePointSensitivity(ndf.Observation, ccySettle).withCurrency(ccySettle).multipliedBy(forwardRateBar);

            return(sensiDsc.combinedWith(sensiFx).build());
        }
Exemplo n.º 15
0
        // sensitivity to the spread for a payment period with FLAT compounding type
        private PointSensitivityBuilder pvbpSensitivtyCompoundedFlat(RatePaymentPeriod paymentPeriod, RatesProvider provider)
        {
            Currency ccy   = paymentPeriod.Currency;
            int      nbCmp = paymentPeriod.AccrualPeriods.size();

            double[] rate = paymentPeriod.AccrualPeriods.Select(ap => rawRate(ap, provider)).ToArray();
            double   df   = provider.discountFactor(ccy, paymentPeriod.PaymentDate);
            double   rB1  = 1.0;

            double[] cpaAccumulatedB1 = new double[nbCmp + 1];
            cpaAccumulatedB1[nbCmp] = paymentPeriod.Notional * df * rB1;
            for (int j = nbCmp - 1; j >= 0; j--)
            {
                RateAccrualPeriod accrualPeriod = paymentPeriod.AccrualPeriods.get(j);
                cpaAccumulatedB1[j] = (1.0d + accrualPeriod.YearFraction * rate[j] * accrualPeriod.Gearing) * cpaAccumulatedB1[j + 1];
            }
            // backward sweep
            double pvbpB2 = 1.0d;

            double[] cpaAccumulatedB1B2 = new double[nbCmp + 1];
            double[] rateB2             = new double[nbCmp];
            for (int j = 0; j < nbCmp; j++)
            {
                RateAccrualPeriod accrualPeriod = paymentPeriod.AccrualPeriods.get(j);
                cpaAccumulatedB1B2[j + 1] += accrualPeriod.YearFraction * pvbpB2;
                cpaAccumulatedB1B2[j + 1] += (1.0d + accrualPeriod.YearFraction * rate[j] * accrualPeriod.Gearing) * cpaAccumulatedB1B2[j];
                rateB2[j] += accrualPeriod.YearFraction * accrualPeriod.Gearing * cpaAccumulatedB1[j + 1] * cpaAccumulatedB1B2[j];
            }
            double dfB2 = paymentPeriod.Notional * rB1 * cpaAccumulatedB1B2[nbCmp];
            PointSensitivityBuilder dfdr   = provider.discountFactors(ccy).zeroRatePointSensitivity(paymentPeriod.PaymentDate);
            PointSensitivityBuilder pvbpdr = dfdr.multipliedBy(dfB2);

            for (int j = 0; j < nbCmp; j++)
            {
                RateAccrualPeriod accrualPeriod = paymentPeriod.AccrualPeriods.get(j);
                pvbpdr = pvbpdr.combinedWith(rateComputationFn.rateSensitivity(accrualPeriod.RateComputation, accrualPeriod.StartDate, accrualPeriod.EndDate, provider).multipliedBy(rateB2[j]));
            }
            return(pvbpdr);
        }