Beispiel #1
0
        /// <summary>
        /// Calculates the present value of the swaption product.
        /// <para>
        /// The result is expressed using the currency of the swapion.
        ///
        /// </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 present value </returns>
        public virtual CurrencyAmount presentValue(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(CurrencyAmount.of(swap.Legs.get(0).Currency, 0d));
            }
            ResolvedSwapLeg cashFlowEquiv = CashFlowEquivalentCalculator.cashFlowEquivalentSwap(swap, ratesProvider);
            int             nPayments     = cashFlowEquiv.PaymentEvents.size();

            double[] alpha = new double[nPayments];
            double[] discountedCashFlow = new double[nPayments];
            for (int loopcf = 0; loopcf < nPayments; loopcf++)
            {
                NotionalExchange payment      = (NotionalExchange)cashFlowEquiv.PaymentEvents.get(loopcf);
                LocalDate        maturityDate = payment.PaymentDate;
                alpha[loopcf] = hwProvider.alpha(ratesProvider.ValuationDate, expiryDate, expiryDate, maturityDate);
                discountedCashFlow[loopcf] = paymentPricer.presentValueAmount(payment.Payment, ratesProvider);
            }
            double omega = (swap.getLegs(SwapLegType.FIXED).get(0).PayReceive.Pay ? -1d : 1d);
            double kappa = computeKappa(hwProvider, discountedCashFlow, alpha, omega);
            double pv    = 0.0;

            for (int loopcf = 0; loopcf < nPayments; loopcf++)
            {
                pv += discountedCashFlow[loopcf] * NORMAL.getCDF(omega * (kappa + alpha[loopcf]));
            }
            return(CurrencyAmount.of(cashFlowEquiv.Currency, pv * (swaption.LongShort.Long ? 1d : -1d)));
        }
        /// <summary>
        /// Validates that the swaption is single currency cash par-yield.
        /// </summary>
        /// <param name="swaption">  the swaption </param>
        protected internal virtual void validateSwaption(ResolvedSwaption swaption)
        {
            ArgChecker.isFalse(swaption.Underlying.CrossCurrency, "Underlying swap must be single currency");
            ArgChecker.isTrue(swaption.SwaptionSettlement.SettlementType.Equals(SettlementType.CASH), "Swaption must be cash settlement");
            CashSwaptionSettlement cashSettle = (CashSwaptionSettlement)swaption.SwaptionSettlement;

            ArgChecker.isTrue(cashSettle.Method.Equals(CashSwaptionSettlementMethod.PAR_YIELD), "Cash settlement method must be par yield");
        }
        //-------------------------------------------------------------------------
        /// <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));
        }
        //-------------------------------------------------------------------------
        /// <summary>
        /// Computes the implied volatility of the swaption.
        /// </summary>
        /// <param name="swaption">  the swaption </param>
        /// <param name="ratesProvider">  the rates provider </param>
        /// <param name="swaptionVolatilities">  the volatilities </param>
        /// <returns> the implied volatility associated with the swaption </returns>
        public virtual double impliedVolatility(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);

            ArgChecker.isTrue(expiry >= 0d, "Option must be before expiry to compute an implied volatility");
            double forward = SwapPricer.parRate(underlying, ratesProvider);
            double strike  = calculateStrike(fixedLeg);
            double tenor   = swaptionVolatilities.tenor(fixedLeg.StartDate, fixedLeg.EndDate);

            return(swaptionVolatilities.volatility(expiry, tenor, strike, forward));
        }
