Esempio n. 1
0
 private void FrmCadastroFeriado_Load(object sender, EventArgs e)
 {
     dtAno = DateTime.Now;
     ListaFeriados(dtAno);
     TxtAno.Text = dtAno.ToString("yyyy");
     MktData.Select();
 }
Esempio n. 2
0
 private void Reset()
 {
     TxtAno.Text = dtAno.ToString("yyyy");
     TxtDescricao.Clear();
     BtnAlterar.Enabled = false;
     BtnExcluir.Enabled = false;
     BtnGravar.Enabled  = true;
     MktData.Clear();
     MktData.Focus();
 }
Esempio n. 3
0
        private void _Core_OnManagedTickPrice(object sender, TickPriceArg e)
        {
            string field = TickType.getField(e.field);
            var    mkt   = _MktData.Where(x => x.ReqId == e.tickerId).FirstOrDefault();

            if (mkt == null)
            {
                mkt = new MktData(e.tickerId, field, e.price);
                _MktData.Add(mkt);
            }
            else
            {
                mkt.AddUpdate(field, e.price);
            }
        }
Esempio n. 4
0
        private void _Core_OntickOptionComputation(object sender, TickOptionComputationArg e)
        {
            var mkt = _MktData.Where(x => x.ReqId == e.tickerId).FirstOrDefault();

            if (mkt == null)
            {
                mkt = new MktData(e.tickerId, "delta", e.delta);
                _MktData.Add(mkt);
            }
            else
            {
                mkt.AddUpdate("delta", e.delta);
            }
            mkt.AddUpdate("gamma", e.gamma);
            mkt.AddUpdate("theta", e.theta);
            mkt.AddUpdate("vega", e.vega);
            mkt.AddUpdate("iv", e.impliedVolatility);
            mkt.AddUpdate("optPrice", e.optPrice);
            mkt.AddUpdate("undPrice", e.undPrice);
            mkt.AddUpdate("pvDividend", e.pvDividend);
        }
Esempio n. 5
0
        static void Main(string[] args)
        {
            // Classes
            MiscFunctions     MF = new MiscFunctions();
            DiffEvoAlgo       DE = new DiffEvoAlgo();
            NelderMeadAlgo    NM = new NelderMeadAlgo();
            ObjectiveFunction OF = new ObjectiveFunction();

            // 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]);
                }

            // Option settings
            OPSet opset;

            opset.S    = 137.14;
            opset.r    = 0.0010;
            opset.q    = 0.0068;
            opset.trap = 1;

            // Bisection algorithm settings
            double a            = 0.01;
            double b            = 3.0;
            double Tol          = 1e-5;
            int    MaxIter      = 1000;
            int    ObjectiveFun = 1;

            // Read in SP500 implied volatilities
            int NT = 4;
            int NK = 7;

            double[,] MktIV = new Double[7, 4]
            {
                { 0.2780, 0.2638, 0.2532, 0.2518 },
                { 0.2477, 0.2402, 0.2364, 0.2369 },
                { 0.2186, 0.2158, 0.2203, 0.2239 },
                { 0.1878, 0.1930, 0.2047, 0.2098 },
                { 0.1572, 0.1712, 0.1894, 0.1970 },
                { 0.1334, 0.1517, 0.1748, 0.1849 },
                { 0.1323, 0.1373, 0.1618, 0.1736 }
            };
            double[] K = new Double[7] {
                120.0, 125.0, 130.0, 135.0, 140.0, 145.0, 150.0
            };
            double[] T = new Double[4] {
                0.123287671232877, 0.268493150684932, 0.715068493150685, 0.953424657534247
            };

            // PutCall identifiers
            string[,] PutCall = new String[NK, NT];
            for (int k = 0; k <= NK - 1; k++)
            {
                for (int t = 0; t <= NT - 1; t++)
                {
                    PutCall[k, t] = "C";
                }
            }

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

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

            // Place the market data in the structure
            MktData data = new MktData();

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

            // Estimation bounds
            double e = 1e-5;
            double kappaL = e; double kappaU = 10;
            double thetaL = e; double thetaU = 5;
            double sigmaL = e; double sigmaU = 5;
            double v0L = e; double v0U = 1;
            double rhoL = -.9; double rhoU = 0;

            double[] ub = new double[5] {
                kappaU, thetaU, sigmaU, v0U, rhoU
            };
            double[] lb = new double[5] {
                kappaL, thetaL, sigmaL, v0L, rhoL
            };

            // Objective function settings;
            OFSet ofset;

            ofset.opset        = opset;
            ofset.data         = data;
            ofset.X            = X;
            ofset.W            = W;
            ofset.LossFunction = 4;           // Choice of loss function 1=MSE, 2=RMSE, 3=IVMSE, 4=Christoffersen et al.
            ofset.lb           = lb;
            ofset.ub           = ub;
            ofset.CF           = "Heston"; // Choice of c.f. "Heston" or "Attari"

            // Settings for the Differential Evolution algorithm
            DEParam ParamLim = new DEParam();

            ParamLim.ub = ub;
            ParamLim.lb = lb;
            ParamLim.NG = 500;
            ParamLim.NP = 75;
            ParamLim.F  = 0.5;
            ParamLim.CR = 0.8;

            // Run the differential evolution algorithm
            HParam DEparam = DE.HestonDE(ParamLim, opset, data, ObjectiveFun, a, b, Tol, MaxIter, X, W, ofset.CF);

            // Starting values (vertices) in vector form.  Add random increment about each starting value
            double kappaS = 9;
            double thetaS = 0.05;
            double sigmaS = 0.3;
            double v0S    = 0.05;
            double rhoS   = -0.8;
            int    N      = 5;

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

            // Nelder Mead settings
            NMSet nmset;

            nmset.ofset     = ofset;
            nmset.N         = 5;                // Number of Heston parameters
            nmset.MaxIters  = 1000;             // Maximum number of iterations
            nmset.Tolerance = 1e-4;             // Tolerance on best and worst function values

            // Run the Nelder Mead algorithm
            double[] B       = NM.NelderMead(OF.f, nmset, s);
            HParam   NMparam = new HParam();

            NMparam.kappa = B[0];
            NMparam.theta = B[1];
            NMparam.sigma = B[2];
            NMparam.v0    = B[3];
            NMparam.rho   = B[4];

            // Calculate IVMSE under both parameter estimates
            double[,] NMPrice = new double[NK, NT];
            double[,] DEPrice = new double[NK, NT];
            double[,] NMIV    = new double[NK, NT];
            double[,] DEIV    = new double[NK, NT];
            double NMIVMSE = 0.0;
            double DEIVMSE = 0.0;
            double S       = opset.S;
            double r       = opset.r;
            double q       = opset.q;
            int    trap    = opset.trap;

            HestonPrice HP = new HestonPrice();
            Bisection   BA = new Bisection();

            for (int t = 0; t < NT; t++)
            {
                for (int k = 0; k < NK; k++)
                {
                    NMPrice[k, t] = HP.HestonPriceGaussLaguerre(NMparam, S, K[k], r, q, T[t], trap, PutCall[k, t], X, W);
                    NMIV[k, t]    = BA.BisecBSIV(PutCall[k, t], S, K[k], r, q, T[t], a, b, NMPrice[k, t], Tol, MaxIter);
                    NMIVMSE      += Math.Pow(MktIV[k, t] - NMIV[k, t], 2) / Convert.ToDouble(NT * NK);
                    DEPrice[k, t] = HP.HestonPriceGaussLaguerre(DEparam, S, K[k], r, q, T[t], trap, PutCall[k, t], X, W);
                    DEIV[k, t]    = BA.BisecBSIV(PutCall[k, t], S, K[k], r, q, T[t], a, b, DEPrice[k, t], Tol, MaxIter);
                    DEIVMSE      += Math.Pow(MktIV[k, t] - DEIV[k, t], 2) / Convert.ToDouble(NT * NK);
                }
            }

            // Output the result
            Console.WriteLine("  ");
            Console.WriteLine("Parameter Estimates --------------------");
            Console.WriteLine("                 Differential Evolution     Nelder Mead");
            Console.WriteLine("kappa            {0,10:F4} {1,25:F4}", DEparam.kappa, NMparam.kappa);
            Console.WriteLine("theta            {0,10:F4} {1,25:F4}", DEparam.theta, NMparam.theta);
            Console.WriteLine("sigma            {0,10:F4} {1,25:F4}", DEparam.sigma, NMparam.sigma);
            Console.WriteLine("v0               {0,10:F4} {1,25:F4}", DEparam.v0, NMparam.v0);
            Console.WriteLine("rho              {0,10:F4} {1,25:F4}", DEparam.rho, NMparam.rho);
            Console.WriteLine("  ");
            Console.WriteLine("IV MSE ---------------------------------");
            Console.WriteLine("Differential Evolution IVMSE {0:E8}", DEIVMSE);
            Console.WriteLine("Nelder Mead IVMSE            {0:E8}", NMIVMSE);
            Console.WriteLine("  ");
        }
