public HybridHestonHullWhiteProcess(HestonProcess hestonProcess, HullWhiteForwardProcess hullWhiteProcess, double corrEquityShortRate, Discretization discretization = Discretization.BSMHullWhite) { hestonProcess_ = hestonProcess; hullWhiteProcess_ = hullWhiteProcess; hullWhiteModel_ = new HullWhite(hestonProcess.riskFreeRate(), hullWhiteProcess.a(), hullWhiteProcess.sigma()); corrEquityShortRate_ = corrEquityShortRate; disc_ = discretization; maxRho_ = Math.Sqrt(1 - hestonProcess.rho() * hestonProcess.rho()) - Math.Sqrt(Const.QL_EPSILON) /* reserve for rounding errors */; T_ = hullWhiteProcess.getForwardMeasureTime(); endDiscount_ = hestonProcess.riskFreeRate().link.discount(T_); Utils.QL_REQUIRE(corrEquityShortRate * corrEquityShortRate + hestonProcess.rho() * hestonProcess.rho() <= 1.0, () => "correlation matrix is not positive definite"); Utils.QL_REQUIRE(hullWhiteProcess.sigma() > 0.0, () => "positive vol of Hull White process is required"); }
private Complex Phi(HestonProcess process, Complex a, double nu_0, double nu_t, double dt) { double theta = process.theta(); double kappa = process.kappa(); double sigma = process.sigma(); double sigma2 = sigma * sigma; Complex ga = Complex.Sqrt(kappa * kappa - 2 * sigma2 * a * new Complex(0.0, 1.0)); double d = 4 * theta * kappa / sigma2; double nu = 0.5 * d - 1; Complex z = ga * Complex.Exp(-0.5 * ga * dt) / (1.0 - Complex.Exp(-ga * dt)); Complex log_z = -0.5 * ga * dt + Complex.Log(ga / (1.0 - Complex.Exp(-ga * dt))); Complex alpha = 4.0 * ga * Complex.Exp(-0.5 * ga * dt) / (sigma2 * (1.0 - Complex.Exp(-ga * dt))); Complex beta = 4.0 * kappa * Complex.Exp(-0.5 * kappa * dt) / (sigma2 * (1.0 - Complex.Exp(-kappa * dt))); return(ga * Complex.Exp(-0.5 * (ga - kappa) * dt) * (1 - Complex.Exp(-kappa * dt)) / (kappa * (1.0 - Complex.Exp(-ga * dt))) * Complex.Exp((nu_0 + nu_t) / sigma2 * ( kappa * (1.0 + Complex.Exp(-kappa * dt)) / (1.0 - Complex.Exp(-kappa * dt)) - ga * (1.0 + Complex.Exp(-ga * dt)) / (1.0 - Complex.Exp(-ga * dt)))) * Complex.Exp(nu * log_z) / Complex.Pow(z, nu) * ((nu_t > 1e-8) ? Utils.modifiedBesselFunction_i(nu, Complex.Sqrt(nu_0 * nu_t) * alpha) / Utils.modifiedBesselFunction_i(nu, Complex.Sqrt(nu_0 * nu_t) * beta) : Complex.Pow(alpha / beta, nu) )); }
private double cornishFisherEps(HestonProcess process, double nu_0, double nu_t, double dt, double eps) { // use moment generating function to get the // first,second, third and fourth moment of the distribution double d = 1e-2; double p2 = Phi(process, new Complex(0, -2 * d), nu_0, nu_t, dt).Real; double p1 = Phi(process, new Complex(0, -d), nu_0, nu_t, dt).Real; double p0 = Phi(process, new Complex(0, 0), nu_0, nu_t, dt).Real; double pm1 = Phi(process, new Complex(0, d), nu_0, nu_t, dt).Real; double pm2 = Phi(process, new Complex(0, 2 * d), nu_0, nu_t, dt).Real; double avg = (pm2 - 8 * pm1 + 8 * p1 - p2) / (12 * d); double m2 = (-pm2 + 16 * pm1 - 30 * p0 + 16 * p1 - p2) / (12 * d * d); double var = m2 - avg * avg; double stdDev = Math.Sqrt(var); double m3 = (-0.5 * pm2 + pm1 - p1 + 0.5 * p2) / (d * d * d); double skew = (m3 - 3 * var * avg - avg * avg * avg) / (var * stdDev); double m4 = (pm2 - 4 * pm1 + 6 * p0 - 4 * p1 + p2) / (d * d * d * d); double kurt = (m4 - 4 * m3 * avg + 6 * m2 * avg * avg - 3 * avg * avg * avg * avg) / (var * var); // Cornish-Fisher relation to come up with an improved // estimate of 1-F(u_\eps) < \eps double q = new InverseCumulativeNormal().value(1 - eps); double w = q + (q * q - 1) / 6 * skew + (q * q * q - 3 * q) / 24 * (kurt - 3) - (2 * q * q * q - 5 * q) / 36 * skew * skew; return(avg + w * stdDev); }
public ch(HestonProcess _process, double _x, double _nu_0, double _nu_t, double _dt) { process = _process; x = _x; nu_0 = _nu_0; nu_t = _nu_t; dt = _dt; }
protected override void generateArguments() { process_ = new HestonProcess(process_.riskFreeRate(), process_.dividendYield(), process_.s0(), v0(), kappa(), theta(), sigma(), rho()); }
public cdf_nu_ds(HestonProcess _process, double _nu_0, double _nu_t, double _dt, Discretization _discretization) { process = _process; nu_0 = _nu_0; nu_t = _nu_t; dt = _dt; discretization = _discretization; }
public MakeMGenericHestonInstrument(HestonProcess process) { process_ = process; antithetic_ = true; steps_ = null; stepsPerYear_ = null; samples_ = null; maxSamples_ = null; tolerance_ = null; brownianBridge_ = false; seed_ = 0; }
public MCGenericHestonInstrument(HestonProcess process, bool antithetic, int?steps, int?stepsPerYear, int?samples, int?maxSamples, double?tolerance, bool brownianBridge, ulong seed) : base(process, antithetic, steps, stepsPerYear, samples, maxSamples, tolerance, brownianBridge, seed) { }
protected override double blackVolImpl(double t, double strike) { HestonProcess process = hestonModel_.link.process(); double df = process.riskFreeRate().link.discount(t, true); double div = process.dividendYield().link.discount(t, true); double spotPrice = process.s0().link.value(); double fwd = spotPrice * process.dividendYield().link.discount(t, true) / process.riskFreeRate().link.discount(t, true); var payoff = new PlainVanillaPayoff(fwd > strike ? Option.Type.Put : Option.Type.Call, strike); double kappa = hestonModel_.link.kappa(); double theta = hestonModel_.link.theta(); double rho = hestonModel_.link.rho(); double sigma = hestonModel_.link.sigma(); double v0 = hestonModel_.link.v0(); AnalyticHestonEngine.ComplexLogFormula cpxLogFormula = AnalyticHestonEngine.ComplexLogFormula.Gatheral; AnalyticHestonEngine hestonEnginePtr = null; double?npv = null; int evaluations = 0; AnalyticHestonEngine.doCalculation( df, div, spotPrice, strike, t, kappa, theta, sigma, v0, rho, payoff, integration_, cpxLogFormula, hestonEnginePtr, ref npv, ref evaluations); if (npv <= 0.0) { return(Math.Sqrt(theta)); } Brent solver = new Brent(); solver.setMaxEvaluations(10000); double guess = Math.Sqrt(theta); double accuracy = Const.QL_EPSILON; var f = new ImpliedVolHelper(payoff.optionType(), strike, fwd, t, df, npv.Value); return(solver.solve(f, accuracy, guess, 0.01)); }
public HestonModel(HestonProcess process) : base(5) { process_ = process; arguments_[0] = new ConstantParameter(process.theta(), new PositiveConstraint()); arguments_[1] = new ConstantParameter(process.kappa(), new PositiveConstraint()); arguments_[2] = new ConstantParameter(process.sigma(), new PositiveConstraint()); arguments_[3] = new ConstantParameter(process.rho(), new BoundaryConstraint(-1.0, 1.0)); arguments_[4] = new ConstantParameter(process.v0(), new PositiveConstraint()); generateArguments(); process_.riskFreeRate().registerWith(update); process_.dividendYield().registerWith(update); process_.s0().registerWith(update); }
protected override IPricingEngine controlPricingEngine() { HybridHestonHullWhiteProcess process = process_ as HybridHestonHullWhiteProcess; Utils.QL_REQUIRE(process != null, () => "invalid process"); HestonProcess hestonProcess = process.hestonProcess(); HullWhiteForwardProcess hullWhiteProcess = process.hullWhiteProcess(); HestonModel hestonModel = new HestonModel(hestonProcess); HullWhite hwModel = new HullWhite(hestonProcess.riskFreeRate(), hullWhiteProcess.a(), hullWhiteProcess.sigma()); return(new AnalyticHestonHullWhiteEngine(hestonModel, hwModel, 144)); }
protected override PathPricer <IPath> controlPathPricer() { HybridHestonHullWhiteProcess process = process_ as HybridHestonHullWhiteProcess; Utils.QL_REQUIRE(process != null, () => "invalid process"); HestonProcess hestonProcess = process.hestonProcess(); Utils.QL_REQUIRE(hestonProcess != null, () => "first constituent of the joint stochastic process need to be of type HestonProcess"); Exercise exercise = this.arguments_.exercise; Utils.QL_REQUIRE(exercise.type() == Exercise.Type.European, () => "only european exercise is supported"); double exerciseTime = process.time(exercise.lastDate()); return(new HestonHullWhitePathPricer(exerciseTime, this.arguments_.payoff, process)); }
public override void calculate() { // this is a european option pricer Utils.QL_REQUIRE(arguments_.exercise.type() == Exercise.Type.European, () => "not an European option"); // plain vanilla PlainVanillaPayoff payoff = arguments_.payoff as PlainVanillaPayoff; Utils.QL_REQUIRE(payoff != null, () => "non plain vanilla payoff given"); HestonProcess process = model_.link.process(); double riskFreeDiscount = process.riskFreeRate().link.discount(arguments_.exercise.lastDate()); double dividendDiscount = process.dividendYield().link.discount(arguments_.exercise.lastDate()); double spotPrice = process.s0().link.value(); Utils.QL_REQUIRE(spotPrice > 0.0, () => "negative or null underlying given"); double strikePrice = payoff.strike(); double term = process.time(arguments_.exercise.lastDate()); double?resultsValue = null; doCalculation(riskFreeDiscount, dividendDiscount, spotPrice, strikePrice, term, model_.link.kappa(), model_.link.theta(), model_.link.sigma(), model_.link.v0(), model_.link.rho(), payoff, integration_, cpxLog_, this, ref resultsValue, ref evaluations_); results_.value = resultsValue; }
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; }