static void Main(string[] args) { // Settings from Clarke and Parrott double[] S = new double[5] { 8.0, 9.0, 10.0, 11.0, 12.0 }; double[] TruePrice = new double[5] { 2.00, 1.107641, 0.520030, 0.213668, 0.082036 }; double Strike = 10; double r = 0.1; double q = 0; double T = 0.25; // Heston parameters double kappaV = 5.0; double thetaV = 0.16; double sigmaV = 0.9; double rho = 0.1; double v0 = 0.0625; double lambda = 0.0; int trap = 1; HParam param = new HParam(); param.kappa = kappaV; param.theta = thetaV; param.sigma = sigmaV; param.v0 = v0; param.rho = rho; param.lambda = lambda; // Option settings OpSet opset = new OpSet(); opset.K = Strike; opset.r = r; opset.q = q; opset.T = T; opset.PutCall = "P"; opset.trap = trap; // Settings for Medvedev-Scaillet expansion MSSet msset = new MSSet(); msset.yinf = 1e4; msset.A = 1.0e-10; msset.B = 150.0; msset.N = 10000; msset.method = 3; msset.a = -25.0; msset.b = +25.0; msset.MaxIter = 50000; msset.tol = 1.0e-10; msset.dt = 1e-5; msset.NumTerms = 4; // Initialize the barriers, the puts, the pricing errors double[] MSAmerPut = new double[5]; double[] theta = new double[5]; double[] y = new double[5]; double[] error = new double[5]; double[] Aerror = new double[5]; double[] output = new double[6]; double[] Theta = new double[5]; // Find the Medvedev-Scaillet Heston price MSPriceHeston MS = new MSPriceHeston(); for (int k = 0; k <= 4; k++) { opset.S = S[k]; output = MS.MSPrice(param, opset, msset); MSAmerPut[k] = output[2]; theta[k] = output[4]; y[k] = output[5]; error[k] = TruePrice[k] - MSAmerPut[k]; Aerror[k] = Math.Abs(error[k]); } double TotalError = Aerror.Sum(); // Write the results Console.WriteLine("-----------------------------------------------------------"); Console.WriteLine("Medvedev-Scaillet {0:F0}-term approximation", msset.NumTerms); Console.WriteLine("Clarke and Parrott prices "); Console.WriteLine("-----------------------------------------------------------"); Console.WriteLine("Spot TruePrice MSPrice Error Barrier Moneyness"); Console.WriteLine("-----------------------------------------------------------"); for (int k = 0; k <= 4; k++) { Console.WriteLine("{0,3:F0} {1,10:F5} {2,10:F5} {3,10:F5} {4,10:F5} {5,10:F5}", S[k], TruePrice[k], MSAmerPut[k], error[k], y[k], theta[k]); } Console.WriteLine("-----------------------------------------------------------"); Console.WriteLine("Total Absolute Error with {0:F0} terms {1:F5}", msset.NumTerms, TotalError); Console.WriteLine("-----------------------------------------------------------"); }
public double[] MSPriceHeston(HParam param, OpSet opset, MSSet msset) { // param = Heston parameters // opset = option settings // msset = Medvedev-Scaillet expansion settings // Extract quantities from the option settings double K = opset.K; double S = opset.S; double v0 = param.v0; double T = opset.T; double r = opset.r; double q = opset.q; // Extract quantities from the MS structure int N = msset.N; double a = msset.a; double b = msset.b; double A = msset.A; double B = msset.B; double dt = msset.dt; double tol = msset.tol; int MaxIter = msset.MaxIter; int NumTerms = msset.NumTerms; double yinf = msset.yinf; int method = msset.method; // Closed-form European put NewtonCotes NC = new NewtonCotes(); double EuroPutClosed = NC.HestonPriceNewtonCotes(param, opset, method, A, B, N); // Moneyness double theta = Math.Log(K / S) / Math.Sqrt(v0) / Math.Sqrt(T); // Find the barrier level // Bisection method to find y // a = Math.Max(1.25,0.95*theta); // b = 3.0; // double y = BisectionMS(a,b,theta,K,param,r,q,T,NumTerms,tol,MaxIter,dt); // Golden section search method to find y GoldenSearch GS = new GoldenSearch(); a = 1.5; b = 2.5; double y = GS.GoldenSearchMS(a, b, tol, MaxIter, K, param, theta, r, q, T, NumTerms); if (y < theta) { y = theta; } // Find the early exercise premium MSExpansionHeston MS = new MSExpansionHeston(); double AmerPutMS = MS.MSPutHeston(y, theta, K, param, r, q, T, NumTerms); double EuroPutMS = MS.MSPutHeston(yinf, theta, K, param, r, q, T, NumTerms); double EEP = AmerPutMS - EuroPutMS; // Control variate American put double AmerPut = EuroPutClosed + EEP; // Output the results double[] output = new double[6]; output[0] = EuroPutClosed; output[1] = AmerPutMS; output[2] = AmerPut; // Medvedev and Scaillet recommend this one. output[3] = EEP; output[4] = theta; output[5] = y; return(output); }
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]); } }