Beispiel #1
0
//JAVA TO C# CONVERTER TODO TASK: Most Java annotations will not have direct .NET equivalent attributes:
//ORIGINAL LINE: @Test public void log_normal_cube()
        public virtual void log_normal_cube()
        {
            double  beta         = 0.50;
            Surface betaSurface  = ConstantSurface.of("Beta", beta).withMetadata(DefaultSurfaceMetadata.builder().xValueType(ValueType.YEAR_FRACTION).yValueType(ValueType.YEAR_FRACTION).zValueType(ValueType.SABR_BETA).surfaceName("Beta").build());
            double  shift        = 0.0000;
            Surface shiftSurface = ConstantSurface.of("Shift", shift).withMetadata(DefaultSurfaceMetadata.builder().xValueType(ValueType.YEAR_FRACTION).yValueType(ValueType.YEAR_FRACTION).surfaceName("Shift").build());
            SabrParametersSwaptionVolatilities calibrated = SABR_CALIBRATION.calibrateWithFixedBetaAndShift(DEFINITION, CALIBRATION_TIME, DATA_SPARSE, MULTICURVE, betaSurface, shiftSurface);

            for (int looptenor = 0; looptenor < TENORS.Count; looptenor++)
            {
                double tenor = TENORS[looptenor].get(ChronoUnit.YEARS);
                for (int loopexpiry = 0; loopexpiry < EXPIRIES.Count; loopexpiry++)
                {
                    LocalDate     expiry         = EUR_FIXED_1Y_EURIBOR_6M.FloatingLeg.StartDateBusinessDayAdjustment.adjust(CALIBRATION_DATE.plus(EXPIRIES[loopexpiry]), REF_DATA);
                    LocalDate     effectiveDate  = EUR_FIXED_1Y_EURIBOR_6M.calculateSpotDateFromTradeDate(expiry, REF_DATA);
                    LocalDate     endDate        = effectiveDate.plus(TENORS[looptenor]);
                    SwapTrade     swap           = EUR_FIXED_1Y_EURIBOR_6M.toTrade(CALIBRATION_DATE, effectiveDate, endDate, BuySell.BUY, 1.0, 0.0);
                    double        parRate        = SWAP_PRICER.parRate(swap.resolve(REF_DATA).Product, MULTICURVE);
                    ZonedDateTime expiryDateTime = expiry.atTime(11, 0).atZone(ZoneId.of("Europe/Berlin"));
                    double        time           = calibrated.relativeTime(expiryDateTime);
                    for (int loopmoney = 0; loopmoney < MONEYNESS.size(); loopmoney++)
                    {
                        if (!double.IsNaN(DATA_LOGNORMAL[looptenor][loopexpiry][loopmoney]))
                        {
                            double strike         = parRate + MONEYNESS.get(loopmoney);
                            double volBlack       = calibrated.volatility(expiryDateTime, tenor, strike, parRate);
                            double priceComputed  = BlackFormulaRepository.price(parRate + shift, parRate + MONEYNESS.get(loopmoney) + shift, time, volBlack, true);
                            double priceLogNormal = BlackFormulaRepository.price(parRate, parRate + MONEYNESS.get(loopmoney), time, DATA_LOGNORMAL[looptenor][loopexpiry][loopmoney], true);
                            assertEquals(priceComputed, priceLogNormal, TOLERANCE_PRICE_CALIBRATION_LS);
                        }
                    }
                }
            }
        }
        //-------------------------------------------------------------------------
        /// <summary>
        /// Computes the present value of CMS coupon by simple forward rate estimation.
        /// </summary>
        /// <param name="cmsPeriod">  the CMS </param>
        /// <param name="provider">  the rates provider </param>
        /// <returns> the present value </returns>
        public virtual CurrencyAmount presentValue(CmsPeriod cmsPeriod, RatesProvider provider)
        {
            Currency  ccy           = cmsPeriod.Currency;
            LocalDate valuationDate = provider.ValuationDate;

            if (valuationDate.isAfter(cmsPeriod.PaymentDate))
            {
                return(CurrencyAmount.zero(ccy));
            }
            LocalDate fixingDate = cmsPeriod.FixingDate;
            double    dfPayment  = provider.discountFactor(ccy, cmsPeriod.PaymentDate);

            if (!fixingDate.isAfter(valuationDate))
            {     // Using fixing
                double?fixedRate = provider.timeSeries(cmsPeriod.Index).get(fixingDate);
                if (fixedRate.HasValue)
                {
                    double payoff = 0d;
                    switch (cmsPeriod.CmsPeriodType)
                    {
                    case CAPLET:
                        payoff = Math.Max(fixedRate.Value - cmsPeriod.Strike, 0d);
                        break;

                    case FLOORLET:
                        payoff = Math.Max(cmsPeriod.Strike - fixedRate.Value, 0d);
                        break;

                    case COUPON:
                        payoff = fixedRate.Value;
                        break;

                    default:
                        throw new System.ArgumentException("unsupported CMS type");
                    }
                    return(CurrencyAmount.of(ccy, payoff * dfPayment * cmsPeriod.Notional * cmsPeriod.YearFraction));
                }
                else if (fixingDate.isBefore(valuationDate))
                {
                    throw new System.ArgumentException(Messages.format("Unable to get fixing for {} on date {}, no time-series supplied", cmsPeriod.Index, fixingDate));
                }
            }
            if (!cmsPeriod.CmsPeriodType.Equals(CmsPeriodType.COUPON))
            {
                throw new System.ArgumentException("Unable to price cap or floor in this pricer");
            }
            // Using forward
            ResolvedSwap swap    = cmsPeriod.UnderlyingSwap;
            double       forward = swapPricer.parRate(swap, provider);

            return(CurrencyAmount.of(ccy, forward * dfPayment * cmsPeriod.Notional * cmsPeriod.YearFraction));
        }
