public void CallNaiveImplemXCheck() { var maturities = GridUtils.RegularGrid(0.1, 5.0, 100); var vols = GridUtils.RegularGrid(0.01, 1.0, 10); var volMoneynesses = GridUtils.RegularGrid(-3, 3, 100); foreach (var mat in maturities) { foreach (var vol in vols) { var sigma = Math.Sqrt(mat) * vol; foreach (var vm in volMoneynesses) { var strike = Math.Exp(vm * sigma); var call = BlackScholesOption.Price(1.0, strike, vol, mat, 1); //Naive implementation of black-scholes formulae var d_plus = -(vm * sigma) / sigma + 0.5 * sigma; var d_minus = d_plus - sigma; var call_xcheck = NormalDistribution.Cumulative(d_plus) - strike * NormalDistribution.Cumulative(d_minus); if (DoubleUtils.EqualZero(call)) { Assert.IsTrue(DoubleUtils.EqualZero(call_xcheck)); } else { var errRelative = (call - call_xcheck) / call_xcheck; Assert.IsTrue(Math.Abs(errRelative) < 1.0e-11); } } } } }
/// <summary> /// Price option using Lehman Brother proxy. /// </summary> /// <param name="maturity">option maturity</param> /// <param name="strike">option strike</param> /// <param name="vol">volatility</param> /// <param name="q">option type : 1 for call, -1 for put</param> /// <returns></returns> public double PriceLehman(double maturity, double strike, double vol, double q) { double effectiveForward, strikeShift; affineDivUtils.LehmanProxy(maturity, spot, out effectiveForward, out strikeShift); return(BlackScholesOption.Price(effectiveForward, strike + strikeShift, vol, maturity, q)); }
public static object BlackGreek(double fwd, double strike, double maturity, double vol, string request) { return(FunctionRunnerUtils.Run("BlackGreek", () => { double gamma, theta, vega, vanna, vomma; BlackScholesOption.Greeks(fwd, strike, maturity, vol, out gamma, out theta, out vega, out vanna, out vomma); switch (request.Trim().ToLower()) { case "gamma": return gamma; case "theta": return theta; case "vega": return vega; case "vanna": return vanna; case "vomma": return vomma; default: throw new Exception(string.Format("Unknow greek : {0}", request)); } })); }
public static double Cumulative(double forward, double maturity, Func <double, double> vol, double strike) { var v = vol(strike); var dk = strike * 1e-5; var skew = (vol(strike + dk) - vol(strike - dk)) / (2.0 * dk); return(BlackScholesOption.PriceDigit(forward, strike, v, maturity, -1.0, skew)); }
public void Implied_VolSample_Test() { const double mat = 1.0; const double strike = 1.50; var vols = GridUtils.RegularGrid(0.015, 2.0, 100); foreach (double vol in vols) { var option = BlackScholesOption.Price(1.0, strike, vol, mat, 1); var impliedVol = BlackScholesOption.ImpliedVol(option, 1.0, strike, mat, 1); var errRelative = (impliedVol - vol) / vol; Assert.IsTrue(Math.Abs(errRelative) < 6 * DoubleUtils.MachineEpsilon); } }
private double Price(double volBeforeMidT, double volAfterMidT, double q) { double aCvx = a * Math.Exp(-0.5 * volBeforeMidT * volBeforeMidT * midT); var price = 0.0; for (int i = 0; i < z.Length; i++) { double x = aCvx * Math.Exp(volBeforeMidT * z[i]) + b; double midTprice = (x > 0.0) ? BlackScholesOption.Price(x, k, volAfterMidT, dT, q) : (q > 0.0) ? 0.0 : k - x; price += quadWeights[i] * midTprice; } return(price); }
public double PriceProxy(double maturity, double strike, double vol, double q) { var growth = affineDivUtils.AssetGrowth(maturity); double cashBpv = affineDivUtils.CashDivBpv(maturity); double cashBpvTimeWAvg = affineDivUtils.CashBpvTimeWeightedAverage(maturity); double cashBpbAvg = affineDivUtils.CashBpvAverage(0.0, maturity); double volAdj = 1.0 + (cashBpvTimeWAvg - cashBpbAvg) / spot; double displacement = cashBpvTimeWAvg / volAdj; double formulaForward = growth * (spot - displacement); double formulaStrike = strike + growth * (cashBpv - displacement); double formulaVol = vol * volAdj; return(BlackScholesOption.Price(formulaForward, formulaStrike, formulaVol, maturity, q)); }
public void ImpliedVol_MoneynessSample_Test() { const double mat = 0.5; const double vol = 0.253251; var moneynesses = GridUtils.RegularGrid(-5.0, 5.0, 100); foreach (double m in moneynesses) { var strike = Math.Exp(m); var option = BlackScholesOption.Price(1.0, strike, vol, mat, m > 0 ? 1 : -1); var impliedVol = BlackScholesOption.ImpliedVol(option, 1.0, strike, mat, m > 0 ? 1 : -1); var errRelative = (impliedVol - vol) / vol; Assert.IsTrue(Math.Abs(errRelative) < 6 * DoubleUtils.MachineEpsilon); } }
public static object BlackImpliedVol(double forward, double strike, double maturity, double price, string optionType) { return(FunctionRunnerUtils.Run("BlackImpliedVol", () => { double q; switch (optionType.Trim().ToLower()) { case "call": q = 1.0; break; case "put": q = -1.0; break; default: throw new Exception(string.Format("Unknow option type : {0}", optionType)); } return BlackScholesOption.ImpliedVol(price, forward, strike, maturity, q); })); }
/// <summary> /// Implied volatility from option price. (Inversion of the two step quadrature formula.) /// </summary> /// <param name="maturity">option maturity</param> /// <param name="strike">option strike</param> /// <param name="price">option price </param> /// <param name="q">option type : 1 for call, -1 for put</param> /// <returns></returns> public double ImpliedVol(double maturity, double strike, double price, double q) { //Proxy using Lehman Formula double proxyFwd, proxyDk; affineDivUtils.LehmanProxy(maturity, spot, out proxyFwd, out proxyDk); double lehmanTargetVol = BlackScholesOption.ImpliedVol(price, proxyFwd, strike + proxyDk, maturity, q); var pricer = new BsDivPrice(maturity, strike, spot, affineDivUtils, quadPoints, quadWeights); Func <double, double> volToLehmanVolErr = v => BlackScholesOption.ImpliedVol(pricer.Price(v, q), proxyFwd, strike + proxyDk, maturity, q) - lehmanTargetVol; //Solve double v1 = lehmanTargetVol; double err1 = volToLehmanVolErr(v1); double v2 = lehmanTargetVol - err1; double err2 = volToLehmanVolErr(v2); double v3 = v1 - err1 * (v2 - v1) / (err2 - err1); if (Math.Abs(v3 - v2) < v2 * 1.0e-13) { return(v3); } double err3 = volToLehmanVolErr(v3); double v4 = RootUtils.TrinomRoot(v1, v2, v3, err1, err2, err3); if (Math.Abs(v4 - v3) < v3 * 1.0e-13) { return(v4); } double err4 = volToLehmanVolErr(v4); double v5 = RootUtils.TrinomRoot(v2, v3, v4, err2, err3, err4); return(v5); }
public double[] CalibrateVol(double[] maturities, double[] targetPrices, double[] strikes, double[] optionTypes) { Contract.Requires(EnumerableUtils.IsSorted(maturities)); Contract.Requires(maturities.Length == strikes.Length && strikes.Length == targetPrices.Length && targetPrices.Length == optionTypes.Length); double[] variances = new double[maturities.Length + 1]; double[] varPillars = new[] { 0.0 }.Concat(maturities).ToArray(); double[] calibVols = new double[maturities.Length]; for (int step = 0; step < maturities.Length; step++) { var maturity = maturities[step]; var strike = strikes[step]; var targetPrice = targetPrices[step]; var q = optionTypes[step]; //Proxy using Lehman Formula double proxyFwd, proxyDk; affineDivUtils.LehmanProxy(maturity, spot, out proxyFwd, out proxyDk); double lehmanTargetVol = BlackScholesOption.ImpliedVol(targetPrice, proxyFwd, strike + proxyDk, maturity, q); var pricer = new BsDivPrice(maturities[step], strikes[step], spot, affineDivUtils, quadPoints, quadWeights); Func <double, double> volToLehmanVolErr = v => { variances[1 + step] = v * v * maturity; var varFunc = RrFunctions.LinearInterpolation(varPillars, variances); Func <double, double> volFunc = t => Math.Sqrt(varFunc.Eval(t) / t); var price = pricer.Price(volFunc, q); return(BlackScholesOption.ImpliedVol(price, proxyFwd, strike + proxyDk, maturity, q) - lehmanTargetVol); };//TODO use a cache //Bracket & Solve double v1 = lehmanTargetVol; double v2; if (step == 0) { v2 = lehmanTargetVol - volToLehmanVolErr(lehmanTargetVol); } else { var volIfZeroVolOnStep = Math.Sqrt(calibVols[step - 1] * calibVols[step - 1] * maturities[step - 1] / maturities[step]); var minError = volToLehmanVolErr(volIfZeroVolOnStep); if (minError > 0.0) //saturation case { calibVols[step] = volIfZeroVolOnStep; variances[1 + step] = volIfZeroVolOnStep * volIfZeroVolOnStep * maturity; continue; } v2 = volIfZeroVolOnStep; } if (!RootUtils.Bracket(volToLehmanVolErr, v1, v2, out v1, out v2)) { throw new Exception("Failed to inverse vol"); } var impliedVol = RootUtils.Brenth(volToLehmanVolErr, v1, v2, 1.0e-10, 2.0 * DoubleUtils.MachineEpsilon, 10); calibVols[step] = impliedVol; variances[1 + step] = impliedVol * impliedVol * maturity; } return(calibVols); }