Beispiel #5
0
        //-------------------------------------------------------------------------
        /// <summary>
        /// Calculates the present value sensitivity to piecewise constant volatility parameters of the Hull-White model.
        /// </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 present value Hull-White model parameter sensitivity of the swaption product </returns>
        public virtual DoubleArray presentValueSensitivityModelParamsHullWhite(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(DoubleArray.EMPTY);
            }
            ResolvedSwapLeg cashFlowEquiv = CashFlowEquivalentCalculator.cashFlowEquivalentSwap(swap, ratesProvider);
            int             nPayments     = cashFlowEquiv.PaymentEvents.size();

            double[]   alpha              = new double[nPayments];
            double[][] alphaAdjoint       = new double[nPayments][];
            double[]   discountedCashFlow = new double[nPayments];
            for (int loopcf = 0; loopcf < nPayments; loopcf++)
            {
                NotionalExchange payment    = (NotionalExchange)cashFlowEquiv.PaymentEvents.get(loopcf);
                ValueDerivatives valueDeriv = hwProvider.alphaAdjoint(ratesProvider.ValuationDate, expiryDate, expiryDate, payment.PaymentDate);
                alpha[loopcf]              = valueDeriv.Value;
                alphaAdjoint[loopcf]       = valueDeriv.Derivatives.toArray();
                discountedCashFlow[loopcf] = paymentPricer.presentValueAmount(payment.Payment, ratesProvider);
            }
            double omega   = (swap.getLegs(SwapLegType.FIXED).get(0).PayReceive.Pay ? -1d : 1d);
            double kappa   = computeKappa(hwProvider, discountedCashFlow, alpha, omega);
            int    nParams = alphaAdjoint[0].Length;

            if (Math.Abs(kappa) > 1d / SMALL)
            {     // decays exponentially
                return(DoubleArray.filled(nParams));
            }
            double[] pvSensi = new double[nParams];
            double   sign    = (swaption.LongShort.Long ? 1d : -1d);

            for (int i = 0; i < nParams; ++i)
            {
                for (int loopcf = 0; loopcf < nPayments; loopcf++)
                {
                    pvSensi[i] += sign * discountedCashFlow[loopcf] * NORMAL.getPDF(omega * (kappa + alpha[loopcf])) * omega * alphaAdjoint[loopcf][i];
                }
            }
            return(DoubleArray.ofUnsafe(pvSensi));
        }
Beispiel #6
0
        //-------------------------------------------------------------------------
        /// <summary>
        /// Computes the implied normal volatility from the present value of a swaption.
        /// <para>
        /// The guess volatility for the start of the root-finding process is 1%.
        ///
        /// </para>
        /// </summary>
        /// <param name="swaption">  the product </param>
        /// <param name="ratesProvider">  the rates provider </param>
        /// <param name="dayCount">  the day-count used to estimate the time between valuation date and swaption expiry </param>
        /// <param name="presentValue">  the present value of the swaption product </param>
        /// <returns> the implied volatility associated with the present value </returns>
        public virtual double impliedVolatilityFromPresentValue(ResolvedSwaption swaption, RatesProvider ratesProvider, DayCount dayCount, double presentValue)
        {
            double sign = swaption.LongShort.sign();

            ArgChecker.isTrue(presentValue * sign > 0, "Present value sign must be in line with the option Long/Short flag ");
            validateSwaption(swaption);
            LocalDate valuationDate = ratesProvider.ValuationDate;
            LocalDate expiryDate    = swaption.ExpiryDate;

            ArgChecker.isTrue(expiryDate.isAfter(valuationDate), "Expiry must be after valuation date to compute an implied volatility");
            double          expiry     = dayCount.yearFraction(valuationDate, expiryDate);
            ResolvedSwap    underlying = swaption.Underlying;
            ResolvedSwapLeg fixedLeg   = this.fixedLeg(underlying);
            double          forward    = SwapPricer.parRate(underlying, ratesProvider);
            double          numeraire  = calculateNumeraire(swaption, fixedLeg, forward, ratesProvider);
            double          strike     = calculateStrike(fixedLeg);
            PutCall         putCall    = PutCall.ofPut(fixedLeg.PayReceive.Receive);

            return(NormalFormulaRepository.impliedVolatility(Math.Abs(presentValue), forward, strike, expiry, 0.01, numeraire, putCall));
        }
        //-------------------------------------------------------------------------
        /// <summary>
        /// Calculates the present value of the swaption.
        /// <para>
        /// The result is expressed using the currency of the swaption.
        ///
        /// </para>
        /// </summary>
        /// <param name="swaption">  the swaption </param>
        /// <param name="ratesProvider">  the rates provider </param>
        /// <param name="swaptionVolatilities">  the volatilities </param>
        /// <returns> the present value </returns>
        public virtual CurrencyAmount presentValue(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(CurrencyAmount.of(fixedLeg.Currency, 0d));
            }
            double  forward    = swapPricer.parRate(underlying, ratesProvider);
            double  numeraire  = calculateNumeraire(swaption, fixedLeg, forward, ratesProvider);
            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      = numeraire * swaptionVolatilities.price(expiry, tenor, putCall, strike, forward, volatility);

            return(CurrencyAmount.of(fixedLeg.Currency, price * swaption.LongShort.sign()));
        }
