예제 #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>
        /// Computes cash flow equivalent of Ibor leg.
        /// <para>
        /// The return type is {@code ResolvedSwapLeg} in which individual payments are
        /// represented in terms of {@code NotionalExchange}.
        ///
        /// </para>
        /// </summary>
        /// <param name="iborLeg">  the Ibor leg </param>
        /// <param name="ratesProvider">  the rates provider </param>
        /// <returns> the cash flow equivalent </returns>
        public static ResolvedSwapLeg cashFlowEquivalentIborLeg(ResolvedSwapLeg iborLeg, RatesProvider ratesProvider)
        {
            ArgChecker.isTrue(iborLeg.Type.Equals(SwapLegType.IBOR), "Leg type should be IBOR");
            ArgChecker.isTrue(iborLeg.PaymentEvents.Empty, "PaymentEvent should be empty");
            IList <NotionalExchange> paymentEvents = new List <NotionalExchange>();

            foreach (SwapPaymentPeriod paymentPeriod in iborLeg.PaymentPeriods)
            {
                ArgChecker.isTrue(paymentPeriod is RatePaymentPeriod, "rate payment should be RatePaymentPeriod");
                RatePaymentPeriod ratePaymentPeriod = (RatePaymentPeriod)paymentPeriod;
                ArgChecker.isTrue(ratePaymentPeriod.AccrualPeriods.size() == 1, "rate payment should not be compounding");
                RateAccrualPeriod    rateAccrualPeriod = ratePaymentPeriod.AccrualPeriods.get(0);
                CurrencyAmount       notional          = ratePaymentPeriod.NotionalAmount;
                LocalDate            paymentDate       = ratePaymentPeriod.PaymentDate;
                IborIndexObservation obs             = ((IborRateComputation)rateAccrualPeriod.RateComputation).Observation;
                IborIndex            index           = obs.Index;
                LocalDate            fixingStartDate = obs.EffectiveDate;
                double           fixingYearFraction  = obs.YearFraction;
                double           beta     = (1d + fixingYearFraction * ratesProvider.iborIndexRates(index).rate(obs)) * ratesProvider.discountFactor(paymentPeriod.Currency, paymentPeriod.PaymentDate) / ratesProvider.discountFactor(paymentPeriod.Currency, fixingStartDate);
                double           ycRatio  = rateAccrualPeriod.YearFraction / fixingYearFraction;
                NotionalExchange payStart = NotionalExchange.of(notional.multipliedBy(beta * ycRatio), fixingStartDate);
                NotionalExchange payEnd   = NotionalExchange.of(notional.multipliedBy(-ycRatio), paymentDate);
                paymentEvents.Add(payStart);
                paymentEvents.Add(payEnd);
            }
            ResolvedSwapLeg leg = ResolvedSwapLeg.builder().paymentEvents(paymentEvents).payReceive(PayReceive.RECEIVE).type(SwapLegType.OTHER).build();

            return(leg);
        }
예제 #4
0
        //-------------------------------------------------------------------------
        /// <summary>
        /// Calculates the present value of the Ibor caplet/floorlet period.
        /// <para>
        /// The result is expressed using the currency of the period.
        ///
        /// </para>
        /// </summary>
        /// <param name="period">  the Ibor caplet/floorlet period </param>
        /// <param name="ratesProvider">  the rates provider </param>
        /// <param name="volatilities">  the volatilities </param>
        /// <returns> the present value </returns>
        public virtual CurrencyAmount presentValue(IborCapletFloorletPeriod period, RatesProvider ratesProvider, IborCapletFloorletVolatilities volatilities)
        {
            validate(volatilities);
            Currency currency = period.Currency;

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

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

            return(CurrencyAmount.of(currency, price * period.Notional));
        }
        public virtual void test_ratesProvider()
        {
            ImmutableMap <Currency, CurveId> discounts = ImmutableMap.of(USD, CURVE_ID_DSC);
            ImmutableMap <Index, CurveId>    forwards  = ImmutableMap.of(USD_FED_FUND, CURVE_ID_DSC, USD_LIBOR_3M, CURVE_ID_FWD, US_CPI_U, CURVE_ID_FWD);
            RatesMarketDataLookup            test      = RatesMarketDataLookup.of(discounts, forwards);
            LocalDate     valDate       = date(2015, 6, 30);
            Curve         dscCurve      = ConstantCurve.of(Curves.discountFactors(CURVE_ID_DSC.CurveName, ACT_360), 1d);
            Curve         fwdCurve      = ConstantCurve.of(Curves.discountFactors(CURVE_ID_FWD.CurveName, ACT_360), 2d);
            MarketData    md            = ImmutableMarketData.of(valDate, ImmutableMap.of(CURVE_ID_DSC, dscCurve, CURVE_ID_FWD, fwdCurve));
            RatesProvider ratesProvider = test.ratesProvider(md);

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

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

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

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

            assertEquals(ratesProvider.toImmutableRatesProvider(), expectedImmutable);
        }
