public void TestEval() { var abs = new[] { 0.0, 0.5, 0.99, 2.5 }; var vals = new[] { 5.0, 5.4, 3.1, 1.0 }; const double leftSlope = 0.0; const double rightSlope = 0.98181; var stepFunc = RrFunctions.LinearInterpolation(abs, vals, leftSlope, rightSlope); foreach (var i in Enumerable.Range(0, abs.Length)) { Assert.AreEqual(stepFunc.Eval(abs[i]), vals[i]); if (i < abs.Length - 1) { var midPoint = 0.5 * (abs[i] + abs[i + 1]); Assert.AreEqual(stepFunc.Eval(midPoint), 0.5 * (vals[i] + vals[i + 1])); } } double leftExtrapolPoint = abs[0] - 10.0; Assert.AreEqual(stepFunc.Eval(leftExtrapolPoint), vals[0] + leftSlope * (leftExtrapolPoint - abs[0])); double rightExtrapolPoint = abs[abs.Length - 1] + 10.0; Assert.AreEqual(stepFunc.Eval(rightExtrapolPoint), vals[abs.Length - 1] + rightSlope * (rightExtrapolPoint - abs[abs.Length - 1])); }
public static DiscountCurve LinearRateInterpol(FinancingId financing, DateTime[] pillars, double[] zcs, ITimeMeasure time) { if (pillars.Length != zcs.Length) throw new Exception("LinearRateDiscountProvider : Incompatible size"); var dates = time[pillars]; var zcRates = new double[pillars.Length]; if (DoubleUtils.EqualZero(dates[0])) { if (!DoubleUtils.MachineEquality(1.0, zcs[0])) throw new Exception("LinearRateInterpol : Discount for refDate must equal to 1.0 "); zcRates[0] = 0.0; } else { zcRates[0] = -Math.Log(zcs[0]) / dates[0]; } for (int i = 1; i < zcs.Length; i++) { zcRates[i] = -Math.Log(zcs[i]) / dates[i]; } return new DiscountCurveFromRate(financing, time, RrFunctions.LinearInterpolation(dates, zcRates)); }
private static RrFunction BuildXi(MapRawDatas <DateOrDuration, double> sigma, ITimeMeasure time) { var matVars = EnumerableUtils.For(0, sigma.Pillars.Length, i => { var mat = time[sigma.Pillars[i].ToDate(time.RefDate)]; var variance = sigma.Values[i] * sigma.Values[i] * mat; return(new { Mat = mat, Variance = variance }); }).OrderBy(t => t.Mat).ToArray(); if (!DoubleUtils.EqualZero(matVars.First().Mat)) { matVars = matVars.Concat(new[] { new { Mat = 0.0, Variance = 0.0 } }) .OrderBy(t => t.Mat).ToArray(); } var varianceFunc = RrFunctions.LinearInterpolation(matVars.Map(t => t.Mat), matVars.Map(t => t.Variance), 0.0, double.NaN); return(varianceFunc.Derivative()); }
public double[] CalibrateVol(double[] maturities, double[] targetPrices, double[] strikes, double[] optionTypes) { Contract.Requires(EnumerableUtils.IsSorted(maturities)); Contract.Requires(maturities.Length == strikes.Length && strikes.Length == targetPrices.Length && targetPrices.Length == optionTypes.Length); double[] variances = new double[maturities.Length + 1]; double[] varPillars = new[] { 0.0 }.Concat(maturities).ToArray(); double[] calibVols = new double[maturities.Length]; for (int step = 0; step < maturities.Length; step++) { var maturity = maturities[step]; var strike = strikes[step]; var targetPrice = targetPrices[step]; var q = optionTypes[step]; //Proxy using Lehman Formula double proxyFwd, proxyDk; affineDivUtils.LehmanProxy(maturity, spot, out proxyFwd, out proxyDk); double lehmanTargetVol = BlackScholesOption.ImpliedVol(targetPrice, proxyFwd, strike + proxyDk, maturity, q); var pricer = new BsDivPrice(maturities[step], strikes[step], spot, affineDivUtils, quadPoints, quadWeights); Func <double, double> volToLehmanVolErr = v => { variances[1 + step] = v * v * maturity; var varFunc = RrFunctions.LinearInterpolation(varPillars, variances); Func <double, double> volFunc = t => Math.Sqrt(varFunc.Eval(t) / t); var price = pricer.Price(volFunc, q); return(BlackScholesOption.ImpliedVol(price, proxyFwd, strike + proxyDk, maturity, q) - lehmanTargetVol); };//TODO use a cache //Bracket & Solve double v1 = lehmanTargetVol; double v2; if (step == 0) { v2 = lehmanTargetVol - volToLehmanVolErr(lehmanTargetVol); } else { var volIfZeroVolOnStep = Math.Sqrt(calibVols[step - 1] * calibVols[step - 1] * maturities[step - 1] / maturities[step]); var minError = volToLehmanVolErr(volIfZeroVolOnStep); if (minError > 0.0) //saturation case { calibVols[step] = volIfZeroVolOnStep; variances[1 + step] = volIfZeroVolOnStep * volIfZeroVolOnStep * maturity; continue; } v2 = volIfZeroVolOnStep; } if (!RootUtils.Bracket(volToLehmanVolErr, v1, v2, out v1, out v2)) { throw new Exception("Failed to inverse vol"); } var impliedVol = RootUtils.Brenth(volToLehmanVolErr, v1, v2, 1.0e-10, 2.0 * DoubleUtils.MachineEpsilon, 10); calibVols[step] = impliedVol; variances[1 + step] = impliedVol * impliedVol * maturity; } return(calibVols); }