// Objective function ===========================================================================
        public double f(double[] param, OFSet ofset)
        {
            BGMPrice      BGM = new BGMPrice();
            BisectionAlgo BA  = new BisectionAlgo();

            double S           = ofset.opset.S;
            double r           = ofset.opset.r;
            double q           = ofset.opset.q;
            int    trap        = ofset.opset.trap;
            int    ObjFunction = ofset.ObjFunction;
            OPSet  opset       = ofset.opset;

            double[,] MktIV    = ofset.data.MktIV;
            double[,] MktPrice = ofset.data.MktPrice;
            string[,] PutCall  = ofset.data.PutCall;
            double[] K = ofset.data.K;
            double[] T = ofset.data.T;
            double[] X = ofset.X;
            double[] W = ofset.W;

            int NK = PutCall.GetLength(0);
            int NT = PutCall.GetLength(1);

            // Separate out the parameters from the "param" vector;
            int    N     = param.Length;
            double kappa = param[0];
            double v0    = param[1];

            double[] THETA = new double[NT];
            double[] SIGMA = new double[NT];
            double[] RHO   = new double[NT];
            for (int k = 0; k <= NT - 1; k++)
            {
                THETA[k] = param[3 * k + 2];
                SIGMA[k] = param[3 * k + 3];
                RHO[k]   = param[3 * k + 4];
            }

            // Settings for the Bisection algorithm
            double a       = 0.001;
            double b       = 3.0;
            double Tol     = 1e5;
            int    MaxIter = 10000;

            // Initialize the model price and model implied vol vectors, and the objective function value
            double[,] ModelPrice = new double[NK, NT];
            double[,] ModelIV    = new double[NK, NT];
            double Vega  = 0.0;
            double Error = 0.0;
            double pi    = Math.PI;

            double[] lb = ofset.lb;
            double[] ub = ofset.ub;

            double kappaLB = lb[0]; double kappaUB = ub[0];
            double thetaLB = lb[1]; double thetaUB = ub[1];
            double sigmaLB = lb[2]; double sigmaUB = ub[2];
            double v0LB = lb[3]; double v0UB = ub[3];
            double rhoLB = lb[4]; double rhoUB = ub[4];

            List <double> MatList   = new List <double>();
            List <double> thetaList = new List <double>();
            List <double> sigmaList = new List <double>();
            List <double> rhoList   = new List <double>();

            double[] Mat, theta, sigma, rho;

            if ((kappa <= kappaLB) || (kappa >= kappaUB) || (v0 <= v0LB) || (v0 >= v0UB))
            {
                Error = 1e50;
            }
            for (int k = 0; k <= NT - 1; k++)
            {
                if ((THETA[k] <= thetaLB) || (THETA[k] >= thetaUB) || (SIGMA[k] <= sigmaLB) || (SIGMA[k] >= sigmaUB) || (RHO[k] <= rhoLB) || (RHO[k] >= rhoUB))
                {
                    Error = 1e50;
                }
            }
            {
                for (int t = 0; t < NT; t++)
                {
                    MatList.Add(T[t]);
                    thetaList.Add(THETA[t]);
                    sigmaList.Add(SIGMA[t]);
                    rhoList.Add(RHO[t]);
                    Mat   = MatList.ToArray();
                    theta = thetaList.ToArray();
                    sigma = sigmaList.ToArray();
                    rho   = rhoList.ToArray();
                    Mat.Reverse();
                    Array.Reverse(theta);
                    Array.Reverse(sigma);
                    Array.Reverse(rho);

                    for (int k = 0; k < NK; k++)
                    {
                        ModelPrice[k, t] = BGM.BGMApproxPriceTD(kappa, v0, theta, sigma, rho, opset, K[k], Mat);
                        switch (ObjFunction)
                        {
                        case 1:
                            // MSE Loss Function
                            Error += Math.Pow(ModelPrice[k, t] - MktPrice[k, t], 2.0);
                            break;

                        case 2:
                            // RMSE Loss Function
                            Error += Math.Pow(ModelPrice[k, t] - MktPrice[k, t], 2.0) / MktPrice[k, t];
                            break;

                        case 3:
                            // IVMSE Loss Function
                            ModelIV[k, t] = BA.BisecBSIV(opset, K[k], T[t], a, b, ModelPrice[k, t], Tol, MaxIter);
                            Error        += Math.Pow(ModelIV[k, t] - MktIV[k, t], 2);
                            break;

                        case 4:
                            // IVRMSE Christoffersen, Heston, Jacobs proxy
                            double d       = (Math.Log(S / K[k]) + (r - q + MktIV[k, t] * MktIV[k, t] / 2.0) * T[t]) / MktIV[k, t] / Math.Sqrt(T[t]);
                            double NormPDF = Math.Exp(-0.5 * d * d) / Math.Sqrt(2.0 * pi);
                            Vega   = S * NormPDF * Math.Sqrt(T[t]);
                            Error += Math.Pow(ModelPrice[k, t] - MktPrice[k, t], 2) / (Vega * Vega);
                            break;
                        }
                    }
                }
            }
            return(Error);
        }
