Example #1
0
        public static double beta_black_normal_vol(double beta, double F, double K, double T, double sigma)
        {
            var optType = OptionType.Put; // F > K ? OptionType.Put : OptionType.Call;
            var bbPrice = beta_black(beta, optType, F, K, T, sigma);

            try
            {
                return(ClosedForm.ibachelier(optType, F, K, T, bbPrice));
            }
            catch (Exception e)
            {
                FS.WithInfo(e, $"beta ={beta}, optType = {optType}, F = {F}, K = {K}, T = {T}, sigma = {sigma}, bbPrice = {bbPrice}");
                throw;
            }
        }
Example #2
0
        public static double black76(OptionType optType, double F, double K, double sdev)
        {
            var num = optType.ToEpsilon();

            if (sdev < 0.0)
            {
                throw FS.FailWith($"sdev must be positive. Got {sdev}");
            }
            if (sdev == 0.0 || K <= 0.0)
            {
                return(Math.Max(num * (F - K), 0.0));
            }
            else
            {
                var num2 = (Math.Log(F / K) + 0.5 * sdev * sdev) / sdev;
                var num3 = num2 - sdev;
                return(num * (F * SpecialFunction.cdf_normal(num * num2) -
                              K * SpecialFunction.cdf_normal(num * num3)));
            }
        }
Example #3
0
        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);
            }
        }