Esempio n. 6
0
        // Objective function ===========================================================================
        public double DHObjFunSVC(double[] param, OpSet settings, MktData data, double[] X, double[] W, int objectivefun, double[] lb, double[] ub)
        {
            HestonPriceDH HPDH = new HestonPriceDH();
            BisectionAlgo BA   = new BisectionAlgo();

            double S    = settings.S;
            double r    = settings.r;
            double q    = settings.q;
            int    trap = settings.trap;

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

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

            DHParam param2 = new DHParam();

            param2.kappa1 = param[0];
            param2.theta1 = param[1];
            param2.sigma1 = param[2];
            param2.v01    = param[3];
            param2.rho1   = param[4];
            param2.kappa2 = param[5];
            param2.theta2 = param[6];
            param2.sigma2 = param[7];
            param2.v02    = param[8];
            param2.rho2   = param[9];

            // Settings for the Bisection algorithm
            double a           = 0.001;
            double b           = 3.0;
            double Tol         = 1e5;
            int    BSIVMaxIter = 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 BSVega = 0.0;
            double Error  = 0.0;
            double pi     = Math.PI;

            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];
            double  phi, P1, P2, CallPrice;
            Complex Integrand1, Integrand2;
            Complex i = Complex.ImaginaryOne;

            Complex[] f2   = new Complex[NX];
            Complex[] f1   = new Complex[NX];
            double[]  int1 = new double[NX];
            double[]  int2 = new double[NX];

            if ((param2.kappa1 <= kappaLB) || (param2.theta1 <= thetaLB) || (param2.sigma1 <= sigmaLB) || (param2.v01 <= v0LB) || (param2.rho1 <= rhoLB) ||
                (param2.kappa1 >= kappaUB) || (param2.theta1 >= thetaUB) || (param2.sigma1 >= sigmaUB) || (param2.v01 >= v0UB) || (param2.rho1 >= rhoUB) ||
                (param2.kappa2 <= kappaLB) || (param2.theta2 <= thetaLB) || (param2.sigma2 <= sigmaLB) || (param2.v02 <= v0LB) || (param2.rho2 <= rhoLB) ||
                (param2.kappa2 >= kappaUB) || (param2.theta2 >= thetaUB) || (param2.sigma2 >= sigmaUB) || (param2.v02 >= v0UB) || (param2.rho2 >= rhoUB))
            {
                Error = 1e50;
            }
            else
            {
                for (int t = 0; t < NT; t++)
                {
                    for (int j = 0; j < NX; j++)
                    {
                        settings.T = T[t];
                        phi        = X[j];
                        f2[j]      = HPDH.HestonDoubleCF(phi, param2, settings);
                        f1[j]      = HPDH.HestonDoubleCF(phi - i, param2, settings);
                    }
                    for (int k = 0; k < NK; k++)
                    {
                        for (int j = 0; j < NX; j++)
                        {
                            phi        = X[j];
                            Integrand2 = Complex.Exp(-i * phi * Complex.Log(K[k])) * f2[j] / i / phi;
                            int2[j]    = W[j] * Integrand2.Real;
                            Integrand1 = Complex.Exp(-i * phi * Complex.Log(K[k])) * f1[j] / i / phi / S / Complex.Exp((r - q) * T[t]);
                            int1[j]    = W[j] * Integrand1.Real;
                        }
                        P1 = 0.5 + 1.0 / pi * int1.Sum();
                        P2 = 0.5 + 1.0 / pi * int2.Sum();

                        // The call price
                        CallPrice = S * Math.Exp(-q * T[t]) * P1 - K[k] * Math.Exp(-r * T[t]) * P2;
                        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];
                        }

                        switch (objectivefun)
                        {
                        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(PutCall[k, t], S, K[k], r, q, T[t], a, b, ModelPrice[k, t], Tol, BSIVMaxIter);
                            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);
                            BSVega = S * NormPDF * Math.Sqrt(T[t]);
                            Error += Math.Pow(ModelPrice[k, t] - MktPrice[k, t], 2.0) / (BSVega * BSVega);
                            break;
                        }
                    }
                }
            }
            return(Error);
        }