Beispiel #8
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));
        }
        //-------------------------------------------------------------------------
        /// <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)));
        }
 //-------------------------------------------------------------------------
 /// <summary>
 /// Computes the currency exposure of the swaption.
 /// <para>
 /// This is equivalent to the present value of the swaption.
 ///
 /// </para>
 /// </summary>
 /// <param name="swaption">  the swaption </param>
 /// <param name="ratesProvider">  the rates provider </param>
 /// <param name="swaptionVolatilities">  the volatilities </param>
 /// <returns> the currency exposure </returns>
 public virtual MultiCurrencyAmount currencyExposure(ResolvedSwaption swaption, RatesProvider ratesProvider, SwaptionVolatilities swaptionVolatilities)
 {
     return(MultiCurrencyAmount.of(presentValue(swaption, ratesProvider, swaptionVolatilities)));
 }
        //-------------------------------------------------------------------------
        /// <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 to the SABR model parameters of the swaption product.
        /// <para>
        /// The sensitivity of the present value to the SABR model parameters, alpha, beta, rho and nu.
        ///
        /// </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 SABR model parameters </returns>
        public virtual PointSensitivityBuilder presentValueSensitivityModelParamsSabr(ResolvedSwaption swaption, RatesProvider ratesProvider, SabrSwaptionVolatilities swaptionVolatilities)
        {
            validate(swaption, ratesProvider, swaptionVolatilities);
            double          expiry     = swaptionVolatilities.relativeTime(swaption.Expiry);
            ResolvedSwap    underlying = swaption.Underlying;
            ResolvedSwapLeg fixedLeg   = this.fixedLeg(underlying);
            double          tenor      = swaptionVolatilities.tenor(fixedLeg.StartDate, fixedLeg.EndDate);
            double          shift      = swaptionVolatilities.shift(expiry, tenor);
            double          pvbp       = SwapPricer.LegPricer.pvbp(fixedLeg, ratesProvider);
            double          strike     = SwapPricer.LegPricer.couponEquivalent(fixedLeg, ratesProvider, pvbp);

            if (expiry < 0d)
            {     // Option has expired already
                return(PointSensitivityBuilder.none());
            }
            double      forward    = SwapPricer.parRate(underlying, ratesProvider);
            double      volatility = swaptionVolatilities.volatility(expiry, tenor, strike, forward);
            DoubleArray derivative = swaptionVolatilities.volatilityAdjoint(expiry, tenor, strike, forward).Derivatives;
            // Backward sweep
            double vega = Math.Abs(pvbp) * BlackFormulaRepository.vega(forward + shift, strike + shift, expiry, volatility) * swaption.LongShort.sign();
            // sensitivities
            Currency ccy = fixedLeg.Currency;
            SwaptionVolatilitiesName name = swaptionVolatilities.Name;

            return(PointSensitivityBuilder.of(SwaptionSabrSensitivity.of(name, expiry, tenor, ALPHA, ccy, vega * derivative.get(2)), SwaptionSabrSensitivity.of(name, expiry, tenor, BETA, ccy, vega * derivative.get(3)), SwaptionSabrSensitivity.of(name, expiry, tenor, RHO, ccy, vega * derivative.get(4)), SwaptionSabrSensitivity.of(name, expiry, tenor, NU, ccy, vega * derivative.get(5))));
        }
