예제 #1
0
        public void ValueTest()
        {
            double[] xValues = { 0.00273972602739726,
                                 0.0191780821917808,
                                 0.0383561643835616,
                                 0.0821917808219178,
                                 0.16986301369863,
                                 0.252054794520547,
                                 0.265753424657534,
                                 0.506849315068493,
                                 0.753424657534246,
                                 1.01369863013698,
                                 1.26301369863013,
                                 1.50410958904109,
                                 1.75068493150684,
                                 2.01369863 };

            double[] yValues = { 0.000198610398037118,
                                 0.00144115280642265,
                                 0.00292486360387681,
                                 0.00631290829444216,
                                 0.0129485443009048,
                                 0.0191542839259883,
                                 0.0203498757471952,
                                 0.0391594113610678,
                                 0.0585407323615074,
                                 0.0789041494478555,
                                 0.0982464310004563,
                                 0.116728055717234,
                                 0.135405191240189,
                                 0.154521506325593 };


            var plc = new LinearInterpolation(xValues, yValues);
            // Test the actual nodes
            double actual   = plc.ValueAt(0.00273972602739726);
            var    expected = 0.000198610398037118;

            Assert.AreEqual(expected, actual);

            actual   = plc.ValueAt(2.01369863);
            expected = 0.154521506325593;
            Assert.AreEqual(expected, actual);

            actual   = plc.ValueAt(1.75068493150684);
            expected = 0.135405191240189;
            Assert.AreEqual(expected, actual);

            // Test mid point
            actual   = plc.ValueAt(1.882191780822);
            expected = 0.14496334878289;
            AssertExtension.LessOrEqual(Math.Abs(actual - expected), 10E-12);
        }
예제 #2
0
        /// <summary>
        /// Verifies that the interpolation supports the linear case appropriately
        /// </summary>
        /// <param name="samples">Samples array.</param>
        public void SupportsLinearCase(int samples)
        {
            double[] x, y, xtest, ytest;
            LinearInterpolationCase.Build(out x, out y, out xtest, out ytest, samples);
            var ip = new LinearInterpolation(x, y);

            for (int i = 0; i < xtest.Length; i++)
            {
                Assert.AreEqual(ytest[i], ip.ValueAt(xtest[i]), 1e-15, "Linear with {0} samples, sample {1}", samples, i);
            }
        }
예제 #3
0
        /// <summary>
        /// Bootstraps the specified priceable assets, where the assets
        /// are simple commodity asset with single cash flows on a
        /// single index observation.
        /// </summary>
        /// <param name="priceableAssets">The priceable assets.</param>
        /// <param name="referenceCurve">The reference curve.</param>
        /// <param name="baseDate">The base date.</param>
        /// <param name="extrapolationPermitted">The extrapolationPermitted flag.</param>
        /// <param name="tolerance">The tolerance for the solver</param>
        /// <param name="spreadXArray">THe spread interpolator produced in the bootstrapper</param>
        /// <param name="spreadYArray">THe spread interpolator produced in the bootstrapper</param>
        /// <returns></returns>
        public static TermPoint[] Bootstrap(IEnumerable <IPriceableCommoditySpreadAssetController> priceableAssets,
                                            ICommodityCurve referenceCurve, DateTime baseDate, bool extrapolationPermitted, double tolerance, ref IList <double> spreadXArray, ref IList <double> spreadYArray)
        {
            //only works for linear on zero.
            //InterpolationMethod interp = InterpolationMethodHelper.Parse("LinearInterpolation");
            //  Add the first element (date : discount factor) to the list
            var points = new Dictionary <DateTime, double>();
            var items
                = new SortedDictionary <DateTime, Pair <string, decimal> >();
            var dayCounter = new Actual365();

            foreach (var priceableAsset in priceableAssets)
            {
                DateTime assetMaturityDate = priceableAsset.GetRiskMaturityDate();
                if (points.Keys.Contains(assetMaturityDate))
                {
                    continue;
                }
                //This now should automatically extrapolate the required discount factor on a flat rate basis.
                if (IsSpreadAsset(priceableAsset))
                {
                    //These are simple assts so the solver is unnecessary.
                    var value    = (double)priceableAsset.CalculateImpliedQuoteWithSpread(referenceCurve);
                    var dayCount = dayCounter.YearFraction(baseDate, assetMaturityDate);
                    spreadXArray.Add(dayCount);
                    spreadYArray.Add((double)priceableAsset.MarketQuote.value);  //TODO Get the marketquote
                    points.Add(assetMaturityDate, value);
                    items.Add(assetMaturityDate,
                              new Pair <string, decimal>(priceableAsset.Id, (decimal)points[assetMaturityDate]));
                }
            }
            if (spreadXArray.Count > 2)
            {
                var spreadCurveInterpolator = new LinearInterpolation(spreadXArray.ToArray(),
                                                                      spreadYArray.ToArray());
                var index = 0;
                foreach (var assetMaturityDate in referenceCurve.GetTermCurve().GetListTermDates())
                {
                    if (points.Keys.Contains(assetMaturityDate))
                    {
                        continue;
                    }
                    var    dayCount    = dayCounter.YearFraction(baseDate, assetMaturityDate);
                    double spreadValue = spreadCurveInterpolator.ValueAt(dayCount, true);
                    var    value       = referenceCurve.GetForward(baseDate, assetMaturityDate);
                    points.Add(assetMaturityDate, value + spreadValue);
                    items.Add(assetMaturityDate,
                              new Pair <string, decimal>("RefCurvePillar_" + index, (decimal)points[assetMaturityDate]));
                    index++;
                }
                return(TermPointsFactory.Create(items));
            }
            return(null);
        }