Esempio n. 7
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]);
            }
        }
        // Nelder Mead Algorithm ===============================================================================================
        public double[] NelderMead(ObjFun f, int N, double NumIters, int MaxIters, double Tolerance, double[,] x, OpSet settings, MktData data, double[] X, double[] W, int LossFunction, double[] lb, double[] ub)
        {
            int i, j;

            // 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, settings, data, X, W, LossFunction, lb, ub);                // 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, settings, data, X, W, LossFunction, lb, ub);

            // 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, settings, data, X, W, LossFunction, lb, ub);

            // 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, settings, data, X, W, LossFunction, lb, ub);

            // 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, settings, data, X, W, LossFunction, lb, ub);

            // Reflection point xr and function fr
            double[] xr = new Double[N]; xr = VSub(VAdd(xm, xm), xn1);
            double   fr = f(xr, settings, data, X, W, LossFunction, lb, ub);

            // Expansion point xe and function fe
            double[] xe = new Double[N]; xe = VSub(VAdd(xr, xr), xm);
            double   fe = f(xe, settings, data, X, W, LossFunction, lb, ub);

            // 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, settings, data, X, W, LossFunction, lb, ub);

            // 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, settings, data, X, W, LossFunction, lb, ub);

            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);
        }
        static void Main(string[] args)
        {
            // Classes
            HestonPrice       HP = new HestonPrice();
            BlackScholesPrice BS = new BlackScholesPrice();
            Bisection         BA = new Bisection();
            NelderMeadAlgo    NM = new NelderMeadAlgo();
            ObjectiveFunction OF = new ObjectiveFunction();

            // 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]);
                }
            }

            // Option settings
            OPSet opset;

            opset.S    = 137.14;
            opset.r    = 0.0010;
            opset.q    = 0.0068;
            opset.trap = 1;

            // Read in SP500 implied volatilities
            int NT = 4;
            int NK = 7;

            double[,] MktIV = new Double[7, 4] {
                { 0.2780, 0.2638, 0.2532, 0.2518 }, { 0.2477, 0.2402, 0.2364, 0.2369 },
                { 0.2186, 0.2158, 0.2203, 0.2239 }, { 0.1878, 0.1930, 0.2047, 0.2098 },
                { 0.1572, 0.1712, 0.1894, 0.1970 }, { 0.1334, 0.1517, 0.1748, 0.1849 },
                { 0.1323, 0.1373, 0.1618, 0.1736 }
            };
            double[] K = new Double[7] {
                120.0, 125.0, 130.0, 135.0, 140.0, 145.0, 150.0
            };
            double[] T = new Double[4] {
                0.123287671232877, 0.268493150684932, 0.715068493150685, 0.953424657534247
            };

            // PutCall identifiers
            string[,] PutCall = new String[NK, NT];
            for (int k = 0; k <= NK - 1; k++)
            {
                for (int t = 0; t <= NT - 1; t++)
                {
                    PutCall[k, t] = "C";
                }
            }

            // Obtain the market prices
            double[,] MktPrice = new Double[NK, NT];
            for (int k = 0; k <= NK - 1; k++)
            {
                for (int t = 0; t <= NT - 1; t++)
                {
                    MktPrice[k, t] = BS.BlackScholes(opset.S, K[k], T[t], opset.r, opset.q, MktIV[k, t], PutCall[k, t]);
                }
            }

            // settings for the market data
            MktData data = new MktData();

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

            // 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, 2.0, 2.0, 0.99
            };

            // C.F. choice and Loss function choice
            string CF           = "Heston";         // Choice of c.f. "Heston" or "Attari"
            int    LossFunction = 1;                // Choice of loss function
                                                    // 1=MSE, 2=RMSE, 3=IVMSE, 4=Christoffersen et al.

            // Settings for the objective function
            OFSet ofset;

            ofset.opset        = opset;
            ofset.data         = data;
            ofset.X            = X;
            ofset.W            = W;
            ofset.LossFunction = LossFunction;
            ofset.lb           = lb;
            ofset.ub           = ub;
            ofset.CF           = CF;

            // Settings for the Nelder Mead algorithm
            NMSet nmsettings;

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

            // Starting values (vertices) in vector form.  Add random increment about each starting value
            double kappaS = 9;
            double thetaS = 0.05;
            double sigmaS = 0.3;
            double v0S    = 0.05;
            double rhoS   = -0.8;
            int    N      = nmsettings.N;

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

            // Find the Nelder-Mead parameter estimates
            double[] B = NM.NelderMead(OF.f, nmsettings, s);

            // Output the estimation result
            Console.WriteLine("  ");
            Console.WriteLine("Parameter Estimates --------------------");
            Console.WriteLine("  ");
            Console.WriteLine("kappa   =  {0:F5}", B[0]);
            Console.WriteLine("theta   =  {0:F5}", B[1]);
            Console.WriteLine("sigma   =  {0:F5}", B[2]);
            Console.WriteLine("v0      =  {0:F5}", B[3]);
            Console.WriteLine("rho     =  {0:F5}", B[4]);
            Console.WriteLine("  ");
            Console.WriteLine("Value of the objective function is  {0:F5}", B[5]);
            Console.WriteLine("  ");
            Console.WriteLine("Number of iterations required       {0}", B[6]);
            Console.WriteLine("  ");
            Console.WriteLine("----------------------------------------");

            // Obtain the model prices and model implied volatilities
            HParam paramNM = new HParam();

            paramNM.kappa = B[0];
            paramNM.theta = B[1];
            paramNM.sigma = B[2];
            paramNM.v0    = B[3];
            paramNM.rho   = B[4];
            double a       = 0.01;
            double b       = 3.0;
            double Tol     = 1e-5;
            int    MaxIter = 1000;

            double[,] ModelPrice = new double[NK, NT];
            double[,] ModelIV    = new double[NK, NT];
            double IVMSE = 0.0;

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

            for (int k = 0; k < NK; k++)
            {
                for (int t = 0; t < NT; t++)
                {
                    ModelPrice[k, t] = HP.HestonPriceGaussLaguerre(paramNM, S, K[k], r, q, T[t], trap, PutCall[k, t], X, W);
                    ModelIV[k, t]    = BA.BisecBSIV(PutCall[k, t], S, K[k], r, q, T[t], a, b, ModelPrice[k, t], Tol, MaxIter);
                    IVMSE           += Math.Pow(MktIV[k, t] - ModelIV[k, t], 2) / Convert.ToDouble(NT * NK);
                }
            }

            // Output the results
            Console.Write("MSE between model and market implied vols  = {0}", IVMSE);
            Console.WriteLine("  ");
            Console.WriteLine("----------------------------------------");
            Console.WriteLine("Market implied volatilities");
            Console.WriteLine("  ");
            for (int k = 0; k < NK; k++)
            {
                for (int t = 0; t < NT; t++)
                {
                    if (t < NT - 1)
                    {
                        Console.Write("{0:F4}   ", MktIV[k, t]);
                    }
                    else
                    {
                        Console.WriteLine("{0:F4}   ", MktIV[k, t]);
                    }
                }
            }

            Console.WriteLine("  ");
            Console.WriteLine("----------------------------------------");
            Console.WriteLine("Model implied volatilities");
            Console.WriteLine("  ");
            for (int k = 0; k < NK; k++)
            {
                for (int t = 0; t < NT; t++)
                {
                    if (t < NT - 1)
                    {
                        Console.Write("{0:F4}   ", ModelIV[k, t]);
                    }
                    else
                    {
                        Console.WriteLine("{0:F4}   ", ModelIV[k, t]);
                    }
                }
            }

            Console.WriteLine("----------------------------------------");
        }
        // Differential evolution algorithm
        public HParam HestonDE(DEParam DEsettings, OPSet settings, MktData data, int LossFunction, double a, double b, double Tol, int MaxIter, double[] X, double[] W, string CF)
        {
            // NG = Number of generations (iterations)
            // NP = Number of population members
            // CR = Crossover ratio (=0.5)
            // F  = Threshold (=0.8)
            // Hi = Vector of upper bounds for the parameters
            // Lo = Vector of lower bounds for the parameters
            // S  = Spot Price
            // K1 = First strike point for the FRFT
            // rf = Risk free rate
            // q  = Dividend Yield
            // MktPrice = Market quotes for prices
            // K = Vector of Strikes
            // T = Vector of Maturities
            // PutCall = Matrix of 'P'ut or 'C'all
            // MktIV = Market quotes for implied volatilities
            // LossFunction = Type of Objective Function 1 = MSE; 2 = RMSE; 3 = IVMSE; 4 = Christoffersen, Jacobs, Heston (2009)
            // Bisection method settings; a = Lower limit; b = upper limit; Tol = Tolerance; MaxIter = Max number of iterations
            // trap = 1 is "Little Trap" c.f., 0 is Heston c.f.
            // X, W = Gauss Laguerre abscissas and weights
            // CF = "Heston" or "Attari" characteristic function

            ObjectiveFunction OF = new ObjectiveFunction();
            MiscFunctions     MF = new MiscFunctions();

            double[] Hi = DEsettings.ub;
            double[] Lo = DEsettings.lb;
            double   CR = DEsettings.CR;
            double   kappaU = Hi[0]; double kappaL = Lo[0];
            double   thetaU = Hi[1]; double thetaL = Lo[1];
            double   sigmaU = Hi[2]; double sigmaL = Lo[2];
            double   v0U = Hi[3]; double v0L = Lo[3];
            double   rhoU = Hi[4]; double rhoL = Lo[4];

            // Create the structure for the objective function;
            OFSet ofset;

            ofset.opset        = settings;
            ofset.data         = data;
            ofset.X            = X;
            ofset.W            = W;
            ofset.LossFunction = LossFunction;
            ofset.lb           = DEsettings.lb;
            ofset.ub           = DEsettings.ub;
            ofset.CF           = CF;

            // Step1.  Generate the population matrix of random parameters
            int    NP = DEsettings.NP;
            int    NG = DEsettings.NG;
            double F  = DEsettings.F;

            double[,] P = new double[5, NP];
            for (int j = 0; j <= NP - 1; j++)
            {
                P[0, j] = kappaL + (kappaU - kappaL) * MF.RandomNum(0.0, 1.0);
                P[1, j] = thetaL + (thetaU - thetaL) * MF.RandomNum(0.0, 1.0);
                P[2, j] = sigmaL + (sigmaU - sigmaL) * MF.RandomNum(0.0, 1.0);
                P[3, j] = v0L + (v0U - v0L) * MF.RandomNum(0.0, 1.0);
                P[4, j] = rhoL + (rhoU - rhoL) * MF.RandomNum(0.0, 1.0);
            }

            // Generate the random numbers outside the loop
            double[, ,] U = new double[5, NP, NG];
            for (int k = 0; k <= NG - 1; k++)
            {
                for (int j = 0; j <= NP - 1; j++)
                {
                    for (int i = 0; i <= 4; i++)
                    {
                        U[i, j, k] = MF.RandomNum(0.0, 1.0);
                    }
                }
            }

            // Initialize the variables
            double[] Pr1 = new double[5];
            double[] Pr2 = new double[5];
            double[] Pr3 = new double[5];
            double[] P0  = new double[5];

            // Loop through the generations
            for (int k = 0; k <= NG - 1; k++)
            {
                Console.Write("Differential Evolution iteration "); Console.WriteLine(k);

                // Loop through the population
                for (int i = 0; i <= NP - 1; i++)
                {
                    // Select the i-th member of the population
                    for (int s = 0; s <= 4; s++)
                    {
                        P0[s] = P[s, i];
                    }

Step0:
                    // Select random indices for three other distinct members
                    int[] Integers0toNP1 = new int[NP];
                    for (int s = 0; s <= NP - 1; s++)
                    {
                        Integers0toNP1[s] = s;
                    }


                    // Random perumation of the indices (0,1,...,NP-1)
                    int[] I = MF.RandomPerm(Integers0toNP1);

                    // Find the index in I that is not equal to i and keep the first 3 positions
                    int[] L = MF.RemoveIndex(I, i);
                    int[] r = new int[3];
                    for (int s = 0; s <= 2; s++)
                    {
                        r[s] = L[s];
                    }

                    // The three distinct members of the population
                    for (int s = 0; s <= 4; s++)
                    {
                        Pr1[s] = P[s, r[0]];
                        Pr2[s] = P[s, r[1]];
                        Pr3[s] = P[s, r[2]];
                    }
                    int[]    Integers1to5 = { 1, 2, 3, 4, 5 };
                    int[]    R            = MF.RandomPerm(Integers1to5);
                    double[] Pnew         = { 0.0, 0.0, 0.0, 0.0, 0.0 };

                    // Steps 2 and 3.  Mutation and recombination
                    double Ri;
                    double u;
                    for (int j = 0; j <= 4; j++)
                    {
                        Ri = R[0];
                        u  = U[j, i, k];
                        if ((u <= CR) | (j == Ri))
                        {
                            Pnew[j] = Pr1[j] + F * (Pr2[j] - Pr3[j]);
                        }
                        else
                        {
                            Pnew[j] = P0[j];
                        }
                    }
                    // Repeat above to code to ensure new members fall within the
                    // range of acceptable parameter values

                    int[] Flag = new int[5] {
                        0, 0, 0, 0, 0
                    };
                    for (int s = 0; s <= 4; s++)
                    {
                        if (Pnew[s] <= Lo[s] | Pnew[s] >= Hi[s])
                        {
                            Flag[s] = 1;
                        }
                    }
                    int Condition = Flag.Sum();
                    if (Condition > 0)
                    {
                        goto Step0;
                    }

                    // Step 4.  Selection
                    // Calculate the objective function for the ith member and for the candidate
                    double f0   = OF.f(P0, ofset);
                    double fnew = OF.f(Pnew, ofset);

                    // Verify whether the candidate should replace the i-th member
                    // in the population and replace if conditions are satisfied
                    if (fnew < f0)
                    {
                        for (int s = 0; s <= 4; s++)
                        {
                            P[s, i] = Pnew[s];
                        }
                    }
                }
            }

            // Calculate the objective function for each member in the updated population
            double[] fs      = new double[NP];
            double[] Pmember = new double[5];
            for (int s = 0; s <= NP - 1; s++)
            {
                for (int t = 0; t <= 4; t++)
                {
                    Pmember[t] = P[t, s];
                }
                fs[s] = OF.f(Pmember, ofset);
            }

            // Find the member with the lowest objective function
            double Minf   = fs[0];
            int    Minpos = 0;

            for (int s = 0; s <= NP - 1; s++)
            {
                if (fs[s] < Minf)
                {
                    Minf   = fs[s];
                    Minpos = s;
                }
            }

            // Return the selected member/parameter
            HParam Pfinal = new HParam();

            Pfinal.kappa = P[0, Minpos];
            Pfinal.theta = P[1, Minpos];
            Pfinal.sigma = P[2, Minpos];
            Pfinal.v0    = P[3, Minpos];
            Pfinal.rho   = P[4, Minpos];

            return(Pfinal);
        }