예제 #6
0
        //-------------------------------------------------------------------------
        /// <summary>
        /// Computes the implied volatility of the Ibor caplet/floorlet.
        /// </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 implied volatility </returns>
        public virtual double impliedVolatility(IborCapletFloorletPeriod period, RatesProvider ratesProvider, IborCapletFloorletVolatilities volatilities)
        {
            validate(volatilities);
            double expiry = volatilities.relativeTime(period.FixingDateTime);

            ArgChecker.isTrue(expiry >= 0d, "Option must be before expiry to compute an implied volatility");
            double forward = ratesProvider.iborIndexRates(period.Index).rate(period.IborRate.Observation);
            double strike  = period.Strike;

            return(volatilities.volatility(expiry, strike, forward));
        }
예제 #7
0
        /// <summary>
        /// Computes cash flow equivalent and sensitivity of Ibor leg.
        /// <para>
        /// The return type is a map of {@code NotionalExchange} and {@code PointSensitivityBuilder}.
        ///
        /// </para>
        /// </summary>
        /// <param name="iborLeg">  the Ibor leg </param>
        /// <param name="ratesProvider">  the rates provider </param>
        /// <returns> the cash flow equivalent and sensitivity </returns>
        public static ImmutableMap <Payment, PointSensitivityBuilder> cashFlowEquivalentAndSensitivityIborLeg(ResolvedSwapLeg iborLeg, RatesProvider ratesProvider)
        {
            ArgChecker.isTrue(iborLeg.Type.Equals(SwapLegType.IBOR), "Leg type should be IBOR");
            ArgChecker.isTrue(iborLeg.PaymentEvents.Empty, "PaymentEvent should be empty");
            IDictionary <Payment, PointSensitivityBuilder> res = new Dictionary <Payment, PointSensitivityBuilder>();

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

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

                PointSensitivityBuilder factorIndexSensi     = ratesProvider.iborIndexRates(index).ratePointSensitivity(obs).multipliedBy(fixingYearFraction * dfPayment * factor);
                PointSensitivityBuilder dfPaymentSensitivity = ratesProvider.discountFactors(paymentPeriod.Currency).zeroRatePointSensitivity(paymentPeriod.PaymentDate).multipliedBy(factorIndex * factor);
                PointSensitivityBuilder dfStartSensitivity   = ratesProvider.discountFactors(paymentPeriod.Currency).zeroRatePointSensitivity(fixingStartDate).multipliedBy(-factorIndex * dfPayment * factor / dfStart);
                res[payStart] = factorIndexSensi.combinedWith(dfPaymentSensitivity).combinedWith(dfStartSensitivity);
                res[payEnd]   = PointSensitivityBuilder.none();
            }
            return(ImmutableMap.copyOf(res));
        }
        /* Check calibration for forward curve directly interpolated on forward rates. */
        public virtual void calibration_present_value_simple_forward()
        {
            InterpolatedNodalCurveDefinition dsc    = InterpolatedNodalCurveDefinition.builder().name(DSCON_CURVE_NAME).xValueType(ValueType.YEAR_FRACTION).yValueType(ValueType.ZERO_RATE).dayCount(CURVE_DC).interpolator(INTERPOLATOR_LINEAR).extrapolatorLeft(EXTRAPOLATOR_FLAT).extrapolatorRight(EXTRAPOLATOR_FLAT).nodes(DSC_NODES).build();
            InterpolatedNodalCurveDefinition fwd    = InterpolatedNodalCurveDefinition.builder().name(FWD3_CURVE_NAME).xValueType(ValueType.YEAR_FRACTION).yValueType(ValueType.FORWARD_RATE).dayCount(CURVE_DC).interpolator(INTERPOLATOR_LINEAR).extrapolatorLeft(EXTRAPOLATOR_FLAT).extrapolatorRight(EXTRAPOLATOR_FLAT).nodes(FWD3_NODES).build();
            RatesCurveGroupDefinition        config = RatesCurveGroupDefinition.builder().name(CURVE_GROUP_NAME).addCurve(dsc, USD, USD_FED_FUND).addForwardCurve(fwd, USD_LIBOR_3M).build();
            RatesProvider result = CALIBRATOR.calibrate(config, ALL_QUOTES_BD, REF_DATA);

            assertResult(result, ALL_QUOTES_BD);
            IborIndexRates ibor3M = result.iborIndexRates(USD_LIBOR_3M);

            assertTrue(ibor3M is SimpleIborIndexRates, "USD-LIBOR-3M curve should be simple interpolation on forward rates");
            double shift = 1.0E-6;

            System.Func <MarketData, RatesProvider> f = marketData => CALIBRATOR.calibrate(config, marketData, REF_DATA);
            calibration_market_quote_sensitivity_check(f, config, shift, TS_EMPTY);
        }
