public static double NormalVol(double forward, double strike, double time, SABRParams sabr_params) { if (!sabr_params.isValid) { return(Double.NaN); } double alpha = sabr_params.Alpha; double beta = sabr_params.Beta; double rho = sabr_params.Rho; double nu = sabr_params.Nu; double K = strike; double F = forward; double t = time; double A = Pow(F * K, 1.0 - beta); double sqrtA = Sqrt(A); double log_r; if (Abs(F - K) > 1e-12) { log_r = Log(F / K); } else { double epsilon = (F - K) / K; log_r = epsilon - 0.5 * epsilon * epsilon; } double z = (nu / alpha) * sqrtA * log_r; double B = 1.0 - 2.0 * rho * z + z * z; double C = (1.0 - beta) * (1.0 - beta) * log_r * log_r; double D = log_r * log_r; double tmp = (Sqrt(B) + z - rho) / (1.0 - rho); double xx = Log(tmp); double E_1 = (1.0 + D / 24.0 + D * D / 1920.0); double E_2 = (1.0 + C / 24.0 + C * C / 1920.0); double E = E_1 / E_2; double d = 1.0 + t * (-beta * (2 - beta) * alpha * alpha / (24.0 * A) + 0.25 * rho * beta * nu * alpha / sqrtA + (2.0 - 3.0 * rho * rho) * (nu * nu / 24.0)); double coef; if (Abs(z * z) > 2.22045e-15) { coef = z / xx; } else { coef = 1.0 - 0.5 * rho * z - (3.0 * rho * rho - 2.0) * z * z / 12.0; } return(alpha * Pow(F * K, beta / 2.0) * E * coef * d); }
public static double Price(double forward, double strike, double time, double rate, SABRParams sabr_params, bool isCall, bool useNormalApprox = false) { double price = Double.NaN; if (sabr_params.isValid) { if (useNormalApprox) { double normal_vol = HaganSABR.NormalVol(forward, strike, time, sabr_params); price = Bachelier.Price(forward, strike, time, rate, normal_vol, isCall); } else { double black_vol = HaganSABR.BlackVol(forward, strike, time, sabr_params); price = Black.Price(forward, strike, time, rate, black_vol, isCall); } } return(price); }