Esempio n. 11
0
        // Objective function ===========================================================================
        public double DHObjFun(double[] param, OpSet settings, MktData data, double[] X, double[] W, int objectivefun, double[] lb, double[] ub)
        {
            HestonPriceDH HPDH = new HestonPriceDH();
            BisectionAlgo BA   = new BisectionAlgo();

            double S    = settings.S;
            double r    = settings.r;
            double q    = settings.q;
            int    trap = settings.trap;

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

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

            DHParam param2 = new DHParam();

            param2.kappa1 = param[0];
            param2.theta1 = param[1];
            param2.sigma1 = param[2];
            param2.v01    = param[3];
            param2.rho1   = param[4];
            param2.kappa2 = param[5];
            param2.theta2 = param[6];
            param2.sigma2 = param[7];
            param2.v02    = param[8];
            param2.rho2   = param[9];

            // 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 BSVega = 0.0;
            double Error  = 0.0;
            double pi     = Math.PI;

            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];

            if ((param2.kappa1 <= kappaLB) || (param2.theta1 <= thetaLB) || (param2.sigma1 <= sigmaLB) || (param2.v01 <= v0LB) || (param2.rho1 <= rhoLB) ||
                (param2.kappa1 >= kappaUB) || (param2.theta1 >= thetaUB) || (param2.sigma1 >= sigmaUB) || (param2.v01 >= v0UB) || (param2.rho1 >= rhoUB) ||
                (param2.kappa2 <= kappaLB) || (param2.theta2 <= thetaLB) || (param2.sigma2 <= sigmaLB) || (param2.v02 <= v0LB) || (param2.rho2 <= rhoLB) ||
                (param2.kappa2 >= kappaUB) || (param2.theta2 >= thetaUB) || (param2.sigma2 >= sigmaUB) || (param2.v02 >= v0UB) || (param2.rho2 >= rhoUB))
            {
                Error = 1e50;
            }
            else
            {
                for (int k = 0; k < NK; k++)
                {
                    for (int t = 0; t < NT; t++)
                    {
                        settings.K       = K[k];
                        settings.T       = T[t];
                        ModelPrice[k, t] = HPDH.DoubleHestonPriceGaussLaguerre(param2, settings, X, W);
                        switch (objectivefun)
                        {
                        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(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.0);
                            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);
                            BSVega = S * NormPDF * Math.Sqrt(T[t]);
                            Error += Math.Pow(ModelPrice[k, t] - MktPrice[k, t], 2.0) / (BSVega * BSVega);
                            break;
                        }
                    }
                }
            }
            return(Error);
        }