Beispiel #3
0
        //-------------------------------------------------------------------------
        public virtual void test_explainPresentValue()
        {
            ExplainMap explain = LEG_PRICER.explainPresentValue(CAP_LEG, RATES_PROVIDER, VOLATILITIES);

            assertEquals(explain.get(ExplainKey.ENTRY_TYPE).get(), "CmsLeg");
            assertEquals(explain.get(ExplainKey.PAY_RECEIVE).get().ToString(), "Receive");
            assertEquals(explain.get(ExplainKey.PAYMENT_CURRENCY).get().Code, "EUR");
            assertEquals(explain.get(ExplainKey.START_DATE).get(), LocalDate.of(2015, 10, 21));
            assertEquals(explain.get(ExplainKey.END_DATE).get(), LocalDate.of(2020, 10, 21));
            assertEquals(explain.get(ExplainKey.INDEX).get().ToString(), "EUR-EURIBOR-1100-5Y");
            assertEquals(explain.get(ExplainKey.PRESENT_VALUE).get().Amount, 39728.51321029542);

            IList <ExplainMap> paymentPeriods = explain.get(ExplainKey.PAYMENT_PERIODS).get();

            assertEquals(paymentPeriods.Count, 5);
            //Test First Period
            ExplainMap cmsPeriod0 = paymentPeriods[0];

            assertEquals(cmsPeriod0.get(ExplainKey.ENTRY_TYPE).get(), "CmsCapletPeriod");
            assertEquals(cmsPeriod0.get(ExplainKey.STRIKE_VALUE).Value, 0.0125d);
            assertEquals(cmsPeriod0.get(ExplainKey.NOTIONAL).get().Amount, 1000000d);
            assertEquals(cmsPeriod0.get(ExplainKey.PAYMENT_DATE).get(), LocalDate.of(2016, 10, 21));
            assertEquals(cmsPeriod0.get(ExplainKey.DISCOUNT_FACTOR).Value, 0.9820085531995826d);
            assertEquals(cmsPeriod0.get(ExplainKey.START_DATE).get(), LocalDate.of(2015, 10, 21));
            assertEquals(cmsPeriod0.get(ExplainKey.END_DATE).get(), LocalDate.of(2016, 10, 21));
            assertEquals(cmsPeriod0.get(ExplainKey.FIXING_DATE).get(), LocalDate.of(2015, 10, 19));
            assertEquals(cmsPeriod0.get(ExplainKey.ACCRUAL_YEAR_FRACTION).Value, 1.0166666666666666d);
            double forwardSwapRate = PRICER_SWAP.parRate(CAP_LEG.CmsPeriods.get(0).UnderlyingSwap, RATES_PROVIDER);

            assertEquals(cmsPeriod0.get(ExplainKey.FORWARD_RATE).Value, forwardSwapRate);
            CurrencyAmount pv = PERIOD_PRICER.presentValue(CAP_LEG.CmsPeriods.get(0), RATES_PROVIDER, VOLATILITIES);

            assertEquals(cmsPeriod0.get(ExplainKey.PRESENT_VALUE).get(), pv);
        }
        //-------------------------------------------------------------------------
        public virtual void test_presentValue()
        {
            CurrencyAmount computedRec = SWAPTION_PRICER.presentValue(SWAPTION_REC_LONG, RATE_PROVIDER, VOLS);
            CurrencyAmount computedPay = SWAPTION_PRICER.presentValue(SWAPTION_PAY_SHORT, RATE_PROVIDER, VOLS);
            double         forward     = SWAP_PRICER.parRate(RSWAP_REC, RATE_PROVIDER);
            double         pvbp        = SWAP_PRICER.LegPricer.pvbp(RSWAP_REC.getLegs(SwapLegType.FIXED).get(0), RATE_PROVIDER);
            double         volatility  = VOLS.volatility(SWAPTION_REC_LONG.Expiry, TENOR_YEAR, RATE, forward);
            double         maturity    = VOLS.relativeTime(SWAPTION_REC_LONG.Expiry);
            double         expectedRec = pvbp * BlackFormulaRepository.price(forward + SwaptionSabrRateVolatilityDataSet.SHIFT, RATE + SwaptionSabrRateVolatilityDataSet.SHIFT, maturity, volatility, false);
            double         expectedPay = -pvbp *BlackFormulaRepository.price(forward + SwaptionSabrRateVolatilityDataSet.SHIFT, RATE + SwaptionSabrRateVolatilityDataSet.SHIFT, maturity, volatility, true);

            assertEquals(computedRec.Currency, USD);
            assertEquals(computedRec.Amount, expectedRec, NOTIONAL * TOL);
            assertEquals(computedPay.Currency, USD);
            assertEquals(computedPay.Amount, expectedPay, NOTIONAL * TOL);
        }
