Пример #1
0
        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);
        }
Пример #2
0
        public void SABRParamToIVFacts()
        {
            //for  beta==1 and zero nu and rho we get a flat surface with vol==alpha
            var vol = SABR.CalcImpVol_Beta1(100, 100, 1, 0.32, 0, 0);

            Assert.Equal(0.32, vol, 10);
            vol = SABR.CalcImpVol_Beta1(100, 150, 1, 0.32, 0, 0);
            Assert.Equal(0.32, vol, 10);
            vol = SABR.CalcImpVol_Beta1(100, 50, 1, 0.32, 0, 0);
            Assert.Equal(0.32, vol, 10);

            //for positive rho should see upside vols > downside
            var volU = SABR.CalcImpVol_Beta1(100, 150, 1, 0.32, 0.5, 0.16);
            var volD = SABR.CalcImpVol_Beta1(100, 75, 1, 0.32, 0.5, 0.16);

            Assert.True(volU > volD);

            //for negative rho should see upside vols < downside
            volU = SABR.CalcImpVol_Beta1(100, 150, 1, 0.32, -0.5, 0.16);
            volD = SABR.CalcImpVol_Beta1(100, 75, 1, 0.32, -0.5, 0.16);
            Assert.True(volU < volD);

            //for larger nu should see upside wing vols higher
            volU = SABR.CalcImpVol_Beta1(100, 150, 1, 0.32, 0, 0.16);
            volD = SABR.CalcImpVol_Beta1(100, 75, 1, 0.32, 0, 0.16);
            var wingLow = volU + volD;

            volU = SABR.CalcImpVol_Beta1(100, 150, 1, 0.32, 0, 0.32);
            volD = SABR.CalcImpVol_Beta1(100, 75, 1, 0.32, 0, 0.32);
            var wingHigh = volU + volD;

            Assert.True(wingHigh > wingLow);

            //for GB parameterization, should see no sensitivity to rho and nu at ATM
            var volA = SABR.CalcImpVol_GB(100, 100, 1, 0.32, 0, 0.16);
            var volB = SABR.CalcImpVol_GB(100, 100, 1, 0.32, -0.5, 0.26);

            Assert.Equal(volA, volB, 10);

            //for hagan and berestycki, should see agreement in most cases
            var volHa = SABR.CalcImpVol_Hagan(100, 100, 1, 0.32, 0.9, 0.5, 0.16);
            var volBe = SABR.CalcImpVol_Berestycki(100, 100, 1, 0.32, 0.9, 0.5, 0.16);

            Assert.Equal(volHa, volBe, 5);
            volHa = SABR.CalcImpVol_Hagan(100, 150, 1, 0.32, 0.5, 0.5, 0.16);
            volBe = SABR.CalcImpVol_Berestycki(100, 150, 1, 0.32, 0.5, 0.5, 0.16);
            Assert.Equal(volHa, volBe, 3);
        }
Пример #3
0
        public double GetVolForAbsoluteStrike(double strike, double maturity, double forward)
        {
            var alpha = _alphaInterp.Interpolate(maturity);
            var beta  = _betaInterp.Interpolate(maturity);
            var nu    = _nuInterp.Interpolate(maturity);
            var rho   = _rhoInterp.Interpolate(maturity);
            var fwd   = forward;

            if (beta >= 1.0)
            {
                return(SABR.CalcImpVol_Beta1(fwd, strike, maturity, alpha, rho, nu));
            }
            else
            {
                return(SABR.CalcImpVol_Hagan(fwd, strike, maturity, alpha, beta, rho, nu));
            }
        }
Пример #4
0
 public double CalcImpVol_Beta1(double k, SABRParameters currentSABR) => SABR.CalcImpVol_Beta1(_fwd, k, _tExp, currentSABR.Alpha, currentSABR.Rho, currentSABR.Nu);
Пример #5
0
 public static double GetVolForAbsoluteStrike(double strike, double maturity, double forward, SABRParameters sabrParams) => sabrParams.Beta >= 1.0
         ? SABR.CalcImpVol_Beta1(forward, strike, maturity, sabrParams.Alpha, sabrParams.Rho, sabrParams.Nu)
         : SABR.CalcImpVol_Hagan(forward, strike, maturity, sabrParams.Alpha, sabrParams.Beta, sabrParams.Rho, sabrParams.Nu);