Esempio n. 12
0
        static void Main(string[] args)
        {
            // Classes
            BisectionAlgo     BA = new BisectionAlgo();
            BlackScholesPrice BS = new BlackScholesPrice();
            HestonPrice       HP = new HestonPrice();
            ElicesAlgo        EA = new ElicesAlgo();
            NelderMeadAlgo    NM = new NelderMeadAlgo();
            ObjectiveFunction OF = new ObjectiveFunction();

            // 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]);
                }
            }

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

            double[] lb = new double[5] {
                e, e, e, -0.99, e
            };
            double[] ub = new double[5] {
                10.0, 3.0, 10.0, 0.99, 3.0
            };

            // Read in SP500 implied volatilities
            const int NT = 4;
            const int NK = 13;

            double[][] MktIV = new double[NT][];
            MktIV[0] = new double[NK] {
                0.1962, 0.1910, 0.1860, 0.1810, 0.1761, 0.1718, 0.1671, 0.1644, 0.1645, 0.1661, 0.1701, 0.1755, 0.1796
            };
            MktIV[1] = new double[NK] {
                0.1947, 0.1905, 0.1861, 0.1812, 0.1774, 0.1743, 0.1706, 0.1671, 0.1641, 0.1625, 0.1602, 0.1610, 0.1657
            };
            MktIV[2] = new double[NK] {
                0.2019, 0.1980, 0.1943, 0.1907, 0.1871, 0.1842, 0.1813, 0.1783, 0.1760, 0.1743, 0.1726, 0.1716, 0.1724
            };
            MktIV[3] = new double[NK] {
                0.2115, 0.2082, 0.2057, 0.2021, 0.2000, 0.1974, 0.1950, 0.1927, 0.1899, 0.1884, 0.1862, 0.1846, 0.1842
            };
            double[] K = new double[NK] {
                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[NT] {
                37.0 / 365.0, 72.0 / 365.0, 135.0 / 365.0, 226.0 / 365.0
            };

            // PutCall identifier
            string PutCall = "P";

            // Maturity increments
            double[] tau = new double[NT];
            tau[0] = T[0];
            for (int t = 1; t <= NT - 1; t++)
            {
                tau[t] = T[t] - T[t - 1];
            }

            // Option settings
            OPSet opsettings;

            opsettings.S    = 129.14;
            opsettings.r    = 0.0010;
            opsettings.q    = 0.0068;
            opsettings.trap = 1;

            // Obtain the market prices for Elices, jagged array, and Heston (two dimensional array)
            double[][] MktPrice = new double[4][];
            double[,] MktPriceH = new double[NT, NK];
            double[,] MktIVH    = new double[NT, NK];
            for (int t = 0; t <= NT - 1; t++)
            {
                MktPrice[t] = new double[13];
                for (int k = 0; k <= NK - 1; k++)
                {
                    MktPrice[t][k]  = BS.BlackScholes(opsettings.S, K[k], T[t], opsettings.r, opsettings.q, MktIV[t][k], PutCall);
                    MktPriceH[t, k] = MktPrice[t][k];
                    MktIVH[t, k]    = MktIV[t][k];
                }
            }

            // Settings for the Elices objective function
            OFSetE ofsetE = new OFSetE();

            ofsetE.opsettings   = opsettings;
            ofsetE.X            = X;
            ofsetE.W            = W;
            ofsetE.LossFunction = 1;
            ofsetE.lb           = lb;
            ofsetE.ub           = ub;

            // Elices Settings for the Market data
            MktData MktData = new MktData();

            MktData.K       = K;
            MktData.PutCall = PutCall;
            ofsetE.data     = MktData;

            // Settings for the Heston objective function
            OFSetH ofsetH = new OFSetH();

            ofsetH.opsettings   = opsettings;
            ofsetH.X            = X;
            ofsetH.W            = W;
            ofsetH.LossFunction = ofsetE.LossFunction;
            ofsetH.lb           = ofsetE.lb;
            ofsetH.ub           = ofsetE.ub;
            ofsetH.MktPrice     = MktPriceH;
            ofsetH.MktIV        = MktIVH;
            ofsetH.K            = K;
            ofsetH.T            = T;
            ofsetH.PutCall      = PutCall;

            // Parameter initial values
            double kappaS = 2.00;
            double thetaS = 0.10;
            double sigmaS = 1.20;
            double v0S    = 0.03;
            double rhoS   = -0.80;

            // Heston and Elices starting values (vertices) in vector form.  Add random increment about each starting value
            double[,] startH = new double[5, 6];
            double[,] startE = new double[4, 5];
            for (int j = 0; j <= 5; j++)
            {
                startH[0, j] = kappaS + BA.RandomNum(-0.05, 0.05) * kappaS;
                startH[1, j] = thetaS + BA.RandomNum(-0.05, 0.05) * thetaS;
                startH[2, j] = sigmaS + BA.RandomNum(-0.05, 0.05) * sigmaS;
                startH[3, j] = rhoS + BA.RandomNum(-0.05, 0.05) * rhoS;
                startH[4, j] = v0S + BA.RandomNum(-0.05, 0.05) * v0S;
            }
            for (int j = 0; j <= 4; j++)
            {
                startE[0, j] = startH[0, j];
                startE[1, j] = startH[1, j];
                startE[2, j] = startH[2, j];
                startE[3, j] = startH[3, j];
            }

            // Settings for the Nelder Mead algorithm
            NMSet nmsettings = new NMSet();

            nmsettings.MaxIters    = 50;        // Maximum number of iterations
            nmsettings.Tolerance   = 1e-20;     // Tolerance on best and worst function values
            nmsettings.ofsettingsE = ofsetE;    // Settings for the Elices objective function
            nmsettings.ofsettingsH = ofsetH;    // Settings for the Heston objective function

            // Heston Parameter Estimation all maturities ===========================================================================================
            nmsettings.choice = "Heston";
            int N = 5;

            nmsettings.N = N;
            double[] ParamH = new double[7];
            ParamH = NM.NelderMead(OF.f, nmsettings, startH);

            // Elices Parameter Estimation maturity by maturity ====================================================================================
            nmsettings.choice = "Elices";
            N            = 4;
            nmsettings.N = N;
            double v0 = ParamH[4];

            ofsetE.v0 = v0;
            double[][] ParamTD      = new double[4][];
            double[]   B            = new double[6];
            double[]   LossFunction = new double[NT];

            // Initialize maturities
            List <double> MatsList = new List <double>();

            double[] Mats;
            MatsList.Add(tau[0]);
            MatsList.Add(tau[1]);
            Mats = MatsList.ToArray();

            // Loop through the maturities, estimating parameters
            for (int t = 0; t <= NT - 1; t++)
            {
                ofsetE.t             = t;
                ofsetE.data.MktIV    = MktIV[t];            // Vector of market Implied vol
                ofsetE.data.MktPrice = MktPrice[t];         // Vector of market prices
                ofsetE.paramfixed    = ParamTD;             // Fixed parameters
                if (t >= 1)
                {
                    for (int j = 0; j <= N; j++)                       // Starting values are last period's estimates
                    {
                        startE[0, j] = B[0] + BA.RandomNum(-0.01, 0.01) * B[0];
                        startE[1, j] = B[1] + BA.RandomNum(-0.01, 0.01) * B[1];
                        startE[2, j] = B[2] + BA.RandomNum(-0.01, 0.01) * B[2];
                        startE[3, j] = B[3] + BA.RandomNum(-0.01, 0.01) * B[3];
                    }
                }
                if (t >= 2)
                {
                    MatsList.Add(tau[t]);
                    Mats = MatsList.ToArray();
                }
                ofsetE.T = Mats;
                nmsettings.ofsettingsE = ofsetE;
                B          = NM.NelderMead(OF.f, nmsettings, startE);
                ParamTD[t] = new double[4] {
                    B[0], B[1], B[2], B[3]
                };
                LossFunction[t] = B[4];
                Console.WriteLine("------ Finished maturity {0:F0} ------", ofsetE.t);
            }
            // Write the parameters
            Console.WriteLine("Heston statict parameters");
            Console.WriteLine("------------------------------------------------------------------");
            Console.WriteLine("    kappa      theta      sigma      rho         v0    LossFunction");
            Console.WriteLine("------------------------------------------------------------------");
            Console.WriteLine("{0,10:F5} {1,10:F5} {2,10:F5} {3,10:F5} {4,10:F5} {5,10:F5}",
                              ParamH[0], ParamH[1], ParamH[2], ParamH[3], ParamH[4], ParamH[5]);
            Console.WriteLine("------------------------------------------------------------------");
            Console.WriteLine(" ");
            Console.WriteLine("Elices Time dependent parameters");
            Console.WriteLine("-------------------------------------------------------------");
            Console.WriteLine("    kappa      theta      sigma      rho     LossFunction");
            Console.WriteLine("-------------------------------------------------------------");
            for (int t = 0; t <= NT - 1; t++)
            {
                Console.WriteLine("{0,10:F5} {1,10:F5} {2,10:F5} {3,10:F5} {4,10:F5}",
                                  ParamTD[t][0], ParamTD[t][1], ParamTD[t][2], ParamTD[t][3], LossFunction[t]);
            }
            Console.WriteLine("-------------------------------------------------------------");


            // Fitting Elices prices and implied vols ==========================================================================================================
            // Matrices for prices, parameters, and fixed parameters
            double[,] PriceE = new double[NK, NT];
            double[]   param      = new double[4];
            double[][] paramfixed = new double[NT - 1][];
            paramfixed[0] = ParamTD[0];

            // Define the dynamic array for the maturities and assign the first two maturities
            List <double> MatList = new List <double>();

            double[] Mat;
            MatList.Add(tau[0]);
            MatList.Add(tau[1]);
            Mat = MatList.ToArray();

            // Elices Implied volatilities
            double[,] IVE = new double[NK, NT];
            double a            = 0.01;
            double b            = 3.0;
            double tol          = 1.0e-5;
            int    MaxIter      = 1000;
            double ElicesIVRMSE = 0.0;

            // Find the prices and implied vols
            for (int t = 0; t <= NT - 1; t++)
            {
                for (int j = 0; j <= 3; j++)
                {
                    param[j] = ParamTD[t][j];
                }
                if (t == 0)
                {
                    for (int k = 0; k <= NK - 1; k++)
                    {
                        PriceE[k, 0] = EA.ElicesPrice(PutCall, opsettings.S, K[k], Mat, opsettings.r, opsettings.q, param, v0, opsettings.trap, X, W);
                    }
                }
                if (t == 1)
                {
                    for (int k = 0; k <= NK - 1; k++)
                    {
                        PriceE[k, 1] = EA.ElicesPrice(PutCall, opsettings.S, K[k], Mat, opsettings.r, opsettings.q, param, v0, opsettings.trap, X, W, paramfixed);
                    }
                }
                if (t >= 2)
                {
                    MatList.Add(tau[t]);
                    Mat = MatList.ToArray();
                    paramfixed[t - 1] = ParamTD[t - 1];
                    for (int k = 0; k <= NK - 1; k++)
                    {
                        PriceE[k, t] = EA.ElicesPrice(PutCall, opsettings.S, K[k], Mat, opsettings.r, opsettings.q, param, v0, opsettings.trap, X, W, paramfixed);
                    }
                }
                for (int k = 0; k <= NK - 1; k++)
                {
                    IVE[k, t]     = BA.BisecBSIV(PutCall, opsettings.S, K[k], opsettings.r, opsettings.q, T[t], a, b, PriceE[k, t], tol, MaxIter);
                    ElicesIVRMSE += Math.Pow(IVE[k, t] - MktIV[t][k], 2.0);
                }
            }
            // Fitting Heston prices and implied vols ==========================================================================================================
            double[,] PriceH = new double[NK, NT];
            double[,] IVH    = new double[NK, NT];
            HParam ParamTI = new HParam();

            ParamTI.kappa = ParamH[0];
            ParamTI.sigma = ParamH[1];
            ParamTI.theta = ParamH[2];
            ParamTI.rho   = ParamH[3];
            ParamTI.v0    = ParamH[4];
            double HestonIVRMSE = 0.0;

            for (int k = 0; k <= NK - 1; k++)
            {
                for (int t = 0; t <= NT - 1; t++)
                {
                    PriceH[k, t]  = HP.HestonPriceGaussLaguerre(ParamTI, ofsetH.opsettings, K[k], T[t], PutCall, X, W);
                    IVH[k, t]     = BA.BisecBSIV(PutCall, opsettings.S, K[k], opsettings.r, opsettings.q, T[t], a, b, PriceH[k, t], tol, MaxIter);
                    HestonIVRMSE += Math.Pow(IVH[k, t] - MktIVH[t, k], 2.0);
                }
            }
            Console.WriteLine("Heston IVRMSE {0,2:E5}", HestonIVRMSE);
            Console.WriteLine("Elices IVRMSE {0,2:E5}", ElicesIVRMSE);
        }
