public double WeightedPrice(double thet, double[,] L, double S0, double V0, double K, double r, double q, double Mat, double[] S, double[] V, double[] T, double[,] A, double[,] invA, double[,] B) { // Heston Call price using the Weighted Method // Requires a uniform grid for the stock price, volatility, and maturity // INPUTS // thet = theta parameter for the Weighted method // L = operator matrix for the Heston model // params = vector of Heston parameters // S0 = Spot price at which to price the call // V0 = variance at which to price the call // K = Strike price // r = risk free rate // q = dividend yield // Mat = maturity // S = uniform grid for the stock price // V = uniform grid for the volatility // T = uniform grid for the maturity // A = "A" matrix for weighted method // invA = A inverse // B = "B" matrix for weighted method // OUTPUT // y = 2-D interpolated European Call price MatrixOps MO = new MatrixOps(); Interpolation IP = new Interpolation(); // Required vector lengths and time increment int NS = S.Length; int NV = V.Length; int NT = T.Length; double dt = T[1] - T[0]; // Identity matrix int N = NS * NV; double[,] I = MO.CreateI(N); // Initialize the U and u vectors double[] U = new double[N]; double[] u = new double[N]; // U(0) vector - value of U(T) at maturity double[] Si = new double[N]; int k = 0; for (int v = 0; v <= NV - 1; v++) { for (int s = 0; s <= NS - 1; s++) { Si[k] = S[s]; U[k] = Math.Max(Si[k] - K, 0.0); k += 1; } } // Loop through the time increments, updating U(t) to U(t+1) at each step for (int t = 2; t <= NT; t++) { for (k = 0; k <= N - 1; k++) { u[k] = U[k]; } if (thet == 0.0) { U = MO.MVMult(B, u); // Explicit Method } else if (thet == 1.0) { U = MO.MVMult(invA, u); // Implicit Method } else { U = MO.MVMult(invA, MO.MVMult(B, u)); // Weighted Methods } } // Restack the U vector to output a matrix double[,] UU = new double[NS, NV]; k = 0; for (int v = 0; v <= NV - 1; v++) { for (int s = 0; s <= NS - 1; s++) { UU[s, v] = U[k]; k += 1; } } // Interpolate to get the price at S0 and v0 return(IP.interp2(V, S, UU, V0, S0)); }
public LMatrices BuildDerivatives(double[] S, double[] V, double[] T) { // Build the first- and second-order derivatives for the "L" operator matrix // for the Weighted method // INPUTS // S = vector for uniform stock price grid // V = vector for uniform volatility grid // T = vector for uniform maturity grid // thet = parameter for the weighted scheme // OUTPUTS // Matrices of dimnension N x N (N=NS+NV) // derS = Matrix for first-order derivative dU/dS // derSS = Matrix for second-order derivative dU2/dS2 // derV1 = Matrix for first-order derivative dU/dV, kappa*theta portion // derV2 = Matrix for first-order derivative dU/dV, -kappa*V portion // derVV = Matrix for first-order derivative dU2/dV2 // derSV = Matrix for first-order derivative dU2/dSdV // R = Matrix for r*S(v,t) portion of the PDE Interpolation IP = new Interpolation(); // Length of stock price, volatility, and maturity int NS = S.Length; int NV = V.Length; int NT = T.Length; double Smin = S[0]; double Smax = S[NS - 1]; double Vmin = V[0]; double Vmax = V[NV - 1]; double Tmin = T[0]; double Tmax = T[NT - 1]; // Increment for Stock Price, Volatility, and Maturity double ds = (Smax - Smin) / Convert.ToDouble(NS - 1); double dv = (Vmax - Vmin) / Convert.ToDouble(NV - 1); double dt = (Tmax - Tmin) / Convert.ToDouble(NT - 1); // Preliminary quantities // Size of the U(t) vector and L matrix int N = NS * NV; // The vectors for S and V, stacked double[] Si = new double[N]; double[] Vi = new double[N]; int k = 0; for (int v = 0; v <= NV - 1; v++) { for (int s = 0; s <= NS - 1; s++) { Si[k] = S[s]; Vi[k] = V[v]; k += 1; } } // Identification of the boundary points int[] VminB = new int[N]; int[] VmaxB = new int[N]; int[] SminB = new int[N]; int[] SmaxB = new int[N]; // Vmin and Vmax for (int v = 0; v <= NS - 2; v++) { VminB[v] = 1; } for (int v = N - NS + 1; v <= N - 2; v++) { VmaxB[v] = 1; } VmaxB[N - 1] = 1; // Smin and Smax k = 0; for (int v = 0; v <= NV - 1; v++) { for (int s = 0; s <= NS - 1; s++) { if (s == 0) { SminB[k] = 1; } else if (s == NS - 1) { SmaxB[k] = 1; } k += 1; } } SminB[0] = 0; SmaxB[NS - 1] = 0; SmaxB[N - 1] = 0; // Identification of the non-boundary points int[] NB = new int[N]; for (k = 0; k <= N - 1; k++) { if (SminB[k] == 0 & SmaxB[k] == 0 & VminB[k] == 0 & VmaxB[k] == 0) { NB[k] = 1; } } // Forward, backward and central differences for S int[] Cs = new int[N]; int[] Fs = new int[N]; int[] Bs = new int[N]; k = 0; for (int v = 0; v <= NV - 2; v++) { for (int s = 0; s <= NS - 1; s++) { if (s == 1) { Fs[k] = 1; } else if (s == NS - 2) { Bs[k] = 1; } else if (s >= 2 & s <= NS - 3) { Cs[k] = 1; } k += 1; } } Fs[1] = 0; Bs[NS - 2] = 0; for (k = 2; k <= NS - 3; k++) { Cs[k] = 0; } // Forward, backward and central differences for V int[] Cv = new int[N]; int[] Fv = new int[N]; int[] Bv = new int[N]; for (k = NS + 1; k <= 2 * NS - 2; k++) { Fv[k] = 1; } for (k = (NV - 2) * NS + 1; k <= (NV - 1) * NS - 2; k++) { Bv[k] = 1; } k = 0; for (int v = 0; v <= NV - 3; v++) { for (int s = 0; s <= NS - 1; s++) { if (s >= 1 & s <= NS - 2) { Cv[k] = 1; } k += 1; } } for (k = 0; k <= 2 * NS - 1; k++) { Cv[k] = 0; } // Central difference for SV-derivatives int[] Csv = new int[N]; k = 0; for (int v = 0; v <= NV - 2; v++) { for (int s = 0; s <= NS - 1; s++) { if (s >= 1 & s <= NS - 2) { Csv[k] = 1; } k += 1; } } for (k = 0; k <= NS - 1; k++) { Csv[k] = 0; } // Create the matrices for the derivatives double[,] derS = new double[N, N]; double[,] derSS = new double[N, N]; double[,] derV1 = new double[N, N]; double[,] derV2 = new double[N, N]; double[,] derVV = new double[N, N]; double[,] derSV = new double[N, N]; double[,] R = new double[N, N]; for (int i = 0; i <= N - 1; i++) { for (int j = 0; j <= N - 1; j++) { if (i == j) { R[i, j] = 1.0; } } } int M; int[] I; // Create the matrices for the derivatives // NON BOUNDARY POINTS ---------------------------------- I = IP.Find(Cs); M = I.Length; for (k = 0; k <= M - 1; k++) { // Central differences derS[I[k], I[k] - 1] = -0.5 / ds * Si[I[k]]; // U(s-1,v) derS[I[k], I[k]] = 0.0; // U(s,v) derS[I[k], I[k] + 1] = 0.5 / ds * Si[I[k]]; // U(s+1,v) derSS[I[k], I[k] - 1] = 1.0 / ds / ds * Vi[I[k]] * Si[I[k]] * Si[I[k]]; // U(s-1,v) derSS[I[k], I[k]] = -2.0 / ds / ds * Vi[I[k]] * Si[I[k]] * Si[I[k]]; // U(s,v) derSS[I[k], I[k] + 1] = 1.0 / ds / ds * Vi[I[k]] * Si[I[k]] * Si[I[k]]; // U(s+1,v) } I = IP.Find(Fs); M = I.Length; for (k = 0; k <= M - 1; k++) { // Forward differences derS[I[k], I[k]] = -1.5 / ds * Si[I[k]]; // U(s,v) derS[I[k], I[k] + 1] = 2.0 / ds * Si[I[k]]; // U(s+1,v) derS[I[k], I[k] + 2] = -1.0 / ds * Si[I[k]]; // U(s+2,v) derSS[I[k], I[k]] = 1.0 / ds / ds * Vi[I[k]] * Si[I[k]] * Si[I[k]]; // U(s,v) derSS[I[k], I[k] + 1] = -2.0 / ds / ds * Vi[I[k]] * Si[I[k]] * Si[I[k]]; // U(s+1,v) derSS[I[k], I[k] + 2] = 1.0 / ds / ds * Vi[I[k]] * Si[I[k]] * Si[I[k]]; // U(s+2,v) } I = IP.Find(Bs); M = I.Length; for (k = 0; k <= M - 1; k++) { // Backward differences derS[I[k], I[k] - 2] = -0.5 / ds * Si[I[k]]; // U(s-2,v) derS[I[k], I[k] - 1] = -2.0 / ds * Si[I[k]]; // U(s-1,v) derS[I[k], I[k]] = 1.5 / ds * Si[I[k]]; // U(s,v) derSS[I[k], I[k] - 2] = 1.0 / ds / ds * Vi[I[k]] * Si[I[k]] * Si[I[k]]; // U(s-2,v) derSS[I[k], I[k] - 1] = -2.0 / ds / ds * Vi[I[k]] * Si[I[k]] * Si[I[k]]; // U(s-1,v) derSS[I[k], I[k]] = 1.0 / ds / ds * Vi[I[k]] * Si[I[k]] * Si[I[k]]; // U(s,v) } // Create the matrix for V-derivatives I = IP.Find(Cv); M = I.Length; for (k = 0; k <= M - 1; k++) { // Central differences derV1[I[k], I[k] - NS] = -0.5 / dv; // U(s,v-1) derV1[I[k], I[k]] = 0.0; // U(s,v) derV1[I[k], I[k] + NS] = 0.5 / dv; // U(s,v+1) derV2[I[k], I[k] - NS] = -0.5 / dv * Vi[I[k]]; // U(s,v-1) derV2[I[k], I[k]] = 0.0; // U(s,v) derV2[I[k], I[k] + NS] = 0.5 / dv * Vi[I[k]]; // U(s,v+1) derVV[I[k], I[k] - NS] = 1.0 / dv / dv * Vi[I[k]]; // U(s,v-1) derVV[I[k], I[k]] = -2.0 / dv / dv * Vi[I[k]]; // U(s,v) derVV[I[k], I[k] + NS] = 1.0 / dv / dv * Vi[I[k]]; // U(s,v+1) } I = IP.Find(Fv); M = I.Length; for (k = 0; k <= M - 1; k++) { // Forward differences derV1[I[k], I[k]] = -1.5 / dv; // U(s,v) derV1[I[k], I[k] + NS] = 2.0 / dv; // U(s,v+1) derV1[I[k], I[k] + 2 * NS] = -1.0 / dv; // U(s,v+2) derV2[I[k], I[k]] = -1.5 / dv * Vi[I[k]]; // U(s,v) derV2[I[k], I[k] + NS] = 2.0 / dv * Vi[I[k]]; // U(s,v+1) derV2[I[k], I[k] + 2 * NS] = -1.0 / dv * Vi[I[k]]; // U(s,v+2) derVV[I[k], I[k]] = 1.0 / dv / dv * Vi[I[k]]; // U(s,v) derVV[I[k], I[k] + NS] = -2.0 / dv / dv * Vi[I[k]]; // U(s,v+1) derVV[I[k], I[k] + 2 * NS] = 1.0 / dv / dv * Vi[I[k]]; // U(s,v+2) } I = IP.Find(Bv); M = I.Length; for (k = 0; k <= M - 1; k++) { // Backward differences derV1[I[k], I[k] - 2 * NS] = -0.5 / dv; // U(s,v-2) derV1[I[k], I[k] - NS] = -2.0 / dv; // U(s,v-1) derV1[I[k], I[k]] = 1.5 / dv; // U(s,v) derV2[I[k], I[k] - 2 * NS] = -0.5 / dv * Vi[I[k]]; // U(s,v-2) derV2[I[k], I[k] - NS] = -2.0 / dv * Vi[I[k]]; // U(s,v-1) derV2[I[k], I[k]] = 1.5 / dv * Vi[I[k]]; // U(s,v) derVV[I[k], I[k] - 2 * NS] = 1.0 / dv / dv * Vi[I[k]]; // U(s,v-2) derVV[I[k], I[k] - NS] = -2.0 / dv / dv * Vi[I[k]]; // U(s,v-1) derVV[I[k], I[k]] = 1.0 / dv / dv * Vi[I[k]]; // U(s,v) } // Create the matrix for SV-derivatives I = IP.Find(Csv); M = I.Length; for (k = 0; k <= M - 1; k++) { derSV[I[k], I[k] + NS + 1] = 1.0 / (4.0 * ds * dv) * Vi[I[k]] * Si[I[k]]; // U(s+1,v+1) derSV[I[k], I[k] + NS - 1] = -1.0 / (4.0 * ds * dv) * Vi[I[k]] * Si[I[k]]; // U(s-1,v+1) derSV[I[k], I[k] - NS - 1] = 1.0 / (4.0 * ds * dv) * Vi[I[k]] * Si[I[k]]; // U(s-1,v-1) derSV[I[k], I[k] - NS + 1] = -1.0 / (4.0 * ds * dv) * Vi[I[k]] * Si[I[k]]; // U(s+1,v-1) } // BOUNDARY POINTS ---------------------------------- // Boundary for Smin I = IP.Find(SminB); M = I.Length; for (k = 0; k <= M - 1; k++) { derS[I[k], I[k]] = 0.0; derSS[I[k], I[k]] = 0.0; derV1[I[k], I[k]] = 0.0; derV2[I[k], I[k]] = 0.0; derVV[I[k], I[k]] = 0.0; derSV[I[k], I[k]] = 0.0; R[I[k], I[k]] = 0.0; } // Boundary condition for Smax I = IP.Find(SmaxB); M = I.Length; for (k = 0; k <= M - 1; k++) { derS[I[k], I[k]] = Si[I[k]]; derSS[I[k], I[k]] = 0.0; derSV[I[k], I[k]] = 0.0; // Central difference derV1[I[k], I[k] - NS] = -0.5 / dv; // U(s,v-1) derV1[I[k], I[k]] = 0; // U(s,v) derV1[I[k], I[k] + NS] = 0.5 / dv; // U(s,v+1) derV2[I[k], I[k] - NS] = -0.5 / dv * Vi[I[k]]; // U(s,v-1) derV2[I[k], I[k]] = 0.0; // U(s,v) derV2[I[k], I[k] + NS] = 0.5 / dv * Vi[I[k]]; // U(s,v+1) derVV[I[k], I[k] - NS] = 1.0 / dv / dv * Vi[I[k]]; // U(s,v-1) derVV[I[k], I[k]] = -2.0 / dv / dv * Vi[I[k]]; // U(s,v) derVV[I[k], I[k] + NS] = 1.0 / dv / dv * Vi[I[k]]; // U(s,v+1) } // Boundary condition for Vmax. Only the LS submatrix is non-zero. I = IP.Find(VmaxB); M = I.Length; for (k = 0; k <= M - 1; k++) { derS[I[k], I[k]] = Si[I[k]]; } // Boundary condition for Vmin // First row derS[0, 0] = -1.5 / ds * Si[0]; // U(s,v) derS[0, 1] = 2.0 / ds * Si[0]; // U(s+1,v) derS[0, 2] = -1.0 / ds * Si[0]; // U(s+2,v) derV1[0, 0] = -1.5 / dv; // U(s,v) derV1[0, NS] = 2.0 / dv; // U(s,v+1) derV1[0, 2 * NS] = -1.0 / dv; // U(s,v+2) // Last row derS[N - 2, N - 4] = -0.5 / ds * Si[N - 2]; // U(s-2,v) derS[N - 2, N - 3] = -2.0 / ds * Si[N - 2]; // U(s-1,v) derS[N - 2, N - 2] = 1.5 / ds * Si[N - 2]; // U(s,v) derV1[NS - 2, NS - 2 + 2 * NS] = -0.5 / dv * Vi[NS - 2]; // U(s,v+2) derV1[NS - 2, NS - 2 + NS] = 2.0 / dv * Vi[NS - 2]; // U(s,v+1) derV1[NS - 2, NS - 2] = -1.5 / dv * Vi[NS - 2]; // U(s,v) // Other rows for (int i = 1; i <= NS - 3; i++) { derS[i, i - 1] = -0.5 / ds * Si[i]; // U(s-1,v) derS[i, i] = 0.0; // U(s,v) derS[i, i + 1] = 0.5 / ds * Si[i]; // U(s+1,v) derV1[i, i] = -1.5 / dv; // U(s,v) derV1[i, i + NS] = 2.0 / dv; // U(s,v+1) derV1[i, i + 2 * NS] = -1.0 / dv; // U(s,v+2) } // Output the sub-matrices LMatrices LMat; LMat.derS = derS; LMat.derSS = derSS; LMat.derV1 = derV1; LMat.derV2 = derV2; LMat.derVV = derVV; LMat.derSV = derSV; LMat.R = R; return(LMat); }