Beispiel #5
0
        public virtual void test_presentValue()
        {
            CurrencyAmount computedRec = PRICER.presentValue(SWAPTION_REC_LONG, RATE_PROVIDER, VOLS);
            CurrencyAmount computedPay = PRICER.presentValue(SWAPTION_PAY_SHORT, RATE_PROVIDER, VOLS);
            double         forward     = SWAP_PRICER.parRate(RSWAP_REC, RATE_PROVIDER);
            double         annuityCash = SWAP_PRICER.LegPricer.annuityCash(RFIXED_LEG_REC, forward);
            double         expiry      = VOLS.relativeTime(SWAPTION_REC_LONG.Expiry);
            double         tenor       = VOLS.tenor(SETTLE, END);
            double         volatility  = SURFACE.zValue(expiry, tenor);
            double         settle      = ACT_ACT_ISDA.relativeYearFraction(VAL_DATE, SETTLE);
            double         df          = Math.Exp(-DSC_CURVE.yValue(settle) * settle);
            double         expectedRec = df * annuityCash * BlackFormulaRepository.price(forward, RATE, expiry, volatility, false);
            double         expectedPay = -df *annuityCash *BlackFormulaRepository.price(forward, RATE, expiry, volatility, true);

            assertEquals(computedRec.Currency, EUR);
            assertEquals(computedRec.Amount, expectedRec, NOTIONAL * TOL);
            assertEquals(computedPay.Currency, EUR);
            assertEquals(computedPay.Amount, expectedPay, NOTIONAL * TOL);
        }