예제 #4
0
        public void TestInterpolate()
        {
            //// Degenerate case of a single point.
            double[]            xArray1    = { 0.1 };
            double[]            yArray1    = { -3.45 };
            LinearInterpolation interpObj1 =
                new LinearInterpolation(xArray1, yArray1);

            Assert.AreNotEqual(interpObj1, null);
            double target1 = 10;
            var    val     = interpObj1.ValueAt(target1, true);

            Assert.AreEqual(val, yArray1[0]);
            // Generic case.
            double[]            xArray2       = { 0.0028, 0.0250, 0.0444 };
            double[]            yArray2       = { 3.3285, 3.3174, 3.3222 };//3.3285
            double[]            expectedArray = { 3.829899999999995, 3.3174, 3.8060597938144243 };
            LinearInterpolation interpObj2    =
                new LinearInterpolation(xArray2, yArray2);

            Assert.AreNotEqual(interpObj2, null);
            double target2 = -1; // left end extrapolation

            val = interpObj2.ValueAt(target2, true);
            Assert.AreEqual(val, expectedArray[0]);
            double target3 = 2; // right end extrapolation

            val = interpObj2.ValueAt(target3, true);
            Assert.AreEqual(val, expectedArray[2]);
            double target4 = 0.0250; // nodal point

            val = interpObj2.ValueAt(target4, true);
            Assert.AreEqual(val, expectedArray[1]);
            double target5 = 0.0347;

            val = interpObj2.ValueAt(target5, true);
            double expected  = 3.3198;
            double tolerance = 1.0E-10;

            AssertExtension.Less(Math.Abs(val - expected), tolerance);
        }
예제 #5
0
        /// <summary>
        /// Calcs the forward vols.
        /// </summary>
        /// <param name="times">The times.</param>
        /// <param name="vols">The vols.</param>
        /// <returns></returns>
        double[] CalcForwardVariance(double[] times, double[] vols)
        {
            int n = times.Length;

            double[]      quadvar  = new double[n];
            List <double> quadvar0 = new List <double>();
            List <double> quadt0   = new List <double>();

            double[] quadvar1 = new double[n];
            double[] fwdvols  = new double[n];
            for (int idx = 0; idx < n; idx++)
            {
                quadvar[idx] = vols[idx] * vols[idx] * times[idx];
            }
            //create List quadvar0 of quadratic variations and associated times,
            //dropping negative fwd vols
            int jdx = 1;

            quadvar0.Add(quadvar[0]);
            quadt0.Add(times[0]);
            for (int idx = 1; idx < n; idx++)
            {
                if (quadvar[idx] > quadvar[idx - 1])
                {
                    quadvar0.Add(quadvar[idx]);
                    quadt0.Add(times[idx]);
                    jdx++;
                }
            }
            //interpolate cut down list to original time vector
            for (int idx = 0; idx < n; idx++)
            {
                double time1 = times[idx];
                var    li    = new LinearInterpolation();
                li.Initialize(quadt0.ToArray(), quadvar0.ToArray());
                double y = li.ValueAt(time1, false);
                quadvar1[idx] = y;
            }

            //convert back from quadratic variatons to forward vols
            fwdvols[0] = vols[0] * vols[0];
            for (int idx = 0; idx < n - 1; idx++)
            {
                double vol0   = quadvar1[idx];
                double vol1   = quadvar1[idx + 1];
                double fwdvol = Math.Sqrt((vol1 - vol0) / (times[idx + 1] - times[idx]));
                fwdvols[idx + 1] = fwdvol * fwdvol;
            }

            return(fwdvols);
        }
        /// <summary>
        /// Update required extra points, using Linear interpolation and flat line extrapolation
        /// </summary>
        public void UpdateDiscountFactors(DateTime baseDate)
        {
            double[]            zeroRateDays  = _zeroRateSpreads.Select(a => (double)a.Key.Subtract(baseDate).Days).ToArray();
            var                 values        = _zeroRateSpreads.Values.ToArray();
            LinearInterpolation interpolation = new LinearInterpolation(zeroRateDays, values);

            foreach (KeyValuePair <DateTime, string> extraPoint in _extraPoints)
            {
                double day            = extraPoint.Key.Subtract(baseDate).Days;
                double zeroRateSpread = interpolation.ValueAt(day);
                double df             = RateBootstrapperNewtonRaphson.GetAdjustedDiscountFactor(baseDate, extraPoint.Key, _dayCounter, zeroRateSpread, _baseCurve);
                _items[extraPoint.Key].Second = (decimal)df;
            }
        }
        /// <summary>
        /// Compute a one dimensional (piecewise) Linear interpolation. Extrapolation is flat-line.
        /// </summary>
        /// <param name="xValues">One dimensional array of x-values. Array is not required to be in ascending order.</param>
        /// <param name="yValues">One dimensional array of known y-values. Length of the array must be equal to the length of the XArray parameter.</param>
        /// <param name="target">Value at which to compute the interpolation.</param>
        /// <returns></returns>
        public double LinearInterpolate(Double[] xValues, Double[] yValues, double target)
        {
            if (xValues == null)
            {
                return(0);
            }
            if (yValues == null)
            {
                return(0);
            }
            var li = new LinearInterpolation();

            li.Initialize(xValues, yValues);
            return(li.ValueAt(target, true));
        }
