示例#1
0
        // Heston Price by Gauss-Laguerre Integration
        public double HestonPriceConsol(HParam param, OpSet settings, double[] x, double[] w)
        {
            double[] int1 = new Double[32];
            // Numerical integration
            for (int j = 0; j <= 31; j++)
            {
                int1[j] = w[j] * HestonProbConsol(x[j], param, settings);
            }

            // Define P1 and P2
            double pi = Math.PI;
            double I  = int1.Sum();

            // The call price
            double S       = settings.S;
            double K       = settings.K;
            double r       = settings.r;
            double q       = settings.q;
            double T       = settings.T;
            string PutCall = settings.PutCall;
            double HestonC = 0.5 * S * Math.Exp(-q * T) - 0.5 * K * Math.Exp(-r * T) + I / pi;

            // The put price by put-call parity
            double HestonP = HestonC - S * Math.Exp(-q * T) + K * Math.Exp(-r * T);

            // Output the option price
            if (PutCall == "C")
            {
                return(HestonC);
            }
            else
            {
                return(HestonP);
            }
        }
示例#2
0
        // Mikhailov and Nogel (2003) Time dependent D function
        public Complex Dt(double phi, HParam param, double r, double q, double T, OpSet settings, int Pnum, Complex C0, Complex D0)
        {
            Complex i = new Complex(0.0, 1.0);                   // Imaginary unit
            double  kappa = param.kappa;
            double  theta = param.theta;
            double  sigma = param.sigma;
            double  v0 = param.v0;
            double  rho = param.rho;
            int     Trap = settings.trap;
            Complex b, u, d, g, G, D = new Complex();

            // Parameters "u" and "b" are different for P1 and P2
            if (Pnum == 1)
            {
                u = 0.5;
                b = kappa - rho * sigma;
            }
            else
            {
                u = -0.5;
                b = kappa;
            }
            d = Complex.Sqrt(Complex.Pow(rho * sigma * i * phi - b, 2) - sigma * sigma * (2.0 * u * i * phi - phi * phi));
            g = (b - rho * sigma * i * phi + d - D0 * sigma * sigma) / (b - rho * sigma * i * phi - d - D0 * sigma * sigma);
            G = (1.0 - g * Complex.Exp(d * T)) / (1.0 - g);
            D = ((b - rho * sigma * i * phi) * (1 - g * Complex.Exp(d * T)) + d * (1 + g * Complex.Exp(d * T))) / (sigma * sigma * (1 - g * Complex.Exp(d * T)));

            return(D);
        }
        static void Main(string[] args)
        {
            // 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]);
                }
            HParam param = new HParam();

            param.kappa  = 6.2;
            param.theta  = 0.06;
            param.sigma  = 0.5;
            param.v0     = 0.03;
            param.rho    = -0.7;
            param.lambda = 0.0;

            OpSet settings = new OpSet();

            settings.S       = 100.0;
            settings.K       = 100.0;
            settings.T       = 0.25;
            settings.r       = 0.03;
            settings.q       = 0.02;
            settings.PutCall = "C";
            settings.trap    = 1;

            // Simulation settings
            double gamma1 = 0.5;
            double gamma2 = 0.5;
            double phic   = 1.5;
            int    MC     = 1;
            int    NT     = 100;
            int    NS     = 1500;

            // Calculate the IJK price
            QESimulation QE           = new QESimulation();
            double       QuadExpPrice = QE.QEPrice(param, settings, gamma1, gamma2, NT, NS, MC, phic, settings.PutCall);

            // Calculate the closed-form European option price
            HestonPrice HP          = new HestonPrice();
            double      ClosedPrice = HP.HestonPriceGaussLaguerre(param, settings, x, w);

            // Calculate the errors;
            double QError = Math.Abs((QuadExpPrice - ClosedPrice) / ClosedPrice * 100);

            // Output the results
            Console.WriteLine("European Heston price by simulation --------------------");
            Console.WriteLine("Uses  {0:0} stock price paths and {1:0} time increments", NS, NT);
            Console.WriteLine("--------------------------------------------------------");
            Console.WriteLine("Closed form price        {0:F5}", ClosedPrice);
            Console.WriteLine("Quadratic exp price      {0:F5}      Error {1,5:F5}", QuadExpPrice, QError);
            Console.WriteLine("--------------------------------------------------------");
            Console.WriteLine(" ");
        }
        static void Main(string[] args)
        {
            // 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]);
                }
            HParam param = new HParam();

            param.kappa  = 6.2;
            param.theta  = 0.06;
            param.sigma  = 0.5;
            param.v0     = 0.03;
            param.rho    = -0.7;
            param.lambda = 0.0;

            OpSet settings = new OpSet();

            settings.S       = 100.0;
            settings.K       = 90.0;
            settings.T       = 3.0 / 12.0;
            settings.r       = 0.03;
            settings.q       = 0.02;
            settings.PutCall = "C";
            settings.trap    = 1;

            // Simulation settings
            int NT = 100;
            int NS = 2000;

            // Calculate the Euler price and the transformed volatility price
            TVSimulation TV         = new TVSimulation();
            double       TVolPrice  = TV.TransVolPrice("TV", param, settings, NT, NS);
            double       EulerPrice = TV.TransVolPrice("Euler", param, settings, NT, NS);

            // Calculate the closed-form European option price
            double ClosedPrice = HestonPriceGaussLaguerre(param, settings, x, w);

            // Calculate the errors;
            double TVolError  = Math.Abs((TVolPrice - ClosedPrice) / ClosedPrice * 100);
            double EulerError = Math.Abs((EulerPrice - ClosedPrice) / ClosedPrice * 100);

            // Output the results
            Console.WriteLine("Uses  {0:0} stock price paths and {1:0} time increments", NS, NT);
            Console.WriteLine("--------------------------------------------------------");
            Console.WriteLine("Method                       Price     PercentError");
            Console.WriteLine("--------------------------------------------------------");
            Console.WriteLine("Exact with Gauss Laguerre  {0,10:F5}", ClosedPrice);
            Console.WriteLine("Euler discretization       {0,10:F5}  {1,10:F5}", EulerPrice, EulerError);
            Console.WriteLine("Transformed volatility     {0,10:F5}  {1,10:F5}", TVolPrice, TVolError);
            Console.WriteLine("--------------------------------------------------------");
            Console.WriteLine(" ");
        }
示例#5
0
        // Heston Integrand
        public double HestonProb(double phi, HParam param, OpSet settings, int Pnum)
        {
            Complex i = new Complex(0.0, 1.0);                   // Imaginary unit
            double  S = settings.S;
            double  K = settings.K;
            double  T = settings.T;
            double  r = settings.r;
            double  q = settings.q;
            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  x = Math.Log(S);
            double  a = kappa * theta;
            int     Trap = settings.trap;
            Complex b, u, d, g, c, D, G, C, f, integrand = new Complex();

            // Parameters "u" and "b" are different for P1 and P2
            if (Pnum == 1)
            {
                u = 0.5;
                b = kappa + lambda - rho * sigma;
            }
            else
            {
                u = -0.5;
                b = kappa + lambda;
            }
            d = Complex.Sqrt(Complex.Pow(rho * sigma * i * phi - b, 2) - sigma * sigma * (2.0 * u * i * phi - phi * phi));
            g = (b - rho * sigma * i * phi + d) / (b - rho * sigma * i * phi - d);
            if (Trap == 1)
            {
                // "Little Heston Trap" formulation
                c = 1.0 / g;
                D = (b - rho * sigma * i * phi - d) / sigma / sigma * ((1.0 - Complex.Exp(-d * T)) / (1.0 - c * Complex.Exp(-d * T)));
                G = (1.0 - c * Complex.Exp(-d * T)) / (1 - c);
                C = (r - q) * i * phi * T + a / sigma / sigma * ((b - rho * sigma * i * phi - d) * T - 2.0 * Complex.Log(G));
            }
            else
            {
                // Original Heston formulation.
                G = (1.0 - g * Complex.Exp(d * T)) / (1.0 - g);
                C = (r - q) * i * phi * T + a / sigma / sigma * ((b - rho * sigma * i * phi + d) * T - 2.0 * Complex.Log(G));
                D = (b - rho * sigma * i * phi + d) / sigma / sigma * ((1.0 - Complex.Exp(d * T)) / (1.0 - g * Complex.Exp(d * T)));
            }

            // The characteristic function.
            f = Complex.Exp(C + D * v0 + i * phi * x);

            // The integrand.
            integrand = Complex.Exp(-i * phi * Complex.Log(K)) * f / i / phi;

            // Return the real part of the integrand.
            return(integrand.Real);
        }