Beispiel #6
0
        //-------------------------------------------------------------------------
        public virtual void test_implied_volatility()
        {
            double forward     = PRICER_SWAP.parRate(RSWAP_REC, MULTI_USD);
            double volExpected = BLACK_VOLS_USD_STD.volatility(SWAPTION_LONG_REC.Expiry, SWAP_TENOR_YEAR, STRIKE, forward);
            double volComputed = PRICER_SWAPTION_BLACK.impliedVolatility(SWAPTION_LONG_PAY, MULTI_USD, BLACK_VOLS_USD_STD);

            assertEquals(volComputed, volExpected, TOLERANCE_RATE);
        }
        //-------------------------------------------------------------------------
        /// <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()));
        }
        //-----------------------------------------------------------------------
        public virtual void test_VanillaFixedVsLibor3mSwap()
        {
            SwapLeg           payLeg     = fixedLeg(LocalDate.of(2014, 9, 12), LocalDate.of(2021, 9, 12), P6M, PAY, NOTIONAL, 0.015, null);
            SwapLeg           receiveLeg = iborLeg(LocalDate.of(2014, 9, 12), LocalDate.of(2021, 9, 12), USD_LIBOR_3M, RECEIVE, NOTIONAL, null);
            ResolvedSwapTrade trade      = SwapTrade.builder().info(TradeInfo.builder().tradeDate(LocalDate.of(2014, 9, 10)).build()).product(Swap.of(payLeg, receiveLeg)).build().resolve(REF_DATA);

            // test pv
            DiscountingSwapTradePricer pricer = swapPricer();
            CurrencyAmount             pv     = pricer.presentValue(trade, provider()).getAmount(USD);

            assertEquals(pv.Amount, 7170391.798257509, TOLERANCE_PV);
            // test par rate
            double parRate = PRICER_PRODUCT.parRate(trade.Product, provider());

            assertEquals(parRate, 0.02589471566819517, TOLERANCE_RATE);
            // test par rate vs pv
            ResolvedSwap   swapPV0 = Swap.of(fixedLeg(LocalDate.of(2014, 9, 12), LocalDate.of(2021, 9, 12), P6M, PAY, NOTIONAL, parRate, null), receiveLeg).resolve(REF_DATA);
            CurrencyAmount pv0     = PRICER_PRODUCT.presentValue(swapPV0, provider()).getAmount(USD);

            assertEquals(pv0.Amount, 0, TOLERANCE_PV);     // PV at par rate should be 0
        }
        //-------------------------------------------------------------------------
        public virtual void test_presentValue()
        {
            CurrencyAmount        pvRecComputed = PRICER_SWAPTION.presentValue(SWAPTION_REC_LONG, RATE_PROVIDER, VOLS);
            CurrencyAmount        pvPayComputed = PRICER_SWAPTION.presentValue(SWAPTION_PAY_SHORT, RATE_PROVIDER, VOLS);
            double                forward       = PRICER_SWAP.parRate(RSWAP_REC, RATE_PROVIDER);
            double                annuityCash   = PRICER_SWAP.LegPricer.annuityCash(RSWAP_REC.getLegs(SwapLegType.FIXED).get(0), forward);
            double                volatility    = VOLS.volatility(SWAPTION_REC_LONG.Expiry, SWAP_TENOR_YEAR, STRIKE, forward);
            double                discount      = RATE_PROVIDER.discountFactor(USD, SETTLE_DATE);
            NormalFunctionData    normalData    = NormalFunctionData.of(forward, annuityCash * discount, volatility);
            double                expiry        = VOLS.relativeTime(SWAPTION_REC_LONG.Expiry);
            EuropeanVanillaOption optionRec     = EuropeanVanillaOption.of(STRIKE, expiry, PutCall.PUT);
            EuropeanVanillaOption optionPay     = EuropeanVanillaOption.of(STRIKE, expiry, PutCall.CALL);
            double                pvRecExpected = NORMAL.getPriceFunction(optionRec).apply(normalData);
            double                pvPayExpected = -NORMAL.getPriceFunction(optionPay).apply(normalData);

            assertEquals(pvRecComputed.Currency, USD);
            assertEquals(pvRecComputed.Amount, pvRecExpected, NOTIONAL * TOL);
            assertEquals(pvPayComputed.Currency, USD);
            assertEquals(pvPayComputed.Amount, pvPayExpected, NOTIONAL * TOL);
        }
        //-------------------------------------------------------------------------
        /// <summary>
        /// Runs the calibration of swaptions and print the calibrated smile results on the console.
        /// </summary>
        /// <param name="args">  -s to use the sparse data, i.e. a cube with missing data points </param>
        public static void Main(string[] args)
        {
            // select data
            TenorRawOptionData data = DATA_FULL;

            if (args.Length > 0)
            {
                if (args[0].Equals("-s"))
                {
                    data = DATA_SPARSE;
                }
            }
            Console.WriteLine("Start calibration");
            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("Shift", shift);
            SabrParametersSwaptionVolatilities calibrated = SABR_CALIBRATION.calibrateWithFixedBetaAndShift(DEFINITION, CALIBRATION_TIME, data, MULTICURVE, betaSurface, shiftSurface);

            Console.WriteLine("End calibration");
            /* Graph calibration */
            int    nbStrikesGraph = 50;
            double moneyMin       = -0.0250;
            double moneyMax       = +0.0300;

            double[] moneyGraph = new double[nbStrikesGraph + 1];
            for (int i = 0; i < nbStrikesGraph + 1; i++)
            {
                moneyGraph[i] = moneyMin + i * (moneyMax - moneyMin) / nbStrikesGraph;
            }
//JAVA TO C# CONVERTER NOTE: The following call to the 'RectangularArrays' helper class reproduces the rectangular array initialization that is automatic in Java:
//ORIGINAL LINE: double[][][] strikesGraph = new double[NB_TENORS][NB_EXPIRIES][nbStrikesGraph + 1];
            double[][][] strikesGraph = RectangularArrays.ReturnRectangularDoubleArray(NB_TENORS, NB_EXPIRIES, nbStrikesGraph + 1);
//JAVA TO C# CONVERTER NOTE: The following call to the 'RectangularArrays' helper class reproduces the rectangular array initialization that is automatic in Java:
//ORIGINAL LINE: double[][][] volLNGraph = new double[NB_TENORS][NB_EXPIRIES][nbStrikesGraph + 1];
            double[][][] volLNGraph = RectangularArrays.ReturnRectangularDoubleArray(NB_TENORS, NB_EXPIRIES, nbStrikesGraph + 1);
//JAVA TO C# CONVERTER NOTE: The following call to the 'RectangularArrays' helper class reproduces the rectangular array initialization that is automatic in Java:
//ORIGINAL LINE: double[][][] volNGraph = new double[NB_TENORS][NB_EXPIRIES][nbStrikesGraph + 1];
            double[][][] volNGraph = RectangularArrays.ReturnRectangularDoubleArray(NB_TENORS, NB_EXPIRIES, nbStrikesGraph + 1);
//JAVA TO C# CONVERTER NOTE: The following call to the 'RectangularArrays' helper class reproduces the rectangular array initialization that is automatic in Java:
//ORIGINAL LINE: double[][] parRate = new double[NB_TENORS][NB_EXPIRIES];
            double[][] parRate = RectangularArrays.ReturnRectangularDoubleArray(NB_TENORS, NB_EXPIRIES);
            for (int looptenor = 0; looptenor < TENORS.size(); looptenor++)
            {
                double tenor = TENORS.get(looptenor).get(ChronoUnit.YEARS);
                for (int loopexpiry = 0; loopexpiry < EXPIRIES.size(); loopexpiry++)
                {
                    LocalDate expiry        = EUR_FIXED_1Y_EURIBOR_6M.FloatingLeg.StartDateBusinessDayAdjustment.adjust(CALIBRATION_DATE.plus(EXPIRIES.get(loopexpiry)), REF_DATA);
                    LocalDate effectiveDate = EUR_FIXED_1Y_EURIBOR_6M.calculateSpotDateFromTradeDate(expiry, REF_DATA);
                    LocalDate endDate       = effectiveDate.plus(TENORS.get(looptenor));
                    SwapTrade swap          = EUR_FIXED_1Y_EURIBOR_6M.toTrade(CALIBRATION_DATE, effectiveDate, endDate, BuySell.BUY, 1.0, 0.0);
                    parRate[looptenor][loopexpiry] = SWAP_PRICER.parRate(swap.resolve(REF_DATA).Product, MULTICURVE);
                    ZonedDateTime expiryDateTime = expiry.atTime(11, 0).atZone(ZoneId.of("Europe/Berlin"));
                    double        time           = calibrated.relativeTime(expiryDateTime);
                    for (int i = 0; i < nbStrikesGraph + 1; i++)
                    {
                        strikesGraph[looptenor][loopexpiry][i] = parRate[looptenor][loopexpiry] + moneyGraph[i];
                        volLNGraph[looptenor][loopexpiry][i]   = calibrated.volatility(expiryDateTime, tenor, strikesGraph[looptenor][loopexpiry][i], parRate[looptenor][loopexpiry]);
                        volNGraph[looptenor][loopexpiry][i]    = NormalFormulaRepository.impliedVolatilityFromBlackApproximated(parRate[looptenor][loopexpiry] + shift, strikesGraph[looptenor][loopexpiry][i] + shift, time, volLNGraph[looptenor][loopexpiry][i]);
                    }
                }
            }

            /* Graph export */
            string svn = "Moneyness";

            for (int looptenor = 0; looptenor < TENORS.size(); looptenor++)
            {
                for (int loopexpiry = 0; loopexpiry < EXPIRIES.size(); loopexpiry++)
                {
                    svn = svn + ", Strike_" + EXPIRIES.get(loopexpiry).ToString() + "x" + TENORS.get(looptenor).ToString() + ", NormalVol_" + EXPIRIES.get(loopexpiry).ToString() + "x" + TENORS.get(looptenor).ToString();
                }
            }
            svn = svn + "\n";
            for (int i = 0; i < nbStrikesGraph + 1; i++)
            {
                svn = svn + moneyGraph[i];
                for (int looptenor = 0; looptenor < TENORS.size(); looptenor++)
                {
                    for (int loopexpiry = 0; loopexpiry < EXPIRIES.size(); loopexpiry++)
                    {
                        svn = svn + ", " + strikesGraph[looptenor][loopexpiry][i];
                        svn = svn + ", " + volNGraph[looptenor][loopexpiry][i];
                    }
                }
                svn = svn + "\n";
            }
            Console.WriteLine(svn);
        }
        //-------------------------------------------------------------------------
        /// <summary>
        /// Computes the present value by replication in SABR framework with extrapolation on the right.
        /// </summary>
        /// <param name="cmsPeriod">  the CMS </param>
        /// <param name="provider">  the rates provider </param>
        /// <param name="swaptionVolatilities">  the swaption volatilities </param>
        /// <returns> the present value </returns>
        public CurrencyAmount presentValue(CmsPeriod cmsPeriod, RatesProvider provider, SwaptionVolatilities swaptionVolatilities)
        {
            Currency  ccy           = cmsPeriod.Currency;
            LocalDate valuationDate = provider.ValuationDate;

            if (valuationDate.isAfter(cmsPeriod.PaymentDate))
            {
                return(CurrencyAmount.zero(ccy));
            }
            LocalDate fixingDate = cmsPeriod.FixingDate;
            double    dfPayment  = provider.discountFactor(ccy, cmsPeriod.PaymentDate);

            if (!fixingDate.isAfter(valuationDate))
            {     // Using fixing
                double?fixedRate = provider.timeSeries(cmsPeriod.Index).get(fixingDate);
                if (fixedRate.HasValue)
                {
                    double payoff = 0d;
                    switch (cmsPeriod.CmsPeriodType)
                    {
                    case CAPLET:
                        payoff = Math.Max(fixedRate.Value - cmsPeriod.Strike, 0d);
                        break;

                    case FLOORLET:
                        payoff = Math.Max(cmsPeriod.Strike - fixedRate.Value, 0d);
                        break;

                    case COUPON:
                        payoff = fixedRate.Value;
                        break;

                    default:
                        throw new System.ArgumentException("unsupported CMS type");
                    }
                    return(CurrencyAmount.of(ccy, payoff * dfPayment * cmsPeriod.Notional * cmsPeriod.YearFraction));
                }
                else if (fixingDate.isBefore(valuationDate))
                {
                    throw new System.ArgumentException(Messages.format("Unable to get fixing for {} on date {}, no time-series supplied", cmsPeriod.Index, fixingDate));
                }
            }
            if (!cmsPeriod.CmsPeriodType.Equals(CmsPeriodType.COUPON))
            {
                throw new System.ArgumentException("Unable to price cap or floor in this pricer");
            }
            // Using forward
            SwapIndex        index              = cmsPeriod.Index;
            ResolvedSwap     swap               = cmsPeriod.UnderlyingSwap;
            ResolvedSwapLeg  fixedLeg           = swap.getLegs(SwapLegType.FIXED).get(0);
            int              nbFixedPaymentYear = (int)(long)Math.Round(1d / ((RatePaymentPeriod)fixedLeg.PaymentPeriods.get(0)).AccrualPeriods.get(0).YearFraction, MidpointRounding.AwayFromZero);
            int              nbFixedPeriod      = fixedLeg.PaymentPeriods.size();
            double           forward            = swapPricer.parRate(swap, provider);
            double           tenor              = swaptionVolatilities.tenor(swap.StartDate, swap.EndDate);
            double           expiryTime         = swaptionVolatilities.relativeTime(fixingDate.atTime(index.FixingTime).atZone(index.FixingZone));
            double           volatility         = swaptionVolatilities.volatility(expiryTime, tenor, forward, forward);
            ValueDerivatives annuityDerivatives = swapPricer.LegPricer.annuityCash2(nbFixedPaymentYear, nbFixedPeriod, volatility);
            double           forwardAdjustment  = -0.5 * forward * forward * volatility * volatility * expiryTime * annuityDerivatives.getDerivative(1) / annuityDerivatives.getDerivative(0);

            return(CurrencyAmount.of(ccy, (forward + forwardAdjustment) * dfPayment * cmsPeriod.Notional * cmsPeriod.YearFraction));
        }