public FdmHestonLocalVolatilityVarianceMesher(int size, HestonProcess process, LocalVolTermStructure leverageFct, double maturity, int tAvgSteps = 10, double epsilon = 0.0001) : base(size) { leverageFct_ = leverageFct; FdmHestonVarianceMesher mesher = new FdmHestonVarianceMesher(size, process, maturity, tAvgSteps, epsilon); for (int i = 0; i < size; ++i) { dplus_[i] = mesher.dplus(i); dminus_[i] = mesher.dminus(i); locations_[i] = mesher.location(i); } volaEstimate_ = mesher.volaEstimate(); if (leverageFct != null) { double s0 = process.s0().currentLink().value(); List <double> acc = new List <double>(); acc.Add(leverageFct.localVol(0.0, s0, true)); Handle <YieldTermStructure> rTS = process.riskFreeRate(); Handle <YieldTermStructure> qTS = process.dividendYield(); for (int l = 1; l <= tAvgSteps; ++l) { double t = (maturity * l) / tAvgSteps; double vol = volaEstimate_ * acc.Average(); double fwd = s0 * qTS.currentLink().discount(t) / rTS.currentLink().discount(t); int sAvgSteps = 50; Vector u = new Vector(sAvgSteps), sig = new Vector(sAvgSteps); for (int i = 0; i < sAvgSteps; ++i) { u[i] = epsilon + ((1.0 - 2.0 * epsilon) / (sAvgSteps - 1.0)) * i; double x = new InverseCumulativeNormal().value(u[i]); double gf = x * vol * Math.Sqrt(t); double f = fwd * Math.Exp(gf); sig[i] = Math.Pow(leverageFct.localVol(t, f, true), 2.0); } double leverageAvg = new GaussLobattoIntegral(10000, 1E-4).value(new interpolated_volatility(u, sig).value, u.First(), u.Last()) / (1.0 - 2.0 * epsilon); acc.Add(leverageAvg); } volaEstimate_ *= acc.Average(); } }
public FdmHestonVarianceMesher(int size, HestonProcess process, double maturity, int tAvgSteps = 10, double epsilon = 0.0001) : base(size) { List <double> vGrid = new InitializedList <double>(size, 0.0); List <double> pGrid = new InitializedList <double>(size, 0.0); double df = 4.0 * process.theta() * process.kappa() / Math.Pow(process.sigma(), 2); try { List <pair_double> grid = new List <pair_double>(); for (int l = 1; l <= tAvgSteps; ++l) { double t = (maturity * l) / tAvgSteps; double ncp = 4 * process.kappa() * Math.Exp(-process.kappa() * t) / (Math.Pow(process.sigma(), 2) * (1 - Math.Exp(-process.kappa() * t))) * process.v0(); double k = Math.Pow(process.sigma(), 2) * (1 - Math.Exp(-process.kappa() * t)) / (4 * process.kappa()); double qMin = 0.0; // v_min = 0.0; double qMax = Math.Max(process.v0(), k * new InverseNonCentralCumulativeChiSquareDistribution( df, ncp, 100, 1e-8).value(1 - epsilon)); double minVStep = (qMax - qMin) / (50 * size); double ps, p = 0.0; double vTmp = qMin; grid.Add(new pair_double(qMin, epsilon)); for (int i = 1; i < size; ++i) { ps = (1 - epsilon - p) / (size - i); p += ps; double tmp = k * new InverseNonCentralCumulativeChiSquareDistribution( df, ncp, 100, 1e-8).value(p); double vx = Math.Max(vTmp + minVStep, tmp); p = new NonCentralCumulativeChiSquareDistribution(df, ncp).value(vx / k); vTmp = vx; grid.Add(new pair_double(vx, p)); } } Utils.QL_REQUIRE(grid.Count == size * tAvgSteps, () => "something wrong with the grid size"); grid.Sort(); List <Pair <double, double> > tp = new List <Pair <double, double> >(grid); for (int i = 0; i < size; ++i) { int b = (i * tp.Count) / size; int e = ((i + 1) * tp.Count) / size; for (int j = b; j < e; ++j) { vGrid[i] += tp[j].first / (e - b); pGrid[i] += tp[j].second / (e - b); } } } catch (Exception) { // use default mesh double vol = process.sigma() * Math.Sqrt(process.theta() / (2 * process.kappa())); double mean = process.theta(); double upperBound = Math.Max(process.v0() + 4 * vol, mean + 4 * vol); double lowerBound = Math.Max(0.0, Math.Min(process.v0() - 4 * vol, mean - 4 * vol)); for (int i = 0; i < size; ++i) { pGrid[i] = i / (size - 1.0); vGrid[i] = lowerBound + i * (upperBound - lowerBound) / (size - 1.0); } } double skewHint = ((process.kappa() != 0.0) ? Math.Max(1.0, process.sigma() / process.kappa()) : 1.0); pGrid.Sort(); volaEstimate_ = new GaussLobattoIntegral(100000, 1e-4).value( new interpolated_volatility(pGrid, vGrid).value, pGrid.First(), pGrid.Last()) * Math.Pow(skewHint, 1.5); double v0 = process.v0(); for (int i = 1; i < vGrid.Count; ++i) { if (vGrid[i - 1] <= v0 && vGrid[i] >= v0) { if (Math.Abs(vGrid[i - 1] - v0) < Math.Abs(vGrid[i] - v0)) { vGrid[i - 1] = v0; } else { vGrid[i] = v0; } } } locations_ = vGrid.Select(x => x).ToList(); for (int i = 0; i < size - 1; ++i) { dminus_[i + 1] = dplus_[i] = vGrid[i + 1] - vGrid[i]; } dplus_[dplus_.Count - 1] = null; dminus_[0] = null; }