// Objective function ===========================================================================
        public double f(double[] param, OFSet ofset)
        {
            Bisection   BA   = new Bisection();
            HestonPrice HP   = new HestonPrice();
            double      S    = ofset.opsettings.S;
            double      r    = ofset.opsettings.r;
            double      q    = ofset.opsettings.q;
            int         trap = ofset.opsettings.trap;

            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;

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

            HParam param2 = new HParam();

            param2.kappa = param[0];
            param2.theta = param[1];
            param2.sigma = param[2];
            param2.v0    = param[3];
            param2.rho   = param[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];

            int LossFunction = ofset.LossFunction;

            double[] X = ofset.X;
            double[] W = ofset.W;

            // Penalty for inadmissible parameter values
            if ((param2.kappa <= kappaLB) || (param2.theta <= thetaLB) || (param2.sigma <= sigmaLB) || (param2.v0 <= v0LB) || (param2.rho <= rhoLB) ||
                (param2.kappa >= kappaUB) || (param2.theta >= thetaUB) || (param2.sigma >= sigmaUB) || (param2.v0 >= v0UB) || (param2.rho >= rhoUB))
            {
                Error = 1e50;
            }
            else
            {
                for (int k = 0; k < NK; k++)
                {
                    for (int t = 0; t < NT; t++)
                    {
                        ModelPrice[k, t] = HP.HestonPriceGaussLaguerre(param2, S, K[k], r, q, T[t], trap, PutCall[k, t], X, W);
                        switch (LossFunction)
                        {
                        case 1:
                            // MSE Loss Function
                            Error += Math.Pow(ModelPrice[k, t] - MktPrice[k, t], 2) / Convert.ToDouble(NT * NK);
                            break;

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

                        case 3:
                            // IVMSE Loss Function
                            ModelIV[k, t] = BA.BisecBSIV(PutCall[k, t], S, K[k], r, q, T[t], a, b, ModelPrice[k, t], Tol, MaxIter);
                            Error        += Math.Pow(ModelIV[k, t] - MktIV[k, t], 2) / Convert.ToDouble(NT * NK);;
                            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 / Convert.ToDouble(NT * NK);
                            break;
                        }
                    }
                }
            }
            return(Error);
        }
