public void GetForwardRateTest1()
        {
            var target = new ForwardRatesMatrix(_assetExpiries, _assetTenors, _assetData, _id);
            // Check for valid expiry/tenor pair
            Period        expiry   = PeriodHelper.Parse("1y");
            Period        tenor    = PeriodHelper.Parse("4y");
            const decimal expected = 6.8227m / 100.0m;
            decimal       actual;

            try
            {
                actual = target.GetAssetPrice(expiry, tenor);
                Assert.AreEqual(expected, actual);
            }
            catch (ArgumentException ex)
            {
                Assert.AreEqual("Invalid Expiry/Tenor pair supplied.", ex.Message);
            }

            // Check for invalid expiry/tenor pair
            expiry = PeriodHelper.Parse("6y");
            tenor  = PeriodHelper.Parse("4y");

            try
            {
                actual = target.GetAssetPrice(expiry, tenor);
                Assert.AreEqual(expected, actual);
            }
            catch (ArgumentException ex)
            {
                Assert.AreEqual("Invalid Expiry/Tenor pair supplied.", ex.Message);
            }
        }
Exemple #2
0
        /// <summary>
        /// Generate a new set of full calibration engines for the supplied data.
        /// Add or overwrite the engine store for the new engine.
        /// Each engineId will point to a set of engines indexed by swap tenor and option expiry
        /// Calibration assumes that the format of the grid data is as follows:
        ///
        ///     + XXXX |  lbl0  |  lbl1  | ... |  lbln  +
        ///     | lbl0 | d[0,0] | d[0,1] | ... | d[0,n] |
        ///     | lbl1 | d[1,0] | d[1,1] | ... | d[1,n] |
        ///     | ...  |   ...  |   ...  | ... |   ...  |
        ///     + lbln | d[n,0] | d[n,1] | ... | d[n,n] +
        ///
        /// </summary>
        /// <param name="engineHandle">Calibration Engine handle</param>
        /// <param name="settingsHandle">Calibartion settings handle</param>
        /// <param name="rawVols">A grid of volatilities (with row/column labels)</param>
        /// <param name="rawAssets">A grid of asset values</param>
        /// <param name="optionEx">The ption expiry to index against</param>
        /// <returns></returns>
        public string SABRCalibrateModel(string engineHandle, string settingsHandle, object[,] rawVols, object[,] rawAssets, string optionEx)
        {
            // Create the asset and volatility data grids
            SwaptionDataMatrix volatilityGrid = ParseVolatilityInput(rawVols, optionEx);
            ForwardRatesMatrix assetGrid      = ParseAssetInputWithInterpolation(rawAssets);

            // Retrieve the calibration settings to use with this calibration engine
            if (!_sabrSettings.ContainsKey(settingsHandle))
            {
                throw new ArgumentException($"Configuration '{settingsHandle}' has not been set up.");
            }
            SABRCalibrationSettings settings = _sabrSettings[settingsHandle];
            // Generate the CalibrationEngine Id
            string calibrationEngineId = engineHandle;
            string optionExpiry        = GenerateTenorLabel(optionEx);
            // Create a new engine holder object
            SortedDictionary <SABRKey, SABRCalibrationEngine> sabrEngine =
                BuildEngineCollection(volatilityGrid, assetGrid, settings, calibrationEngineId, optionExpiry);

            // We have an asset grid (forward rates) with this engine type so we should keep it
            // for future reference (that is during the lifetime of this session)
            if (_engineRatesGrid.ContainsKey(engineHandle))
            {
                _engineRatesGrid[engineHandle] = assetGrid;
            }
            else
            {
                _engineRatesGrid.Add(engineHandle, assetGrid);
            }

            // Add the SABREngine to the persistent store
            if (_sabrEngines.ContainsKey(calibrationEngineId))
            {
                _sabrEngines[calibrationEngineId] = sabrEngine;
            }
            else
            {
                _sabrEngines.Add(calibrationEngineId, sabrEngine);
            }
            return(engineHandle);
        }
        /// <summary>
        /// Parse the raw assets grid to create the labels and values arrays
        /// required by a <see cref="SwaptionDataMatrix"/> used to store the data
        /// for use by the SABR calibration/calulation routines
        /// This version uses Interpolation to include Swap Tenors that are not
        /// included as part of the grid but fall within the minimum and maximum tenor
        /// values of the grid.
        /// </summary>
        /// <param name="expiry">An array of expiries.</param>
        /// <param name="rawAsset">The raw volatility data</param>
        /// <param name="tenors">An array of tenors.</param>
        /// <returns>The rawdata as a SwaptionDataGrid</returns>
        private static ForwardRatesMatrix ParseAssetInputWithInterpolation(String[] tenors, String[] expiry,
                                                                           Decimal[,] rawAsset)
        {
            // Set the upper/lower bounds of the converted array
            //var lo1D = rawAsset.GetLowerBound(0);
            int hi1D = rawAsset.GetUpperBound(0) + 1;
            //var lo2D = rawAsset.GetLowerBound(1);
            int hi2D = rawAsset.GetUpperBound(1) + 1;

            // Add arrays for the values
            var values = new decimal[hi1D][];

            for (int idx = 0; idx < hi1D; idx++)
            {
                values[idx] = new decimal[hi2D];
                for (int jdx = 0; jdx < hi2D; jdx++)
                {
                    values[idx][jdx] = rawAsset[idx, jdx];
                }
            }
            // Set up the lists we shall use to insert any interpolated column entries
            var fullTenors = new List <string>();
            var fullValues = new List <List <decimal> >();
            // Convert the tenors to doubles
            var tenorsAsDouble = new decimal[tenors.Length];//Tenor must be years.

            for (int idx = 0; idx < tenors.Length; idx++)
            {
                tenorsAsDouble[idx] = (decimal)(PeriodHelper.Parse(tenors[idx]).ToYearFraction());
            }
            // Set up the min and max column (tenor) values
            var min = (int)(tenorsAsDouble[0]);
            var max = (int)(tenorsAsDouble[tenorsAsDouble.Length - 1]);

            // Loop through the expiry values testing the tenor values
            // Copy existing tenors or add new tenor values using interpolation
            for (int expiryIdx = 0; expiryIdx < expiry.Length; expiryIdx++)
            {
                int tenorIdx = 0;
                var inner    = new List <decimal>();
                var lin      = new LinearInterpolation(tenorsAsDouble, values[expiryIdx]);
                // Loop from the min to the max testing for valid tenor entries
                // and inserting new values where necessary
                for (int idx = min; idx <= max; idx++)
                {
                    if (idx == int.Parse(PeriodHelper.Parse(tenors[tenorIdx]).periodMultiplier))
                    {
                        // Add an existing tenor and its values array - Remember to check we haven't already added the tenor
                        if (!fullTenors.Contains(tenors[tenorIdx]))
                        {
                            fullTenors.Add(tenors[tenorIdx]);
                        }
                        inner.Add(values[expiryIdx][tenorIdx++]);
                    }
                    else
                    {
                        // Add the interpolated tenor and its value - Remember to check we haven't already added the tenor
                        if (!fullTenors.Contains(tenors[tenorIdx]))
                        {
                            fullTenors.Add(idx.ToString(CultureInfo.InvariantCulture) + 'Y');
                        }
                        inner.Add(lin.ValueAt((decimal)idx));
                    }
                }
                fullValues.Add(inner);
            }

            // Regenerate the arrays to use in the grid
            string[] interpolatedTenors = fullTenors.ToArray();
            var      interpolatedValues = new decimal[fullValues.Count][];

            for (int idx = 0; idx < fullValues.Count; idx++)
            {
                interpolatedValues[idx] = fullValues[idx].ToArray();
            }
            // Create the grid
            var grid = new ForwardRatesMatrix(expiry, interpolatedTenors, interpolatedValues);

            return(grid);
        }
        /// <summary>
        /// Create a full calibration model.This version uses the volatility grid to generate an engine
        /// for each swap tenor (row values)
        /// </summary>
        /// <param name="volatilityGrid">The vols grid</param>
        /// <param name="assetGrid">The asset grid</param>
        /// <param name="settings">The SABR settings</param>
        /// <param name="calibrationEngineId">The id of this engine</param>
        /// <param name="optionExpiry">The ATM pointer</param>
        private static SortedDictionary <SABRKey, SABRCalibrationEngine> BuildEngineCollection(SwaptionDataMatrix volatilityGrid,
                                                                                               ForwardRatesMatrix assetGrid, SABRCalibrationSettings settings, string calibrationEngineId, string optionExpiry)
        {
            var engineCollection = new SortedDictionary <SABRKey, SABRCalibrationEngine>(new SABRKey());

            // Generate a new entry in the engineCollection for each row in the volatility grid
            foreach (string tenor in volatilityGrid.GetTenors())
            {
                var assetPrice   = assetGrid.GetAssetPrice(optionExpiry, tenor);
                var exerciseTime = (decimal)SABRHelper.GenerateDayValue(optionExpiry, 365.0d);
                // Generate the Vols and Strikes lists for the engine
                List <decimal> vols    = volatilityGrid.GetVolatility(tenor).ToList();
                List <decimal> strikes = volatilityGrid.GetStrikes().Select(strike => assetPrice + strike).ToList();
                // Only add a new Calibration Engine (and Calibrate it) if the vols are greater than 0
                if (!SABRHelper.ValidateData(vols))
                {
                    continue;
                }
                // Create a new instance of the engine
                var calibrationEngine =
                    new SABRCalibrationEngine(calibrationEngineId, settings, strikes, vols, assetPrice, exerciseTime);
                // Calibrate the engine
                calibrationEngine.CalibrateSABRModel();
                // Add the new engine to our collection
                var key = new SABRKey(optionExpiry, tenor);
                engineCollection.Add(key, calibrationEngine);
            }
            return(engineCollection);
        }
