예제 #1
0
        public override Vector evolve(double t0, Vector x0, double dt, Vector dw)
        {
            Vector retVal = new Vector(2);
            double vol, vol2, mu, nu, dy;

            double sdt    = Math.Sqrt(dt);
            double sqrhov = Math.Sqrt(1.0 - rho_ * rho_);

            switch (discretization_)
            {
            // For the definition of PartialTruncation, FullTruncation
            // and Reflection  see Lord, R., R. Koekkoek and D. van Dijk (2006),
            // "A Comparison of biased simulation schemes for
            //  stochastic volatility models",
            // Working Paper, Tinbergen Institute
            case Discretization.PartialTruncation:
                vol  = (x0[1] > 0.0) ? Math.Sqrt(x0[1]) : 0.0;
                vol2 = sigma_ * vol;
                mu   = riskFreeRate_.link.forwardRate(t0, t0 + dt, Compounding.Continuous).value()
                       - dividendYield_.link.forwardRate(t0, t0 + dt, Compounding.Continuous).value()
                       - 0.5 * vol * vol;
                nu = kappa_ * (theta_ - x0[1]);

                retVal[0] = x0[0] * Math.Exp(mu * dt + vol * dw[0] * sdt);
                retVal[1] = x0[1] + nu * dt + vol2 * sdt * (rho_ * dw[0] + sqrhov * dw[1]);
                break;

            case Discretization.FullTruncation:
                vol  = (x0[1] > 0.0) ? Math.Sqrt(x0[1]) : 0.0;
                vol2 = sigma_ * vol;
                mu   = riskFreeRate_.link.forwardRate(t0, t0 + dt, Compounding.Continuous).value()
                       - dividendYield_.link.forwardRate(t0, t0 + dt, Compounding.Continuous).value()
                       - 0.5 * vol * vol;
                nu = kappa_ * (theta_ - vol * vol);

                retVal[0] = x0[0] * Math.Exp(mu * dt + vol * dw[0] * sdt);
                retVal[1] = x0[1] + nu * dt + vol2 * sdt * (rho_ * dw[0] + sqrhov * dw[1]);
                break;

            case Discretization.Reflection:
                vol  = Math.Sqrt(Math.Abs(x0[1]));
                vol2 = sigma_ * vol;
                mu   = riskFreeRate_.link.forwardRate(t0, t0 + dt, Compounding.Continuous).value()
                       - dividendYield_.link.forwardRate(t0, t0 + dt, Compounding.Continuous).value()
                       - 0.5 * vol * vol;
                nu = kappa_ * (theta_ - vol * vol);

                retVal[0] = x0[0] * Math.Exp(mu * dt + vol * dw[0] * sdt);
                retVal[1] = vol * vol
                            + nu * dt + vol2 * sdt * (rho_ * dw[0] + sqrhov * dw[1]);
                break;

            case Discretization.NonCentralChiSquareVariance:
                // use Alan Lewis trick to decorrelate the equity and the variance
                // process by using y(t)=x(t)-\frac{rho}{sigma}\nu(t)
                // and Ito's Lemma. Then use exact sampling for the variance
                // process. For further details please read the Wilmott thread
                // "QuantLib code is very high quality"
                vol = (x0[1] > 0.0) ? Math.Sqrt(x0[1]) : 0.0;
                mu  = riskFreeRate_.link.forwardRate(t0, t0 + dt, Compounding.Continuous).value()
                      - dividendYield_.link.forwardRate(t0, t0 + dt, Compounding.Continuous).value()
                      - 0.5 * vol * vol;

                retVal[1] = varianceDistribution(x0[1], dw[1], dt);
                dy        = (mu - rho_ / sigma_ * kappa_
                             * (theta_ - vol * vol)) * dt + vol * sqrhov * dw[0] * sdt;

                retVal[0] = x0[0] * Math.Exp(dy + rho_ / sigma_ * (retVal[1] - x0[1]));
                break;

            case Discretization.QuadraticExponential:
            case Discretization.QuadraticExponentialMartingale:
            {
                // for details of the quadratic exponential discretization scheme
                // see Leif Andersen,
                // Efficient Simulation of the Heston Stochastic Volatility Model
                double ex = Math.Exp(-kappa_ * dt);

                double m  = theta_ + (x0[1] - theta_) * ex;
                double s2 = x0[1] * sigma_ * sigma_ * ex / kappa_ * (1 - ex)
                            + theta_ * sigma_ * sigma_ / (2 * kappa_) * (1 - ex) * (1 - ex);
                double psi = s2 / (m * m);

                double g1 = 0.5;
                double g2 = 0.5;
                double k0 = -rho_ * kappa_ * theta_ * dt / sigma_;
                double k1 = g1 * dt * (kappa_ * rho_ / sigma_ - 0.5) - rho_ / sigma_;
                double k2 = g2 * dt * (kappa_ * rho_ / sigma_ - 0.5) + rho_ / sigma_;
                double k3 = g1 * dt * (1 - rho_ * rho_);
                double k4 = g2 * dt * (1 - rho_ * rho_);
                double A  = k2 + 0.5 * k4;

                if (psi < 1.5)
                {
                    double b2 = 2 / psi - 1 + Math.Sqrt(2 / psi * (2 / psi - 1));
                    double b  = Math.Sqrt(b2);
                    double a  = m / (1 + b2);

                    if (discretization_ == Discretization.QuadraticExponentialMartingale)
                    {
                        // martingale correction
                        Utils.QL_REQUIRE(A < 1 / (2 * a), () => "illegal value");
                        k0 = -A * b2 * a / (1 - 2 * A * a) + 0.5 * Math.Log(1 - 2 * A * a)
                             - (k1 + 0.5 * k3) * x0[1];
                    }
                    retVal[1] = a * (b + dw[1]) * (b + dw[1]);
                }
                else
                {
                    double p    = (psi - 1) / (psi + 1);
                    double beta = (1 - p) / m;

                    double u = new CumulativeNormalDistribution().value(dw[1]);

                    if (discretization_ == Discretization.QuadraticExponentialMartingale)
                    {
                        // martingale correction
                        Utils.QL_REQUIRE(A < beta, () => "illegal value");
                        k0 = -Math.Log(p + beta * (1 - p) / (beta - A)) - (k1 + 0.5 * k3) * x0[1];
                    }
                    retVal[1] = ((u <= p) ? 0.0 : Math.Log((1 - p) / (1 - u)) / beta);
                }

                mu = riskFreeRate_.link.forwardRate(t0, t0 + dt, Compounding.Continuous).value()
                     - dividendYield_.link.forwardRate(t0, t0 + dt, Compounding.Continuous).value();

                retVal[0] = x0[0] * Math.Exp(mu * dt + k0 + k1 * x0[1] + k2 * retVal[1]
                                             + Math.Sqrt(k3 * x0[1] + k4 * retVal[1]) * dw[0]);
            }
            break;

            case Discretization.BroadieKayaExactSchemeLobatto:
            case Discretization.BroadieKayaExactSchemeLaguerre:
            case Discretization.BroadieKayaExactSchemeTrapezoidal:
            {
                double nu_0 = x0[1];
                double nu_t = varianceDistribution(nu_0, dw[1], dt);

                double x = Math.Min(1.0 - Const.QL_EPSILON,
                                    Math.Max(0.0, new CumulativeNormalDistribution().value(dw[2])));

                cdf_nu_ds f   = new cdf_nu_ds(this, nu_0, nu_t, dt, discretization_);
                double    vds = new Brent().solve(f, 1e-5, -x, theta_ * dt, 0.1 * theta_ * dt);

                //double vds = new Brent().solve( boost::lambda::bind(&cdf_nu_ds, *this, boost::lambda::_1,
                //                               nu_0, nu_t, dt, discretization_)-x,
                //                               1e-5, theta_*dt, 0.1*theta_*dt);

                double vdw = (nu_t - nu_0 - kappa_ * theta_ * dt + kappa_ * vds) / sigma_;

                mu = (riskFreeRate_.link.forwardRate(t0, t0 + dt, Compounding.Continuous).value()
                      - dividendYield_.link.forwardRate(t0, t0 + dt, Compounding.Continuous).value()) * dt
                     - 0.5 * vds + rho_ * vdw;

                double sig = Math.Sqrt((1 - rho_ * rho_) * vds);
                double s   = x0[0] * Math.Exp(mu + sig * dw[0]);

                retVal[0] = s;
                retVal[1] = nu_t;
            }
            break;

            default:
                Utils.QL_FAIL("unknown discretization schema");
                break;
            }

            return(retVal);
        }
예제 #2
0
 public cdf_nu_ds_minus_x(double _x0, HestonProcess _process, double _nu_0, double _nu_t, double _dt,
                          Discretization _discretization)
 {
     cdf_nu = new cdf_nu_ds(_process, _nu_0, _nu_t, _dt, _discretization);
     x0     = _x0;
 }