示例#6
0
        // Characteristic function for the double Heston model
        public Complex DoubleHestonCF(Complex phi, DHParam param, OpSet settings)
        {
            Complex i = new Complex(0.0, 1.0);                   // Imaginary unit
            double  S = settings.S;
            double  K = settings.K;
            double  T = settings.T;
            double  r = settings.r;
            double  q = settings.q;
            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;
            double  x0 = Math.Log(S);
            int     Trap = settings.trap;
            Complex d1, d2, G1, G2, B1, B2, X1, X2, A, g1, g2 = new Complex();

            if (Trap == 1)
            {
                // Little Trap formulation of the characteristic function
                d1 = Complex.Sqrt(Complex.Pow(kappa1 - rho1 * sigma1 * i * phi, 2) + sigma1 * sigma1 * phi * (phi + i));
                d2 = Complex.Sqrt(Complex.Pow(kappa2 - rho2 * sigma2 * i * phi, 2) + sigma2 * sigma2 * phi * (phi + i));
                G1 = (kappa1 - rho1 * sigma1 * phi * i - d1) / (kappa1 - rho1 * sigma1 * phi * i + d1);
                G2 = (kappa2 - rho2 * sigma2 * phi * i - d2) / (kappa2 - rho2 * sigma2 * phi * i + d2);
                B1 = (kappa1 - rho1 * sigma1 * phi * i - d1) * (1.0 - Complex.Exp(-d1 * T)) / (sigma1 * sigma1) / (1.0 - G1 * Complex.Exp(-d1 * T));
                B2 = (kappa2 - rho2 * sigma2 * phi * i - d2) * (1.0 - Complex.Exp(-d2 * T)) / (sigma2 * sigma2) / (1.0 - G2 * Complex.Exp(-d2 * T));
                X1 = (1.0 - G1 * Complex.Exp(-d1 * T)) / (1.0 - G1);
                X2 = (1.0 - G2 * Complex.Exp(-d2 * T)) / (1.0 - G2);
                A  = (r - q) * phi * i * T
                     + kappa1 * theta1 / sigma1 / sigma1 * ((kappa1 - rho1 * sigma1 * phi * i - d1) * T - 2.0 * Complex.Log(X1))
                     + kappa2 * theta2 / sigma2 / sigma2 * ((kappa2 - rho2 * sigma2 * phi * i - d2) * T - 2.0 * Complex.Log(X2));
            }
            else
            {
                // Original Heston formulation of the characteristic function
                d1 = Complex.Sqrt(Complex.Pow(kappa1 - rho1 * sigma1 * phi * i, 2) + sigma1 * sigma1 * (phi * i + phi * phi));
                d2 = Complex.Sqrt(Complex.Pow(kappa2 - rho2 * sigma2 * phi * i, 2) + sigma2 * sigma2 * (phi * i + phi * phi));
                g1 = (kappa1 - rho1 * sigma1 * phi * i + d1) / (kappa1 - rho1 * sigma1 * phi * i - d1);
                g2 = (kappa2 - rho2 * sigma2 * phi * i + d2) / (kappa2 - rho2 * sigma2 * phi * i - d2);
                B1 = (kappa1 - rho1 * sigma1 * phi * i + d1) * (1.0 - Complex.Exp(d1 * T)) / (sigma1 * sigma1) / (1.0 - g1 * Complex.Exp(d1 * T));
                B2 = (kappa2 - rho2 * sigma2 * phi * i + d2) * (1.0 - Complex.Exp(d2 * T)) / (sigma2 * sigma2) / (1.0 - g2 * Complex.Exp(d2 * T));
                X1 = (1.0 - g1 * Complex.Exp(d1 * T)) / (1.0 - g1);
                X2 = (1.0 - g2 * Complex.Exp(d2 * T)) / (1.0 - g2);
                A  = (r - q) * phi * i * T
                     + kappa1 * theta1 / sigma1 / sigma1 * ((kappa1 - rho1 * sigma1 * phi * i + d1) * T - 2.0 * Complex.Log(X1))
                     + kappa2 * theta2 / sigma2 / sigma2 * ((kappa2 - rho2 * sigma2 * phi * i + d2) * T - 2.0 * Complex.Log(X2));
            }

            // The characteristic function.
            return(Complex.Exp(A + B1 * v01 + B2 * v02 + i * phi * x0));
        }
        public double DoubleHestonPriceGaussLaguerre(DHParam param, OpSet settings, double[] X, double[] W)
        {
            int     N       = X.Length;
            double  S       = settings.S;
            double  K       = settings.K;
            double  r       = settings.r;
            double  q       = settings.q;
            double  T       = settings.T;
            string  PutCall = settings.PutCall;
            Complex i       = new Complex(0.0, 1.0);
            Complex u       = new Complex(0.0, 0.0);

            Complex[] f2   = new Complex[N];
            Complex[] f1   = new Complex[N];
            double[]  Int1 = new double[N];
            double[]  Int2 = new double[N];
            Complex   I1   = new Complex(0.0, 0.0);
            Complex   I2   = new Complex(0.0, 0.0);

            for (int k = 0; k <= N - 1; k++)
            {
                u       = X[k];
                f2[k]   = HestonDoubleProb(u, param, settings);
                f1[k]   = HestonDoubleProb(u - i, param, settings);
                I2      = Complex.Exp(-i * u * Complex.Log(K)) * f2[k] / i / u;
                I1      = Complex.Exp(-i * u * Complex.Log(K)) * f1[k] / i / u / S / Complex.Exp((r - q) * T);
                Int2[k] = W[k] * I2.Real;
                Int1[k] = W[k] * I1.Real;
            }

            // The ITM probabilities
            double pi = Math.PI;
            double P1 = 0.5 + 1.0 / pi * Int1.Sum();
            double P2 = 0.5 + 1.0 / pi * Int2.Sum();

            // The Double Heston call price
            double HestonC = S * Math.Exp(-q * T) * P1 - K * Math.Exp(-r * T) * P2;

            // The put price by put-call parity
            double HestonP = HestonC - S * Math.Exp(-q * T) + K * Math.Exp(-r * T);

            // Output the option price
            if (PutCall == "C")
            {
                return(HestonC);
            }
            else
            {
                return(HestonP);
            }
        }
示例#8
0
        // Simulation of stock price paths and variance paths using Euler or Milstein schemes
        public double[,] MMSim(HParam param, OpSet settings, int NT, int NS, double[,] Zv, double[,] Zs)
        {
            // Heston parameters
            double kappa  = param.kappa;
            double theta  = param.theta;
            double sigma  = param.sigma;
            double v0     = param.v0;
            double rho    = param.rho;
            double lambda = param.lambda;

            // option settings
            double r = settings.r;
            double q = settings.q;

            // Time increment
            double dt = settings.T / Convert.ToDouble(NT);

            // Initialize the variance and stock processes
            double[,] V = new double[NT, NS];
            double[,] S = new double[NT, NS];

            // Flags for negative variances
            int F = 0;

            // Starting values for the variance and stock processes
            for (int s = 0; s <= NS - 1; s++)
            {
                S[0, s] = settings.S; // Spot price
                V[0, s] = v0;         // Heston v0 initial variance
            }

            // Generate the stock and volatility paths
            for (int s = 0; s <= NS - 1; s++)
            {
                for (int t = 1; t <= NT - 1; t++)
                {
                    // Matched moment lognormal approximation
                    double dW  = Math.Sqrt(dt) * Zv[t, s];
                    double num = 0.5 * sigma * sigma * V[t - 1, s] * (1.0 - Math.Exp(-2.0 * kappa * dt)) / kappa;
                    double den = Math.Pow(Math.Exp(-kappa * dt) * V[t - 1, s] + (1.0 - Math.Exp(-kappa * dt)) * theta, 2);
                    double Gam = Math.Log(1 + num / den);
                    V[t, s] = (Math.Exp(-kappa * dt) * V[t - 1, s] + (1.0 - Math.Exp(-kappa * dt)) * theta) * Math.Exp(-0.5 * Gam * Gam + Gam * Zv[t, s]);

                    // Euler/Milstein discretization scheme for the log stock prices
                    S[t, s] = S[t - 1, s] * Math.Exp((r - q - V[t - 1, s] / 2) * dt + Math.Sqrt(V[t - 1, s] * dt) * Zs[t, s]);
                }
            }
            return(S);
        }
        // Heston Price by Gauss-Laguerre Integration
        public double HestonPriceGaussLaguerre(HParam param, OpSet settings, double[] x, double[] w)
        {
            Complex i = new Complex(0.0, 1.0);

            Complex[] f1   = new Complex[32];
            Complex[] f2   = new Complex[32];
            double[]  int1 = new double[32];
            double[]  int2 = new double[32];

            double S = settings.S;
            double K = settings.K;
            double T = settings.T;
            double r = settings.r;
            double q = settings.q;

            // Numerical integration
            for (int j = 0; j <= 31; j++)
            {
                double phi = x[j];
                f1[j] = HestonCF(phi - i, param, settings) / (S * Math.Exp((r - q) * T));
                f2[j] = HestonCF(phi, param, settings);
                Complex FF1 = Complex.Exp(-i * phi * Complex.Log(K)) * f1[j] / i / phi;
                Complex FF2 = Complex.Exp(-i * phi * Complex.Log(K)) * f2[j] / i / phi;
                int1[j] = w[j] * FF1.Real;
                int2[j] = w[j] * FF2.Real;
            }

            // Define P1 and P2
            double pi = Math.PI;
            double P1 = 0.5 + 1.0 / pi * int1.Sum();
            double P2 = 0.5 + 1.0 / pi * int2.Sum();

            // The call price
            string PutCall = settings.PutCall;
            double HestonC = S * Math.Exp(-q * T) * P1 - K * Math.Exp(-r * T) * P2;

            // The put price by put-call parity
            double HestonP = HestonC - S * Math.Exp(-q * T) + K * Math.Exp(-r * T);

            // Output the option price
            if (PutCall == "C")
            {
                return(HestonC);
            }
            else
            {
                return(HestonP);
            }
        }
