// Objective function =========================================================================== public double f(double[] param, OFSet ofsettings) { // Option price settings double S = ofsettings.opsettings.S; double r = ofsettings.opsettings.r; double q = ofsettings.opsettings.q; double T = ofsettings.opsettings.T; int trap = ofsettings.opsettings.trap; // Market data double[] MktIV = ofsettings.data.MktIV; int NK = MktIV.Length; // MS settings double dt = ofsettings.mssettings.dt; double a = ofsettings.mssettings.a; double b = ofsettings.mssettings.b; double tol = ofsettings.mssettings.tol; int MaxIter = ofsettings.mssettings.MaxIter; // Optimizatin settings double[] lb = ofsettings.lb; double[] ub = ofsettings.ub; double[] X = ofsettings.X; double[] W = ofsettings.W; HParam param2 = new HParam(); param2.kappa = param[0]; param2.theta = param[1]; param2.sigma = param[2]; param2.v0 = param[3]; param2.rho = param[4]; param2.lambda = 0.0; // Settings for the Bisection algorithm a = 0.01; b = 3.0; double B = 3.0; // Initialize the model price and model implied vol vectors, and the objective function value double[] ModelPrice = new double[NK]; double[] ModelIV = new double[NK]; double[] Error = new double[NK]; double SumError = 0.0; // Parameter bounds double kappaLB = lb[0]; double kappaUB = ub[0]; double thetaLB = lb[1]; double thetaUB = ub[1]; double sigmaLB = lb[2]; double sigmaUB = ub[2]; double v0LB = lb[3]; double v0UB = ub[3]; double rhoLB = lb[4]; double rhoUB = ub[4]; // Classes MSPrices MS = new MSPrices(); BisectionImpliedVol BA = new BisectionImpliedVol(); // Penalty for inadmissible parameter values if ((param2.kappa <= kappaLB) || (param2.theta <= thetaLB) || (param2.sigma <= sigmaLB) || (param2.v0 <= v0LB) || (param2.rho <= rhoLB) || (param2.kappa >= kappaUB) || (param2.theta >= thetaUB) || (param2.sigma >= sigmaUB) || (param2.v0 >= v0UB) || (param2.rho >= rhoUB)) { SumError = 1.0e50; } // Penalty for inadmissible implied vol else { Console.WriteLine("----------------------------------------"); Console.WriteLine("ModelPrice ImpliedVol MktVol Error"); Console.WriteLine("----------------------------------------"); for (int k = 0; k <= NK - 1; k++) { double Strike = ofsettings.data.K[k]; ofsettings.opsettings.K = Strike; double[] output = new double[6]; output = MS.MSPriceHeston(param2, ofsettings.opsettings, ofsettings.mssettings); ModelPrice[k] = Math.Max(0.01, output[2]); ModelIV[k] = BA.BisectionMSIV(S, Strike, r, q, T, a, b, ModelPrice[k], tol, MaxIter, B, dt); if (ModelIV[k] == -1.0) { Error[k] = 1.0e50; } else { Error[k] = Math.Pow(ModelIV[k] - MktIV[k], 2.0); } Console.WriteLine("{0,7:F4} {1,10:F4} {2,10:F4} {3,10:F6}", ModelPrice[k], ModelIV[k], MktIV[k], Error[k]); SumError += Error[k]; } } return(SumError); }
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]); } }