Esempio n. 13
0
        static void Main(string[] args)
        {
            // 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]);
                }
            }
            // SP500 Historical prices.  Oldest prices are first
            double[] S = new Double[120];
            double[] x = new double[120];
            using (TextReader reader = File.OpenText("../../SPY Historical Prices.txt"))
            {
                for (int k = 0; k <= 119; k++)
                {
                    string   text = reader.ReadLine();
                    string[] bits = text.Split(' ');
                    S[k] = double.Parse(bits[0]);
                    x[k] = Math.Log(S[k]);
                }
            }

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

            double[] lb = new double[5] {
                e, e, e, e, -0.999
            };
            double[] ub = new double[5] {
                30.0, 3.0, 3.0, 2.0, 0.999
            };

            // Option settings
            OPSet opsettings;

            opsettings.S    = 137.14;
            opsettings.r    = 0.0010;
            opsettings.q    = 0.0068;
            opsettings.trap = 1;

            // Read in SP500 implied volatilities
            int NT = 4;
            int NK = 7;

            double[,] MktIV = new Double[7, 4] {
                { 0.2780, 0.2638, 0.2532, 0.2518 }, { 0.2477, 0.2402, 0.2364, 0.2369 },
                { 0.2186, 0.2158, 0.2203, 0.2239 }, { 0.1878, 0.1930, 0.2047, 0.2098 },
                { 0.1572, 0.1712, 0.1894, 0.1970 }, { 0.1334, 0.1517, 0.1748, 0.1849 },
                { 0.1323, 0.1373, 0.1618, 0.1736 }
            };
            double[] K = new Double[7] {
                120.0, 125.0, 130.0, 135.0, 140.0, 145.0, 150.0
            };
            double[] T = new Double[4] {
                45.0 / 365.0, 98.0 / 365.0, 261.0 / 365.0, 348.0 / 365.0
            };

            // PutCall identifiers
            string[,] PutCall = new String[NK, NT];
            for (int k = 0; k <= NK - 1; k++)
            {
                for (int t = 0; t <= NT - 1; t++)
                {
                    PutCall[k, t] = "C";
                }
            }

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

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

            // Place the market data in the structure
            MktData data = new MktData();

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

            // True parameter values
            int Lmethod = 2;

            double[] True = new double[5] {
                8.9832, 0.0524, 1.0982, 0.0325, -0.9921
            };
            double dt = 1.0 / 252.0;

            // Settings for the objective function
            OFSet ofsettings;

            ofsettings.x      = x;
            ofsettings.r      = opsettings.r;
            ofsettings.q      = opsettings.q;
            ofsettings.dt     = dt;
            ofsettings.method = Lmethod;

            // Settings for the Nelder Mead algorithm
            NMSet nmsettings;

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

            // Starting values (vertices) in vector form.  Add random increment about each starting value
            double kappaS = 9.00;
            double thetaS = 0.05;
            double sigmaS = 0.30;
            double v0S    = 0.05;
            double rhoS   = -0.80;
            int    N      = nmsettings.N;

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

            // Obtain the parameter estimates
            NelderMeadAlgo NM = new NelderMeadAlgo();
            Likelihood     LL = new Likelihood();

            double[] B = NM.NelderMead(LL.f, nmsettings, xs);

            // Output the estimation result
            Console.WriteLine("  ");
            Console.WriteLine("Atiya-Wall (2009) MLE parameters --------------------");
            Console.WriteLine("  ");
            Console.WriteLine("Parameter    MLE     True Value  ");
            Console.WriteLine("----------------------------------------");
            Console.WriteLine("kappa    {0,10:F5} {1,10:F5}", B[0], True[0]);
            Console.WriteLine("theta    {0,10:F5} {1,10:F5}", B[1], True[1]);
            Console.WriteLine("sigma    {0,10:F5} {1,10:F5}", B[2], True[2]);
            Console.WriteLine("v0       {0,10:F5} {1,10:F5}", B[3], True[3]);
            Console.WriteLine("rho      {0,10:F5} {1,10:F5}", B[4], True[4]);
            Console.WriteLine("----------------------------------------");
            Console.WriteLine("  ");
            Console.WriteLine("Value of the objective function is  {0:F5}", B[5]);
            Console.WriteLine("  ");
            Console.WriteLine("Number of iterations required       {0:0}", B[6]);
            Console.WriteLine("  ");
            Console.WriteLine("----------------------------------------");
        }
