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); }
/// <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); } }
/// <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); }
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); }
/// <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)); }
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}"); } }
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); }
/// <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<-1,3+x,x<0,-1-3*x,x<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); }
/// <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> /// 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); }