예제 #9
0
        //-------------------------------------------------------------------------
        /// <summary>
        /// Calculates the present value volatility sensitivity of the Ibor caplet/floorlet.
        /// <para>
        /// The present value volatility sensitivity of the caplet/floorlet is the sensitivity
        /// of the present value to the implied volatility.
        /// </para>
        /// <para>
        /// The sensitivity to the implied volatility is also called vega.
        ///
        /// </para>
        /// </summary>
        /// <param name="period">  the Ibor caplet/floorlet period </param>
        /// <param name="ratesProvider">  the rates provider </param>
        /// <param name="volatilities">  the volatilities </param>
        /// <returns> the point sensitivity to the volatility </returns>
        public virtual PointSensitivityBuilder presentValueSensitivityModelParamsVolatility(IborCapletFloorletPeriod period, RatesProvider ratesProvider, IborCapletFloorletVolatilities volatilities)
        {
            validate(volatilities);
            double   expiry   = volatilities.relativeTime(period.FixingDateTime);
            double   strike   = period.Strike;
            Currency currency = period.Currency;

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

            return(IborCapletFloorletSensitivity.of(volatilities.Name, expiry, strike, forward, currency, vega * period.Notional));
        }
예제 #10
0
        //-------------------------------------------------------------------------
        /// <summary>
        /// Calculates the present value theta of the Ibor caplet/floorlet period.
        /// <para>
        /// The present value theta is given by the minus of the present value sensitivity to the {@code timeToExpiry}
        /// parameter of the model.
        ///
        /// </para>
        /// </summary>
        /// <param name="period">  the Ibor caplet/floorlet period </param>
        /// <param name="ratesProvider">  the rates provider </param>
        /// <param name="volatilities">  the volatilities </param>
        /// <returns> the present value theta </returns>
        public virtual CurrencyAmount presentValueTheta(IborCapletFloorletPeriod period, RatesProvider ratesProvider, IborCapletFloorletVolatilities volatilities)
        {
            validate(volatilities);
            double   expiry   = volatilities.relativeTime(period.FixingDateTime);
            Currency currency = period.Currency;

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

            return(CurrencyAmount.of(currency, priceTheta * period.Notional));
        }
예제 #11
0
        //-------------------------------------------------------------------------
        /// <summary>
        /// Calculates the present value sensitivity to the SABR model parameters of the Ibor caplet/floorlet.
        /// <para>
        /// The sensitivity of the present value to the SABR model parameters, alpha, beta, rho and nu.
        ///
        /// </para>
        /// </summary>
        /// <param name="period">  the Ibor caplet/floorlet period </param>
        /// <param name="ratesProvider">  the rates provider </param>
        /// <param name="volatilities">  the volatilities </param>
        /// <returns> the point sensitivity to the SABR model parameters </returns>
        public virtual PointSensitivityBuilder presentValueSensitivityModelParamsSabr(IborCapletFloorletPeriod period, RatesProvider ratesProvider, SabrIborCapletFloorletVolatilities volatilities)
        {
            double expiry = volatilities.relativeTime(period.FixingDateTime);

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

            return(PointSensitivityBuilder.of(IborCapletFloorletSabrSensitivity.of(name, expiry, ALPHA, currency, vega * derivative.get(2)), IborCapletFloorletSabrSensitivity.of(name, expiry, BETA, currency, vega * derivative.get(3)), IborCapletFloorletSabrSensitivity.of(name, expiry, RHO, currency, vega * derivative.get(4)), IborCapletFloorletSabrSensitivity.of(name, expiry, NU, currency, vega * derivative.get(5))));
        }