Exemplo n.º 2
0
        // SVC objective function ===========================================================================
        public double f(double[] param, OFSet ofset)
        {
            HestonPrice HP = new HestonPrice();
            Bisection   B  = new Bisection();

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

            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;
            string   CF           = ofset.CF;
            int      LossFunction = ofset.LossFunction;

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

            HParam param2 = new HParam();

            param2.kappa = param[0];
            param2.theta = param[1];
            param2.sigma = param[2];
            param2.v0    = param[3];
            param2.rho   = param[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;

            if ((param2.kappa <= 0) || (param2.theta <= 0) || (param2.sigma <= 0) || (param2.v0 <= 0) || (param2.rho <= -1) ||
                (param2.kappa >= 20) || (param2.theta >= 2) || (param2.sigma >= 2) || (param2.v0 >= 3) || (param2.rho >= 1))
            {
                Error = 1e50;
            }
            else
            {
                Complex   phi       = new Complex(0.0, 0.0);
                double    phi2      = 0.0;
                Complex   i         = new Complex(0.0, 1.0);
                Complex[] f2        = new Complex[NX];
                Complex[] f1        = new Complex[NX];
                Complex[] f         = new Complex[NX];
                double[]  int1      = new double[NX];
                double[]  int2      = new double[NX];
                Complex   I1        = new Complex(0.0, 0.0);
                Complex   I2        = new Complex(0.0, 0.0);
                double    CallPrice = 0.0;

                for (int t = 0; t < NT; t++)
                {
                    for (int j = 0; j < NX; j++)
                    {
                        phi = X[j];
                        if (CF == "Heston")
                        {
                            f2[j] = HP.HestonCF(phi, param2, S, r, q, T[t], trap);
                            f1[j] = HP.HestonCF(phi - i, param2, S, r, q, T[t], trap) / (S * Math.Exp((r - q) * T[t]));
                        }
                        else if (CF == "Attari")
                        {
                            phi2 = X[j];
                        }
                        f[j] = HP.AttariCF(phi2, param2, T[t], S, r, q, trap);
                    }
                    for (int k = 0; k < NK; k++)
                    {
                        double L = Math.Log(Math.Exp(-r * T[t]) * K[k] / S);
                        for (int j = 0; j < NX; j++)
                        {
                            phi = X[j];
                            if (CF == "Heston")
                            {
                                I1      = Complex.Exp(-i * phi * Complex.Log(K[k])) * f1[j] / i / phi;
                                int1[j] = W[j] * I1.Real;
                                I2      = Complex.Exp(-i * phi * Complex.Log(K[k])) * f2[j] / i / phi;
                                int2[j] = W[j] * I2.Real;
                            }
                            else if (CF == "Attari")
                            {
                                phi2 = X[j];
                                double fR = f[j].Real;
                                double fI = f[j].Imaginary;
                                int1[j] = W[j] * ((fR + fI / phi2) * Math.Cos(L * phi2) + (fI - fR / phi2) * Math.Sin(L * phi2)) / (1 + phi2 * phi2);
                            }
                        }
                        if (CF == "Heston")
                        {
                            double P1 = 0.5 + 1.0 / pi * int1.Sum();
                            double P2 = 0.5 + 1.0 / pi * int2.Sum();
                            CallPrice = S * Math.Exp(-q * T[t]) * P1 - K[k] * Math.Exp(-r * T[t]) * P2;
                        }
                        else if (CF == "Attari")
                        {
                            CallPrice = S * Math.Exp(-q * T[t]) - K[k] * Math.Exp(-r * T[t]) * (0.5 + 1.0 / pi * int1.Sum());
                        }

                        if (PutCall[k, t] == "C")
                        {
                            ModelPrice[k, t] = CallPrice;
                        }
                        else
                        {
                            ModelPrice[k, t] = CallPrice - S * Math.Exp(-q * T[t]) + Math.Exp(-r * T[t]) * K[k];
                        }

                        // Select the objective function
                        switch (LossFunction)
                        {
                        case 1:
                            // MSE Loss Function
                            Error += Math.Pow(ModelPrice[k, t] - MktPrice[k, t], 2) / Convert.ToDouble(NT * NK);;
                            break;

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

                        case 3:
                            // IVMSE Loss Function
                            ModelIV[k, t] = B.BisecBSIV(PutCall[k, t], S, K[k], r, q, T[t], a, b, ModelPrice[k, t], Tol, MaxIter);
                            Error        += Math.Pow(ModelIV[k, t] - MktIV[k, t], 2) / Convert.ToDouble(NT * NK);;
                            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 * pi);
                            Vega   = S * NormPDF * Math.Sqrt(T[t]);
                            Error += Math.Pow(ModelPrice[k, t] - MktPrice[k, t], 2) / Vega / Vega / Convert.ToDouble(NT * NK);
                            break;
                        }
                    }
                }
            }
            return(Error);
        }
