public DHSim DHQuadExpSim(DHParam param, double S0, double Strike, double Mat, double r, double q, int T, int N, string PutCall) { RandomNumber RN = new RandomNumber(); NormInverse NI = new NormInverse(); Regression RE = new Regression(); double kappa1 = param.kappa1; double theta1 = param.theta1; double sigma1 = param.sigma1; double v01 = param.v01; double rho1 = param.rho1; double kappa2 = param.kappa2; double theta2 = param.theta2; double sigma2 = param.sigma2; double v02 = param.v02; double rho2 = param.rho2; // Time increment double dt = Mat / T; // Required quantities double K01 = -rho1 * kappa1 * theta1 * dt / sigma1; double K11 = dt / 2.0 * (kappa1 * rho1 / sigma1 - 0.5) - rho1 / sigma1; double K21 = dt / 2.0 * (kappa1 * rho1 / sigma1 - 0.5) + rho1 / sigma1; double K31 = dt / 2.0 * (1.0 - rho1 * rho1); double K02 = -rho2 * kappa2 * theta2 * dt / sigma2; double K12 = dt / 2.0 * (kappa2 * rho2 / sigma2 - 0.5) - rho2 / sigma2; double K22 = dt / 2.0 * (kappa2 * rho2 / sigma2 - 0.5) + rho2 / sigma2; double K32 = dt / 2.0 * (1.0 - rho2 * rho2); // Initialize the variance and stock processes double[,] V1 = new double[T, N]; double[,] V2 = new double[T, N]; double[,] S = new double[T, N]; // Starting values for the variance and stock processes for (int k = 0; k <= N - 1; k++) { S[0, k] = S0; // Spot price V1[0, k] = v01; // Heston v0 initial variance V2[0, k] = v02; // Heston v0 initial variance } // Generate the stock and volatility paths double m1, s1, phi1, p1, U1, b1, a1, Zv1; double m2, s2, phi2, p2, U2, b2, a2, Zv2; double beta1, beta2, B1, B2, logS; for (int k = 0; k <= N - 1; k++) { for (int t = 1; t <= T - 1; t++) { m1 = theta1 + (V1[t - 1, k] - theta1) * Math.Exp(-kappa1 * dt); s1 = V1[t - 1, k] * sigma1 *sigma1 *Math.Exp(-kappa1 *dt) / kappa1 * (1.0 - Math.Exp(-kappa1 * dt)) + theta1 * sigma1 * sigma1 / 2.0 / kappa1 * Math.Pow(1.0 - Math.Exp(-kappa1 * dt), 2.0); phi1 = s1 / (m1 * m1); p1 = (phi1 - 1.0) / (phi1 + 1.0); U1 = RN.RandomNum(0.0, 1.0); if (phi1 < 0.5) { b1 = Math.Sqrt(2.0 / phi1 - 1.0 + Math.Sqrt(2.0 / phi1 * (2.0 / phi1 - 1.0))); a1 = m1 / (1.0 + b1 * b1); Zv1 = NI.normICDF(U1); V1[t, k] = a1 * (b1 + Zv1) * (b1 + Zv1); } else if (phi1 >= 0.5) { if (U1 <= p1) { V1[t, k] = 0.0; } else if (U1 > p1) { beta1 = (1.0 - p1) / m1; V1[t, k] = Math.Log((1.0 - p1) / (1 - U1)) / beta1; } } m2 = theta2 + (V2[t - 1, k] - theta2) * Math.Exp(-kappa2 * dt); s2 = V2[t - 1, k] * sigma2 *sigma2 *Math.Exp(-kappa2 *dt) / kappa2 * (1.0 - Math.Exp(-kappa2 * dt)) + theta2 * sigma2 * sigma2 / 2.0 / kappa2 * Math.Pow(1.0 - Math.Exp(-kappa2 * dt), 2.0); phi2 = s2 / (m2 * m2); p2 = (phi2 - 1.0) / (phi2 + 1.0); U2 = RN.RandomNum(0.0, 1.0); if (phi2 < 0.5) { b2 = Math.Sqrt(2.0 / phi2 - 1.0 + Math.Sqrt(2.0 / phi2 * (2.0 / phi2 - 1.0))); a2 = m2 / (1.0 + b2 * b2); Zv2 = NI.normICDF(U2); V2[t, k] = a2 * (b2 + Zv2) * (b2 + Zv2); } else if (phi2 >= 0.5) { if (U2 <= p2) { V2[t, k] = 0.0; } else if (U2 > p2) { beta2 = (1.0 - p2) / m2; V2[t, k] = Math.Log((1.0 - p2) / (1.0 - U2)) / beta2; } } // Predictor-Corrector for the stock price B1 = RN.RandomNorm(); B2 = RN.RandomNorm(); logS = Math.Log(Math.Exp(-r * Convert.ToDouble(t) * dt) * S[t - 1, k]) + K01 + K11 * V1[t - 1, k] + K21 * V1[t, k] + Math.Sqrt(K31 * (V1[t, k] + V1[t - 1, k])) * B1 + K02 + K12 * V2[t - 1, k] + K22 * V2[t, k] + Math.Sqrt(K32 * (V2[t, k] + V2[t - 1, k])) * B2; S[t, k] = Math.Exp(logS) * Math.Exp(r * Convert.ToDouble(t + 1) * dt); } } // Terminal stock prices double[] ST = new double[N]; for (int k = 0; k <= N - 1; k++) { ST[k] = S[T - 1, k]; } // Payoff vectors double[] Payoff = new double[N]; for (int k = 0; k <= N - 1; k++) { if (PutCall == "C") { Payoff[k] = Math.Max(ST[k] - Strike, 0.0); } else if (PutCall == "P") { Payoff[k] = Math.Max(Strike - ST[k], 0.0); } } // Simulated price double SimPrice = Math.Exp(-r * Mat) * RE.VMean(Payoff); // Output the results DHSim output = new DHSim(); output.S = S; output.EuroPrice = SimPrice; return(output); }
static void Main(string[] args) { // Classes HestonPriceDH HPDH = new HestonPriceDH(); EulerAlfonsiSimulation EA = new EulerAlfonsiSimulation(); TVSimulation TV = new TVSimulation(); QESimulation QE = new QESimulation(); Regression RE = new Regression(); LSM LSM = new LSM(); // Spot price, risk free rate, dividend yield double S0 = 61.90; double K = 61.90; double Mat = 1.0; double rf = 0.03; double q = 0.0; string PutCall = "P"; // Double Heston parameter values DHParam param; param.v01 = 0.36; param.v02 = 0.49; param.sigma1 = 0.10; param.sigma2 = 0.20; param.kappa1 = 0.90; param.kappa2 = 1.20; param.rho1 = -0.5; param.rho2 = -0.5; param.theta1 = 0.10; param.theta2 = 0.15; // 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]); } // Settings for the option OpSet settings; settings.S = S0; settings.K = K; settings.T = Mat; settings.r = rf; settings.q = q; settings.PutCall = PutCall; settings.trap = 1; // Closed form price double TrueEuroPrice = HPDH.DoubleHestonPriceGaussLaguerre(param, settings, X, W); // Simulation settings int NS = 50000; int NT = 1000; // Settings for the clock; Stopwatch sw = new Stopwatch(); // Select the simulation scheme string scheme = "Euler"; double LSMEuro, LSMAmer, Premium, CVPrice; // Zhu-Euler Double Heston prices DHSim Soutput = new DHSim(); sw.Reset(); sw.Start(); if ((scheme == "Euler") || (scheme == "Alfonsi")) { Soutput = EA.DHEulerAlfonsiSim(scheme, param, S0, K, Mat, rf, q, NT, NS, PutCall); } else if ((scheme == "ZhuEuler") || (scheme == "ZhuTV")) { Soutput = TV.DHTransVolSim(scheme, param, S0, K, Mat, rf, q, NT, NS, PutCall); } else if (scheme == "QE") { Soutput = QE.DHQuadExpSim(param, S0, K, Mat, rf, q, NT, NS, PutCall); } double[,] S = Soutput.S; double SimEuro = Soutput.EuroPrice; sw.Stop(); TimeSpan ts = sw.Elapsed; // LSM algorithm double[] LSMoutput = new double[2]; double[,] St1 = RE.MTrans(S); LSMoutput = LSM.HestonLSM(St1, K, rf, q, Mat, NT, NS, PutCall); LSMEuro = LSMoutput[0]; LSMAmer = LSMoutput[1]; Premium = LSMAmer - LSMEuro; // Control variate American price CVPrice = TrueEuroPrice + Premium; // Output the results Console.WriteLine("----------------------------------------------------------------------"); Console.WriteLine("Number of simulations {0:F0}", NS); Console.WriteLine("Number of time steps {0:F0}", NT); Console.WriteLine("Simulation Scheme : {0}", scheme); Console.WriteLine("----------------------------------------------------------------------"); Console.WriteLine("Method Euro Amer Premium ControlVar Sec mSec"); Console.WriteLine("----------------------------------------------------------------------"); Console.WriteLine("Closed {0,10:F4}", TrueEuroPrice); Console.WriteLine("Simulation {0,10:F4} {1,10:F4} {2,10:F4} {3,10:F4} {4,5:F0} {5,5:F0}", LSMEuro, LSMAmer, Premium, CVPrice, ts.Seconds, ts.Milliseconds); Console.WriteLine("----------------------------------------------------------------------"); }
public DHSim DHEulerAlfonsiSim(string scheme, DHParam param, double S0, double Strike, double Mat, double r, double q, int T, int N, string PutCall) { RandomNumber RN = new RandomNumber(); Regression RE = new Regression(); double kappa1 = param.kappa1; double theta1 = param.theta1; double sigma1 = param.sigma1; double v01 = param.v01; double rho1 = param.rho1; double kappa2 = param.kappa2; double theta2 = param.theta2; double sigma2 = param.sigma2; double v02 = param.v02; double rho2 = param.rho2; HParam param1; param1.kappa = kappa1; param1.theta = theta1; param1.sigma = sigma1; param1.v0 = v01; param1.rho = rho1; HParam param2; param2.kappa = kappa2; param2.theta = theta2; param2.sigma = sigma2; param2.v0 = v02; param2.rho = rho2; // Time increment double dt = Mat / T; // Required quantities double K01 = -rho1 * kappa1 * theta1 * dt / sigma1; double K11 = dt / 2.0 * (kappa1 * rho1 / sigma1 - 0.5) - rho1 / sigma1; double K21 = dt / 2.0 * (kappa1 * rho1 / sigma1 - 0.5) + rho1 / sigma1; double K31 = dt / 2.0 * (1.0 - rho1 * rho1); double K02 = -rho2 * kappa2 * theta2 * dt / sigma2; double K12 = dt / 2.0 * (kappa2 * rho2 / sigma2 - 0.5) - rho2 / sigma2; double K22 = dt / 2.0 * (kappa2 * rho2 / sigma2 - 0.5) + rho2 / sigma2; double K32 = dt / 2.0 * (1.0 - rho2 * rho2); // Initialize the variance and stock processes double[,] V1 = new double[T, N]; double[,] V2 = new double[T, N]; double[,] S = new double[T, N]; // Starting values for the variance and stock processes for (int k = 0; k <= N - 1; k++) { S[0, k] = S0; // Spot price V1[0, k] = v01; // Heston v0 initial variance V2[0, k] = v02; // Heston v0 initial variance } double G1, G2, B1, B2, logS; // Generate the stock and volatility paths for (int k = 0; k <= N - 1; k++) { for (int t = 1; t <= T - 1; t++) { if (scheme == "Euler") { // Generate two in dependent N(0,1) variables G1 = RN.RandomNorm(); G2 = RN.RandomNorm(); // Euler discretization with full truncation for the variances V1[t, k] = V1[t - 1, k] + kappa1 * (theta1 - V1[t - 1, k]) * dt + sigma1 * Math.Sqrt(V1[t - 1, k] * dt) * G1; V2[t, k] = V2[t - 1, k] + kappa2 * (theta2 - V2[t - 1, k]) * dt + sigma2 * Math.Sqrt(V2[t - 1, k] * dt) * G2; V1[t, k] = Math.Max(0, V1[t, k]); V2[t, k] = Math.Max(0, V2[t, k]); } else if (scheme == "Alfonsi") { // Alfonsi discretization V1[t, k] = AlfonsiV(param1, V1[t - 1, k], dt); V2[t, k] = AlfonsiV(param2, V2[t - 1, k], dt); } // Predictor-Corrector for the stock price B1 = RN.RandomNorm(); B2 = RN.RandomNorm(); logS = Math.Log(Math.Exp(-r * Convert.ToDouble(t) * dt) * S[t - 1, k]) + K01 + K11 * V1[t - 1, k] + K21 * V1[t, k] + Math.Sqrt(K31 * (V1[t, k] + V1[t - 1, k])) * B1 + K02 + K12 * V2[t - 1, k] + K22 * V2[t, k] + Math.Sqrt(K32 * (V2[t, k] + V2[t - 1, k])) * B2; S[t, k] = Math.Exp(logS) * Math.Exp(r * Convert.ToDouble(t + 1) * dt); } } // Terminal stock prices double[] ST = new double[N]; for (int k = 0; k <= N - 1; k++) { ST[k] = S[T - 1, k]; } // Payoff vectors double[] Payoff = new double[N]; for (int k = 0; k <= N - 1; k++) { if (PutCall == "C") { Payoff[k] = Math.Max(ST[k] - Strike, 0.0); } else if (PutCall == "P") { Payoff[k] = Math.Max(Strike - ST[k], 0.0); } } // Simulated price double SimPrice = Math.Exp(-r * Mat) * RE.VMean(Payoff); // Output the results DHSim output = new DHSim(); output.S = S; output.EuroPrice = SimPrice; return(output); }
public DHSim DHTransVolSim(string scheme, DHParam param, double S0, double Strike, double Mat, double r, double q, int T, int N, string PutCall) { // Heston parameters double kappa1 = param.kappa1; double theta1 = param.theta1; double sigma1 = param.sigma1; double v01 = param.v01; double rho1 = param.rho1; double kappa2 = param.kappa2; double theta2 = param.theta2; double sigma2 = param.sigma2; double v02 = param.v02; double rho2 = param.rho2; // Time increment double dt = Mat / T; // Required quantities double K01 = -rho1 * kappa1 * theta1 * dt / sigma1; double K11 = dt / 2.0 * (kappa1 * rho1 / sigma1 - 0.5) - rho1 / sigma1; double K21 = dt / 2.0 * (kappa1 * rho1 / sigma1 - 0.5) + rho1 / sigma1; double K31 = dt / 2.0 * (1.0 - rho1 * rho1); double K02 = -rho2 * kappa2 * theta2 * dt / sigma2; double K12 = dt / 2.0 * (kappa2 * rho2 / sigma2 - 0.5) - rho2 / sigma2; double K22 = dt / 2.0 * (kappa2 * rho2 / sigma2 - 0.5) + rho2 / sigma2; double K32 = dt / 2.0 * (1.0 - rho2 * rho2); // Initialize the volatility and stock processes double[,] w1 = new double[T, N]; double[,] w2 = new double[T, N]; double[,] S = new double[T, N]; // Starting values for the variance and stock processes for (int k = 0; k <= N - 1; k++) { S[0, k] = S0; // Spot price w1[0, k] = Math.Sqrt(v01); // Heston initial volatility w2[0, k] = Math.Sqrt(v02); } // Generate the stock and volatility paths RandomNumber RN = new RandomNumber(); double Zv1, m11, m12, beta1, thetav1; double Zv2, m21, m22, beta2, thetav2; double B1, B2, logS; for (int k = 0; k <= N - 1; k++) { for (int t = 1; t <= T - 1; t++) { Zv1 = RN.RandomNorm(); Zv2 = RN.RandomNorm(); if (scheme == "ZhuEuler") { // Transformed variance scheme w1[t, k] = w1[t - 1, k] + 0.5 * kappa1 * ((theta1 - sigma1 * sigma1 / 4.0 / kappa1) / w1[t - 1, k] - w1[t - 1, k]) * dt + 0.5 * sigma1 * Math.Sqrt(dt) * Zv1; w2[t, k] = w2[t - 1, k] + 0.5 * kappa2 * ((theta2 - sigma2 * sigma2 / 4.0 / kappa2) / w2[t - 1, k] - w2[t - 1, k]) * dt + 0.5 * sigma2 * Math.Sqrt(dt) * Zv2; } else if (scheme == "ZhuTV") { // Zhu (2010) process for the transformed volatility m11 = theta1 + (w1[t - 1, k] * w1[t - 1, k] - theta1) * Math.Exp(-kappa1 * dt); m21 = theta2 + (w2[t - 1, k] * w2[t - 1, k] - theta2) * Math.Exp(-kappa2 * dt); m12 = sigma1 * sigma1 / 4.0 / kappa1 * (1.0 - Math.Exp(-kappa1 * dt)); m22 = sigma2 * sigma2 / 4.0 / kappa2 * (1.0 - Math.Exp(-kappa2 * dt)); beta1 = Math.Sqrt(Math.Max(0, m11 - m12)); beta2 = Math.Sqrt(Math.Max(0, m21 - m22)); thetav1 = (beta1 - w1[t - 1, k] * Math.Exp(-kappa1 * dt / 2.0)) / (1.0 - Math.Exp(-kappa1 * dt / 2.0)); thetav2 = (beta2 - w2[t - 1, k] * Math.Exp(-kappa2 * dt / 2.0)) / (1.0 - Math.Exp(-kappa2 * dt / 2.0)); w1[t, k] = w1[t - 1, k] + 0.5 * kappa1 * (thetav1 - w1[t - 1, k]) * dt + 0.5 * sigma1 * Math.Sqrt(dt) * Zv1; w2[t, k] = w2[t - 1, k] + 0.5 * kappa2 * (thetav2 - w2[t - 1, k]) * dt + 0.5 * sigma2 * Math.Sqrt(dt) * Zv2; } // Predictor-Corrector for the stock price B1 = RN.RandomNorm(); B2 = RN.RandomNorm(); logS = Math.Log(Math.Exp(-r * Convert.ToDouble(t) * dt) * S[t - 1, k]) + K01 + K11 * w1[t - 1, k] * w1[t - 1, k] + K21 * w1[t, k] * w1[t, k] + Math.Sqrt(K31 * (w1[t, k] * w1[t, k] + w1[t - 1, k] * w1[t - 1, k])) * B1 + K02 + K12 * w2[t - 1, k] * w2[t - 1, k] + K22 * w2[t, k] * w2[t, k] + Math.Sqrt(K32 * (w2[t, k] * w2[t, k] + w2[t - 1, k] * w2[t - 1, k])) * B2; S[t, k] = Math.Exp(logS) * Math.Exp(r * Convert.ToDouble(t + 1) * dt); } } // Terminal stock prices double[] ST = new double[N]; for (int k = 0; k <= N - 1; k++) { ST[k] = S[T - 1, k]; } // Payoff vectors double[] Payoff = new double[N]; for (int k = 0; k <= N - 1; k++) { if (PutCall == "C") { Payoff[k] = Math.Max(ST[k] - Strike, 0.0); } else if (PutCall == "P") { Payoff[k] = Math.Max(Strike - ST[k], 0.0); } } // Simulated price Regression RE = new Regression(); double SimPrice = Math.Exp(-r * Mat) * RE.VMean(Payoff); // Output the results DHSim output = new DHSim(); output.S = S; output.EuroPrice = SimPrice; return(output); }