示例#10
0
        public Complex HestonBivariateCF(Complex phi1, Complex phi2, HParam param, OpSet settings)
        {
            Complex i = new Complex(0.0, 1.0);                  // Imaginary unit
            Complex S = new Complex(settings.S, 0.0);           // Spot Price
            Complex K = new Complex(settings.K, 0.0);           // Strike Price
            Complex T = new Complex(settings.T, 0.0);           // Maturity in years
            Complex r = new Complex(settings.r, 0.0);           // Interest rate
            Complex q = new Complex(settings.q, 0.0);           // Dividend yield
            Complex rho = new Complex(param.rho, 0.0);          // Heston parameter: correlation
            Complex kappa = new Complex(param.kappa, 0.0);      // Heston parameter: mean reversion speed
            Complex theta = new Complex(param.theta, 0.0);      // Heston parameter: mean reversion speed
            Complex lambda = new Complex(param.lambda, 0.0);    // Heston parameter: price of volatility risk
            Complex sigma = new Complex(param.sigma, 0.0);      // Heston parameter: volatility of variance
            Complex v0 = new Complex(param.v0, 0.0);            // Heston parameter: initial variance
            Complex x = Complex.Log(S);
            Complex a = kappa * theta;
            int     trap = settings.trap;
            Complex b, u, d, g, c, A = 0.0, C = 0.0, B, G = new Complex();

            // Log stock price
            Complex x0 = Complex.Log(S);

            u = -0.5;
            b = kappa + lambda;

            d = Complex.Sqrt(Complex.Pow(rho * sigma * i * phi1 - b, 2) - sigma * sigma * (2.0 * u * i * phi1 - phi1 * phi1));
            g = (b - rho * sigma * i * phi1 + d - sigma * sigma * i * phi2)
                / (b - rho * sigma * i * phi1 - d - sigma * sigma * i * phi2);
            c = 1 / g;
            B = i * phi1;

            if (trap == 1)
            {
                // Little Trap formulation in Kahl (2008)
                G = (c * Complex.Exp(-d * T) - 1.0) / (c - 1.0);
                A = (r - q) * i * phi1 * T + a / sigma / sigma * ((b - rho * sigma * i * phi1 - d) * T - 2.0 * Complex.Log(G));
                C = ((b - rho * sigma * i * phi1 - d) - (b - rho * sigma * i * phi1 + d) * c * Complex.Exp(-d * T)) / (sigma * sigma) / (1 - c * Complex.Exp(-d * T));
            }
            else if (trap == 0)
            {
                // Original Heston formulation.
                G = (1.0 - g * Complex.Exp(d * T)) / (1.0 - g);
                A = (r - q) * i * phi1 * T + a / sigma / sigma * ((b - rho * sigma * i * phi1 + d) * T - 2.0 * Complex.Log(G));
                C = ((b - rho * sigma * i * phi1 + d) - (b - rho * sigma * i * phi1 - d) * g * Complex.Exp(d * T)) / (sigma * sigma) / (1.0 - g * Complex.Exp(d * T));
            }

            // The characteristic function.
            return(Complex.Exp(A + B * x0 + C * v0));
        }
        static void Main(string[] args)
        {
            // 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]);
                }
            }
            // Heston parameters
            HParam param = new HParam();

            param.kappa  = 1.5;
            param.theta  = 0.04;
            param.sigma  = 0.3;
            param.v0     = 0.05412;
            param.rho    = -0.9;
            param.lambda = 0.0;

            // Option settings
            OpSet settings = new OpSet();

            settings.S       = 101.52;
            settings.K       = 100.0;
            settings.T       = 0.15;
            settings.r       = 0.02;
            settings.q       = 0.0;
            settings.PutCall = "C";
            settings.trap    = 1;

            // The Heston price
            HestonPrice HP    = new HestonPrice();
            double      Price = HP.HestonPriceGaussLaguerre(param, settings, x, w);

            Console.WriteLine("Heston price using 32-point Gauss Laguerre");
            Console.WriteLine("------------------------------------------ ");
            Console.WriteLine("Option Flavor =  {0,0:F5}", settings.PutCall);
            Console.WriteLine("Strike Price  =  {0,0:0}", settings.K);
            Console.WriteLine("Maturity      =  {0,0:F2}", settings.T);
            Console.WriteLine("Price         =  {0,0:F4}", Price);
            Console.WriteLine("------------------------------------------ ");
            Console.WriteLine(" ");
        }
示例#12
0
        static void Main(string[] args)
        {
            // 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]);
                }
            }
            HParam param = new HParam();

            param.rho    = -0.9;                            // Heston Parameter: Correlation
            param.kappa  = 2;                               // Heston Parameter: Mean reversion speed
            param.theta  = 0.05;                            // Heston Parameter: Mean reversion level
            param.lambda = 0.0;                             // Heston Parameter: Risk parameter
            param.sigma  = 0.3;                             // Heston Parameter: Volatility of Variance
            param.v0     = 0.035;                           // Heston Parameter: Current Variance

            OpSet settings = new OpSet();

            settings.S       = 100.0;           // Spot Price
            settings.K       = 100.0;           // Strike Price
            settings.T       = 0.25;            // Maturity in Years
            settings.r       = 0.05;            // Interest Rate
            settings.q       = 0.02;            // Dividend yield
            settings.PutCall = "P";             // "P"ut or "C"all
            settings.trap    = 1;               // 1="Little Trap" characteristic function

            // The Heston price
            HestonPriceConsolidated HPC = new HestonPriceConsolidated();
            double Price = HPC.HestonPriceConsol(param, settings, x, w);

            Console.WriteLine("Heston price using consolidated integral");
            Console.WriteLine("------------------------------------------------ ");
            Console.WriteLine("Option Flavor =  {0,0:F5}", settings.PutCall);
            Console.WriteLine("Strike Price  =  {0,0:0}", settings.S);
            Console.WriteLine("Maturity      =  {0,0:F2}", settings.T);
            Console.WriteLine("Price         =  {0,0:F4}", Price);
            Console.WriteLine("------------------------------------------------ ");
            Console.WriteLine(" ");
        }
        // Bisection Algorithm for Black Scholes Implied Volatility =================================================================================
        public double BisecBSIV(OpSet settings, double K, double T, double a, double b, double MktPrice, double Tol, int MaxIter)
        {
            BlackScholesPrice BS      = new BlackScholesPrice();
            double            S       = settings.S;
            double            rf      = settings.r;
            double            q       = settings.q;
            string            PutCall = settings.PutCall;

            double lowCdif  = MktPrice - BS.BlackScholes(S, K, T, rf, q, a, PutCall);
            double highCdif = MktPrice - BS.BlackScholes(S, K, T, rf, q, b, PutCall);
            double BSIV     = 0.0;
            double midP;

            if (lowCdif * highCdif > 0.0)
            {
                BSIV = -1.0;
            }
            else
            {
                for (int x = 0; x <= MaxIter; x++)
                {
                    midP = (a + b) / 2.0;
                    double midCdif = MktPrice - BS.BlackScholes(S, K, T, rf, q, midP, PutCall);
                    if (Math.Abs(midCdif) < Tol)
                    {
                        break;
                    }
                    else
                    {
                        if (midCdif > 0.0)
                        {
                            a = midP;
                        }
                        else
                        {
                            b = midP;
                        }
                    }
                    BSIV = midP;
                }
            }
            return(BSIV);
        }
示例#14
0
        // Price by simulation
        public double MMPrice(HParam param, OpSet settings, int NT, int NS)
        {
            RandomNumbers RN = new RandomNumbers();

            double[] STe   = MMSim(param, settings, NT, NS);
            double[] Price = new double[NS];
            for (int s = 0; s <= NS - 1; s++)
            {
                if (settings.PutCall == "C")
                {
                    Price[s] = Math.Max(STe[s] - settings.K, 0.0);
                }
                else if (settings.PutCall == "P")
                {
                    Price[s] = Math.Max(settings.K - STe[s], 0.0);
                }
            }
            return(Math.Exp(-settings.r * settings.T) * RN.Mean(Price));
        }
示例#15
0
        // Price by simulation
        public double EulerMilsteinPrice(string scheme, string negvar, HParam param, OpSet settings, double alpha, int NT, int NS, string PutCall)
        {
            RandomNumbers RA = new RandomNumbers();

            double[] STe   = EulerMilsteinSim(scheme, negvar, param, settings, alpha, NT, NS);
            double[] Price = new double[NS];
            for (int s = 0; s <= NS - 1; s++)
            {
                if (settings.PutCall == "C")
                {
                    Price[s] = Math.Max(STe[s] - settings.K, 0.0);
                }
                else if (settings.PutCall == "P")
                {
                    Price[s] = Math.Max(settings.K - STe[s], 0.0);
                }
            }
            return(Math.Exp(-settings.r * settings.T) * RA.Mean(Price));
        }
示例#16
0
        // Price by simulation
        public double QEPrice(HParam param, OpSet settings, double gamma1, double gamma2, int NT, int NS, int MC, double phic, string PutCall)
        {
            RandomNumbers RN = new RandomNumbers();

            double[] STe   = QESim(param, settings, gamma1, gamma2, NT, NS, MC, phic);
            double[] Price = new double[NS];
            for (int s = 0; s <= NS - 1; s++)
            {
                if (settings.PutCall == "C")
                {
                    Price[s] = Math.Max(STe[s] - settings.K, 0.0);
                }
                else if (settings.PutCall == "P")
                {
                    Price[s] = Math.Max(settings.K - STe[s], 0.0);
                }
            }
            return(Math.Exp(-settings.r * settings.T) * RN.Mean(Price));
        }