Exemplo n.º 3
0
        // Nelder Mead Algorithm ===============================================================================================
        public double[] NelderMead(ObjFun f, NMSet nmsettings, double[,] x)
        {
            int    NumIters = 0;
            int    i, j;
            int    N          = nmsettings.N;
            int    MaxIters   = nmsettings.MaxIters;
            double Tolerance  = nmsettings.Tolerance;
            OFSet  ofsettings = nmsettings.ofsettings;

            // Value of the function at the vertices
            double[][] F = new Double[N + 1][];
            for (i = 0; i <= N; i++)
            {
                F[i] = new double[2] {
                    0.0, 0.0
                }
            }
            ;

            // Step 0.  Ordering and Best and Worst points
            // Order according to the functional values, compute the best and worst points
step0:
            NumIters = NumIters + 1;
            Console.Write("Nelder Mead iteration ");
            Console.WriteLine(NumIters);
            for (j = 0; j <= N; j++)
            {
                double[] z = new double[N];
                for (i = 0; i <= N - 1; i++)
                {
                    z[i]    = x[i, j];
                    F[j][0] = f(z, ofsettings);    // Function values
                    F[j][1] = j;                   // Original index positions
                }
            }
            // Sort the F array w.r.t column 0
            int column = 0;

            Array.Sort(F, delegate(double[] w1, double[] w2)
            {
                return((w1[column] as IComparable).CompareTo(w2[column]));
            });

            // New vertices order first N best initial vectors and
            // last (N+1)st vertice is the worst vector
            // y is the matrix of vertices, ordered so that the worst vertice is last
            double[,] y = new double[N, N + 1];
            for (j = 0; j <= N; j++)
            {
                for (i = 0; i <= N - 1; i++)
                {
                    y[i, j] = x[i, Convert.ToInt32(F[j][1])];
                }
            }

            //  First best vector y(1) and function value f1
            double[] x1 = new double[N]; for (i = 0; i <= N - 1; i++)
            {
                x1[i] = y[i, 0];
            }
            double f1 = f(x1, ofsettings);

            // Last best vector y(N) and function value fn
            double[] xn = new Double[N]; for (i = 0; i <= N - 1; i++)
            {
                xn[i] = y[i, N - 1];
            }
            double fn = f(xn, ofsettings);

            // Worst vector y(N+1) and function value fn1
            double[] xn1 = new Double[N]; for (i = 0; i <= N - 1; i++)
            {
                xn1[i] = y[i, N];
            }
            double fn1 = f(xn1, ofsettings);

            // z is the first N vectors from y, excludes the worst y(N+1)
            double[,] zz = new Double[N, N];
            for (j = 0; j <= N - 1; j++)
            {
                for (i = 0; i <= N - 1; i++)
                {
                    zz[i, j] = y[i, j];
                }
            }

            // Mean of best N values and function value fm
            double[] xm = new Double[N]; xm = VMean(zz, N);
            double   fm = f(xm, ofsettings);

            // Reflection point xr and function fr
            double[] xr = new Double[N]; xr = VSub(VAdd(xm, xm), xn1);
            double   fr = f(xr, ofsettings);

            // Expansion point xe and function fe
            double[] xe = new Double[N]; xe = VSub(VAdd(xr, xr), xm);
            double   fe = f(xe, ofsettings);

            // Outside contraction point and function foc
            double[] xoc = new Double[N]; xoc = VAdd(VMult(xr, 0.5), VMult(xm, 0.5));
            double   foc = f(xoc, ofsettings);

            // Inside contraction point and function foc
            double[] xic = new Double[N]; xic = VAdd(VMult(xm, 0.5), VMult(xn1, 0.5));
            double   fic = f(xic, ofsettings);

            while ((NumIters <= MaxIters) && (Math.Abs(f1 - fn1) >= Tolerance))
            {
                // Step 1. Reflection Rule
                if ((f1 <= fr) && (fr < fn))
                {
                    for (j = 0; j <= N - 1; j++)
                    {
                        for (i = 0; i <= N - 1; i++)
                        {
                            x[i, j] = y[i, j];
                        }
                    }
                    for (i = 0; i <= N - 1; i++)
                    {
                        x[i, N] = xr[i];
                    }
                    goto step0;
                }
                // Step 2.  Expansion Rule
                if (fr < f1)
                {
                    for (j = 0; j <= N - 1; j++)
                    {
                        for (i = 0; i <= N - 1; i++)
                        {
                            x[i, j] = y[i, j];
                        }
                    }
                    if (fe < fr)
                    {
                        for (i = 0; i <= N - 1; i++)
                        {
                            x[i, N] = xe[i];
                        }
                    }
                    else
                    {
                        for (i = 0; i <= N - 1; i++)
                        {
                            x[i, N] = xr[i];
                        }
                    }
                    goto step0;
                }
                // Step 3.  Outside contraction Rule
                if ((fn <= fr) && (fr < fn1) && (foc <= fr))
                {
                    for (j = 0; j <= N - 1; j++)
                    {
                        for (i = 0; i <= N - 1; i++)
                        {
                            x[i, j] = y[i, j];
                        }
                    }
                    for (i = 0; i <= N - 1; i++)
                    {
                        x[i, N] = xoc[i];
                    }
                    goto step0;
                }
                // Step 4.  Inside contraction Rule
                if ((fr >= fn1) && (fic < fn1))
                {
                    for (j = 0; j <= N - 1; j++)
                    {
                        for (i = 0; i <= N - 1; i++)
                        {
                            x[i, j] = y[i, j];
                        }
                    }
                    for (i = 0; i <= N - 1; i++)
                    {
                        x[i, N] = xic[i];
                    }
                    goto step0;
                }
                // Step 5. Shrink Step
                for (i = 0; i <= N - 1; i++)
                {
                    x[i, 0] = y[i, 0];
                }
                for (i = 0; i <= N - 1; i++)
                {
                    for (j = 1; j <= N; j++)
                    {
                        x[i, j] = 0.5 * (y[i, j] + x[i, 0]);
                    }
                }
                goto step0;
            }

            // Output component
            double[] outvec = new Double[N + 2];
            for (i = 0; i <= N - 1; i++)
            {
                outvec[i] = x1[i];
            }
            outvec[N]     = f1;
            outvec[N + 1] = NumIters;
            return(outvec);
        }