Example #4
0
 private static double lambert_w_boost(double z)
 {
     if (z < 6.0)
     {
         throw FS.FailWith("require(z > 6)");
     }
     else if (z < 18)
     {
         // 6 < z < 18
         // Max error in interpolated form: 1.985e-19
         const double offset = 1.80937194824218750e+00;
         double[]     P      =
         {
             -1.80690935424793635e+00,
             -3.66995929380314602e+00,
             -1.93842957940149781e+00,
             -2.94269984375794040e-01,
             1.81224710627677778e-03,
             2.48166798603547447e-03,
             1.15806592415397245e-04,
             1.43105573216815533e-06,
             3.47281483428369604e-09
         };
         double[] Q =
         {
             1.00000000000000000e+00,
             2.57319080723908597e+00,
             1.96724528442680658e+00,
             5.84501352882650722e-01,
             7.37152837939206240e-02,
             3.97368430940416778e-03,
             8.54941838187085088e-05,
             6.05713225608426678e-07,
             8.17517283816615732e-10
         };
         return(offset + boost_math_tools_evaluate_rational(P, Q, z));
     }
     else if (z < 9897.12905874)  // 2.8 < log(z) < 9.2
     {
         // Max error in interpolated form: 1.195e-18
         double   Y = -1.40297317504882812e+00;
         double[] P =
         {
             1.97011826279311924e+00,
             1.05639945701546704e+00,
             3.33434529073196304e-01,
             3.34619153200386816e-02,
             -5.36238353781326675e-03,
             -2.43901294871308604e-03,
             -2.13762095619085404e-04,
             -4.85531936495542274e-06,
             -2.02473518491905386e-08,
         };
         double[] Q =
         {
             1.00000000000000000e+00,
             8.60107275833921618e-01,
             4.10420467985504373e-01,
             1.18444884081994841e-01,
             2.16966505556021046e-02,
             2.24529766630769097e-03,
             9.82045090226437614e-05,
             1.36363515125489502e-06,
             3.44200749053237945e-09,
         };
         var log_w = Math.Log(z);
         return(log_w + Y + boost_math_tools_evaluate_rational(P, Q, log_w));
     }
     else if (z < 7.896296e+13)  // 9.2 < log(z) <= 32
     {
         // Max error in interpolated form: 6.529e-18
         double   Y = -2.73572921752929688e+00;
         double[] P =
         {
             3.30547638424076217e+00,
             1.64050071277550167e+00,
             4.57149576470736039e-01,
             4.03821227745424840e-02,
             -4.99664976882514362e-04,
             -1.28527893803052956e-04,
             -2.95470325373338738e-06,
             -1.76662025550202762e-08,
             -1.98721972463709290e-11,
         };
         double[] Q =
         {
             1.00000000000000000e+00,
             6.91472559412458759e-01,
             2.48154578891676774e-01,
             4.60893578284335263e-02,
             3.60207838982301946e-03,
             1.13001153242430471e-04,
             1.33690948263488455e-06,
             4.97253225968548872e-09,
             3.39460723731970550e-12,
         };
         var log_w = Math.Log(z);
         return(log_w + Y + boost_math_tools_evaluate_rational(P, Q, log_w));
     }
     else if (z < 2.6881171e+43) // 32 < log(z) < 100
     {
         // Max error in interpolated form: 2.015e-18
         double   Y = -4.01286315917968750e+00;
         double[] P =
         {
             5.07714858354309672e+00,
             -3.32994414518701458e+00,
             -8.61170416909864451e-01,
             -4.01139705309486142e-02,
             -1.85374201771834585e-04,
             1.08824145844270666e-05,
             1.17216905810452396e-07,
             2.97998248101385990e-10,
             1.42294856434176682e-13,
         };
         double[] Q =
         {
             1.00000000000000000e+00,
             -4.85840770639861485e-01,
             -3.18714850604827580e-01,
             -3.20966129264610534e-02,
             -1.06276178044267895e-03,
             -1.33597828642644955e-05,
             -6.27900905346219472e-08,
             -9.35271498075378319e-11,
             -2.60648331090076845e-14,
         };
         var log_w = Math.Log(z);
         return(log_w + Y + boost_math_tools_evaluate_rational(P, Q, log_w));
     }
     else // 100 < log(z) < 710
     {
         // Max error in interpolated form: 5.277e-18
         double   Y = -5.70115661621093750e+00;
         double[] P =
         {
             6.42275660145116698e+00,
             1.33047964073367945e+00,
             6.72008923401652816e-02,
             1.16444069958125895e-03,
             7.06966760237470501e-06,
             5.48974896149039165e-09,
             -7.00379652018853621e-11,
             -1.89247635913659556e-13,
             -1.55898770790170598e-16,
             -4.06109208815303157e-20,
             -2.21552699006496737e-24,
         };
         double[] Q =
         {
             1.00000000000000000e+00,
             3.34498588416632854e-01,
             2.51519862456384983e-02,
             6.81223810622416254e-04,
             7.94450897106903537e-06,
             4.30675039872881342e-08,
             1.10667669458467617e-10,
             1.31012240694192289e-13,
             6.53282047177727125e-17,
             1.11775518708172009e-20,
             3.78250395617836059e-25,
         };
         var log_w = Math.Log(z);
         return(log_w + Y + boost_math_tools_evaluate_rational(P, Q, log_w));
     }
 }