Ejemplo n.º 2
0
        static void Main(string[] args)
        {
            // Classes
            BGMPrice      BGM = new BGMPrice();
            BisectionAlgo BA  = new BisectionAlgo();

            // 32-point Gauss-Laguerre Abscissas and weights
            double[] X = new Double[32];
            double[] W = new Double[32];
            using (TextReader reader = File.OpenText("../../GaussLaguerre32.txt"))
                for (int k = 0; k <= 31; k++)
                {
                    string   text = reader.ReadLine();
                    string[] bits = text.Split(' ');
                    X[k] = double.Parse(bits[0]);
                    W[k] = double.Parse(bits[1]);
                }

            // DJIA ETF (ticker DIA) put data
            double[,] PutIV = new double[13, 4] {
                { 0.1962, 0.1947, 0.2019, 0.2115 }, { 0.1910, 0.1905, 0.1980, 0.2082 },
                { 0.1860, 0.1861, 0.1943, 0.2057 }, { 0.1810, 0.1812, 0.1907, 0.2021 },
                { 0.1761, 0.1774, 0.1871, 0.2000 }, { 0.1718, 0.1743, 0.1842, 0.1974 },
                { 0.1671, 0.1706, 0.1813, 0.1950 }, { 0.1644, 0.1671, 0.1783, 0.1927 },
                { 0.1645, 0.1641, 0.1760, 0.1899 }, { 0.1661, 0.1625, 0.1743, 0.1884 },
                { 0.1701, 0.1602, 0.1726, 0.1862 }, { 0.1755, 0.1610, 0.1716, 0.1846 },
                { 0.1796, 0.1657, 0.1724, 0.1842 }
            };
            double[] K = new double[] { 124.0, 125.0, 126.0, 127.0, 128.0, 129.0, 130.0, 131.0, 132.0, 133.0, 134.0, 135.0, 136.0 };
            double[] T = new double[] { 37.0 / 365.0, 72.0 / 365.0, 135.0 / 365.0, 226.0 / 365.0, };
            double[,] MktIV = PutIV;
            double S  = 129.14;
            double r  = 0.0010;
            double q  = 0.0068;
            int    NT = 4;
            int    NK = 13;

            // Create the market prices
            BlackScholesPrice BS = new BlackScholesPrice();

            string[,] PutCall  = new string[NK, NT];
            double[,] MktPrice = new double[NK, NT];
            for (int t = 0; t < NT; t++)
            {
                for (int k = 0; k < NK; k++)
                {
                    PutCall[k, t]  = "P";
                    MktPrice[k, t] = BS.BlackScholes(S, K[k], T[t], r, q, MktIV[k, t], PutCall[k, t]);
                }
            }

            // Bounds on the parameter estimates
            double e = 1e-3;
            double kappaU = 20.0;       double kappaL = e;
            double thetaU = 3.0;       double thetaL = e;
            double sigmaU = 10.0;       double sigmaL = e;
            double v0U = 3.0;       double v0L = e;
            double rhoU = 0.99;       double rhoL = -0.99;
            int    N = 2 + 3 * NT;

            double[] ub = new double[N];
            double[] lb = new double[N];
            for (int j = 0; j <= N; j++)
            {
                ub[0] = kappaU; lb[0] = kappaL;
                ub[1] = v0U; lb[1] = v0L;
                for (int k = 1; k <= NT; k++)
                {
                    ub[3 * k - 1] = thetaU; lb[3 * k - 1] = thetaL;
                    ub[3 * k]     = sigmaU; lb[3 * k - 1] = sigmaL;
                    ub[3 * k + 1] = rhoU; lb[3 * k + 1] = rhoL;
                }
            }

            // Starting values for the parameters
            // Parameter order is [kappa v0 | theta[0] sigma[0] rho[0] | theta[1] sigma[1] rho[1] | etc...];
            double kappaS = 2.0;
            double thetaS = 0.1;
            double sigmaS = 1.2;
            double v0S    = 0.05;
            double rhoS   = -0.5;

            double[,] s = new double[N, N + 1];
            for (int j = 0; j <= N; j++)
            {
                s[0, j] = kappaS + BS.RandomNum(-0.01, 0.01) * kappaS;
                s[1, j] = v0S + BS.RandomNum(-0.01, 0.01) * v0S;
                for (int k = 1; k <= NT; k++)
                {
                    s[3 * k - 1, j] = thetaS + BS.RandomNum(-0.01, 0.01) * thetaS;
                    s[3 * k, j]     = sigmaS + BS.RandomNum(-0.01, 0.01) * sigmaS;
                    s[3 * k + 1, j] = rhoS + BS.RandomNum(-0.01, 0.01) * rhoS;
                }
            }

            // Structure for the option settings
            OPSet opset;

            opset.S       = S;
            opset.r       = r;
            opset.q       = q;
            opset.trap    = 1;
            opset.PutCall = "P";

            // Structure for the market data
            MktData data;

            data.MktIV    = MktIV;
            data.MktPrice = MktPrice;
            data.K        = K;
            data.T        = T;
            data.PutCall  = PutCall;

            // Structure for the objective function settings
            OFSet ofset;

            ofset.opset       = opset;
            ofset.data        = data;
            ofset.X           = X;
            ofset.W           = W;
            ofset.ObjFunction = 4;
            ofset.lb          = lb;
            ofset.ub          = ub;

            // Structure for the Nelder Mead algorithm settings
            NMSet nmset;

            nmset.ofset     = ofset;
            nmset.MaxIters  = 5000;
            nmset.Tolerance = 1e-8;
            nmset.N         = N;

            // Run the Nelder Mead Algorithm
            NelderMeadAlgo    NM = new NelderMeadAlgo();
            ObjectiveFunction OF = new ObjectiveFunction();

            double[] B  = NM.NelderMead(OF.f, nmset, s);
            int      NB = B.Length;

            // Separate the parameter vector into different vectors
            double kappa = B[0];
            double v0    = B[1];

            double[] theta = new double[NT];
            double[] sigma = new double[NT];
            double[] rho   = new double[NT];
            for (int k = 0; k <= NT - 1; k++)
            {
                theta[k] = B[3 * k + 2];
                sigma[k] = B[3 * k + 3];
                rho[k]   = B[3 * k + 4];
            }

            // Bisection algorithm settings
            double a       = 0.01;
            double b       = 4.0;
            double Tol     = 1e-5;
            int    MaxIter = 2500;

            // Find the implied volatilities
            double[,] ModelPrice = new double[NK, NT];
            double[,] ModelIV    = new double[NK, NT];
            double Error = 0.00;

            List <double> MatList   = new List <double>();
            List <double> thetaList = new List <double>();
            List <double> sigmaList = new List <double>();
            List <double> rhoList   = new List <double>();

            double[] Mat, Theta, Sigma, Rho;
            for (int t = 0; t < NT; t++)
            {
                // Stack the parameters
                MatList.Add(T[t]);
                thetaList.Add(theta[t]);
                sigmaList.Add(sigma[t]);
                rhoList.Add(rho[t]);
                // Convert to arrays
                Mat   = MatList.ToArray();
                Theta = thetaList.ToArray();
                Sigma = sigmaList.ToArray();
                Rho   = rhoList.ToArray();
                for (int k = 0; k < NK; k++)
                {
                    ModelPrice[k, t] = BGM.BGMApproxPriceTD(kappa, v0, Theta, Sigma, Rho, opset, K[k], Mat);
                    ModelIV[k, t]    = BA.BisecBSIV(opset, K[k], T[t], a, b, ModelPrice[k, t], Tol, MaxIter);
                    Error           += Math.Pow(ModelIV[k, t] - MktIV[k, t], 2.0) / Convert.ToDouble(NT * NK);
                }
            }

            // Output the results
            Console.WriteLine("----------------------------------------------------------");
            Console.WriteLine("    kappa      v0         theta      sigma        rho");
            Console.WriteLine("----------------------------------------------------------");
            for (int k = 0; k <= NT - 1; k++)
            {
                Console.WriteLine("{0,10:F5} {1,10:F5} {2,10:F5} {3,10:F5} {4,10:F5}", kappa, v0, theta[k], sigma[k], rho[k]);
            }

            Console.WriteLine("----------------------------------------------------------");
            Console.WriteLine("Value of objective function   {0:F5} ", B[NB - 2]);
            Console.WriteLine("Number of iterations required {0:0}  ", B[NB - 1]);
            Console.WriteLine("----------------------------------------------------------");
            Console.WriteLine(" ");
            Console.WriteLine("Model/Market implied volatilities");
            Console.WriteLine("----------------------------------------------------------");
            Console.WriteLine("Strike    Mat1       Mat2        Mat3       Mat4");
            Console.WriteLine("----------------------------------------------------------");
            for (int k = 0; k <= NK - 1; k++)
            {
                Console.WriteLine("{0,5:0} {1,10:F5} {2,10:F5} {3,10:F5} {4,10:F5}", K[k], ModelIV[k, 0], ModelIV[k, 1], ModelIV[k, 2], ModelIV[k, 3]);
                Console.WriteLine("{0,5:0} {1,10:F5} {2,10:F5} {3,10:F5} {4,10:F5}", K[k], MktIV[k, 0], MktIV[k, 1], MktIV[k, 2], MktIV[k, 3]);
                Console.WriteLine("----------------------------------------------------------");
            }
            Console.WriteLine(" ");
            Console.WriteLine("IV Estimation error {0,5:E5}", Error);
            Console.WriteLine(" ");
        }