示例#17
0
        // Heston Univariate characteristic function (f2)
        public Complex HestonCF(Complex phi, HParam param, OpSet settings)
        {
            Complex i = new Complex(0.0, 1.0);                 // Imaginary unit
            Complex S = new Complex(settings.S, 0.0);          // Spot Price
            Complex K = new Complex(settings.K, 0.0);          // Strike Price
            Complex T = new Complex(settings.T, 0.0);          // Maturity in years
            Complex r = new Complex(settings.r, 0.0);          // Interest rate
            Complex q = new Complex(settings.q, 0.0);          // Dividend yield
            Complex rho = new Complex(param.rho, 0.0);         // Heston parameter: correlation
            Complex kappa = new Complex(param.kappa, 0.0);     // Heston parameter: mean reversion speed
            Complex theta = new Complex(param.theta, 0.0);     // Heston parameter: mean reversion speed
            Complex lambda = new Complex(param.lambda, 0.0);   // Heston parameter: price of volatility risk
            Complex sigma = new Complex(param.sigma, 0.0);     // Heston parameter: volatility of variance
            Complex v0 = new Complex(param.v0, 0.0);           // Heston parameter: initial variance
            Complex x = Complex.Log(S);
            Complex a = kappa * theta;
            int     Trap = settings.trap;
            Complex b, u, d, g, c, D, G, C = new Complex();

            u = -0.5;
            b = kappa + lambda;
            d = Complex.Sqrt(Complex.Pow(rho * sigma * i * phi - b, 2) - sigma * sigma * (2.0 * u * i * phi - phi * phi));
            g = (b - rho * sigma * i * phi + d) / (b - rho * sigma * i * phi - d);
            if (Trap == 1)
            {
                // "Little Heston Trap" formulation
                c = 1.0 / g;
                D = (b - rho * sigma * i * phi - d) / sigma / sigma * ((1.0 - Complex.Exp(-d * T)) / (1.0 - c * Complex.Exp(-d * T)));
                G = (1.0 - c * Complex.Exp(-d * T)) / (1 - c);
                C = (r - q) * i * phi * T + a / sigma / sigma * ((b - rho * sigma * i * phi - d) * T - 2.0 * Complex.Log(G));
            }
            else
            {
                // Original Heston formulation.
                G = (1.0 - g * Complex.Exp(d * T)) / (1.0 - g);
                C = (r - q) * i * phi * T + a / sigma / sigma * ((b - rho * sigma * i * phi + d) * T - 2.0 * Complex.Log(G));
                D = (b - rho * sigma * i * phi + d) / sigma / sigma * ((1.0 - Complex.Exp(d * T)) / (1.0 - g * Complex.Exp(d * T)));
            }

            // The characteristic function.
            return(Complex.Exp(C + D * v0 + i * phi * x));
        }
        // Heston characteristic function (f2)
        public Complex HestonCF(Complex phi, HParam param, OpSet settings)
        {
            Complex i = new Complex(0.0, 1.0);                   // Imaginary unit
            double  S = settings.S;
            double  K = settings.K;
            double  T = settings.T;
            double  r = settings.r;
            double  q = settings.q;
            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  x = Math.Log(S);
            double  a = kappa * theta;
            int     Trap = settings.trap;
            Complex b, u, d, g, c, D, G, C = new Complex();

            u = -0.5;
            b = kappa + lambda;
            d = Complex.Sqrt(Complex.Pow(rho * sigma * i * phi - b, 2) - sigma * sigma * (2.0 * u * i * phi - phi * phi));
            g = (b - rho * sigma * i * phi + d) / (b - rho * sigma * i * phi - d);
            if (Trap == 1)
            {
                // "Little Heston Trap" formulation
                c = 1.0 / g;
                D = (b - rho * sigma * i * phi - d) / sigma / sigma * ((1.0 - Complex.Exp(-d * T)) / (1.0 - c * Complex.Exp(-d * T)));
                G = (1.0 - c * Complex.Exp(-d * T)) / (1 - c);
                C = (r - q) * i * phi * T + a / sigma / sigma * ((b - rho * sigma * i * phi - d) * T - 2.0 * Complex.Log(G));
            }
            else
            {
                // Original Heston formulation.
                G = (1.0 - g * Complex.Exp(d * T)) / (1.0 - g);
                C = (r - q) * i * phi * T + a / sigma / sigma * ((b - rho * sigma * i * phi + d) * T - 2.0 * Complex.Log(G));
                D = (b - rho * sigma * i * phi + d) / sigma / sigma * ((1.0 - Complex.Exp(d * T)) / (1.0 - g * Complex.Exp(d * T)));
            }

            // The characteristic function.
            return(Complex.Exp(C + D * v0 + i * phi * x));
        }
示例#19
0
        // Heston Price by Gauss-Legendre Integration
        public double HestonPriceGaussLegendre(HParam param, OpSet settings, double[] x, double[] w, double a, double b)
        {
            double[] int1 = new Double[32];
            double[] int2 = new Double[32];
            // Numerical integration
            for (int j = 0; j <= 31; j++)
            {
                double X = (a + b) / 2.0 + (b - a) / 2.0 * x[j];
                int1[j] = w[j] * HestonProb(X, param, settings, 1);
                int2[j] = w[j] * HestonProb(X, param, settings, 2);
            }

            // Define P1 and P2
            double pi = Math.PI;
            double P1 = 0.5 + 1.0 / pi * int1.Sum() * (b - a) / 2.0;
            double P2 = 0.5 + 1.0 / pi * int2.Sum() * (b - a) / 2.0;

            // The call price
            double S       = settings.S;
            double K       = settings.K;
            double T       = settings.T;
            double r       = settings.r;
            double q       = settings.q;
            string PutCall = settings.PutCall;
            double HestonC = S * Math.Exp(-q * T) * P1 - K * Math.Exp(-r * T) * P2;

            // The put price by put-call parity
            double HestonP = HestonC - S * Math.Exp(-q * T) + K * Math.Exp(-r * T);

            // Output the option price
            if (PutCall == "C")
            {
                return(HestonC);
            }
            else
            {
                return(HestonP);
            }
        }
示例#20
0
        public double CarrMadanGreeks(double alpha, double tau, HParam param, OpSet Opsettings, string Greek, double[] x, double[] w)
        {
            Complex i = new Complex(0.0, 1.0);       // Imaginary unit
            double  q = 0.0;
            int     N = x.Length;

            // Perform the numerical integration
            Complex J = 0.0;

            double[] I = new double[N];

            for (int j = 0; j <= N - 1; j++)
            {
                double u = x[j];
                J = w[j] * Complex.Exp(-i * u * Math.Log(Opsettings.K)) * Math.Exp(-Opsettings.r * Opsettings.T)
                    * HestonCFGreek(u - (alpha + 1) * i, param, Opsettings, Greek)
                    / (alpha * alpha + alpha - u * u + i * (2.0 * alpha + 1.0) * u);
                I[j] = J.Real;
            }

            // Calculate the desired Greek
            double pi = Math.PI;

            if ((Greek == "Delta") || (Greek == "Gamma") || (Greek == "Rho") ||
                (Greek == "Theta") || (Greek == "Volga") || (Greek == "Price"))
            {
                return(Math.Exp(-alpha * Math.Log(Opsettings.K)) * I.Sum() / pi);
            }
            else if ((Greek == "Vega1") || (Greek == "Vanna"))
            {
                return(Math.Exp(-alpha * Math.Log(Opsettings.K)) * I.Sum() / pi * 2.0 * Math.Sqrt(param.v0));
            }
            else
            {
                return(0.0);
            }
        }
示例#21
0
        // Call price by Fractional Fast Fourier Transform =====================================================================
        public double[,] HestonFRFTGreek(int N, double uplimit, double alpha, string rule, double lambdainc, double eta, HParam param, OpSet settings, string Greek)
        {
            HestonGreeks HG = new HestonGreeks();

            double s0 = Math.Log(settings.S);
            double pi = Math.PI;

            // Initialize and specify the weights
            double[] w = new double[N];
            if (rule == "Trapezoidal")
            {
                w[0]     = 0.5;
                w[N - 1] = 0.5;
                for (int j = 1; j <= N - 2; j++)
                {
                    w[j] = 1;
                }
            }
            else if (rule == "Simpsons")
            {
                w[0]     = 1.0 / 3.0;
                w[N - 1] = 1.0 / 3.0;
                for (int j = 1; j <= N - 1; j++)
                {
                    w[j] = (1.0 / 3.0) * (3 + Math.Pow(-1, j + 1));
                }
            }

            // Specify the b parameter
            double b = Convert.ToDouble(N) * lambdainc / 2.0;

            // Create the grid for the integration
            double[] v = new double[N];
            for (int j = 0; j <= N - 1; j++)
            {
                v[j] = eta * j;
            }

            // Create the grid for the log-strikes and strikes
            double[] k = new double[N];
            double[] K = new double[N];
            for (int j = 0; j <= N - 1; j++)
            {
                k[j] = -b + lambdainc * Convert.ToDouble(j) + s0;
                K[j] = Math.Exp(k[j]);
            }

            // Beta parameter for the FRFT
            double beta = lambdainc * eta / 2.0 / pi;

            // Option price settings
            double tau = settings.T;
            double r   = settings.r;
            double q   = settings.q;

            // Implement the FFT
            Complex i = new Complex(0.0, 1.0);

            Complex[] psi      = new Complex[N];
            Complex[] phi      = new Complex[N];
            Complex[] x        = new Complex[N];
            Complex[] y        = new Complex[N];
            double[]  CallFRFT = new double[N];
            double[]  sume     = new double[N];

            // Build the input vectors for the FRFT
            for (int j = 0; j <= N - 1; j++)
            {
                psi[j] = HG.HestonCFGreek(v[j] - (alpha + 1.0) * i, param, settings, Greek);
                phi[j] = Complex.Exp(-r * tau) * psi[j] / (alpha * alpha + alpha - v[j] * v[j] + i * v[j] * (2.0 * alpha + 1.0));
                x[j]   = Complex.Exp(i * (b - s0) * v[j]) * phi[j] * w[j];
            }
            y = FRFT(x, beta);
            Complex Call = new Complex(0.0, 0.0);

            for (int u = 0; u <= N - 1; u++)
            {
                Call        = eta * Complex.Exp(-alpha * k[u]) * y[u] / pi;
                CallFRFT[u] = Call.Real;
            }

            // Return the FRFT call price and the strikes
            double[,] output = new double[N, 2];
            for (int j = 0; j <= N - 1; j++)
            {
                output[j, 0] = K[j];
                output[j, 1] = CallFRFT[j];
            }
            return(output);
        }
