public double CZNewton(double start, double v0, double v1, double mat, double kappa, double theta, double lambda, double rho, double sigma,
                               double K, double r, double q, double[] xs, double[] ws, double[] xt, double[] wt, int Nt, double B0, double B1, int ACNum, double tol,
                               double A, double B, double C, double D, string DoubleType)
        {
            // Parameters
            HParam param0;

            param0.kappa  = kappa;
            param0.theta  = theta;
            param0.sigma  = sigma;
            param0.v0     = v0;
            param0.rho    = rho;
            param0.lambda = lambda;
            HParam param1;

            param1.kappa  = kappa;
            param1.theta  = theta;
            param1.sigma  = sigma;
            param1.v0     = v1;
            param1.rho    = rho;
            param1.lambda = lambda;

            double db = 0.001;
            double diff = 1.1 * tol;
            double g0, g, g_, b0, b1, CallA1, CallA0;

            double[] Prices = new double[2];
            double   b_new  = 0.0;

            // Set the first value to the starting value
            double b = start;

            // Set the upper time-integration range to the maturity increment
            B = mat;
            CZPrices CZ = new CZPrices();

            while (Math.Abs(diff) > tol)
            {
                if (ACNum == 1)
                {
                    // First set of functions and derivative
                    Prices = CZ.CZAmerCall(Math.Exp(B0 + b * v0), mat, param0, K, r, q, xs, ws, xt, wt, Nt, B0, b, A, B, C, D, DoubleType);
                    CallA1 = Prices[0];
                    g0     = (Math.Log(CallA1 + K) - B0) / v0 - b;

                    Prices = CZ.CZAmerCall(Math.Exp(B0 + (b + db) * v0), mat, param0, K, r, q, xs, ws, xt, wt, Nt, B0, b + db, A, B, C, D, DoubleType);
                    CallA1 = Prices[0];
                    g      = (Math.Log(CallA1 + K) - B0) / v0 - (b + db);

                    Prices = CZ.CZAmerCall(Math.Exp(B0 + (b - db) * v0), mat, param0, K, r, q, xs, ws, xt, wt, Nt, B0, b - db, A, B, C, D, DoubleType);
                    CallA1 = Prices[0];
                    g_     = (Math.Log(CallA1 + K) - B0) / v0 - (b - db);
                }
                else
                {
                    // Second set of functions and derivatives
                    Prices = CZ.CZAmerCall(Math.Exp(b + B1 * v1), mat, param1, K, r, q, xs, ws, xt, wt, Nt, b, B1, A, B, C, D, DoubleType);
                    CallA0 = Prices[0];
                    g0     = (Math.Log(CallA0 + K) - v1 * B1) - b;

                    Prices = CZ.CZAmerCall(Math.Exp(b + db + B1 * v1), mat, param1, K, r, q, xs, ws, xt, wt, Nt, b + db, B1, A, B, C, D, DoubleType);
                    CallA0 = Prices[0];
                    g      = (Math.Log(CallA0 + K) - v1 * B1) - (b + db);

                    Prices = CZ.CZAmerCall(Math.Exp(b - db + B1 * v1), mat, param1, K, r, q, xs, ws, xt, wt, Nt, b - db, B1, A, B, C, D, DoubleType);
                    CallA0 = Prices[0];
                    g_     = (Math.Log(CallA0 + K) - v1 * B1) - (b - db);
                }
                // The derivative
                double dg = (g - g_) / 2.0 / db;

                // Newton's method
                b_new = b - g0 / dg;
                diff  = b_new - b;
                b     = b_new;
            }
            return(b);
        }