Exemplo n.º 4
0
        // Objective function ===========================================================================
        public double f(double[] param, OFSet ofsettings)
        {
            // Option price settings
            double S    = ofsettings.opsettings.S;
            double r    = ofsettings.opsettings.r;
            double q    = ofsettings.opsettings.q;
            double T    = ofsettings.opsettings.T;
            int    trap = ofsettings.opsettings.trap;

            // Market data
            double[] MktIV = ofsettings.data.MktIV;
            int      NK    = MktIV.Length;

            // MS settings
            double dt      = ofsettings.mssettings.dt;
            double a       = ofsettings.mssettings.a;
            double b       = ofsettings.mssettings.b;
            double tol     = ofsettings.mssettings.tol;
            int    MaxIter = ofsettings.mssettings.MaxIter;

            // Optimizatin settings
            double[] lb = ofsettings.lb;
            double[] ub = ofsettings.ub;
            double[] X  = ofsettings.X;
            double[] W  = ofsettings.W;

            HParam param2 = new HParam();

            param2.kappa  = param[0];
            param2.theta  = param[1];
            param2.sigma  = param[2];
            param2.v0     = param[3];
            param2.rho    = param[4];
            param2.lambda = 0.0;

            // Settings for the Bisection algorithm
            a = 0.01;
            b = 3.0;
            double B = 3.0;

            // Initialize the model price and model implied vol vectors, and the objective function value
            double[] ModelPrice = new double[NK];
            double[] ModelIV    = new double[NK];
            double[] Error      = new double[NK];
            double   SumError   = 0.0;

            // Parameter bounds
            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];

            // Classes
            MSPrices            MS = new MSPrices();
            BisectionImpliedVol BA = new BisectionImpliedVol();

            // Penalty for inadmissible parameter values
            if ((param2.kappa <= kappaLB) || (param2.theta <= thetaLB) || (param2.sigma <= sigmaLB) || (param2.v0 <= v0LB) || (param2.rho <= rhoLB) ||
                (param2.kappa >= kappaUB) || (param2.theta >= thetaUB) || (param2.sigma >= sigmaUB) || (param2.v0 >= v0UB) || (param2.rho >= rhoUB))
            {
                SumError = 1.0e50;
            }

            // Penalty for inadmissible implied vol
            else
            {
                Console.WriteLine("----------------------------------------");
                Console.WriteLine("ModelPrice ImpliedVol   MktVol    Error");
                Console.WriteLine("----------------------------------------");
                for (int k = 0; k <= NK - 1; k++)
                {
                    double Strike = ofsettings.data.K[k];
                    ofsettings.opsettings.K = Strike;
                    double[] output = new double[6];
                    output        = MS.MSPriceHeston(param2, ofsettings.opsettings, ofsettings.mssettings);
                    ModelPrice[k] = Math.Max(0.01, output[2]);
                    ModelIV[k]    = BA.BisectionMSIV(S, Strike, r, q, T, a, b, ModelPrice[k], tol, MaxIter, B, dt);
                    if (ModelIV[k] == -1.0)
                    {
                        Error[k] = 1.0e50;
                    }
                    else
                    {
                        Error[k] = Math.Pow(ModelIV[k] - MktIV[k], 2.0);
                    }
                    Console.WriteLine("{0,7:F4} {1,10:F4} {2,10:F4} {3,10:F6}", ModelPrice[k], ModelIV[k], MktIV[k], Error[k]);
                    SumError += Error[k];
                }
            }
            return(SumError);
        }