Exemple #5
0
        /// <summary>
        /// Parse the raw assets grid to create the labels and values arrays
        /// required by a SwaptionDataGrid{T,U} used to store the data
        /// for use by the SABR calibration/calulation routines
        /// This version uses Interpolation to include Swap Tenors that are not
        /// included as part of the grid but fall within the minimum and maximum tenor
        /// values of the grid.
        /// </summary>
        /// <param name="rawAsset">The raw volatility data</param>
        /// <returns>The rawdata as a SwaptionDataGrid</returns>
        private static ForwardRatesMatrix ParseAssetInputWithInterpolation(object[,] rawAsset)
        {
            // Set the upper/lower bounds of the converted array
            int hi1D = rawAsset.GetUpperBound(0);
            int hi2D = rawAsset.GetUpperBound(1);
            // Create and populate the data arrays used to build the SwaptionDataGrid
            // The columns represent tenors, the rows option expiries
            var tenors = new string[hi2D];
            var expiry = new string[hi1D];

            for (int idx = 1; idx <= hi2D; idx++)
            {
                tenors[idx - 1] = rawAsset[0, idx].ToString();
            }
            for (int idx = 1; idx <= hi1D; idx++)
            {
                expiry[idx - 1] = rawAsset[idx, 0].ToString();
            }
            // Add arrays for the values
            var values = new decimal[hi1D][];

            for (int idx = 1; idx <= hi1D; idx++)
            {
                values[idx - 1] = new decimal[hi2D];
                for (int jdx = 1; jdx <= hi2D; jdx++)
                {
                    values[idx - 1][jdx - 1] = decimal.Parse(rawAsset[idx, jdx].ToString());
                }
            }
            // Set up the lists we shall use to insert any interpolated column entries
            var fullTenors = new List <string>();
            var fullValues = new List <List <decimal> >();
            // Convert the tenors to doubles
            var tenorsAsDouble = new decimal[tenors.Length];

            for (int idx = 0; idx < tenors.Length; idx++)
            {
                tenorsAsDouble[idx] = decimal.Parse(tenors[idx]);
            }
            // Set up the min and max column (tenor) values
            int min = int.Parse(tenors[0]);
            int max = int.Parse(tenors[tenors.Length - 1]);

            // Loop through the expiry values testing the tenor values
            // Copy existing tenors or add new tenor values using interpolation
            for (int expiryIdx = 0; expiryIdx < expiry.Length; expiryIdx++)
            {
                int tenorIdx = 0;
                var inner    = new List <decimal>();
                var lin      = new LinearInterpolation(tenorsAsDouble, values[expiryIdx]);
                // Loop from the min to the max testing for valid tenor entries
                // and inserting new values where necessary
                for (int idx = min; idx <= max; idx++)
                {
                    if (idx == int.Parse(tenors[tenorIdx]))
                    {
                        // Add an existing tenor and its values array - Remember to check we haven't already added the tenor
                        if (!fullTenors.Contains(tenors[tenorIdx]))
                        {
                            fullTenors.Add(tenors[tenorIdx]);
                        }
                        inner.Add(values[expiryIdx][tenorIdx++]);
                    }
                    else
                    {
                        // Add the interpolated tenor and its value - Remember to check we haven't already added the tenor
                        if (!fullTenors.Contains(tenors[tenorIdx]))
                        {
                            fullTenors.Add(idx.ToString(CultureInfo.InvariantCulture));
                        }
                        inner.Add(lin.ValueAt((decimal)idx));
                    }
                }
                fullValues.Add(inner);
            }
            // Regenerate the arrays to use in the grid
            string[] interpolatedTenors = fullTenors.Select(a => a.Last() == 'y' ? a : a + "y").ToArray();
            var      interpolatedValues = new decimal[fullValues.Count][];

            for (int idx = 0; idx < fullValues.Count; idx++)
            {
                interpolatedValues[idx] = fullValues[idx].ToArray();
            }
            // Create the grid
            var grid = new ForwardRatesMatrix(expiry, interpolatedTenors, interpolatedValues);

            return(grid);
        }