private const double TOLERANCE_PRICE_CALIBRATION_LS = 5.0E-4;   // Calibration Least Square; result not exact

//JAVA TO C# CONVERTER TODO TASK: Most Java annotations will not have direct .NET equivalent attributes:
//ORIGINAL LINE: @Test public void normal_cube()
        public virtual void 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.0300;
            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.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);
                    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_ARRAY_SPARSE[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 priceNormal   = NormalFormulaRepository.price(parRate, parRate + MONEYNESS.get(loopmoney), time, DATA_ARRAY_SPARSE[looptenor][loopexpiry][loopmoney], PutCall.CALL);
                            assertEquals(priceComputed, priceNormal, TOLERANCE_PRICE_CALIBRATION_LS);
                        }
                    }
                }
            }
        }
Exemplo n.º 2
0
        private void presentValueSensitivityRawDataParallelSensitivity(SabrParametersSwaptionVolatilities sabrCalibrated, TenorRawOptionData dataRaw)
        {
            PointSensitivities             points = LEG_PRICER.presentValueSensitivityModelParamsSabr(FLOOR_LEG, MULTICURVE, sabrCalibrated).build();
            CurrencyParameterSensitivities sabrParametersSurfaceSensitivities = sabrCalibrated.parameterSensitivity(points);
            CurrencyParameterSensitivity   parallelSensitivitiesSurface       = RDSC.parallelSensitivity(sabrParametersSurfaceSensitivities, sabrCalibrated);
            DoubleArray sensitivityArray  = parallelSensitivitiesSurface.Sensitivity;
            double      fdShift           = 1.0E-6;
            int         surfacePointIndex = 0;

            for (int loopexpiry = 0; loopexpiry < EXPIRIES.size(); loopexpiry++)
            {
                for (int looptenor = 0; looptenor < TENORS.size(); looptenor++)
                {
                    Tenor tenor = TENORS.get(looptenor);
                    Pair <DoubleArray, DoubleArray> ds = dataRaw.getData(tenor).availableSmileAtExpiry(EXPIRIES.get(loopexpiry));
                    if (!ds.First.Empty)
                    {
                        double[] pv = new double[2];   // pv with shift up and down
                        for (int loopsign = 0; loopsign < 2; loopsign++)
                        {
                            TenorRawOptionData dataShifted = SabrSwaptionCalibratorSmileTestUtils.rawDataShiftSmile(TENORS, EXPIRIES, ValueType.SIMPLE_MONEYNESS, MONEYNESS, ValueType.NORMAL_VOLATILITY, DATA_ARRAY_FULL, looptenor, loopexpiry, (2 * loopsign - 1) * fdShift);
                            SabrParametersSwaptionVolatilities calibratedShifted = SABR_CALIBRATION.calibrateWithFixedBetaAndShift(DEFINITION, CALIBRATION_TIME, dataShifted, MULTICURVE, BETA_SURFACE, SHIFT_SABR_SURFACE);
                            pv[loopsign] = LEG_PRICER.presentValue(FLOOR_LEG, MULTICURVE, calibratedShifted).Amount;
                        }
                        double sensitivityFd = (pv[1] - pv[0]) / (2 * fdShift);   // FD sensitivity computation
                        SabrSwaptionCalibratorSmileTestUtils.checkAcceptable(sensitivityFd, sensitivityArray.get(surfacePointIndex), 0.10, "Tenor/Expiry: " + TENORS.get(looptenor) + " / " + EXPIRIES.get(loopexpiry));
                        surfacePointIndex++;
                    }
                }
            }
        }
        private static TenorRawOptionData rawData(double[][][] dataArray)
        {
            IDictionary <Tenor, RawOptionData> raw = new SortedDictionary <Tenor, RawOptionData>();

            for (int looptenor = 0; looptenor < dataArray.Length; looptenor++)
            {
                DoubleMatrix matrix = DoubleMatrix.ofUnsafe(dataArray[looptenor]);
                raw[TENORS.get(looptenor)] = RawOptionData.of(EXPIRIES, MONEYNESS, SIMPLE_MONEYNESS, matrix, NORMAL_VOLATILITY);
            }
            return(TenorRawOptionData.of(raw));
        }
        //-------------------------------------------------------------------------
        /// <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);
        }