示例#22
0
        private void GenerateLewisTable_MouseClick(object sender, MouseEventArgs e)
        {
            double S       = 100.0;             // Spot Price
            double T       = 0.25;              // Maturity in Years
            double rf      = 0.0;               // Interest Rate
            double q       = 0.0;               // Dividend yield
            string PutCall = "C";               // "P"ut or "Call"
            int    trap    = 1;                 // 1="Little Trap" characteristic function

            OpSet opset = new OpSet();

            opset.S       = S;
            opset.T       = T;
            opset.r       = rf;
            opset.q       = q;
            opset.PutCall = PutCall;
            opset.trap    = trap;

            double kappa  = 4.0;                        // Heston Parameter
            double theta  = 0.09 / 4.0;                 // Heston Parameter
            double sigma  = 0.1;                        // Heston Parameter: Volatility of Variance
            double v0     = 0.0225;                     // Heston Parameter: Current Variance
            double rho    = -0.5;                       // Heston Parameter: Correlation
            double lambda = 0.0;                        // Heston Parameter

            HParam param = new HParam();

            param.kappa  = kappa;
            param.theta  = theta;
            param.sigma  = sigma;
            param.v0     = v0;
            param.rho    = rho;
            param.lambda = lambda;

            int NK = 7;

            double[] K = new double[7]          // Strikes
            {
                70.0, 80.0, 90.0, 100.0, 110.0, 120.0, 130.0
            };

            // Time average of the deterministic variance and volatility
            double vol = param.theta + (param.v0 - param.theta) * (1.0 - Math.Exp(-param.kappa * T)) / (param.kappa * T);
            double IV  = Math.Sqrt(vol);

            // Classes
            BlackScholes  BS = new BlackScholes();
            NewtonCotes   NC = new NewtonCotes();
            Lewis         L  = new Lewis();
            BisectionAlgo BA = new BisectionAlgo();

            // Table 3.3.1 on Page 81 of Lewis (2001)
            double[] SeriesIPrice  = new double[NK];        // Series I price and implied vol
            double[] IVI           = new double[NK];
            double[] SeriesIIPrice = new double[NK];        // Series II price and implied vol
            double[] IVII          = new double[NK];
            double[] HPrice        = new double[NK];        // Exact Heston price and implied vol
            double[] IVe           = new double[NK];
            double[] BSPrice       = new double[NK];        // Black Scholes price

            // Bisection algorithm settings
            double lo      = 0.01;
            double hi      = 2.0;
            double Tol     = 1.0e-10;
            int    MaxIter = 10000;

            // Newton Cotes settings
            int    method = 3;
            double a      = 1.0e-10;
            double b      = 100.0;
            int    N      = 10000;

            double[] SeriesII = new double[2];
            for (int k = 0; k <= NK - 1; k++)
            {
                // Generate the prices and implied vols
                opset.K          = K[k];
                SeriesIPrice[k]  = L.SeriesICall(S, K[k], rf, q, T, v0, rho, theta, kappa, sigma);
                IVI[k]           = BA.BisecBSIV(PutCall, S, K[k], rf, q, T, lo, hi, SeriesIPrice[k], Tol, MaxIter);
                SeriesII         = L.SeriesIICall(S, K[k], rf, q, T, v0, rho, theta, kappa, sigma);
                SeriesIIPrice[k] = SeriesII[0];
                IVII[k]          = SeriesII[1];
                HPrice[k]        = NC.HestonPriceNewtonCotes(param, opset, method, a, b, N);
                IVe[k]           = BA.BisecBSIV(PutCall, S, K[k], rf, q, T, lo, hi, HPrice[k], Tol, MaxIter);
                BSPrice[k]       = BS.BSC(S, K[k], rf, q, vol, T);

                // Write to the List Boxes
                Strike.Items.Add(K[k]);
                ExactPrice.Items.Add(Math.Round(HPrice[k], 6));
                IVExact.Items.Add(Math.Round(100 * IVe[k], 2));
                SeriesICall.Items.Add(Math.Round(SeriesIPrice[k], 6));
                IV1.Items.Add(Math.Round(100 * IVI[k], 2));
                SeriesIICall.Items.Add(Math.Round(SeriesIIPrice[k], 6));
                IV2.Items.Add(Math.Round(100 * IVII[k], 2));
                BlackScholesPrice.Items.Add(Math.Round(BSPrice[k], 6));
                IVBS.Items.Add(Math.Round(100 * IV, 2));
            }
        }
示例#23
0
        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  = 2.0;
            param.theta  = 0.05;
            param.sigma  = 0.3;
            param.v0     = 0.035;
            param.rho    = -0.9;
            param.lambda = 0.0;

            // Option price settings
            OpSet settings = new OpSet();

            settings.S    = 100.0;
            settings.T    = 0.25;
            settings.r    = 0.05;
            settings.q    = 0.02;
            settings.trap = 1;

            // Lower and upper integration limits
            double a = 0.0;         // Lower Limit for Gauss Legendre and Newton Coates
            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

            int N = 5000;           // Number of points for Newton Coates quadratures

            // Range of strikes and option flavor
            double[] Strikes = new double[] { 90.0, 95.0, 100.0, 105.0, 110.0 };
            settings.PutCall = "C";

            // Initialize the price vectors
            int M = Strikes.Length;

            double[] PriceGLa    = new double[M];
            double[] PriceGLe    = new double[M];
            double[] PriceGLo    = new double[M];
            double[] PriceMP     = new double[M];
            double[] PriceTrapz  = new double[M];
            double[] PriceSimp   = new double[M];
            double[] PriceSimp38 = new double[M];

            // Obtain the prices and output to console
            HestonPrice HP = new HestonPrice();
            NewtonCotes NC = new NewtonCotes();

            Console.WriteLine("Using {0:0} points for Newton Cotes and 32 points for quadrature ", N);
            Console.WriteLine(" ");
            for (int k = 0; k <= M - 1; k++)
            {
                settings.K     = Strikes[k];
                PriceGLa[k]    = HP.HestonPriceGaussLaguerre(param, settings, xGLa, wGLa);       // Gauss Laguerre
                PriceGLe[k]    = HP.HestonPriceGaussLegendre(param, settings, xGLe, wGLe, a, b); // Gauss Legendre
                PriceGLo[k]    = HP.HestonPriceGaussLegendre(param, settings, xGLo, wGLo, A, B); // Gauss Lobatto
                PriceMP[k]     = NC.HestonPriceNewtonCotes(param, settings, 1, a, b, N);         // Mid point rule
                PriceTrapz[k]  = NC.HestonPriceNewtonCotes(param, settings, 2, A, B, N);         // Trapezoidal rule
                PriceSimp[k]   = NC.HestonPriceNewtonCotes(param, settings, 3, A, B, N);         // Simpson's Rule
                PriceSimp38[k] = NC.HestonPriceNewtonCotes(param, settings, 4, A, B, N);         // Simpson's 3/8 rule
                Console.Write("Strike {0,2}", Strikes[k]);
                Console.WriteLine(" ------------------");
                Console.WriteLine("Mid Point       {0:F5}", PriceMP[k]);
                Console.WriteLine("Trapezoidal     {0:F5}", PriceTrapz[k]);
                Console.WriteLine("Simpson's       {0:F5}", PriceSimp[k]);
                Console.WriteLine("Simpson's 3/8   {0:F5}", PriceSimp38[k]);
                Console.WriteLine("Gauss Laguerre  {0:F5}", PriceGLa[k]);
                Console.WriteLine("Gauss Legendre  {0:F5}", PriceGLe[k]);
                Console.WriteLine("Gauss Lobatto   {0:F5}", PriceGLo[k]);
                Console.WriteLine(" ");
            }
        }