Example #5
0
        public static double cdfinv_normal(double p)

        /******************************************************************************/

        /*
         * Purpose:
         *
         *  R8_NORMAL_01_CDF_INVERSE inverts the standard normal CDF.
         *
         * Discussion:
         *
         *  The result is accurate to about 1 part in 10^16.
         *
         * Licensing:
         *
         *  This code is distributed under the GNU LGPL license.
         *
         * Modified:
         *
         *  19 March 2010
         *
         * Author:
         *
         *  Original FORTRAN77 version by Michael Wichura.
         *  C version by John Burkardt.
         *
         * Reference:
         *
         *  Michael Wichura,
         *  The Percentage Points of the Normal Distribution,
         *  Algorithm AS 241,
         *  Applied Statistics,
         *  Volume 37, Number 3, pages 477-484, 1988.
         *
         * Parameters:
         *
         *  Input, double P, the value of the cumulative probability
         *  densitity function.  0 < P < 1.  If P is outside this range, an "infinite"
         *  value is returned.
         *
         *  Output, double R8_NORMAL_01_CDF_INVERSE, the normal deviate value
         *  with the property that the probability of a standard normal deviate being
         *  less than or equal to this value is P.
         */
        {
            var const1 = 0.180625;
            var const2 = 1.6;

            double q;
            double r;
            var    split1 = 0.425;
            var    split2 = 5.0;
            double value;

            if (p <= 0.0)
            {
                if (p < 0)
                {
                    throw FS.FailWith($"p is lower than 0, with {p}");
                }
                value = -R8_HUGE;//r8_huge ( );
                return(value);
            }

            if (1.0 <= p)
            {
                if (p > 1)
                {
                    throw FS.FailWith($"p is higher than 1 with {p}");
                }
                value = R8_HUGE; // r8_huge ( );

                return(value);
            }

            q = p - 0.5;

            //if ( r8_abs ( q ) <= split1 )
            if (Math.Abs(q) <= split1)
            {
                r     = const1 - q * q;
                value = q * (((((((a[7] * r + a[6]) * r + a[5]) * r + a[4]) * r + a[3]) * r + a[2]) * r + a[1]) * r + a[0]) /
                        (((((((b[7] * r + b[6]) * r + b[5]) * r + b[4]) * r + b[3]) * r + b[2]) * r + b[1]) * r + b[0]);
            }
            else
            {
                if (q < 0.0)
                {
                    r = p;
                }
                else
                {
                    r = 1.0 - p;
                }

                if (r <= 0.0)
                {
                    value = -1.0;
                    throw FS.FailWith($"Error, cdfinv with p = {p}");
                    //exit ( 1 );// exception??
                }

                r = Math.Sqrt(-Math.Log(r));

                if (r <= split2)
                {
                    r     = r - const2;
                    value = (((((((c[7] * r + c[6]) * r + c[5]) * r + c[4]) * r + c[3]) * r + c[2]) * r + c[1]) * r + c[0]) /
                            (((((((d[7] * r + d[6]) * r + d[5]) * r + d[4]) * r + d[3]) * r + d[2]) * r + d[1]) * r + d[0]);
                }
                else
                {
                    r     = r - split2;
                    value = (((((((e[7] * r + e[6]) * r + e[5]) * r + e[4]) * r + e[3]) * r + e[2]) * r + e[1]) * r + e[0]) /
                            (((((((f[7] * r + f[6]) * r + f[5]) * r + f[4]) * r + f[3]) * r + f[2]) * r + f[1]) * r + f[0]);
                }

                if (q < 0.0)
                {
                    value = -value;
                }
            }
            return(value);
        }