Ejemplo n.º 2
0
        static void Main(string[] args)
        {
            // 32-point Gauss-Laguerre Abscissas and weights
            double[] xs = new double[32];
            double[] ws = 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(' ');
                    xs[k] = double.Parse(bits[0]);
                    ws[k] = double.Parse(bits[1]);
                }
            // 32-point Gauss-Legendre Abscissas and weights
            double[] xt = new double[32];
            double[] wt = 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(' ');
                    xt[k] = double.Parse(bits[0]);
                    wt[k] = double.Parse(bits[1]);
                }

            // Option settings
            double S0   = 100.0;
            double K    = 100.0;
            double tau  = 0.25;
            double r    = 0.01;
            double q    = 0.12;
            int    trap = 1;

            // Option settings into the structure
            OPSet opset = new OPSet();

            opset.S = S0;
            opset.K = K;
            opset.r = r;
            opset.q = q;

            // Heston parameters
            HParam param = new HParam();

            param.kappa  = 4.0;
            param.theta  = 0.09;
            param.sigma  = 0.1;
            param.v0     = 0.04;
            param.rho    = 0.0;
            param.lambda = 0.0;

            // Time integration limits
            double a = 1e-10;
            double b = tau;

            // Price integration limits
            double c = 1e-10;
            double d = 150;

            // Number of points for double trapezoidal rule
            int Nt = 50;

            // Choose double integration "GLe" or "Trapz"
            string DoubleType = "GLe";

            // Closed form European price
            HestonPrices HP         = new HestonPrices();
            double       EuroClosed = HP.HestonPriceGaussLaguerre(param, opset, "C", tau, trap, xs, ws);

            // Starting values for v0[n], v1[n], b0[n], and b1[n]
            findBfunctions FB  = new findBfunctions();
            double         Evt = FB.EV(param.v0, param.theta, param.kappa, tau, tau);
            double         V00 = Evt + param.sigma / Math.Abs(param.kappa) * Math.Sqrt(param.kappa * param.theta / 2.0);
            double         V10 = Evt - param.sigma / Math.Abs(param.kappa) * Math.Sqrt(param.kappa * param.theta / 2.0);
            double         b00 = Math.Log(K);
            double         b10 = 0.0;

            // Tolerance and maximum number of steps
            double tol0 = 0.005;
            double tol1 = 0.005;
            int    Ntau = 25;
            double Ntol = 1e-8;

            // Vectors B0[n] and B1[n] from the Chiarella algorithm
            BVec bvector = FB.findB(tau, param, K, r, q, V00, V10, b00, b10, xs, ws, xt, wt, Nt, Ntau, tol0, tol1, Ntol, a, b, c, d, DoubleType);

            double[] B0 = bvector.B0;
            double[] B1 = bvector.B1;
            int      Nb = B0.Length;

            // Last values of the vectors go into the American Call price
            double b0 = B0[Nb - 1];
            double b1 = B1[Nb - 1];

            // Compute the call prices with b0 and b1 returned from the optimization
            CZPrices CZ = new CZPrices();

            double[] CallPrices = new double[2];
            CallPrices = CZ.CZAmerCall(S0, tau, param, K, r, q, xs, ws, xt, wt, Nt, b0, b1, a, b, c, d, DoubleType);
            double AmerCZ = CallPrices[0];
            double EuroCZ = CallPrices[1];

            // Prices from the Explicit Method, wUsing a Non-Uniform Grid
            // Minimum and maximum values for the Stock Price, Volatility, and Maturity
            double Smin = 0.0; double Smax = 2.0 * K;
            double Vmin = 0.0; double Vmax = 0.5;
            double Tmin = 0.0; double Tmax = tau;

            // Number of grid points for the stock, volatility, and maturity
            int nS = 89;        // Stock price
            int nV = 49;        // Volatility
            int nT = 5000;      // Maturity

            // The maturity time increment and grid
            double dt = (Tmax - Tmin) / Convert.ToDouble(nT);

            double[] T = new double[nT + 1];
            for (int i = 0; i <= nT; i++)
            {
                T[i] = Convert.ToDouble(i) * dt;
            }

            // The stock price grid
            Interpolation IP = new Interpolation();
            double        cc = K / 5.0;
            double        dz = 1.0 / nS * (IP.aSinh((Smax - K) / cc) - IP.aSinh(-K / cc));

            double[] z = new double[nS + 1];
            double[] S = new double[nS + 1];
            for (int i = 0; i <= nS; i++)
            {
                z[i] = IP.aSinh(-K / cc) + Convert.ToDouble(i) * dz;
                S[i] = K + cc * Math.Sinh(z[i]);
            }
            S[0] = 0;

            // The volatility grid
            double dd = Vmax / 500.0;
            double dn = IP.aSinh(Vmax / dd) / nV;

            double[] n = new double[nV + 1];
            double[] V = new double[nV + 1];
            for (int j = 0; j <= nV; j++)
            {
                n[j] = Convert.ToDouble(j) * dn;
                V[j] = dd * Math.Sinh(n[j]);
            }
            // Solve the PDE using the Explicit Method
            //double[,] AmerU = HestonExplicitPDENonUniformGrid(param,K,r,q,S,V,T,"C","A");
            //double[,] EuroU = HestonExplicitPDENonUniformGrid(param,K,r,q,S,V,T,"C","E");

            // Obtain the American and European price by 2-D interpolation
            //double AmerPDE = interp2(V,S,AmerU,param.v0,S0);
            //double EuroPDE = interp2(V,S,EuroU,param.v0,S0);

            // Obtain the control variate price from the PDE
            double AmerPDE = 3.730064;
            double EuroPDE = 3.508536;
            double AmerCV  = EuroClosed + (AmerPDE - EuroPDE);

            // LSM prices
            //AmerLSM = 3.729049;
            //EuroLSM = 3.501443;
            //AmerCV  = 3.733422;

            // Output the results
            Console.WriteLine("------------------------------------------------------------");
            Console.WriteLine("      b0        b1");
            Console.WriteLine(" {0,10:F5} {1,10:F5}", b0, b1);
            Console.WriteLine("-----------------------------");
            Console.WriteLine("                European   American   AmericanCV");
            Console.WriteLine("-------------------------------------------------");
            Console.WriteLine("Closed        {0,10:F6}                    ", EuroClosed);
            Console.WriteLine("Explicit      {0,10:F6} {1,10:F6} {2,10:F6}", EuroPDE, AmerPDE, AmerCV);
            Console.WriteLine("Chiarella     {0,10:F6} {1,10:F6}          ", EuroCZ, AmerCZ);
            Console.WriteLine("-------------------------------------------------");
        }