示例#24
0
        // Objective function ===========================================================================
        public double DHObjFunSVC(double[] param, OpSet settings, MktData data, double[] X, double[] W, int objectivefun, double[] lb, double[] ub)
        {
            HestonPriceDH HPDH = new HestonPriceDH();
            BisectionAlgo BA   = new BisectionAlgo();

            double S    = settings.S;
            double r    = settings.r;
            double q    = settings.q;
            int    trap = settings.trap;

            double[,] MktIV    = data.MktIV;
            double[,] MktPrice = data.MktPrice;
            string[,] PutCall  = data.PutCall;
            double[] K = data.K;
            double[] T = data.T;

            int NK = PutCall.GetLength(0);
            int NT = PutCall.GetLength(1);
            int NX = X.Length;

            DHParam param2 = new DHParam();

            param2.kappa1 = param[0];
            param2.theta1 = param[1];
            param2.sigma1 = param[2];
            param2.v01    = param[3];
            param2.rho1   = param[4];
            param2.kappa2 = param[5];
            param2.theta2 = param[6];
            param2.sigma2 = param[7];
            param2.v02    = param[8];
            param2.rho2   = param[9];

            // Settings for the Bisection algorithm
            double a           = 0.001;
            double b           = 3.0;
            double Tol         = 1e5;
            int    BSIVMaxIter = 10000;

            // Initialize the model price and model implied vol vectors, and the objective function value
            double[,] ModelPrice = new double[NK, NT];
            double[,] ModelIV    = new double[NK, NT];
            double BSVega = 0.0;
            double Error  = 0.0;
            double pi     = Math.PI;

            double  kappaLB = lb[0]; double kappaUB = ub[0];
            double  thetaLB = lb[1]; double thetaUB = ub[1];
            double  sigmaLB = lb[2]; double sigmaUB = ub[2];
            double  v0LB = lb[3]; double v0UB = ub[3];
            double  rhoLB = lb[4]; double rhoUB = ub[4];
            double  phi, P1, P2, CallPrice;
            Complex Integrand1, Integrand2;
            Complex i = Complex.ImaginaryOne;

            Complex[] f2   = new Complex[NX];
            Complex[] f1   = new Complex[NX];
            double[]  int1 = new double[NX];
            double[]  int2 = new double[NX];

            if ((param2.kappa1 <= kappaLB) || (param2.theta1 <= thetaLB) || (param2.sigma1 <= sigmaLB) || (param2.v01 <= v0LB) || (param2.rho1 <= rhoLB) ||
                (param2.kappa1 >= kappaUB) || (param2.theta1 >= thetaUB) || (param2.sigma1 >= sigmaUB) || (param2.v01 >= v0UB) || (param2.rho1 >= rhoUB) ||
                (param2.kappa2 <= kappaLB) || (param2.theta2 <= thetaLB) || (param2.sigma2 <= sigmaLB) || (param2.v02 <= v0LB) || (param2.rho2 <= rhoLB) ||
                (param2.kappa2 >= kappaUB) || (param2.theta2 >= thetaUB) || (param2.sigma2 >= sigmaUB) || (param2.v02 >= v0UB) || (param2.rho2 >= rhoUB))
            {
                Error = 1e50;
            }
            else
            {
                for (int t = 0; t < NT; t++)
                {
                    for (int j = 0; j < NX; j++)
                    {
                        settings.T = T[t];
                        phi        = X[j];
                        f2[j]      = HPDH.HestonDoubleCF(phi, param2, settings);
                        f1[j]      = HPDH.HestonDoubleCF(phi - i, param2, settings);
                    }
                    for (int k = 0; k < NK; k++)
                    {
                        for (int j = 0; j < NX; j++)
                        {
                            phi        = X[j];
                            Integrand2 = Complex.Exp(-i * phi * Complex.Log(K[k])) * f2[j] / i / phi;
                            int2[j]    = W[j] * Integrand2.Real;
                            Integrand1 = Complex.Exp(-i * phi * Complex.Log(K[k])) * f1[j] / i / phi / S / Complex.Exp((r - q) * T[t]);
                            int1[j]    = W[j] * Integrand1.Real;
                        }
                        P1 = 0.5 + 1.0 / pi * int1.Sum();
                        P2 = 0.5 + 1.0 / pi * int2.Sum();

                        // The call price
                        CallPrice = S * Math.Exp(-q * T[t]) * P1 - K[k] * Math.Exp(-r * T[t]) * P2;
                        if (PutCall[k, t] == "C")
                        {
                            ModelPrice[k, t] = CallPrice;
                        }
                        else
                        {
                            ModelPrice[k, t] = CallPrice - S * Math.Exp(-q * T[t]) + Math.Exp(-r * T[t]) * K[k];
                        }

                        switch (objectivefun)
                        {
                        case 1:
                            // MSE Loss Function
                            Error += Math.Pow(ModelPrice[k, t] - MktPrice[k, t], 2.0);
                            break;

                        case 2:
                            // RMSE Loss Function
                            Error += Math.Pow(ModelPrice[k, t] - MktPrice[k, t], 2.0) / MktPrice[k, t];
                            break;

                        case 3:
                            // IVMSE Loss Function
                            ModelIV[k, t] = BA.BisecBSIV(PutCall[k, t], S, K[k], r, q, T[t], a, b, ModelPrice[k, t], Tol, BSIVMaxIter);
                            Error        += Math.Pow(ModelIV[k, t] - MktIV[k, t], 2);
                            break;

                        case 4:
                            // IVRMSE Christoffersen, Heston, Jacobs proxy
                            double d       = (Math.Log(S / K[k]) + (r - q + MktIV[k, t] * MktIV[k, t] / 2.0) * T[t]) / MktIV[k, t] / Math.Sqrt(T[t]);
                            double NormPDF = Math.Exp(-0.5 * d * d) / Math.Sqrt(2.0 * pi);
                            BSVega = S * NormPDF * Math.Sqrt(T[t]);
                            Error += Math.Pow(ModelPrice[k, t] - MktPrice[k, t], 2.0) / (BSVega * BSVega);
                            break;
                        }
                    }
                }
            }
            return(Error);
        }
        static void Main(string[] args)
        {
            Stopwatch sw = new Stopwatch();
            TimeSpan  ts = sw.Elapsed;

            // 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]);
                }

            // Clarke and Parrott settings
            double[] TruePrice = new double[5] {
                2.0, 1.1070641, 0.520030, 0.213668, 0.082036
            };
            double[] Spot = new double[5] {
                8.0, 9.0, 10.0, 11.0, 12.0
            };

            HParam param = new HParam();

            param.kappa  = 5.0;
            param.theta  = 0.16;
            param.sigma  = 0.9;
            param.v0     = 0.0625;
            param.rho    = 0.1;
            param.lambda = 0.0;

            OpSet settings = new OpSet();

            settings.K       = 10.0;
            settings.T       = 0.25;
            settings.r       = 0.1;
            settings.q       = 0.0;
            settings.PutCall = "P";
            settings.trap    = 1;

            // Simulation settings
            int NT = 100;
            int NS = 5000;

            // Generate the correlated random variables
            RandomNumber RN = new RandomNumber();

            double[,] Zv = new double[NT, NS];
            double[,] Zs = new double[NT, NS];
            double rho = param.rho;

            sw.Reset();
            sw.Start();
            for (int t = 0; t <= NT - 1; t++)
            {
                for (int s = 0; s <= NS - 1; s++)
                {
                    Zv[t, s] = RN.RandomNorm();
                    Zs[t, s] = rho * Zv[t, s] + Math.Sqrt(1 - rho * rho) * RN.RandomNorm();
                }
            }

            // Generate LSM prices using the correlated random variables generated above
            int M = Spot.Length;

            double[] ClosedEuro = new double[M];
            double[] LSMEuro = new double[M];
            double[] LSMAmer = new double[M];
            double[] CVAmer = new double[M];
            double[] ErrorLSM = new double[M];
            double[] ErrorCV = new double[M];
            double[] ErrorE = new double[M];
            double   TotalLSM = 0.0, TotalCV = 0.0, TotalE = 0.0;

            double[] LSMPrice = new double[2];

            // Obtain the prices
            LSMonteCarlo LS = new LSMonteCarlo();
            HestonPrice  HP = new HestonPrice();
            Regression   RE = new Regression();
            MMSimulation MM = new MMSimulation();

            for (int k = 0; k <= M - 1; k++)
            {
                // LSM Euro and American prices
                settings.S = Spot[k];
                LSMPrice   = LS.HestonLSM(RE.MTrans(MM.MMSim(param, settings, NT, NS, Zv, Zs)), settings.K, settings.r, settings.q, settings.T, NT, NS, settings.PutCall);
                LSMEuro[k] = LSMPrice[0];
                LSMAmer[k] = LSMPrice[1];
                // Closed Euro price
                ClosedEuro[k] = HP.HestonPriceGaussLaguerre(param, settings, X, W);
                // Control variate price
                CVAmer[k] = ClosedEuro[k] + (LSMAmer[k] - LSMEuro[k]);
                // The errors and total absolute errors
                ErrorLSM[k] = TruePrice[k] - LSMAmer[k];
                ErrorCV[k]  = TruePrice[k] - CVAmer[k];
                ErrorE[k]   = ClosedEuro[k] - LSMEuro[k];
                TotalLSM   += Math.Abs(ErrorLSM[k]);
                TotalCV    += Math.Abs(ErrorCV[k]);
                TotalE     += Math.Abs(ErrorE[k]);
            }
            sw.Stop();
            ts = sw.Elapsed;

            Console.WriteLine("Comparison of Clarke and Parrott American Put prices with L-S Monte Carlo");
            Console.WriteLine("LSM uses {0:0} time steps and {1:0} stock paths", NT, NS);
            Console.WriteLine("-----------------------------------------------------------");
            Console.WriteLine(" S(0)  TrueAmer  LSMAmer    CVAmer    ClosedEuro  LSMEuro");
            Console.WriteLine("-----------------------------------------------------------");
            for (int k = 0; k <= M - 1; k++)
            {
                Console.WriteLine("{0,3} {1,10:F6} {2,10:F6} {3,10:F6} {4,10:F6} {5,10:F6}",
                                  Spot[k], TruePrice[k], LSMAmer[k], CVAmer[k], ClosedEuro[k], LSMEuro[k]);
            }
            Console.WriteLine("-----------------------------------------------------------");
            Console.WriteLine("AbsError {0,15:F5} {1,10:F5} {2,21:F5}", TotalLSM, TotalCV, TotalE);
            Console.WriteLine("-----------------------------------------------------------");
            Console.WriteLine("Simulation time {0:0} minutes and {1,5:F3} seconds ", ts.Minutes, ts.Seconds);
        }
        public double[] MSPriceHeston(HParam param, OpSet opset, MSSet msset)
        {
            // param  = Heston parameters
            // opset  = option settings
            // msset  = Medvedev-Scaillet expansion settings

            // Extract quantities from the option settings
            double K  = opset.K;
            double S  = opset.S;
            double v0 = param.v0;
            double T  = opset.T;
            double r  = opset.r;
            double q  = opset.q;

            // Extract quantities from the MS structure
            int    N        = msset.N;
            double a        = msset.a;
            double b        = msset.b;
            double A        = msset.A;
            double B        = msset.B;
            double dt       = msset.dt;
            double tol      = msset.tol;
            int    MaxIter  = msset.MaxIter;
            int    NumTerms = msset.NumTerms;
            double yinf     = msset.yinf;
            int    method   = msset.method;

            // Closed-form European put
            NewtonCotes NC            = new NewtonCotes();
            double      EuroPutClosed = NC.HestonPriceNewtonCotes(param, opset, method, A, B, N);

            // Moneyness
            double theta = Math.Log(K / S) / Math.Sqrt(v0) / Math.Sqrt(T);

            // Find the barrier level
            // Bisection method to find y
            // a = Math.Max(1.25,0.95*theta);
            // b = 3.0;
            // double y = BisectionMS(a,b,theta,K,param,r,q,T,NumTerms,tol,MaxIter,dt);

            // Golden section search method to find y
            GoldenSearch GS = new GoldenSearch();

            a = 1.5;
            b = 2.5;
            double y = GS.GoldenSearchMS(a, b, tol, MaxIter, K, param, theta, r, q, T, NumTerms);

            if (y < theta)
            {
                y = theta;
            }

            // Find the early exercise premium
            MSExpansionHeston MS        = new MSExpansionHeston();
            double            AmerPutMS = MS.MSPutHeston(y, theta, K, param, r, q, T, NumTerms);
            double            EuroPutMS = MS.MSPutHeston(yinf, theta, K, param, r, q, T, NumTerms);
            double            EEP       = AmerPutMS - EuroPutMS;

            // Control variate American put
            double AmerPut = EuroPutClosed + EEP;

            // Output the results
            double[] output = new double[6];
            output[0] = EuroPutClosed;
            output[1] = AmerPutMS;
            output[2] = AmerPut;      // Medvedev and Scaillet recommend this one.
            output[3] = EEP;
            output[4] = theta;
            output[5] = y;
            return(output);
        }
        public double MSGreeksFD(HParam param, OpSet opset, int method, double A, double B, int N, double hi, double tol, int MaxIter, int NumTerms, double yinf, string Greek)
        {
            MSExpansionHeston MS = new MSExpansionHeston();

            double[] output = new double[6];
            double   AmerPut, AmerPutp, AmerPutm;
            double   AmerPutpp, AmerPutpm, AmerPutmp, AmerPutmm;

            double S  = opset.S;
            double v0 = param.v0;
            double T  = opset.T;

            // Define the finite difference increments
            double ds = opset.S * 0.005;
            double dt = opset.T * 0.005;
            double dv = param.v0 * 0.005;

            if (Greek == "price")
            {
                output  = MS.MSPrice(param, opset, method, A, B, N, hi, tol, MaxIter, NumTerms, yinf);
                AmerPut = output[2];
                return(AmerPut);
            }
            else if ((Greek == "delta") || (Greek == "gamma"))
            {
                opset.S  = S + ds;
                output   = MS.MSPrice(param, opset, method, A, B, N, hi, tol, MaxIter, NumTerms, yinf);
                AmerPutp = output[2];
                opset.S  = S - ds;
                output   = MS.MSPrice(param, opset, method, A, B, N, hi, tol, MaxIter, NumTerms, yinf);
                AmerPutm = output[2];
                if (Greek == "gamma")
                {
                    opset.S = S;
                    output  = MS.MSPrice(param, opset, method, A, B, N, hi, tol, MaxIter, NumTerms, yinf);
                    AmerPut = output[2];
                    return((AmerPutp - 2.0 * AmerPut + AmerPutm) / ds / ds);
                }
                else
                {
                    return((AmerPutp - AmerPutm) / 2.0 / ds);
                }
            }
            else if (Greek == "theta")
            {
                opset.T  = T + dt;
                output   = MS.MSPrice(param, opset, method, A, B, N, hi, tol, MaxIter, NumTerms, yinf);
                AmerPutp = output[2];
                opset.T  = T - dt;
                output   = MS.MSPrice(param, opset, method, A, B, N, hi, tol, MaxIter, NumTerms, yinf);
                AmerPutm = output[2];
                return(-(AmerPutp - AmerPutm) / 2.0 / dt);
            }
            else if ((Greek == "vega1") || (Greek == "volga"))
            {
                param.v0 = v0 + dv;
                output   = MS.MSPrice(param, opset, method, A, B, N, hi, tol, MaxIter, NumTerms, yinf);
                AmerPutp = output[2];
                param.v0 = v0 - dv;
                output   = MS.MSPrice(param, opset, method, A, B, N, hi, tol, MaxIter, NumTerms, yinf);
                AmerPutm = output[2];
                double Vega1 = (AmerPutp - AmerPutm) / 2.0 / dv * 2.0 * Math.Sqrt(v0);
                if (Greek == "volga")
                {
                    param.v0 = v0;
                    output   = MS.MSPrice(param, opset, method, A, B, N, hi, tol, MaxIter, NumTerms, yinf);
                    AmerPut  = output[2];
                    double dC2 = (AmerPutp - 2.0 * AmerPut + AmerPutm) / dv / dv;
                    return(4.0 * Math.Sqrt(v0) * (dC2 * Math.Sqrt(v0) + Vega1 / 4.0 / v0));
                }
                else
                {
                    return(Vega1);
                }
            }
            else if (Greek == "vanna")
            {
                opset.S   = S + ds;
                param.v0  = v0 + dv;
                output    = MS.MSPrice(param, opset, method, A, B, N, hi, tol, MaxIter, NumTerms, yinf);
                AmerPutpp = output[2];
                param.v0  = v0 - dv;
                output    = MS.MSPrice(param, opset, method, A, B, N, hi, tol, MaxIter, NumTerms, yinf);
                AmerPutpm = output[2];
                opset.S   = S - ds;
                param.v0  = v0 + dv;
                output    = MS.MSPrice(param, opset, method, A, B, N, hi, tol, MaxIter, NumTerms, yinf);
                AmerPutmp = output[2];
                param.v0  = v0 - dv;
                output    = MS.MSPrice(param, opset, method, A, B, N, hi, tol, MaxIter, NumTerms, yinf);
                AmerPutmm = output[2];
                return((AmerPutpp - AmerPutpm - AmerPutmp + AmerPutmm) / 4.0 / dv / ds * 2.0 * Math.Sqrt(v0));
            }
            else
            {
                return(0.0);
            }
        }