Exemplo n.º 5
0
        static void Main(string[] args)
        {
            // 32 point Gauss Laguerre
            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]);
                }
            }

            // Bounds on the parameter estimates
            // kappa theta sigma v0 rho
            double e = 1e-5;

            double[] lb = new double[5] {
                e, e, e, e, -0.99
            };
            double[] ub = new double[5] {
                20.0, 2.0, 5.0, 2.0, 0.99
            };

            //// IBM put prices May 7, 2010
            double S = 122.10;

            //double[,] MktPrice = new double[8,5]{
            //    { 0.130,  0.620,  1.275,  2.950,  4.750},
            //    { 0.260,  0.955,  1.830,  3.925,  6.075},
            //    { 0.485,  1.500,  2.610,  5.200,  7.625},
            //    { 0.995,  2.445,  3.775,  6.800,  9.375},
            //    { 2.155,  3.900,  5.475,  8.800, 11.550},
            //    { 4.525,  6.225,  7.775, 11.225, 13.975},
            //    { 8.375,  9.525, 10.850, 14.125, 16.775},
            //    {13.075, 13.600, 14.575, 17.425, 19.900}};

            // Use the first set of prices, for the first maturity
            double[] MktPrice = new double[8] {
                0.130, 0.260, 0.485, 0.995, 2.155, 4.525, 8.375, 13.075
            };
            double[] K = new double[8] {
                100.0, 105.0, 110.0, 115.0, 120.0, 125.0, 130.0, 135.0
            };
            double r = 0.015;
            double q = 0.01;
            //double[] T = new double[5] {0.0384,0.1151, 0.1918, 0.4411, 0.7096};
            double T  = 0.0384;
            int    NK = 8;

            // Bisection algorithm
            double a       = 0.01;
            double b       = 2.00;
            double Tol     = 1.0e-5;
            int    MaxIter = 1000;
            double B       = 2.0;
            double dt      = 1.0e-10;

            // Implied volatilities
            BisectionImpliedVol BA = new BisectionImpliedVol();

            double[] MktIV = new double[NK];
            for (int k = 0; k <= NK - 1; k++)
            {
                MktIV[k] = BA.BisectionMSIV(S, K[k], r, q, T, a, b, MktPrice[k], Tol, MaxIter, B, dt);
            }

            MktData MktData = new MktData();

            MktData.MktIV   = MktIV;
            MktData.K       = K;
            MktData.PutCall = "P";

            OpSet opsettings = new OpSet();

            opsettings.S       = S;
            opsettings.T       = T;
            opsettings.r       = r;
            opsettings.q       = q;
            opsettings.PutCall = "P";
            opsettings.trap    = 1;

            MSSet mssettings = new MSSet();

            mssettings.method   = 3;
            mssettings.A        = 0.0001;
            mssettings.B        = 100.0;
            mssettings.N        = 3000;
            mssettings.dt       = 1.0e-10;
            mssettings.tol      = 1.0e-5;
            mssettings.MaxIter  = 1000;
            mssettings.NumTerms = 3;
            mssettings.yinf     = 1.0e4;
            mssettings.a        = -10.0;
            mssettings.b        = +10.0;

            OFSet ofsettings = new OFSet();

            ofsettings.opsettings = opsettings;
            ofsettings.mssettings = mssettings;
            ofsettings.data       = MktData;
            ofsettings.X          = X;
            ofsettings.W          = W;
            ofsettings.lb         = lb;
            ofsettings.ub         = ub;

            // Settings for the Nelder Mead algorithm
            NMSet nmsettings;

            nmsettings.N          = 5;               // Number of Heston parameters
            nmsettings.MaxIters   = 20;              // Maximum number of iterations
            nmsettings.Tolerance  = 1e-6;            // Tolerance on best and worst function values
            nmsettings.ofsettings = ofsettings;

            // Starting values (vertices) in vector form.  Add random increment about each starting value
            NelderMeadAlgo NM     = new NelderMeadAlgo();
            double         kappaS = 20.00;
            double         thetaS = 0.036;
            double         sigmaS = 3.9;
            double         v0S    = 0.15;
            double         rhoS   = -0.46;
            int            N      = nmsettings.N;

            double[,] x = new double[N, N + 1];
            for (int j = 0; j <= N; j++)
            {
                x[0, j] = kappaS + NM.RandomNum(-0.01, 0.01) * kappaS;
                x[1, j] = thetaS + NM.RandomNum(-0.01, 0.01) * thetaS;
                x[2, j] = sigmaS + NM.RandomNum(-0.01, 0.01) * sigmaS;
                x[3, j] = v0S + NM.RandomNum(-0.01, 0.01) * v0S;
                x[4, j] = rhoS + NM.RandomNum(-0.01, 0.01) * rhoS;
            }

            // Obtain the parameter estimates
            ObjectiveFunction OF = new ObjectiveFunction();

            double[] BB = NM.NelderMead(OF.f, nmsettings, x);

            HParam paramEst = new HParam();

            paramEst.kappa  = BB[0];
            paramEst.theta  = BB[1];
            paramEst.sigma  = BB[2];
            paramEst.v0     = BB[3];
            paramEst.rho    = BB[4];
            paramEst.lambda = 0.0;

            // Obtain the fitted implied vols
            MSPrices MS = new MSPrices();

            double[] ModelIV    = new double[NK];
            double[] ModelPrice = new double[NK];
            double[] output     = new double[6];
            double   IVMSE      = 0.0;

            for (int k = 0; k <= NK - 1; k++)
            {
                opsettings.K  = K[k];
                output        = MS.MSPriceHeston(paramEst, opsettings, mssettings);
                ModelPrice[k] = output[2];
                ModelIV[k]    = BA.BisectionMSIV(S, K[k], r, q, T, a, b, ModelPrice[k], Tol, MaxIter, B, dt);
                IVMSE        += Math.Pow(ModelIV[k] - MktIV[k], 2.0);
            }

            // Output the estimation result
            Console.WriteLine("  ");
            Console.WriteLine("Parameter Estimates --------------------");
            Console.WriteLine("  ");
            Console.WriteLine("kappa   =  {0:F5}", BB[0]);
            Console.WriteLine("theta   =  {0:F5}", BB[1]);
            Console.WriteLine("sigma   =  {0:F5}", BB[2]);
            Console.WriteLine("v0      =  {0:F5}", BB[3]);
            Console.WriteLine("rho     =  {0:F5}", BB[4]);
            Console.WriteLine("  ");
            Console.WriteLine("Value of the objective function is  {0:E5}", BB[5]);
            Console.WriteLine("Number of iterations required       {0:0}", BB[6]);
            Console.WriteLine("  ");
            Console.WriteLine("----------------------------------------");
            Console.WriteLine(" ");
            Console.WriteLine("Strike    MktIV   ModelIV");
            Console.WriteLine("-------------------------");
            for (int k = 0; k <= NK - 1; k++)
            {
                Console.WriteLine("{0,3:F0} {1,12:F5} {2,12:F5}", K[k], MktIV[k], ModelIV[k]);
            }
        }
