// Returns option prices lattice as a two-dimensional array private static double[,] createLattice(double S, double K, double sigma, double r, double q, OptionType type, OptionExerciseType exerciseType, int nSteps, double dt) { double upFactor = Math.Pow(Math.E, sigma * Math.Sqrt(2 * dt)); double downFactor = 1 / upFactor; double temp_1 = 0.5 * (r - q) * dt; double temp_2 = sigma * Math.Sqrt(0.5 * dt); double pu = Math.Pow((Math.Pow(Math.E, temp_1) - Math.Pow(Math.E, -temp_2)) / (Math.Pow(Math.E, temp_2) - Math.Pow(Math.E, -temp_2)), 2); // probability of an up-move double pd = Math.Pow((Math.Pow(Math.E, temp_2) - Math.Pow(Math.E, temp_1)) / (Math.Pow(Math.E, temp_2) - Math.Pow(Math.E, -temp_2)), 2); // probability of a down-move double pm = 1.0 - pu - pd; // probability that the price will stay the same double[,] underlyingPrice = new double[nSteps + 1, 2 * nSteps + 1]; // a matrix containing underlying prices of the underlying at each step double[,] lattice = new double[nSteps + 1, 2 * nSteps + 1]; // a matrix containing option prices of the underlying at each step // Build trinomial tree for (int i = 0; i <= nSteps; i++) { for (int j = 0; j <= 2 * i; j++) { underlyingPrice[i, j] = S * Math.Pow(upFactor, j - i); } } // Initialise option prices at maturity for (int i = 0; i <= 2 * nSteps; i++) { if (type == OptionType.Call) { lattice[nSteps, i] = Math.Max(underlyingPrice[nSteps, i] - K, 0); } else { lattice[nSteps, i] = Math.Max(K - underlyingPrice[nSteps, i], 0); } } // Step back through the tree for (int i = nSteps - 1; i >= 0; i--) { for (int j = 0; j <= 2 * i; j++) { if (exerciseType == OptionExerciseType.European) { // if European lattice[i, j] = Math.Pow(Math.E, -r * dt) * (pu * lattice[i + 1, j + 2] + pm * lattice[i + 1, j + 1] + pd * lattice[i + 1, j]); } else { // if American if (type == OptionType.Call) // if a call lattice[i, j] = Math.Max(underlyingPrice[i, j] - K, Math.Pow(Math.E, -r * dt) * (pu * lattice[i + 1, j + 2] + pm * lattice[i + 1, j + 1] + pd * lattice[i + 1, j])); else // if a put lattice[i, j] = Math.Max(K - underlyingPrice[i, j], Math.Pow(Math.E, -r * dt) * (pu * lattice[i + 1, j + 2] + pm * lattice[i + 1, j + 1] + pd * lattice[i + 1, j])); } } } return lattice; }
// Returns option prices lattice as a two-dimensional array private static double[,] createLattice(double S, double K, double sigma, double r, double q, OptionType type, OptionExerciseType exerciseType, int nTimeSteps, double dt, int nPriceSteps, double dS) { double[] underlyingPrice = new double[nPriceSteps + 1]; // an array containing underlying prices of the underlying at each step double[,] lattice = new double[nTimeSteps + 1, nPriceSteps + 1]; // a matrix containing option prices of the underlying at each step double pu, pd, pm; // probabilities of an up-move, a down-move and that the price will stay the same // Build stock price grid for (int i = 0; i <= nPriceSteps; i++) { underlyingPrice[i] = i * dS; } // Initialise option prices at maturity for (int i = 0; i <= nPriceSteps; i++) { if (type == OptionType.Call) { lattice[nTimeSteps, i] = Math.Max(underlyingPrice[i] - K, 0); } else { lattice[nTimeSteps, i] = Math.Max(K - underlyingPrice[i], 0); } } // Step back through the tree for (int i = nTimeSteps - 1; i >= 0; i--) { for (int j = 1; j <= nPriceSteps - 1; j++) { // loop from S = 1 to S = (nPriceSteps - 1), because S = 0 and S = nPriceSteps will have boundary conditions pu = 0.5 * (sigma * sigma * j * j + (r - q) * j )* dt; pd = 0.5 * (sigma * sigma * j * j - (r - q) * j) * dt; pm = 1 - sigma * sigma * j * j * dt; lattice[i, 0] = 0; // boundary condition at S = 0 lattice[i, nPriceSteps] = underlyingPrice[nPriceSteps] - K * Math.Pow(Math.E, -r * (nTimeSteps - i) * dt); // boundary condition at S = nPriceSteps // Alternative boundary conditions from Paul Wilmott (do not work yet) //lattice[i, 0] = (1 - r * dt) * lattice[i + 1, 0]; //lattice[i, nPriceSteps] = 2 * lattice[i, nPriceSteps - 1] - lattice[i, nPriceSteps - 2]; if (exerciseType == OptionExerciseType.European) lattice[i, j] = Math.Pow(Math.E, -r * dt) * (pu * lattice[i + 1, j + 1] + pm * lattice[i + 1, j] + pd * lattice[i + 1, j - 1]); else { if (type == OptionType.Call) // if American call lattice[i, j] = Math.Max(underlyingPrice[j] - K, Math.Pow(Math.E, -r * dt) * (pu * lattice[i + 1, j + 1] + pm * lattice[i + 1, j] + pd * lattice[i + 1, j - 1])); else // if American put lattice[i, j] = Math.Max(K - underlyingPrice[j], Math.Pow(Math.E, -r * dt) * (pu * lattice[i + 1, j + 1] + pm * lattice[i + 1, j] + pd * lattice[i + 1, j - 1])); } } } return lattice; }
// Returns option prices lattice as a two-dimensional array private static double[,] createLattice(double S, double K, double sigma, double r, double q, OptionType type, OptionExerciseType exerciseType, int nSteps, double dt) { double upFactor = Math.Pow(Math.E, sigma * Math.Sqrt(dt)); double downFactor = 1 / upFactor; double p = (Math.Pow(Math.E, (r - q) * dt) - downFactor) / (upFactor - downFactor); // probability of an up-move double[,] underlyingPrice = new double[nSteps + 1, nSteps + 1]; // a matrix containing underlying prices of the underlying at each step double[,] lattice = new double[nSteps + 1, nSteps + 1]; // a matrix containing option prices of the underlying at each step // Build binomial tree for (int i = 0; i <= nSteps; i++) { for (int j = 0; j <= i; j++) { underlyingPrice[i, j] = S * Math.Pow(upFactor, j) * Math.Pow(downFactor, i - j); } } // Initialise option prices at maturity for (int i = 0; i <= nSteps; i++) { if (type == OptionType.Call) { lattice[nSteps, i] = Math.Max(underlyingPrice[nSteps, i] - K, 0); } else { lattice[nSteps, i] = Math.Max(K - underlyingPrice[nSteps, i], 0); } } // Step back through the tree for (int i = nSteps - 1; i >= 0; i--) { for (int j = 0; j <= i; j++) { if (exerciseType == OptionExerciseType.European) { // if European lattice[i, j] = Math.Pow(Math.E, -r * dt) * (p * lattice[i + 1, j + 1] + (1 - p) * lattice[i + 1, j]); } else { // if American if (type == OptionType.Call) // if a call lattice[i, j] = Math.Max(underlyingPrice[i, j] - K, Math.Pow(Math.E, -r * dt) * (p * lattice[i + 1, j + 1] + (1 - p) * lattice[i + 1, j])); else // if a put lattice[i, j] = Math.Max(K - underlyingPrice[i, j], Math.Pow(Math.E, -r * dt) * (p * lattice[i + 1, j + 1] + (1 - p) * lattice[i + 1, j])); } } } return lattice; }