public static double beta_black(double beta, OptionType optType, double F, double K, double T, double sigma) { if (T < 0.0) { throw FS.FailWith($"T < 0 not allowed, {T}"); } if (sigma < 0.0) { throw FS.FailWith($"sigma < 0 not allowed {sigma}"); } var stdev = sigma * Math.Sqrt(T); if (stdev == 0.0) { return(Math.Max(optType.ToEpsilon() * (F - K), 0.0)); } var mu = inv_m1_beta_black(beta, F, stdev); var d = (inv_g(beta, K) - mu) / stdev; var t1 = K * SpecialFunction.cdf_normal(d); var t2 = beta_black_trunc(beta, mu, stdev, d); var put = t1 - t2; var intrinsic = Math.Max(optType.ToEpsilon() * (F - K), 0.0); if (optType == OptionType.Put) { return(Math.Max(put, intrinsic)); } else if (optType == OptionType.Call) { return(Math.Max(put + F - K, intrinsic)); } else { throw FS.E_CASE(optType); } }
public static double beta_black_b(double beta, OptionType optType, double F, double K, double T, double sigma , ref double beta_b, ref double F_b, ref double K_b, ref double T_b, ref double sigma_b, double res_b) { if (T < 0.0) { throw FS.FailWith($"T < 0 not allowed, {T}"); } if (sigma < 0.0) { throw FS.FailWith($"sigma < 0 not allowed {sigma}"); } var sqrtT = Math.Sqrt(T); var stdev = sigma * sqrtT; if (stdev == 0.0) { return(Math.Max(optType.ToEpsilon() * (F - K), 0.0)); } var dmu_dbeta = 0.0; var dmu_dF = 0.0; var dmu_dstdev = 0.0; var mu = inv_m1_beta_black_b(beta, F, stdev, ref dmu_dbeta, ref dmu_dF, ref dmu_dstdev, 1.0); var digb_dbeta = 0.0; var digb_dK = 0.0; var igb = inv_g_b(beta, K, ref digb_dbeta, ref digb_dK, 1.0); var d = (igb - mu) / stdev; var dNd_dd = 0.0; var Nd = SpecialFunction.cdf_normal_b(d, ref dNd_dd, 1.0); var t1 = K * Nd; var dt2_dbeta = 0.0; var dt2_dmu = 0.0; var dt2_dstdev = 0.0; var dt2_dd = 0.0; var t2 = beta_black_trunc_b(beta, mu, stdev, d, ref dt2_dbeta, ref dt2_dmu, ref dt2_dstdev, ref dt2_dd, 1.0); var res = t1 - t2; // now rewind var t1_b = res_b; var t2_b = -res_b; beta_b += t2_b * dt2_dbeta; var mu_b = t2_b * dt2_dmu; var stdev_b = t2_b * dt2_dstdev; var d_b = t2_b * dt2_dd; K_b += t1_b * Nd; var Nd_b = t1_b * K; d_b += Nd_b * dNd_dd; var igb_b = d_b / stdev; mu_b += -d_b / stdev; stdev_b += -d_b * (igb - mu) / stdev / stdev; beta_b += igb_b * digb_dbeta; K_b += igb_b * digb_dK; beta_b += mu_b * dmu_dbeta; F_b += mu_b * dmu_dF; stdev_b += mu_b * dmu_dstdev; sigma_b += stdev_b * sqrtT; T_b += stdev_b * sigma / (2.0 * sqrtT); if (optType == OptionType.Put) { return(res); } else if (optType == OptionType.Call) { F_b += res_b; K_b += -res_b; return(res + F - K); } else { throw FS.E_CASE(optType); } }