// Heston Price by Gauss-Legendre Integration public OutputMD HestonPriceGaussLegendreMD(HParam param, OpSet settings, double[] xGLe, double[] wGLe, double[] A, double tol) { int nA = A.Length; int nX = xGLe.Length; double[,] int1 = new double[nA, nX]; double[,] int2 = new double[nA, nX]; double[] sum1 = new double[nA]; double[] sum2 = new double[nA]; // Numerical integration HestonPrice HP = new HestonPrice(); int nj = 0; for (int j = 1; j <= nA - 1; j++) { // Counter for the last point of A used nj += 1; sum1[j] = 0.0; for (int k = 0; k <= nX - 1; k++) { // Lower and upper and limits of the subdomain double a = A[j - 1]; double b = A[j]; double X = (a + b) / 2.0 + (b - a) / 2.0 * xGLe[k]; int1[j, k] = wGLe[k] * HP.HestonProb(X, param, settings, 1) * (b - a) / 2.0; int2[j, k] = wGLe[k] * HP.HestonProb(X, param, settings, 2) * (b - a) / 2.0; sum1[j] += int1[j, k]; sum2[j] += int2[j, k]; } if (Math.Abs(sum1[j]) < tol && Math.Abs(sum2[j]) < tol) { break; } } // Define P1 and P2 double pi = Math.PI; double P1 = 0.5 + 1.0 / pi * sum1.Sum(); double P2 = 0.5 + 1.0 / pi * sum2.Sum(); // The call price double S = settings.S; double K = settings.K; double T = settings.T; double r = settings.r; double q = settings.q; string PutCall = settings.PutCall; double HestonC = S * Math.Exp(-q * T) * P1 - K * Math.Exp(-r * T) * P2; // The put price by put-call parity double HestonP = HestonC - S * Math.Exp(-q * T) + K * Math.Exp(-r * T); // The output structure OutputMD output = new OutputMD(); // Output the option price if (PutCall == "C") { output.Price = HestonC; } else { output.Price = HestonP; } // Output the integration domain; output.lower = A[0]; output.upper = A[nj]; // Output the number of integration points output.Npoints = (nj + 1) * nX; return(output); }
// Heston price by Newton Coates quadratures public double HestonPriceNewtonCotes(HParam param, OpSet settings, int method, double a, double b, int N) { // Built the integration grid // For Simpson's 3/8 rule, the code ensures that N-1 is divisible by 3 double h = (b - a) / (Convert.ToDouble(N) - 1.0); double[] phi = new double[N]; phi[0] = a; phi[N - 1] = b; for (int k = 1; k <= N - 2; k++) { phi[k] = phi[k - 1] + h; } double[] int1 = new double[N]; double[] int2 = new double[N]; // Integration methods HestonPrice HP = new HestonPrice(); if (method == 1) { // Mid-Point rule -------------------------------------- double[] wt = new double[N]; for (int k = 0; k <= N - 1; k++) { wt[k] = h; } for (int k = 0; k <= N - 2; k++) { double mid = (phi[k] + phi[k + 1]) / 2.0; int1[k] = wt[k] * HP.HestonProb(mid, param, settings, 1); int2[k] = wt[k] * HP.HestonProb(mid, param, settings, 2); } int1[N - 1] = 0.0; int2[N - 1] = 0.0; } else if (method == 2) { // Trapezoidal rule -------------------------------------------------- double[] wt = new double[N]; wt[0] = 0.5 * h; wt[N - 1] = 0.5 * h; for (int k = 1; k <= N - 2; k++) { wt[k] = h; } for (int k = 0; k <= N - 1; k++) { int1[k] = wt[k] * HP.HestonProb(phi[k], param, settings, 1); int2[k] = wt[k] * HP.HestonProb(phi[k], param, settings, 2); } } else if (method == 3) { // Simpson's Rule ---------------------------------------------------- double[] wt = new double[N]; wt[0] = h / 3.0; wt[N - 1] = h / 3.0; for (int k = 1; k <= N - 1; k++) { wt[k] = (h / 3.0) * (3 + Math.Pow(-1, k + 1)); } for (int k = 0; k <= N - 1; k++) { int1[k] = wt[k] * HP.HestonProb(phi[k], param, settings, 1); int2[k] = wt[k] * HP.HestonProb(phi[k], param, settings, 2); } } else if (method == 4) { // Simpson's 3/8 rule -------------------------------------------- // Ensure that N-1 is divisible by 3 N = N - (N % 3); // Build the new grid h = (b - a) / (N - 1.0); double[] phi2 = new double[N]; phi2[0] = a; phi2[N - 1] = b; for (int k = 1; k <= N - 2; k++) { phi2[k] = phi2[k - 1] + h; } double[] wt = new double[N]; wt[0] = 3.0 / 8.0 * h; wt[1] = 9.0 / 8.0 * h; wt[2] = 9.0 / 8.0 * h; wt[N - 1] = 3.0 / 8.0 * h; for (int k = 3; k <= N - 1; k++) { if ((k % 3) == 1) { wt[k] = 6.0 / 8.0 * h; } else { wt[k] = 9.0 / 8.0 * h; } } for (int k = 0; k <= N - 1; k++) { int1[k] = wt[k] * HP.HestonProb(phi2[k], param, settings, 1); int2[k] = wt[k] * HP.HestonProb(phi2[k], param, settings, 2); } } // The integrals double I1 = int1.Sum(); double I2 = int2.Sum(); // The probabilities P1 and P2 double pi = Math.PI; double P1 = 0.5 + 1.0 / pi * I1; double P2 = 0.5 + 1.0 / pi * I2; // The call price double S = settings.S; double K = settings.K; double q = settings.q; double r = settings.r; double T = settings.T; string PutCall = settings.PutCall; double HestonC = S * Math.Exp(-q * T) * P1 - K * Math.Exp(-r * T) * P2; // The put price by put-call parity double HestonP = HestonC - S * Math.Exp(-q * T) + K * Math.Exp(-r * T); // Output the option price if (PutCall == "C") { return(HestonC); } else { return(HestonP); } }