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]); } } // Heston parameters HParam param = new HParam(); param.kappa = 0.2; param.theta = 0.05; param.sigma = 0.3; param.v0 = 0.05; param.rho = -0.7; param.lambda = 0.0; // Option settings OpSet settings = new OpSet(); settings.S = 50.0; settings.T = 0.5; settings.r = 0.03; settings.q = 0.05; settings.PutCall = "C"; settings.trap = 1; // FFT settings double M = Math.Pow(2.0, 10.0); int N = Convert.ToInt16(M); double alpha = 1.5; double uplimit = 100.0; string rule = "Trapezoidal"; double[,] PriceFFT = new double[N, 2]; // Discount the spot price by the dividend yield, use as input in FFT settings.S = settings.S * Math.Exp(-settings.q * settings.T); // Obtain the FFT strikes and calls FFT FFT = new FFT(); PriceFFT = FFT.HestonFFT(N, uplimit, alpha, rule, param, settings); // Obtain the extact price and compare to FFT price HestonPrice HP = new HestonPrice(); double[] PriceHeston = new double[N]; for (int j = 0; j <= N - 1; j++) { settings.K = PriceFFT[j, 0]; PriceHeston[j] = HP.HestonPriceGaussLaguerre(param, settings, x, w); } // Output the results near the money int start = N / 2 - 5; int end = N / 2 + 5; Console.WriteLine("Fast Fourier Transform"); Console.WriteLine("----------------------------------------"); Console.WriteLine("Strike FFT Price Heston Price"); Console.WriteLine("----------------------------------------"); for (int j = start; j <= end; j++) { Console.WriteLine("{0,2:F2} {1,15:F4} {2,15:F4} ", PriceFFT[j, 0], PriceFFT[j, 1], PriceHeston[j]); } Console.WriteLine("----------------------------------------"); }
// Fast Fourier Transform public double[,] HestonFFT(int N, double uplimit, double alpha, string rule, HParam param, OpSet settings) { double s0 = Math.Log(settings.S); double pi = Math.PI; // Specify the increments double eta = uplimit / Convert.ToDouble(N); double lambdainc = 2 * pi / Convert.ToDouble(N) / eta; // Initialize and specify the weights double[] w = new double[N]; if (rule == "Trapezoidal") { w[0] = 0.5; w[N - 1] = 0.5; for (int j = 1; j <= N - 2; j++) { w[j] = 1; } } else if (rule == "Simpsons") { w[0] = 1.0 / 3.0; w[N - 1] = 1.0 / 3.0; for (int j = 1; j <= N - 1; j++) { w[j] = (1.0 / 3.0) * (3 + Math.Pow(-1, j + 1)); } } // Specify the b parameter double b = Convert.ToDouble(N) * lambdainc / 2.0; // Create the grid for the integration double[] v = new double[N]; for (int j = 0; j <= N - 1; j++) { v[j] = eta * j; } // Create the grid for the log-strikes and strikes double[] k = new double[N]; double[] K = new double[N]; for (int j = 0; j <= N - 1; j++) { k[j] = -b + lambdainc * Convert.ToDouble(j) + s0; K[j] = Math.Exp(k[j]); } double tau = settings.T; double r = settings.r; double q = settings.q; // Implement the FFT HestonPrice HP = new HestonPrice(); Complex i = new Complex(0.0, 1.0); Complex[] psi = new Complex[N]; Complex[] phi = new Complex[N]; Complex[] x = new Complex[N]; Complex[] e = new Complex[N]; double[] CallFFT = new double[N]; double[] sume = new double[N]; for (int u = 0; u <= N - 1; u++) { for (int j = 0; j <= N - 1; j++) { psi[j] = HP.HestonCF(v[j] - (alpha + 1.0) * i, param, settings); phi[j] = Complex.Exp(-r * tau) * psi[j] / (alpha * alpha + alpha - v[j] * v[j] + i * v[j] * (2.0 * alpha + 1.0)); x[j] = Complex.Exp(i * (b - s0) * v[j]) * phi[j] * w[j]; e[j] = Complex.Exp(-i * 2 * pi / Convert.ToDouble(N) * j * u) * x[j]; sume[u] += e[j].Real; } CallFFT[u] = eta * Math.Exp(-alpha * k[u]) / pi * sume[u]; } // Return the FFT call price and the strikes double[,] output = new double[N, 2]; for (int j = 0; j <= N - 1; j++) { output[j, 0] = K[j]; output[j, 1] = CallFFT[j]; } return(output); }