Esempio n. 14
0
        static void Main(string[] args)
        {
            BlackScholesPrice    BA    = new BlackScholesPrice();
            NelderMeadAlgo       NM    = new NelderMeadAlgo();
            ObjectiveFunction    OF    = new ObjectiveFunction();
            ObjectiveFunctionSVC OFSVC = new ObjectiveFunctionSVC();

            // Settings for the Nelder Mead algorithm
            int    N            = 10;       // Number of Heston parameters
            int    NumIters     = 1;        // First Iteration
            int    MaxIters     = 5000;     // Maximum number of iterations
            double Tolerance    = 1e-3;     // Tolerance on best and worst function values
            int    LossFunction = 3;        // Choice of loss function

            // 1=MSE, 2=RMSE, 3=IVMSE, 4=Christoffersen et al.

            // 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]);
                }
            int NK = 13;
            int NT = 4;

            double[,] MktIV = 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.1764, 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.1661, 0.1641, 0.1760, 0.1899 }, { 0.1661, 0.1625, 0.1743, 0.1884 },
                { 0.1701, 0.1602, 0.1726, 0.1871 }, { 0.1755, 0.1610, 0.1716, 0.1846 },
                { 0.1786, 0.1657, 0.1724, 0.1842 }
            };
            double[] K = new double[13] {
                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[4] {
                37.0 / 365.0, 72.0 / 365.0, 135.0 / 365.0, 226.0 / 365.0
            };
            string[,] PutCall = new String[NK, NT];
            for (int k = 0; k <= NK - 1; k++)
            {
                for (int t = 0; t <= NT - 1; t++)
                {
                    PutCall[k, t] = "C";
                }
            }

            // Option settings
            OpSet settings = new OpSet();

            settings.S    = 129.14;
            settings.r    = 0.0010;
            settings.q    = 0.0068;
            settings.trap = 1;

            settings.r = 0.0;
            settings.q = 0.0;

            // Obtain the market prices
            double[,] MktPrice = new Double[NK, NT];
            for (int k = 0; k <= NK - 1; k++)
            {
                for (int t = 0; t <= NT - 1; t++)
                {
                    MktPrice[k, t] = BA.BlackScholes(settings.S, K[k], T[t], settings.r, settings.q, MktIV[k, t], PutCall[k, t]);
                }
            }

            // Market data
            MktData data = new MktData();

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

            // starting values for the Nelder Mean algorithm
            double kappaS = 3.0;
            double thetaS = 0.06;
            double sigmaS = 0.5;
            double v0S    = 0.04;
            double rhoS   = -0.8;

            // Create the vertices for the starting values
            double[,] s = new double[N, N + 1];
            for (int j = 0; j <= N; j++)
            {
                s[0, j] = kappaS + BA.RandomNum(-0.10, 0.10);
                s[1, j] = thetaS + BA.RandomNum(-0.01, 0.01);
                s[2, j] = sigmaS + BA.RandomNum(-0.01, 0.01);
                s[3, j] = v0S + BA.RandomNum(-0.01, 0.01);
                s[4, j] = rhoS + BA.RandomNum(-0.05, 0.05);
                s[5, j] = kappaS + BA.RandomNum(-0.10, 0.10);
                s[6, j] = thetaS + BA.RandomNum(-0.01, 0.01);
                s[7, j] = sigmaS + BA.RandomNum(-0.01, 0.01);
                s[8, j] = v0S + BA.RandomNum(-0.01, 0.01);
                s[9, j] = rhoS + BA.RandomNum(-0.05, 0.05);
            }

            // Upper and lower parameter bounds
            // kappa theta sigma v0 rho
            double e = 1e-5;

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

            // Settings for the clock;
            Stopwatch sw = new Stopwatch();

            // Estimation of parameters by Nelder Mean -- Ordinary method
            sw.Reset();
            sw.Start();
            double[] B = NM.NelderMead(OF.DHObjFun, N, NumIters, MaxIters, Tolerance, s, settings, data, X, W, LossFunction, lb, ub);
            sw.Stop();
            TimeSpan tsOrd = sw.Elapsed;

            // Estimation of parameters by Nelder Mean -- Strike Vector Computation method
            sw.Reset();
            sw.Start();
            double[] C = NM.NelderMead(OFSVC.DHObjFunSVC, N, NumIters, MaxIters, Tolerance, s, settings, data, X, W, LossFunction, lb, ub);
            sw.Stop();
            TimeSpan tsSVC = sw.Elapsed;

            // Output the results
            Console.WriteLine("---------------------------------------------------");
            Console.WriteLine("Double Heston parameter estimation");
            Console.WriteLine("Parameter            Ordinary method    SVC Method ");
            Console.WriteLine("---------------------------------------------------");
            Console.WriteLine("kappa1     {0,20:F5}      {1,10:F5} ", B[0], C[0]);
            Console.WriteLine("theta1     {0,20:F5}      {1,10:F5} ", B[1], C[1]);
            Console.WriteLine("sigma1     {0,20:F5}      {1,10:F5} ", B[2], C[2]);
            Console.WriteLine("v01        {0,20:F5}      {1,10:F5} ", B[3], C[3]);
            Console.WriteLine("rho1       {0,20:F5}      {1,10:F5} ", B[4], C[4]);
            Console.WriteLine(" ");
            Console.WriteLine("kappa2     {0,20:F5}      {1,10:F5} ", B[5], C[5]);
            Console.WriteLine("theta2     {0,20:F5}      {1,10:F5} ", B[6], C[6]);
            Console.WriteLine("sigma2     {0,20:F5}      {1,10:F5} ", B[7], C[7]);
            Console.WriteLine("v02        {0,20:F5}      {1,10:F5} ", B[8], C[8]);
            Console.WriteLine("rho2       {0,20:F5}      {1,10:F5} ", B[9], C[9]);
            Console.WriteLine("---------------------------------------------------");
            Console.WriteLine("Value of obj function  {0,7:F2}      {1,10:F2} ", B[10], C[10]);
            Console.WriteLine("Number of iterations   {0,6:0}        {1,6:0}  ", B[11], C[11]);
            Console.WriteLine("---------------------------------------------------");
            Console.WriteLine(" ");
            Console.WriteLine("Estimation time          Min   Sec  mSec");
            Console.WriteLine("-------------------------------------------");
            Console.WriteLine("Ordinary ObjFun {0,10:F0} {1,6:F0} {2,6:F0}", tsOrd.Minutes, tsOrd.Seconds, tsOrd.Milliseconds);
            Console.WriteLine("SVC ObjFun      {0,10:F0} {1,6:F0} {2,6:F0}", tsSVC.Minutes, tsSVC.Seconds, tsSVC.Milliseconds);
            Console.WriteLine("-------------------------------------------");
            Console.WriteLine(" ");
        }
Esempio n. 15
0
        // Objective function ===========================================================================
        public double f(double[] param, double tau, double[] tau0, double[,] param0, MktData data, double S, double[] K, double r, double q, int trap,
                        double[] X, double[] W, int LossFunction, double[] lb, double[] ub)
        {
            HestonPriceTD HPTD = new HestonPriceTD();
            BisectionAlgo BA   = new BisectionAlgo();

            double[] MktIV    = data.MktIV;
            double[] MktPrice = data.MktPrice;
            string[] PutCall  = data.PutCall;

            int NK = PutCall.Length;
            int NT = 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];
            double[] ModelIV    = new double[NK];
            double   Vega       = 0.0;
            double   Error      = 0.0;
            double   pi         = Math.PI;

            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];

            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 - 1; k++)
                {
                    ModelPrice[k] = HPTD.MNPriceGaussLaguerre(param2, param0, tau, tau0, S, K[k], r, q, PutCall[k], trap, X, W);
                    switch (LossFunction)
                    {
                    case 1:
                        // MSE Loss Function
                        Error += Math.Pow(ModelPrice[k] - MktPrice[k], 2);
                        break;

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

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

                    case 4:
                        // IVRMSE Christoffersen, Heston, Jacobs proxy
                        double d       = (Math.Log(S / K[k]) + (r - q + MktIV[k] * MktIV[k] / 2.0) * tau) / MktIV[k] / Math.Sqrt(tau);
                        double NormPDF = Math.Exp(-0.5 * d * d) / Math.Sqrt(2.0 * pi);
                        Vega   = S * NormPDF * Math.Sqrt(tau);
                        Error += Math.Pow(ModelPrice[k] - MktPrice[k], 2) / (Vega * Vega);
                        break;
                    }
                }
            }
            return(Error);  //       / Convert.ToDouble(NT*NK);
        }