Beispiel #13
0
 //-------------------------------------------------------------------------
 /// <summary>
 /// Calculates the currency exposure of the swaption product.
 /// </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 currency exposure </returns>
 public virtual MultiCurrencyAmount currencyExposure(ResolvedSwaption swaption, RatesProvider ratesProvider, HullWhiteOneFactorPiecewiseConstantParametersProvider hwProvider)
 {
     return(MultiCurrencyAmount.of(presentValue(swaption, ratesProvider, hwProvider)));
 }
        //-------------------------------------------------------------------------
        /// <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)));
        }
Beispiel #15
0
 //-------------------------------------------------------------------------
 // validate that the rates and volatilities providers are coherent
 private void validate(ResolvedSwaption swaption, RatesProvider ratesProvider, HullWhiteOneFactorPiecewiseConstantParametersProvider hwProvider)
 {
     ArgChecker.isTrue(hwProvider.ValuationDateTime.toLocalDate().Equals(ratesProvider.ValuationDate), "Hull-White model data and rate data should be for the same date");
     ArgChecker.isFalse(swaption.Underlying.CrossCurrency, "underlying swap should be single currency");
     ArgChecker.isTrue(swaption.SwaptionSettlement.SettlementType.Equals(SettlementType.PHYSICAL), "swaption should be physical settlement");
 }
 /// <summary>
 /// Validates that the rates and volatilities providers are coherent
 /// and that the swaption is single currency cash par-yield.
 /// </summary>
 /// <param name="swaption">  the swaption </param>
 /// <param name="ratesProvider">  the rates provider </param>
 /// <param name="swaptionVolatilities">  the volatilities </param>
 protected internal virtual void validate(ResolvedSwaption swaption, RatesProvider ratesProvider, SwaptionVolatilities swaptionVolatilities)
 {
     ArgChecker.isTrue(swaptionVolatilities.ValuationDate.Equals(ratesProvider.ValuationDate), "Volatility and rate data must be for the same date");
     validateSwaption(swaption);
 }
        //-------------------------------------------------------------------------
        /// <summary>
        /// Calculates the present value sensitivity to the implied volatility of the swaption.
        /// <para>
        /// The sensitivity to the implied volatility is also called vega.
        ///
        /// </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 volatility </returns>
        public virtual SwaptionSensitivity presentValueSensitivityModelParamsVolatility(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);
            double          tenor      = swaptionVolatilities.tenor(fixedLeg.StartDate, fixedLeg.EndDate);
            double          pvbp       = SwapPricer.LegPricer.pvbp(fixedLeg, ratesProvider);
            double          strike     = SwapPricer.LegPricer.couponEquivalent(fixedLeg, ratesProvider, pvbp);

            if (expiry < 0d)
            {     // Option has expired already
                return(SwaptionSensitivity.of(swaptionVolatilities.Name, expiry, tenor, strike, 0d, fixedLeg.Currency, 0d));
            }
            double  forward    = SwapPricer.parRate(underlying, ratesProvider);
            double  numeraire  = Math.Abs(pvbp);
            double  volatility = swaptionVolatilities.volatility(expiry, tenor, strike, forward);
            PutCall putCall    = PutCall.ofPut(fixedLeg.PayReceive.Receive);
            double  vega       = numeraire * swaptionVolatilities.priceVega(expiry, tenor, putCall, strike, forward, volatility);

            return(SwaptionSensitivity.of(swaptionVolatilities.Name, expiry, tenor, strike, forward, fixedLeg.Currency, vega * swaption.LongShort.sign()));
        }
 /// <summary>
 /// Validates that the swaption is single currency physical.
 /// </summary>
 /// <param name="swaption">  the swaption </param>
 protected internal virtual void validateSwaption(ResolvedSwaption swaption)
 {
     ArgChecker.isFalse(swaption.Underlying.CrossCurrency, "Underlying swap must be single currency");
     ArgChecker.isTrue(swaption.SwaptionSettlement.SettlementType.Equals(SettlementType.PHYSICAL), "Swaption must be physical settlement");
 }
        //-------------------------------------------------------------------------
        /// <summary>
        /// Runs the calibration of SABR on swaptions and print on the console the present value, bucketed PV01 and
        /// the bucketed Vega of a 18M x 4Y swaption.
        /// </summary>
        /// <param name="args">  -s to use the spares data </param>
        public static void Main(string[] args)
        {
            long start, end;

            // Swaption description
            BuySell          payer            = BuySell.BUY;
            Period           expiry           = Period.ofMonths(18);
            double           notional         = 1_000_000;
            double           strike           = 0.0100;
            Tenor            tenor            = Tenor.TENOR_4Y;
            LocalDate        expiryDate       = EUR_FIXED_1Y_EURIBOR_6M.FloatingLeg.StartDateBusinessDayAdjustment.adjust(CALIBRATION_DATE.plus(expiry), REF_DATA);
            SwapTrade        underlying       = EUR_FIXED_1Y_EURIBOR_6M.createTrade(expiryDate, tenor, payer, notional, strike, REF_DATA);
            Swaption         swaption         = Swaption.builder().expiryDate(AdjustableDate.of(expiryDate)).expiryTime(LocalTime.of(11, 0x0)).expiryZone(ZoneId.of("Europe/Berlin")).underlying(underlying.Product).longShort(LongShort.LONG).swaptionSettlement(PhysicalSwaptionSettlement.DEFAULT).build();
            ResolvedSwaption resolvedSwaption = swaption.resolve(REF_DATA);

            // select data
            TenorRawOptionData data = DATA_FULL;

            if (args.Length > 0)
            {
                if (args[0].Equals("-s"))
                {
                    data = DATA_SPARSE;
                }
            }

            start = DateTimeHelper.CurrentUnixTimeMillis();
            // Curve calibration
            RatesProvider multicurve = CALIBRATOR.calibrate(CONFIGS, MARKET_QUOTES, REF_DATA);

            end = DateTimeHelper.CurrentUnixTimeMillis();
            Console.WriteLine("Curve calibration time: " + (end - start) + " ms.");

            // SABR calibration
            start = DateTimeHelper.CurrentUnixTimeMillis();
            double          beta                    = 0.50;
            SurfaceMetadata betaMetadata            = DefaultSurfaceMetadata.builder().xValueType(ValueType.YEAR_FRACTION).yValueType(ValueType.YEAR_FRACTION).zValueType(ValueType.SABR_BETA).surfaceName("Beta").build();
            Surface         betaSurface             = ConstantSurface.of(betaMetadata, beta);
            double          shift                   = 0.0300;
            Surface         shiftSurface            = ConstantSurface.of("SABR-Shift", shift);
            SabrParametersSwaptionVolatilities sabr = SABR_CALIBRATION.calibrateWithFixedBetaAndShift(DEFINITION, CALIBRATION_TIME, data, multicurve, betaSurface, shiftSurface);

            end = DateTimeHelper.CurrentUnixTimeMillis();
            Console.WriteLine("SABR calibration time: " + (end - start) + " ms.");

            // Price and risk
            Console.WriteLine("Risk measures: ");
            start = DateTimeHelper.CurrentUnixTimeMillis();
            CurrencyAmount pv = SWAPTION_PRICER.presentValue(resolvedSwaption, multicurve, sabr);

            Console.WriteLine("  |-> PV: " + pv.ToString());

            PointSensitivities             deltaPts      = SWAPTION_PRICER.presentValueSensitivityRatesStickyModel(resolvedSwaption, multicurve, sabr).build();
            CurrencyParameterSensitivities deltaBucketed = multicurve.parameterSensitivity(deltaPts);

            Console.WriteLine("  |-> Delta bucketed: " + deltaBucketed.ToString());

            PointSensitivities vegaPts = SWAPTION_PRICER.presentValueSensitivityModelParamsSabr(resolvedSwaption, multicurve, sabr).build();

            Console.WriteLine("  |-> Vega point: " + vegaPts.ToString());

            CurrencyParameterSensitivities vegaBucketed = sabr.parameterSensitivity(vegaPts);

            for (int i = 0; i < vegaBucketed.size(); i++)
            {
                Console.WriteLine("  |-> Vega bucketed: " + vegaBucketed.Sensitivities.get(i));
            }

            end = DateTimeHelper.CurrentUnixTimeMillis();
            Console.WriteLine("PV and risk time: " + (end - start) + " ms.");
        }