示例#28
0
        static void Main(string[] args)
        {
            // 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]);
                }

            // Reproduces ATM prices in Table 8 of Benhamou, Gobet, and Miri
            //"Time Dependent Heston Model"
            // SIAM Journal on Financial Mathematics, Vol. 1, (2010)

            // Exact prices from the BGM (2010) paper
            double[] TruePW = new double[8] {
                3.93, 5.53, 7.85, 11.23, 13.92, 18.37, 22.15, 27.17
            };

            // Spot price, risk free rate, dividend yield
            OpSet settings = new OpSet();

            settings.S       = 100.0;
            settings.r       = 0.0;
            settings.q       = 0.0;
            settings.PutCall = "P";
            settings.trap    = 1;    // Little trap formulation
            double K = 100.0;

            // Heston piecewise constant parameters.
            double kappa = 3.0;
            double v0    = 0.04;

            double[] T     = new double[40];
            double[] THETA = new double[40];
            double[] SIGMA = new double[40];
            double[] RHO   = new double[40];

            // Construct the piecewise constant parameters
            for (int t = 0; t <= 39; t++)
            {
                T[t]     = (Convert.ToDouble(t) + 1) / 4.0;
                THETA[t] = 0.04 + Convert.ToDouble(t) * 0.05 / 100.0;
                SIGMA[t] = 0.30 + Convert.ToDouble(t) * 0.50 / 100.0;
                RHO[t]   = -0.20 + Convert.ToDouble(t) * 0.35 / 100.0;
            }

            // Compute maturity intervals for the Mikhailov-Nogel model
            double[] tau = new double[40];
            tau[0] = T[0];
            for (int t = 1; t <= 39; t++)
            {
                tau[t] = T[t] - T[t - 1];
            }

            // Obtain the Approximate Piecewise and Closed Form Piecewise put prices using the constructed parameters
            List <double>         MatList   = new List <double>();
            List <List <double> > MNparam0  = new List <List <double> >();
            List <double>         tau0      = new List <double>();
            List <double>         thetaList = new List <double>();
            List <double>         sigmaList = new List <double>();
            List <double>         rhoList   = new List <double>();

            HParam        param = new HParam();
            BGMPrice      BGM   = new BGMPrice();
            HestonPrice   HP    = new HestonPrice();
            HestonPriceTD HPTD  = new HestonPriceTD();

            double[] ApproxPW = new double[40];
            double[] ClosedPW = new double[40];
            double[] Mat, theta, sigma, rho;
            for (int t = 0; t <= 39; t++)
            {
                // Stack the maturities and parameters, with the oldest ones at the top, and the newest ones the bottom
                MatList.Add(T[t]);
                Mat = MatList.ToArray();
                thetaList.Add(THETA[t]);
                sigmaList.Add(SIGMA[t]);
                rhoList.Add(RHO[t]);
                theta = thetaList.ToArray();
                sigma = sigmaList.ToArray();
                rho   = rhoList.ToArray();
                // Calculate the approximate formula with the piecewise constant parameters
                ApproxPW[t] = BGM.BGMApproxPriceTD(kappa, v0, theta, sigma, rho, settings, K, Mat);
                if (t == 0)
                {
                    // First iteration for the closed-form price with the PW constant parameters
                    param.kappa = kappa;
                    param.theta = theta[0];
                    param.sigma = sigma[0];
                    param.v0    = v0;
                    param.rho   = rho[0];
                    ClosedPW[t] = HP.HestonPriceGaussLaguerre(param, settings, K, T[0], X, W);
                }
                else if (t == 1)
                {
                    // Second iteration for the closed form price with the PW constant parameters
                    double[] OldMat = new double[1] {
                        0.25
                    };
                    double[,] param0 = new double[1, 5];
                    param0[0, 0]     = kappa;
                    param0[0, 1]     = theta[0]; param0[0, 2] = sigma[0]; param0[0, 3] = v0; param0[0, 4] = rho[0];
                    ClosedPW[t]      = HPTD.HestonPriceGaussLaguerreTD(param, param0, tau[t], OldMat, settings, K, X, W);
                }
                else if (t > 1)
                {
                    // Remaing iteration for the closed form price with PW constant parameters
                    // Current parameter values
                    param.theta = theta[t];
                    param.sigma = sigma[t];
                    param.rho   = rho[t];
                    // Stack the past maturities, oldest on the bottm, newest on top
                    double[] OldMat = new double[t];
                    for (int k = 0; k <= t - 1; k++)
                    {
                        OldMat[k] = tau[t - k - 1];
                    }
                    // Fill in the past parameter values, with the oldest on the bottom and newest on top
                    double[,] param0 = new double[t, 5];
                    for (int k = 0; k <= t - 1; k++)
                    {
                        param0[k, 0] = kappa;
                        param0[k, 1] = theta[t - k - 1];
                        param0[k, 2] = sigma[t - k - 1];
                        param0[k, 3] = v0;
                        param0[k, 4] = rho[t - k - 1];
                    }
                    ClosedPW[t] = HPTD.HestonPriceGaussLaguerreTD(param, param0, tau[t], OldMat, settings, K, X, W);
                }
            }

            // Select only the puts at the maturities
            double[] ClosedPW2 = new double[8];
            double[] ApproxPW2 = new double[8];
            double[] Mats      = new double[8] {
                0.25, 0.5, 1.0, 2.0, 3.0, 5.0, 7.0, 10.0
            };

            for (int t = 0; t <= 39; t++)
            {
                for (int k = 0; k <= 7; k++)
                {
                    if (T[t] == Mats[k])
                    {
                        ClosedPW2[k] = ClosedPW[t];
                        ApproxPW2[k] = ApproxPW[t];
                    }
                }
            }

            // The averaged parameter values
            // Note: v0(4) has been changed
            double[] v0new    = new double[] { 0.04, 0.0397, 0.0328, 0.0464, 0.05624, 0.2858, 0.8492, 0.1454 };
            double[] thetanew = new double[] { 0.04, 0.0404, 0.0438, 0.0402, 0.0404, 0.0268, 0.0059, 0.0457 };
            double[] sigmanew = new double[] { 0.30, 0.3012, 0.3089, 0.3112, 0.3210, 0.3363, 0.3541, 0.3998 };
            double[] rhonew   = new double[] { -0.20, -0.1993, -0.1972, -0.1895, -0.1820, -0.1652, -0.1480, -0.1232 };

            // The closed form prices using the averaged parameter volumes
            HParam newparam = new HParam();

            double[] ClosedAvg = new double[8];
            for (int t = 0; t <= 7; t++)
            {
                newparam.kappa = kappa;
                newparam.theta = thetanew[t];
                newparam.sigma = sigmanew[t];
                newparam.v0    = v0new[t];
                newparam.rho   = rhonew[t];
                ClosedAvg[t]   = HP.HestonPriceGaussLaguerre(newparam, settings, K, Mats[t], X, W);
            }

            // Output the results at the maturities
            Console.WriteLine("----------------------------------------------------------------------------");
            Console.WriteLine("          Original Heston | Mihailov-Nogel |  BGM Matlab    | BGM True Price");
            Console.WriteLine("Maturity    Closed Form   |   Piecewise    |   Piecewise    |   Piecewise   ");
            Console.WriteLine("----------------------------------------------------------------------------");
            for (int t = 0; t <= 7; t++)
            {
                Console.WriteLine("{0,5:0.00} {1,14:F2} {2,16:F2} {3,16:F2} {4,16:F2}", Mats[t], ClosedAvg[t], ClosedPW2[t], ApproxPW2[t], TruePW[t]);
            }
            Console.WriteLine("----------------------------------------------------------------------------");
        }
        // Heston Price by Gauss-Legendre Integration
        public OutputMD HestonPriceGaussLegendreMD(HParam param, OpSet settings, double[] xGLe, double[] wGLe, double[] A, double tol)
        {
            int nA = A.Length;
            int nX = xGLe.Length;

            double[,] int1 = new double[nA, nX];
            double[,] int2 = new double[nA, nX];
            double[] sum1 = new double[nA];
            double[] sum2 = new double[nA];

            // Numerical integration
            HestonPrice HP = new HestonPrice();
            int         nj = 0;

            for (int j = 1; j <= nA - 1; j++)
            {
                // Counter for the last point of A used
                nj     += 1;
                sum1[j] = 0.0;
                for (int k = 0; k <= nX - 1; k++)
                {
                    // Lower and upper and limits of the subdomain
                    double a = A[j - 1];
                    double b = A[j];
                    double X = (a + b) / 2.0 + (b - a) / 2.0 * xGLe[k];
                    int1[j, k] = wGLe[k] * HP.HestonProb(X, param, settings, 1) * (b - a) / 2.0;
                    int2[j, k] = wGLe[k] * HP.HestonProb(X, param, settings, 2) * (b - a) / 2.0;
                    sum1[j]   += int1[j, k];
                    sum2[j]   += int2[j, k];
                }
                if (Math.Abs(sum1[j]) < tol && Math.Abs(sum2[j]) < tol)
                {
                    break;
                }
            }

            // Define P1 and P2
            double pi = Math.PI;
            double P1 = 0.5 + 1.0 / pi * sum1.Sum();
            double P2 = 0.5 + 1.0 / pi * sum2.Sum();

            // The call price
            double S       = settings.S;
            double K       = settings.K;
            double T       = settings.T;
            double r       = settings.r;
            double q       = settings.q;
            string PutCall = settings.PutCall;
            double HestonC = S * Math.Exp(-q * T) * P1 - K * Math.Exp(-r * T) * P2;

            // The put price by put-call parity
            double HestonP = HestonC - S * Math.Exp(-q * T) + K * Math.Exp(-r * T);

            // The output structure
            OutputMD output = new OutputMD();

            // Output the option price
            if (PutCall == "C")
            {
                output.Price = HestonC;
            }
            else
            {
                output.Price = HestonP;
            }

            // Output the integration domain;
            output.lower = A[0];
            output.upper = A[nj];

            // Output the number of integration points
            output.Npoints = (nj + 1) * nX;
            return(output);
        }