Esempio n. 16
0
        static void Main(string[] args)
        {
            // Classes
            BlackScholesPrice BS   = new BlackScholesPrice();
            BisectionAlgo     BA   = new BisectionAlgo();
            NelderMeadAlgo    NM   = new NelderMeadAlgo();
            ObjectiveFunction OF   = new ObjectiveFunction();
            HestonPriceTD     HPTD = new HestonPriceTD();

            // 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]);
                }
            int NT = 4;
            int NK = 13;

            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[13] {
                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[4] {
                0.1014, 0.1973, 0.3699, 0.6192
            };
            string[,] PutCall  = new string[13, 4];
            double[,] MktPrice = new double[13, 4];
            double Spot         = 129.14;
            double r            = 0.0010;
            double q            = 0.0068;
            int    trap         = 1;
            int    LossFunction = 2;

            for (int t = 0; t <= NT - 1; t++)
            {
                for (int k = 0; k <= NK - 1; k++)
                {
                    PutCall[k, t]  = "P";
                    MktPrice[k, t] = BS.BlackScholes(Spot, K[k], T[t], r, q, PutIV[k, t], PutCall[k, t]);
                }
            }

            // Create the maturity increments
            double[] tau = new double[4];
            tau[0] = T[0];
            for (int t = 1; t <= NT - 1; t++)
            {
                tau[t] = T[t] - T[t - 1];
            }

            // Starting values and upper bounds
            double e = 1e-5;

            double[] lb = new double[5] {
                e, e, e, e, -0.999
            };                                                          // Lower bound on the estimates
            double[] ub = new double[5] {
                20.0, 2.0, 2.0, 3.0, 0.999
            };                                                          // Upper bound on the estimates

            // Starting values (vertices) in vector form.  Add random increment about each starting value
            int    N      = 5;
            double kappaS = 4.0;
            double thetaS = 0.1;
            double sigmaS = 1.5;
            double v0S    = 0.04;
            double rhoS   = -0.30;

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

            // Arrays for old maturities and parameters, and current parameters (old parameters, but stacked)
            ArrayList OldTau = new ArrayList();

            double[,] param0  = new double[NT - 1, 5];
            double[,] paramTD = new double[NT, 5];

            // Nelder Mead settings
            int    MaxIters  = 1000;
            double Tolerance = 1e-5;

            // Market data
            MktData data = new MktData();

            double[] MKIV = new double[NK];
            double[] MKPR = new double[NK];
            string[] PC   = new string[NK];

            // Step-by-step parameter estimates
            double[] B            = new double[6];
            double[] ObjectiveFun = new double[NT];
            double[] NumIteration = new double[NT];

            // First maturity parameter estimates ===================================================================
            double[] tau0 = { 0.0 };
            for (int k = 0; k <= NK - 1; k++)
            {
                MKIV[k] = PutIV[k, 0];
                MKPR[k] = MktPrice[k, 0];
                PC[k]   = PutCall[k, 0];
            }
            data.MktIV    = MKIV;
            data.PutCall  = PC;
            data.MktPrice = MKPR;
            B             = NM.NelderMead(OF.f, N, MaxIters, Tolerance, s, tau[0], tau0, param0, data, Spot, K, r, q, trap, X, W, LossFunction, lb, ub);
            Console.WriteLine("Finished parameter estimate set 1");
            for (int k = 0; k <= 4; k++)
            {
                paramTD[0, k] = B[k];
            }
            ObjectiveFun[0] = B[5];
            NumIteration[0] = B[6];

            // Remaining Maturity estimates and updated starting values ==================================================
            for (int mat = 1; mat <= NT - 1; mat++)
            {
                OldTau.Add(tau[mat - 1]);
                for (int k = 0; k <= 4; k++)
                {
                    param0[mat - 1, k] = B[k];
                }
                for (int k = 0; k <= NK - 1; k++)
                {
                    MKIV[k] = PutIV[k, mat];
                    MKPR[k] = MktPrice[k, mat];
                    PC[k]   = PutCall[k, mat];
                }
                data.MktIV    = MKIV;
                data.PutCall  = PC;
                data.MktPrice = MKPR;
                for (int j = 0; j <= N; j++)
                {
                    s[0, j] = B[0] + BA.RandomNum(-0.01, 0.01);
                    s[1, j] = B[1] + BA.RandomNum(-0.01, 0.01);
                    s[2, j] = B[2] + BA.RandomNum(-0.01, 0.01);
                    s[3, j] = B[3] + BA.RandomNum(-0.01, 0.01);
                    s[4, j] = B[4] + BA.RandomNum(-0.01, 0.01);
                }
                B = NM.NelderMead(OF.f, N, MaxIters, Tolerance, s, tau[mat], tau0, param0, data, Spot, K, r, q, trap, X, W, LossFunction, lb, ub);
                Console.WriteLine("Finished parameter estimate set {0}", mat + 1);
                for (int k = 0; k <= 4; k++)
                {
                    paramTD[mat, k] = B[k];
                }
                ObjectiveFun[mat] = B[5];
                NumIteration[mat] = B[6];
            }

            // Fit the prices and implied volatilities ====================================================================
            // Bisection algorithm settings
            double a       = 0.001;
            double b       = 5.0;
            double Tol     = 1e-5;
            int    MaxIter = 5000;

            ArrayList OldTau00 = new ArrayList();

            double[] tau00 = { 0.0 };
            double[,] ModelPrice = new double[NK, NT];
            double[,] ModelIV    = new double[NK, NT];
            Array.Clear(param0, 0, 15);

            // First maturity
            HParam param = new HParam();

            param.kappa = paramTD[0, 0];
            param.theta = paramTD[0, 1];
            param.sigma = paramTD[0, 2];
            param.v0    = paramTD[0, 3];
            param.rho   = paramTD[0, 4];
            for (int k = 0; k <= NK - 1; k++)
            {
                ModelPrice[k, 0] = HPTD.MNPriceGaussLaguerre(param, param0, tau[0], tau00, Spot, K[k], r, q, PutCall[k, 0], trap, X, W);
                ModelIV[k, 0]    = BA.BisecBSIV(PutCall[k, 0], Spot, K[k], r, q, T[0], a, b, ModelPrice[k, 0], Tol, MaxIter);
            }

            // Remaining maturity
            for (int t = 1; t <= NT - 1; t++)
            {
                OldTau00.Add(tau[t - 1]);
                param.kappa = paramTD[t, 0];
                param.theta = paramTD[t, 1];
                param.sigma = paramTD[t, 2];
                param.v0    = paramTD[t, 3];
                param.rho   = paramTD[t, 4];
                for (int j = 0; j <= 4; j++)
                {
                    param0[t - 1, j] = paramTD[t - 1, j];
                }
                for (int k = 0; k <= NK - 1; k++)
                {
                    ModelPrice[k, t] = HPTD.MNPriceGaussLaguerre(param, param0, tau[t], tau00, Spot, K[k], r, q, PutCall[k, t], trap, X, W);
                    ModelIV[k, t]    = BA.BisecBSIV(PutCall[k, t], Spot, K[k], r, q, T[t], a, b, ModelPrice[k, t], Tol, MaxIter);
                }
            }

            // Mean Square Implied Volatility Error
            double Error = 0.0;

            for (int t = 0; t <= NT - 1; t++)
            {
                for (int k = 0; k <= NK - 1; k++)
                {
                    Error += Math.Pow(ModelIV[k, t] - PutIV[k, t], 2);
                }
            }

            Error /= (Convert.ToDouble(NT) * Convert.ToDouble(NK));

            // Output the estimation result
            Console.WriteLine("-----------------------------------------------------------------------------");
            Console.WriteLine("Market/Model implied volatilities");
            Console.WriteLine("    Mat1       Mat2       Mat3       Mat4");
            for (int k = 0; k <= NK - 1; k++)
            {
                Console.WriteLine("--------------------------------------------- Strike {0} Market/Model", K[k]);
                Console.WriteLine("{0,10:F4} {1,10:F4} {2,10:F4} {3,10:F4}", PutIV[k, 0], PutIV[k, 1], PutIV[k, 2], PutIV[k, 3]);
                Console.WriteLine("{0,10:F4} {1,10:F4} {2,10:F4} {3,10:F4}", ModelIV[k, 0], ModelIV[k, 1], ModelIV[k, 2], ModelIV[k, 3]);
            }
            Console.WriteLine("-----------------------------------------------------------------------------");
            Console.WriteLine("Model Price ");
            for (int k = 0; k <= NK - 1; k++)
            {
                Console.WriteLine("{0,10:0} {1,10:F4} {2,10:F4} {3,10:F4} {4,10:F4}", K[k], ModelPrice[k, 0], ModelPrice[k, 1], ModelPrice[k, 2], ModelPrice[k, 3]);
            }
            Console.WriteLine("-----------------------------------------------------------------------------");
            Console.WriteLine("Results of time dependent parameter estimation");
            Console.WriteLine("  ");
            Console.WriteLine("Maturity   kappa   theta   sigma   v0       rho     ObjecFun  NumIterations");
            Console.WriteLine("-----------------------------------------------------------------------------");
            for (int t = 0; t <= NT - 1; t++)
            {
                Console.WriteLine("{0} {1,10:F4} {2,7:F4} {3,7:F4} {4,7:F4} {5,8:F4} {6,8:F4} {7,7:0}",
                                  T[t], paramTD[t, 0], paramTD[t, 1], paramTD[t, 2], paramTD[t, 3], paramTD[t, 4], ObjectiveFun[t], NumIteration[t]);
            }
            Console.WriteLine("-----------------------------------------------------------------------------");
            Console.WriteLine("IVMSE from time dependent estimates {0,10:E5}", Error);
            Console.WriteLine("-----------------------------------------------------------------------------");
        }