// Kahl and Jackel (2005) Heston price, using an integration range of [0,1]. // From "Not-so-Complex Algorithms in the Heston model" public double HestonPriceKahlJackel(HParam param, OpSet settings, double[] X, double[] W) { int N = X.Length; double kappa = param.kappa; double theta = param.theta; double sigma = param.sigma; double v0 = param.v0; double rho = param.rho; double lambda = param.lambda; double S = settings.S; double K = settings.K; double T = settings.T; double r = settings.r; double q = settings.q; string PutCall = settings.PutCall; // Forward price double F = S * Math.Exp((r - q) * T); // Required quantities for integrand double Cinf = Math.Sqrt(1 - rho * rho) / sigma * (v0 + kappa * theta * T); // Required quantities for f1 double ImC1 = (Math.Exp((rho * sigma - kappa) * T) * theta * kappa + theta * kappa * ((kappa - rho * sigma) * T - 1.0)) / 2.0 / Math.Pow(kappa - rho * sigma, 2); double ImD1 = (1.0 - Math.Exp((rho * sigma - kappa) * T)) / 2.0 / (kappa - rho * sigma); // Required quantities for f2 double ImC2 = -(Math.Exp(-kappa * T) * theta * kappa + theta * kappa * (kappa * T - 1.0)) / 2.0 / kappa / kappa; double ImD2 = -(1.0 - Math.Exp(-kappa * T / 2.0)) / 2.0 / kappa; double pi = Math.PI; double[] y = new double[N]; double[] z = new double[N]; HestonPrice HP = new HestonPrice(); for (int u = 0; u <= N - 1; u++) { // Transformation of the abscissa from [-1,1] to [0,1] double x = 0.5 * X[u] + 0.5; if (x == 0.0) { // Integrand at left abscissa 0 y[u] = 0.5 * (F - K); } else if (x == 1.0) { // Integrand at right abscissa 1 double f1 = Math.Log(F / K) + ImC1 + ImD1 * v0; double f2 = Math.Log(F / K) + ImC2 + ImD2 * v0; y[u] = 0.5 * (F - K) + (F * f1 - K * f1) / (pi * Cinf); } else { // Integrand at remaining abscissas double f1 = HP.HestonProb(-Math.Log(x) / Cinf, param, settings, 1); double f2 = HP.HestonProb(-Math.Log(x) / Cinf, param, settings, 2); y[u] = 0.5 * (F - K) + (F * f1 - K * f2) / (x * pi * Cinf); } // Multiply by the weights z[u] = W[u] * y[u]; } // The Call price double HCall = Math.Exp(-r * T) * 0.5 * z.Sum(); // The put price by put call parity if (PutCall == "C") { return(HCall); } else { return(HCall - S * Math.Exp(-q * T) + K * Math.Exp(-r * T)); } }
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 = 1.0; param.theta = 0.06; param.sigma = 0.5; param.v0 = 0.06; param.rho = -0.8; param.lambda = 0.0; // Option price settings OpSet settings = new OpSet(); settings.S = 10.0; settings.K = 7.0; settings.T = 1.0 / 12.0; settings.r = 0.06; settings.q = 0.04; settings.trap = 1; settings.PutCall = "C"; // Lower and upper integration limits double a = 0.0; // Lower Limit for Gauss Legendre 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 // Initialize the price vectors HestonPrice HP = new HestonPrice(); KahlJackel KJ = new KahlJackel(); double PriceGLa = HP.HestonPriceGaussLaguerre(param, settings, xGLa, wGLa); // Heston Gauss Laguerre double PriceGLe = HP.HestonPriceGaussLegendre(param, settings, xGLe, wGLe, a, b); // Heston Gauss Legendre double PriceGLo = HP.HestonPriceGaussLegendre(param, settings, xGLo, wGLo, A, B); // Heston Gauss Lobatto double PriceKJ = KJ.HestonPriceKahlJackel(param, settings, xGLo, wGLo); // Kahl Jackel Gauss Lobatto Console.WriteLine("Kahl Jackel Integration scheme"); Console.WriteLine("Method Price"); Console.WriteLine("-------------------------------------"); Console.WriteLine("Heston Gauss Laguerre {0:F5}", PriceGLa); Console.WriteLine("Heston Gauss Legendre {0:F5}", PriceGLe); Console.WriteLine("Heston Gauss Lobatto {0:F5}", PriceGLo); Console.WriteLine("Kahl Jackel Gauss Lobatto {0:F5}", PriceKJ); Console.WriteLine("-------------------------------------"); }