Example #6
0
        public BetaBlackPack(double beta, OptionType callPut, double f, double k, double t, double sigma)
        {
            if (beta < 0 || beta >= 1.0)
            {
                throw FS.FailWith($"Beta must be in [0, 1.0), got {beta}");
            }
            if (sigma <= 0.0)
            {
                throw FS.FailWith($"Sigma must be positive, got {sigma}");
            }
            Beta    = beta;
            CallPut = callPut;
            F       = f;
            K       = k;
            T       = t;
            Sigma   = sigma;

            //! Nota bene: Use AD for first order derivatives and FD on AD for second order

            //
            // Mu = BetaBlack.inv_m1_beta_black(beta, f, sigma * Math.Sqrt(t));
            double beta_b  = 0.0;
            double f_b     = 0.0;
            double k_b     = 0.0;
            double t_b     = 0.0;
            double sigma_b = 0.0;

            Price     = BetaBlack.beta_black_b(beta, callPut, f, k, t, sigma, ref beta_b, ref f_b, ref k_b, ref t_b, ref sigma_b, 1.0);
            dPV_dS    = f_b;
            dPV_dK    = k_b;
            dPV_dT    = t_b;
            dPV_dVol  = sigma_b;
            dPV_dBeta = beta_b;

            var eps = Math.Sqrt(DoubleUtils.DoubleEpsilon);
            {
                var    dF          = eps * (1.0 + Math.Abs(f));
                double betaUp_b    = 0.0;
                double fUp_b       = 0.0;
                double kUp_b       = 0.0;
                double tUp_b       = 0.0;
                double sigmaUp_b   = 0.0;
                double pUp         = BetaBlack.beta_black_b(beta, callPut, f + dF, k, t, sigma, ref betaUp_b, ref fUp_b, ref kUp_b, ref tUp_b, ref sigmaUp_b, 1.0);
                double betaDown_b  = 0.0;
                double fDown_b     = 0.0;
                double kDown_b     = 0.0;
                double tDown_b     = 0.0;
                double sigmaDown_b = 0.0;
                double pDown       = BetaBlack.beta_black_b(beta, callPut, f - dF, k, t, sigma, ref betaDown_b, ref fDown_b, ref kDown_b, ref tDown_b, ref sigmaDown_b, 1.0);
                d2PV_dFdBeta = (betaUp_b - betaDown_b) / (2.0 * dF);
                d2PV_dS2     = (fUp_b - fDown_b) / (2.0 * dF);
                d2PV_dKdS    = (kUp_b - kDown_b) / (2.0 * dF);
                d2PV_dSdT    = (tUp_b - tDown_b) / (2.0 * dF);
                d2PV_dSdVol  = (sigmaUp_b - sigmaDown_b) / (2.0 * dF);
            }

            {
                var    dK          = eps * (1.0 + Math.Abs(k));
                double betaUp_b    = 0.0;
                double fUp_b       = 0.0;
                double kUp_b       = 0.0;
                double tUp_b       = 0.0;
                double sigmaUp_b   = 0.0;
                double pUp         = BetaBlack.beta_black_b(beta, callPut, f, k + dK, t, sigma, ref betaUp_b, ref fUp_b, ref kUp_b, ref tUp_b, ref sigmaUp_b, 1.0);
                double betaDown_b  = 0.0;
                double fDown_b     = 0.0;
                double kDown_b     = 0.0;
                double tDown_b     = 0.0;
                double sigmaDown_b = 0.0;
                double pDown       = BetaBlack.beta_black_b(beta, callPut, f, k - dK, t, sigma, ref betaDown_b, ref fDown_b, ref kDown_b, ref tDown_b, ref sigmaDown_b, 1.0);
                d2PV_dKdBeta = (betaUp_b - betaDown_b) / (2.0 * dK);
                // d2PV_dKdS = (fUp_b - fDown_b) / (2.0 * dK);
                d2PV_dK2    = (kUp_b - kDown_b) / (2.0 * dK);
                d2PV_dKdT   = (tUp_b - tDown_b) / (2.0 * dK);
                d2PV_dVoldK = (sigmaUp_b - sigmaDown_b) / (2.0 * dK);
            }

            {
                var    dSigma      = eps * (1.0 + Math.Abs(sigma));
                double betaUp_b    = 0.0;
                double fUp_b       = 0.0;
                double kUp_b       = 0.0;
                double tUp_b       = 0.0;
                double sigmaUp_b   = 0.0;
                double pUp         = BetaBlack.beta_black_b(beta, callPut, f, k, t, sigma + dSigma, ref betaUp_b, ref fUp_b, ref kUp_b, ref tUp_b, ref sigmaUp_b, 1.0);
                double betaDown_b  = 0.0;
                double fDown_b     = 0.0;
                double kDown_b     = 0.0;
                double tDown_b     = 0.0;
                double sigmaDown_b = 0.0;
                double pDown       = BetaBlack.beta_black_b(beta, callPut, f, k, t, sigma - dSigma, ref betaDown_b, ref fDown_b, ref kDown_b, ref tDown_b, ref sigmaDown_b, 1.0);
                d2PV_dVoldBeta = (betaUp_b - betaDown_b) / (2.0 * dSigma);
                // d2PV_dSdVol = (fUp_b - fDown_b) / (2.0 * dSigma);
                // d2PV_dVoldK = (kUp_b - kDown_b) / (2.0 * dSigma);
                d2PV_dVoldT = (tUp_b - tDown_b) / (2.0 * dSigma);
                d2PV_dVol2  = (sigmaUp_b - sigmaDown_b) / (2.0 * dSigma);
            }
        }
Example #7
0
        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);
            }
        }