예제 #12
0
        //-------------------------------------------------------------------------
        // computes initial guess for each time step
        private DoubleArray computeInitialValues(RatesProvider ratesProvider, Curve betaCurve, Curve shiftCurve, IList <double> timeList, IList <double> volList, IList <ResolvedIborCapFloorLeg> capList, int[] startIndex, int postion, bool betaFixed, ValueType valueType)
        {
            IList <double>          vols = volList.subList(startIndex[postion], startIndex[postion + 1]);
            ResolvedIborCapFloorLeg cap  = capList[startIndex[postion]];
            double         fwd           = ratesProvider.iborIndexRates(cap.Index).rate(cap.FinalPeriod.IborRate.Observation);
            double         shift         = shiftCurve.yValue(timeList[startIndex[postion]]);
            double         factor        = valueType.Equals(ValueType.BLACK_VOLATILITY) ? 1d : 1d / (fwd + shift);
            IList <double> volsEquiv     = vols.Select(v => v * factor).ToList();
            double         nuFirst;
            double         betaInitial  = betaFixed ? betaCurve.yValue(timeList[startIndex[postion]]) : 0.5d;
            double         alphaInitial = DoubleArray.copyOf(volsEquiv).min() * Math.Pow(fwd, 1d - betaInitial);

            if (alphaInitial == volsEquiv[0] || alphaInitial == volsEquiv[volsEquiv.Count - 1])
            {
                nuFirst       = 0.1d;
                alphaInitial *= 0.95d;
            }
            else
            {
                nuFirst = 1d;
            }
            return(DoubleArray.of(alphaInitial, betaInitial, -0.5 * betaInitial + 0.5 * (1d - betaInitial), nuFirst));
        }