示例#30
0
        // Simulation of stock price paths and variance paths using Euler or Milstein schemes
        public double[] EulerMilsteinSim(string scheme, string negvar, HParam param, OpSet settings, double alpha, int NT, int NS)
        {
            RandomNumbers RN = new RandomNumbers();

            // Heston parameters
            double kappa  = param.kappa;
            double theta  = param.theta;
            double sigma  = param.sigma;
            double v0     = param.v0;
            double rho    = param.rho;
            double lambda = param.lambda;

            // Time increment
            double dt = settings.T / Convert.ToDouble(NT);

            // Initialize the variance and stock processes
            double[,] V = new double[NT, NS];
            double[,] S = new double[NT, NS];

            // Flags for negative variances
            int F = 0;

            // Starting values for the variance and stock processes
            for (int s = 0; s <= NS - 1; s++)
            {
                S[0, s] = settings.S; // Spot price
                V[0, s] = v0;         // Heston v0 initial variance
            }

            // Generate the stock and volatility paths
            double Zv, Zs;

            for (int s = 0; s <= NS - 1; s++)
            {
                for (int t = 1; t <= NT - 1; t++)
                {
                    // Generate two dependent N(0,1) variables with correlation rho
                    Zv = RN.RandomNorm();
                    Zs = rho * Zv + Math.Sqrt(1.0 - rho * rho) * RN.RandomNorm();

                    if (scheme == "Euler")
                    {
                        // Euler discretization for the variance
                        V[t, s] = V[t - 1, s] + kappa * (theta - V[t - 1, s]) * dt + sigma * Math.Sqrt(V[t - 1, s] * dt) * Zv;
                    }
                    else if (scheme == "Milstein")
                    {
                        // Milstein discretization for the variance.
                        V[t, s] = V[t - 1, s] + kappa * (theta - V[t - 1, s]) * dt + sigma * Math.Sqrt(V[t - 1, s] * dt) * Zv + 0.25 * sigma * sigma * dt * (Zv * Zv - 1.0);
                    }
                    else if (scheme == "IM")
                    {
                        // Implicit Milstein for the variance.
                        V[t, s] = (V[t - 1, s] + kappa * theta * dt + sigma * Math.Sqrt(V[t - 1, s] * dt) * Zv + sigma * sigma * dt * (Zv * Zv - 1.0) / 4.0) / (1.0 + kappa * dt);
                    }
                    else if (scheme == "WM")
                    {
                        // Weighted Explicit-Implicit Milstein Scheme
                        V[t, s] = (V[t - 1, s] + kappa * (theta - alpha * V[t - 1, s]) * dt + sigma * Math.Sqrt(V[t - 1, s] * dt) * Zv + sigma * sigma * dt * (Zv * Zv - 1.0) / 4.0) / (1.0 + (1.0 - alpha) * kappa * dt);
                    }

                    // Apply the full truncation or reflection scheme to the variance
                    if (V[t, s] <= 0)
                    {
                        F += 1;
                        if (negvar == "Reflection")          // Reflection: take -V
                        {
                            V[t, s] = Math.Abs(V[t, s]);
                        }
                        else if (negvar == "Truncation")
                        {
                            V[t, s] = Math.Max(0, V[t, s]);   // Truncation: take max(0,V)
                        }
                    }

                    // Discretize the log stock price
                    S[t, s] = S[t - 1, s] * Math.Exp((settings.r - settings.q - V[t - 1, s] / 2.0) * dt + Math.Sqrt(V[t - 1, s] * dt) * Zs);
                }
            }

            // Return the vector or terminal stock prices
            double[] output = new double[NS];
            for (int s = 0; s <= NS - 1; s++)
            {
                output[s] = S[NT - 1, s];
            }

            return(output);
        }