public void Build(DateTime originDate, double[][] strikes, DateTime[] expiries, double[][] vols, Func <double, double> forwardCurve) { OriginDate = originDate; Expiries = expiries; ExpiriesDouble = Expiries.Select(t => TimeBasis.CalculateYearFraction(originDate, t)).ToArray(); if (Expiries.Length != strikes.Length) { throw new InvalidOperationException("Expiries and first dimension of Strikes must of same length"); } if (Expiries.Length != vols.Length) { throw new InvalidOperationException("Expiries and first dimension of Vols must of same length"); } Alphas = new double[Expiries.Length]; Betas = new double[Expiries.Length]; Nus = new double[Expiries.Length]; Rhos = new double[Expiries.Length]; for (var i = 0; i < expiries.Length; i++) { var vs = vols[i]; var ks = strikes[i]; var t = ExpiriesDouble[i]; var fwd = forwardCurve(t); Betas[i] = 1.0; Func <double[], double[]> errorFunc = (x => { var err = ks.Select((k, ix) => vs[ix] - SABR.CalcImpVol_Beta1(fwd, k, t, x[0], x[1], x[2])); return(err.ToArray()); }); var n2Sol = new Math.Solvers.GaussNewton { ObjectiveFunction = errorFunc, InitialGuess = new double[] { vs.Average(), 0.1, 0.1 }, Tollerance = 1e-8, JacobianBump = 0.0000001 }; var paramArr = n2Sol.Solve(); Alphas[i] = paramArr[0]; Rhos[i] = paramArr[1]; Nus[i] = paramArr[2]; } var fwds = ExpiriesDouble.Select(x => forwardCurve(x)).ToArray(); _alphaInterp = InterpolatorFactory.GetInterpolator(ExpiriesDouble, Alphas, TimeInterpolatorType); _betaInterp = InterpolatorFactory.GetInterpolator(ExpiriesDouble, Betas, TimeInterpolatorType); _rhoInterp = InterpolatorFactory.GetInterpolator(ExpiriesDouble, Rhos, TimeInterpolatorType); _nuInterp = InterpolatorFactory.GetInterpolator(ExpiriesDouble, Nus, TimeInterpolatorType); _fwdsInterp = InterpolatorFactory.GetInterpolator(ExpiriesDouble, fwds, TimeInterpolatorType); }
private double GetDeltaStrikeForAbs(double fwd, double strike, double maturity) { var cp = strike < 0 ? OptionType.Put : OptionType.Call; Func <double, double> testFunc = (deltaK => { var interpForStrike = InterpolatorFactory.GetInterpolator(ExpiriesDouble, ExpiriesDouble.Select(e => GetVolForDeltaStrike(deltaK, e, fwd)).ToArray(), TimeInterpolatorType); var vol2 = interpForStrike.Interpolate(maturity); var absK = BlackFunctions.AbsoluteStrikefromDeltaKAnalytic(fwd, deltaK, 0, maturity, vol2); return(absK - strike); }); var solvedStrike = -Math.Solvers.Brent.BrentsMethodSolve(testFunc, -0.99999999999, -0.00000000001, 1e-8); if (solvedStrike == 0.00000000001 || solvedStrike == 0.99999999999) //out of bounds { var upperK = testFunc(-0.00000000001); var lowerK = testFunc(-0.99999999999); if (Abs(upperK - fwd) < Abs(lowerK - fwd)) { solvedStrike = 0.00000000001; } else { solvedStrike = 0.99999999999; } } return(solvedStrike); }
private double GetAbsStrikeForDelta(double fwd, double deltaStrike, double maturity) { var cp = deltaStrike < 0 ? OptionType.Put : OptionType.Call; Func <double, double> testFunc = (absK => { var interpForStrike = InterpolatorFactory.GetInterpolator(ExpiriesDouble, ExpiriesDouble.Select(e => GetVolForAbsoluteStrike(absK, e, fwd)).ToArray(), TimeInterpolatorType); var vol2 = interpForStrike.Interpolate(maturity); var deltaK = BlackFunctions.BlackDelta(fwd, absK, 0, maturity, vol2, cp); return(deltaK - deltaStrike); }); var solvedStrike = Math.Solvers.Brent.BrentsMethodSolve(testFunc, 0.000000001, 50 * fwd, 1e-8); return(solvedStrike); }