static void Main(string[] args) { // 32-point Gauss-Laguerre Abscissas and weights double[] xGLa = new Double[32]; double[] wGLa = 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(' '); xGLa[k] = double.Parse(bits[0]); wGLa[k] = double.Parse(bits[1]); } } // 32-point Gauss-Legendre Abscissas and weights double[] xGLe = new Double[32]; double[] wGLe = new Double[32]; using (TextReader reader = File.OpenText("../../GaussLegendre32.txt")) { for (int k = 0; k <= 31; k++) { string text = reader.ReadLine(); string[] bits = text.Split(' '); xGLe[k] = double.Parse(bits[0]); wGLe[k] = double.Parse(bits[1]); } } // 32-point Gauss-Lobatto Abscissas and weights double[] xGLo = new Double[32]; double[] wGLo = new Double[32]; using (TextReader reader = File.OpenText("../../GaussLobatto32.txt")) { for (int k = 0; k <= 31; k++) { string text = reader.ReadLine(); string[] bits = text.Split(' '); xGLo[k] = double.Parse(bits[0]); wGLo[k] = double.Parse(bits[1]); } } // Heston parameters HParam param = new HParam(); param.kappa = 2.0; param.theta = 0.05; param.sigma = 0.3; param.v0 = 0.035; param.rho = -0.9; param.lambda = 0.0; // Option price settings OpSet settings = new OpSet(); settings.S = 100.0; settings.T = 0.25; settings.r = 0.05; settings.q = 0.02; settings.trap = 1; // Lower and upper integration limits double a = 0.0; // Lower Limit for Gauss Legendre and Newton Coates double b = 100.0; // Upper Limit for Gauss Legendre double A = 1e-5; // Lower Limit for Gauss Lobatto double B = 100.0; // Upper Limit for Gauss Lobatto int N = 5000; // Number of points for Newton Coates quadratures // Range of strikes and option flavor double[] Strikes = new double[] { 90.0, 95.0, 100.0, 105.0, 110.0 }; settings.PutCall = "C"; // Initialize the price vectors int M = Strikes.Length; double[] PriceGLa = new double[M]; double[] PriceGLe = new double[M]; double[] PriceGLo = new double[M]; double[] PriceMP = new double[M]; double[] PriceTrapz = new double[M]; double[] PriceSimp = new double[M]; double[] PriceSimp38 = new double[M]; // Obtain the prices and output to console HestonPrice HP = new HestonPrice(); NewtonCotes NC = new NewtonCotes(); Console.WriteLine("Using {0:0} points for Newton Cotes and 32 points for quadrature ", N); Console.WriteLine(" "); for (int k = 0; k <= M - 1; k++) { settings.K = Strikes[k]; PriceGLa[k] = HP.HestonPriceGaussLaguerre(param, settings, xGLa, wGLa); // Gauss Laguerre PriceGLe[k] = HP.HestonPriceGaussLegendre(param, settings, xGLe, wGLe, a, b); // Gauss Legendre PriceGLo[k] = HP.HestonPriceGaussLegendre(param, settings, xGLo, wGLo, A, B); // Gauss Lobatto PriceMP[k] = NC.HestonPriceNewtonCotes(param, settings, 1, a, b, N); // Mid point rule PriceTrapz[k] = NC.HestonPriceNewtonCotes(param, settings, 2, A, B, N); // Trapezoidal rule PriceSimp[k] = NC.HestonPriceNewtonCotes(param, settings, 3, A, B, N); // Simpson's Rule PriceSimp38[k] = NC.HestonPriceNewtonCotes(param, settings, 4, A, B, N); // Simpson's 3/8 rule Console.Write("Strike {0,2}", Strikes[k]); Console.WriteLine(" ------------------"); Console.WriteLine("Mid Point {0:F5}", PriceMP[k]); Console.WriteLine("Trapezoidal {0:F5}", PriceTrapz[k]); Console.WriteLine("Simpson's {0:F5}", PriceSimp[k]); Console.WriteLine("Simpson's 3/8 {0:F5}", PriceSimp38[k]); Console.WriteLine("Gauss Laguerre {0:F5}", PriceGLa[k]); Console.WriteLine("Gauss Legendre {0:F5}", PriceGLe[k]); Console.WriteLine("Gauss Lobatto {0:F5}", PriceGLo[k]); Console.WriteLine(" "); } }
// 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]; HestonPrice HP = new HestonPrice(); // Integration methods 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); } }