Exemplo n.º 6
0
        public double f(double[] param, OFSet ofset)
        {
            // Name the Heston parameters
            double kappa = param[0];
            double theta = param[1];
            double sigma = param[2];
            double v0    = param[3];
            double rho   = param[4];

            // Likelihood function settings
            double[] x       = ofset.x;
            double   r       = ofset.r;
            double   q       = ofset.q;
            double   dt      = ofset.dt;
            int      Lmethod = ofset.method;

            // Atiya and Wall parameterization
            double alpha = kappa * theta;
            double beta  = kappa;

            // Number of log-stock prices
            int T = x.Length;

            // Drift term
            double mu = r - q;

            // Equation (17)
            double betap = 1.0 - beta * dt;

            // Equation (18) - denominator of d(t)
            double D = 2.0 * Math.PI * sigma * Math.Sqrt(1.0 - rho * rho) * dt;

            // Equation (14)
            double a = (betap * betap + rho * sigma * betap * dt + sigma * sigma * dt * dt / 4.0) / (2.0 * sigma * sigma * (1.0 - rho * rho) * dt);

            // Variance and likelihood at time t = 0
            double[] v = new Double[T];
            double[] L = new Double[T];
            v[0] = v0;
            if (Lmethod == 1)
            {
                L[0] = Math.Exp(-v[0]);    // Construct the Likelihood
            }
            else if (Lmethod == 2)
            {
                L[0] = -v[0];         // Construct the log-likelihood
            }
            // Construction the likelihood for time t = 1 through t = T
            double dx, B, C, bt, x1, x2, E;

            for (int t = 0; t <= T - 2; t++)
            {
                // Stock price increment
                dx = x[t + 1] - x[t];
                // Equations (31) and (32)
                B = -alpha * dt - rho * sigma * (dx - mu * dt);
                C = alpha * alpha * dt * dt + 2.0 * rho * sigma * alpha * dt * (dx - mu * dt) + sigma * sigma * Math.Pow(dx - mu * dt, 2.0) - 2.0 * v[t] * v[t] * a * sigma * sigma * (1.0 - rho * rho) * dt;
                // Equation (30) to update the variance
                if (B * B - C > 0.0)
                {
                    v[t + 1] = Math.Sqrt(B * B - C) - B;
                }
                else
                {
                    // If v[t+1] is negative, use the approximation Equation (33)
                    bt = (Math.Pow(v[t] - alpha * dt, 2.0) - 2.0 * rho * sigma * (v[t] - alpha * dt) * (dx - mu * dt) + sigma * sigma * Math.Pow(dx - mu * dt, 2.0)) / (2.0 * sigma * sigma * (1.0 - rho * rho) * dt);
                    if (bt / a > 0.0)
                    {
                        v[t + 1] = Math.Sqrt(bt / a);
                    }
                    else
                    {
                        // If v[t+1] is still negative, take the previous value
                        v[t + 1] = v[t];
                    }
                }
                // Equation (15) and (16)
                bt = (Math.Pow(v[t + 1] - alpha * dt, 2.0) - 2.0 * rho * sigma * (v[t + 1] - alpha * dt) * (dx - mu * dt) + sigma * sigma * Math.Pow(dx - mu * dt, 2.0)) / (2.0 * sigma * sigma * (1.0 - rho * rho) * dt);
                x1 = ((2.0 * betap + rho * sigma * dt) * (v[t + 1] - alpha * dt) - (2.0 * rho * sigma * betap + sigma * sigma * dt) * (dx - mu * dt)) / (2.0 * sigma * sigma * (1.0 - rho * rho) * dt);
                x2 = -2.0 * Math.Sqrt(a * bt);
                // Compbined exponent for Equation (34)
                E = Math.Exp(x1 + x2) / D;
                if (Lmethod == 1)
                {
                    // Equation (34) for the likelihood L[t+1]
                    L[t + 1] = Math.Pow(a * bt, -0.25) * E * L[t];
                }
                else if (Lmethod == 2)
                {
                    // Alternatively, use the log-likelihood, log of Equation (34)
                    L[t + 1] = -0.25 * Math.Log(a * bt) + x1 + x2 - Math.Log(D) + L[t];
                }
            }
            // Negative likelihood is the last term.
            // Since we maximize the likelihood, we minimize the negative likelihood.
            return(-L[T - 1]);
        }
        // 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);
        }