예제 #8
0
        public void TestLinearInterpolation()
        {
            Random r = new Random(Environment.TickCount);

            TearDown();
            var interpolation = new LinearInterpolation();

            interpolation.Initialize(_times, _rates);
            for (int i = 0; i < 10; ++i)
            {
                double time       = (i + r.Next(-10000, 10000) / 10000);
                double interpRate = interpolation.ValueAt(time, true);
                Debug.WriteLine($"interpolatedRate : {interpRate} Time: {time}");
            }
        }
예제 #9
0
        public double Value(double trialAdjustment)
        {
            // Set the adjustments
            // Adjust the rates with the answer
            if (_spreadStartIndex == 0)
            {
                for (int i = 0; i <= _spreadEndIndex; i++)
                {
                    _adjustments[i] = (decimal)trialAdjustment;
                }
            }
            else
            {
                int startDays = _days[_spreadStartIndex - 1];

                // if there is only one point then don't interpolate
                if (_spreadDays == startDays)
                {
                    _adjustments[_spreadStartIndex] = (decimal)trialAdjustment;
                }
                else
                {
                    var x             = new double[] { startDays, _spreadDays };
                    var y             = new[] { (double)_adjustments[_spreadStartIndex - 1], trialAdjustment };
                    var interpolation = new LinearInterpolation();
                    interpolation.Initialize(x, y);

                    for (int i = _spreadStartIndex; i <= _spreadEndIndex; i++)
                    {
                        int days = _days[i];
                        _adjustments[i] = (decimal)interpolation.ValueAt(days, false);
                    }
                }
            }
            double valueForAdjustment = RateCurve.CalculateImpliedQuote(_logger, _cache, _nameSpace, _baseDate, _properties, _instruments, _rates, _adjustments, _spreadAssetId,
                                                                        _spreadAssetValuation, _fixingCalendar, _rollCalendar);

            return(valueForAdjustment - _valueForZeroAdjustment - _spread);
        }
예제 #10
0
        /// <summary>
        /// Verifies that at points other than the provided sample points, the interpolation matches the one computed by Maple as a reference.
        /// </summary>
        /// <param name="t">Sample point.</param>
        /// <param name="x">Sample value.</param>
        /// <param name="maxAbsoluteError">Maximum absolute error.</param>
        /// <remarks>
        /// Maple:
        /// f := x -> piecewise(x&lt;-1,3+x,x&lt;0,-1-3*x,x&lt;1,-1+x,-1+x);
        /// f(x)
        /// </remarks>
        public void FitsAtArbitraryPoints(double t, double x, double maxAbsoluteError)
        {
            var ip = new LinearInterpolation(_t, _y);

            Assert.AreEqual(x, ip.ValueAt(t), maxAbsoluteError, "Interpolation at {0}", t);
        }
예제 #11
0
        /// <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);
        }
예제 #12
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);
        }