예제 #13
0
        //-------------------------------------------------------------------------
        public override IborCapletFloorletVolatilityCalibrationResult calibrate(IborCapletFloorletVolatilityDefinition definition, ZonedDateTime calibrationDateTime, RawOptionData capFloorData, RatesProvider ratesProvider)
        {
            ArgChecker.isTrue(ratesProvider.ValuationDate.Equals(calibrationDateTime.toLocalDate()), "valuationDate of ratesProvider should be coherent to calibrationDateTime");
            ArgChecker.isTrue(definition is DirectIborCapletFloorletVolatilityDefinition, "definition should be DirectIborCapletFloorletVolatilityDefinition");
            DirectIborCapletFloorletVolatilityDefinition directDefinition = (DirectIborCapletFloorletVolatilityDefinition)definition;
            // unpack cap data, create node caps
            IborIndex index           = directDefinition.Index;
            LocalDate calibrationDate = calibrationDateTime.toLocalDate();
            LocalDate baseDate        = index.EffectiveDateOffset.adjust(calibrationDate, ReferenceData);
            LocalDate startDate       = baseDate.plus(index.Tenor);

            System.Func <Surface, IborCapletFloorletVolatilities> volatilitiesFunction = this.volatilitiesFunction(directDefinition, calibrationDateTime, capFloorData);
            SurfaceMetadata metadata   = directDefinition.createMetadata(capFloorData);
            IList <Period>  expiries   = capFloorData.Expiries;
            DoubleArray     strikes    = capFloorData.Strikes;
            int             nExpiries  = expiries.Count;
            IList <double>  timeList   = new List <double>();
            IList <double>  strikeList = new List <double>();
            IList <double>  volList    = new List <double>();
            IList <ResolvedIborCapFloorLeg> capList = new List <ResolvedIborCapFloorLeg>();
            IList <double> priceList   = new List <double>();
            IList <double> errorList   = new List <double>();
            DoubleMatrix   errorMatrix = capFloorData.Error.orElse(DoubleMatrix.filled(nExpiries, strikes.size(), 1d));

            int[] startIndex = new int[nExpiries + 1];
            for (int i = 0; i < nExpiries; ++i)
            {
                LocalDate   endDate           = baseDate.plus(expiries[i]);
                DoubleArray volatilityForTime = capFloorData.Data.row(i);
                DoubleArray errorForTime      = errorMatrix.row(i);
                reduceRawData(directDefinition, ratesProvider, capFloorData.Strikes, volatilityForTime, errorForTime, startDate, endDate, metadata, volatilitiesFunction, timeList, strikeList, volList, capList, priceList, errorList);
                startIndex[i + 1] = volList.Count;
                ArgChecker.isTrue(startIndex[i + 1] > startIndex[i], "no valid option data for {}", expiries[i]);
            }
            // create caplet nodes and initial caplet vol surface
            ResolvedIborCapFloorLeg cap = capList[capList.Count - 1];
            int         nCaplets        = cap.CapletFloorletPeriods.size();
            DoubleArray capletExpiries  = DoubleArray.of(nCaplets, n => directDefinition.DayCount.relativeYearFraction(calibrationDate, cap.CapletFloorletPeriods.get(n).FixingDateTime.toLocalDate()));
            Triple <DoubleArray, DoubleArray, DoubleArray> capletNodes;
            DoubleArray initialVols = DoubleArray.copyOf(volList);

            if (directDefinition.ShiftCurve.Present)
            {
                metadata = Surfaces.blackVolatilityByExpiryStrike(directDefinition.Name.Name, directDefinition.DayCount);
                Curve shiftCurve = directDefinition.ShiftCurve.get();
                if (capFloorData.DataType.Equals(NORMAL_VOLATILITY))
                {
                    initialVols = DoubleArray.of(capList.Count, n => volList[n] / (ratesProvider.iborIndexRates(index).rate(capList[n].FinalPeriod.IborRate.Observation) + shiftCurve.yValue(timeList[n])));
                }
                InterpolatedNodalSurface capVolSurface = InterpolatedNodalSurface.of(metadata, DoubleArray.copyOf(timeList), DoubleArray.copyOf(strikeList), initialVols, INTERPOLATOR);
                capletNodes          = createCapletNodes(capVolSurface, capletExpiries, strikes, directDefinition.ShiftCurve.get());
                volatilitiesFunction = createShiftedBlackVolatilitiesFunction(index, calibrationDateTime, shiftCurve);
            }
            else
            {
                InterpolatedNodalSurface capVolSurface = InterpolatedNodalSurface.of(metadata, DoubleArray.copyOf(timeList), DoubleArray.copyOf(strikeList), initialVols, INTERPOLATOR);
                capletNodes = createCapletNodes(capVolSurface, capletExpiries, strikes);
            }
            InterpolatedNodalSurface baseSurface   = InterpolatedNodalSurface.of(metadata, capletNodes.First, capletNodes.Second, capletNodes.Third, INTERPOLATOR);
            DoubleMatrix             penaltyMatrix = directDefinition.computePenaltyMatrix(strikes, capletExpiries);
            // solve least square
            LeastSquareResults       res        = solver.solve(DoubleArray.copyOf(priceList), DoubleArray.copyOf(errorList), getPriceFunction(capList, ratesProvider, volatilitiesFunction, baseSurface), getJacobianFunction(capList, ratesProvider, volatilitiesFunction, baseSurface), capletNodes.Third, penaltyMatrix, POSITIVE);
            InterpolatedNodalSurface resSurface = InterpolatedNodalSurface.of(metadata, capletNodes.First, capletNodes.Second, res.FitParameters, directDefinition.Interpolator);

            return(IborCapletFloorletVolatilityCalibrationResult.ofLeastSquare(volatilitiesFunction(resSurface), res.ChiSq));
        }
        //-------------------------------------------------------------------------
        public override IborCapletFloorletVolatilityCalibrationResult calibrate(IborCapletFloorletVolatilityDefinition definition, ZonedDateTime calibrationDateTime, RawOptionData capFloorData, RatesProvider ratesProvider)
        {
            ArgChecker.isTrue(ratesProvider.ValuationDate.Equals(calibrationDateTime.toLocalDate()), "valuationDate of ratesProvider should be coherent to calibrationDateTime");
            ArgChecker.isTrue(definition is SurfaceIborCapletFloorletVolatilityBootstrapDefinition, "definition should be SurfaceIborCapletFloorletVolatilityBootstrapDefinition");
            SurfaceIborCapletFloorletVolatilityBootstrapDefinition bsDefinition = (SurfaceIborCapletFloorletVolatilityBootstrapDefinition)definition;
            IborIndex index           = bsDefinition.Index;
            LocalDate calibrationDate = calibrationDateTime.toLocalDate();
            LocalDate baseDate        = index.EffectiveDateOffset.adjust(calibrationDate, ReferenceData);
            LocalDate startDate       = baseDate.plus(index.Tenor);

            System.Func <Surface, IborCapletFloorletVolatilities> volatilitiesFunction = this.volatilitiesFunction(bsDefinition, calibrationDateTime, capFloorData);
            SurfaceMetadata metadata                = bsDefinition.createMetadata(capFloorData);
            IList <Period>  expiries                = capFloorData.Expiries;
            int             nExpiries               = expiries.Count;
            DoubleArray     strikes                 = capFloorData.Strikes;
            DoubleMatrix    errorsMatrix            = capFloorData.Error.orElse(DoubleMatrix.filled(nExpiries, strikes.size(), 1d));
            IList <double>  timeList                = new List <double>();
            IList <double>  strikeList              = new List <double>();
            IList <double>  volList                 = new List <double>();
            IList <ResolvedIborCapFloorLeg> capList = new List <ResolvedIborCapFloorLeg>();
            IList <double> priceList                = new List <double>();
            IList <double> errorList                = new List <double>();

            int[] startIndex = new int[nExpiries + 1];
            for (int i = 0; i < nExpiries; ++i)
            {
                LocalDate   endDate        = baseDate.plus(expiries[i]);
                DoubleArray volatilityData = capFloorData.Data.row(i);
                DoubleArray errors         = errorsMatrix.row(i);
                reduceRawData(bsDefinition, ratesProvider, strikes, volatilityData, errors, startDate, endDate, metadata, volatilitiesFunction, timeList, strikeList, volList, capList, priceList, errorList);
                startIndex[i + 1] = volList.Count;
                ArgChecker.isTrue(startIndex[i + 1] > startIndex[i], "no valid option data for {}", expiries[i]);
            }
            int nTotal = startIndex[nExpiries];
            IborCapletFloorletVolatilities vols;
            int           start;
            ZonedDateTime prevExpiry;
            DoubleArray   initialVol = DoubleArray.copyOf(volList);

            if (bsDefinition.ShiftCurve.Present)
            {
                Curve       shiftCurve    = bsDefinition.ShiftCurve.get();
                DoubleArray strikeShifted = DoubleArray.of(nTotal, n => strikeList[n] + shiftCurve.yValue(timeList[n]));
                if (capFloorData.DataType.Equals(NORMAL_VOLATILITY))
                {   // correct initial surface
                    metadata   = Surfaces.blackVolatilityByExpiryStrike(bsDefinition.Name.Name, bsDefinition.DayCount).withParameterMetadata(metadata.ParameterMetadata.get());
                    initialVol = DoubleArray.of(nTotal, n => volList[n] / (ratesProvider.iborIndexRates(index).rate(capList[n].FinalPeriod.IborRate.Observation) + shiftCurve.yValue(timeList[n])));
                }
                InterpolatedNodalSurface surface = InterpolatedNodalSurface.of(metadata, DoubleArray.copyOf(timeList), strikeShifted, initialVol, bsDefinition.Interpolator);
                vols       = ShiftedBlackIborCapletFloorletExpiryStrikeVolatilities.of(index, calibrationDateTime, surface, bsDefinition.ShiftCurve.get());
                start      = 0;
                prevExpiry = calibrationDateTime.minusDays(1L);   // included if calibrationDateTime == fixingDateTime
            }
            else
            {
                InterpolatedNodalSurface surface = InterpolatedNodalSurface.of(metadata, DoubleArray.copyOf(timeList), DoubleArray.copyOf(strikeList), initialVol, bsDefinition.Interpolator);
                vols       = volatilitiesFunction(surface);
                start      = 1;
                prevExpiry = capList[startIndex[1] - 1].FinalFixingDateTime;
            }
            for (int i = start; i < nExpiries; ++i)
            {
                for (int j = startIndex[i]; j < startIndex[i + 1]; ++j)
                {
                    System.Func <double, double[]> func   = getValueVegaFunction(capList[j], ratesProvider, vols, prevExpiry, j);
                    GenericImpliedVolatiltySolver  solver = new GenericImpliedVolatiltySolver(func);
                    double priceFixed = i == 0 ? 0d : this.priceFixed(capList[j], ratesProvider, vols, prevExpiry);
                    double capletVol  = solver.impliedVolatility(priceList[j] - priceFixed, initialVol.get(j));
                    vols = vols.withParameter(j, capletVol);
                }
                prevExpiry = capList[startIndex[i + 1] - 1].FinalFixingDateTime;
            }
            return(IborCapletFloorletVolatilityCalibrationResult.ofRootFind(vols));
        }