914 lines
39 KiB
MQL5
914 lines
39 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| Normal.mqh |
|
|
//| Copyright 2000-2025, MetaQuotes Ltd. |
|
|
//| https://www.mql5.com |
|
|
//+------------------------------------------------------------------+
|
|
#include "Math.mqh"
|
|
|
|
const static double normal_cdf_a[5]=
|
|
{
|
|
2.2352520354606839287E00,1.6102823106855587881E02,
|
|
1.0676894854603709582E03,1.8154981253343561249E04,
|
|
6.5682337918207449113E-2
|
|
};
|
|
const static double normal_cdf_b[4]=
|
|
{
|
|
4.7202581904688241870E01,9.7609855173777669322E02,
|
|
1.0260932208618978205E04,4.5507789335026729956E04
|
|
};
|
|
//--- coefficients for approximation in second interval
|
|
const static double normal_cdf_c[9]=
|
|
{
|
|
3.9894151208813466764E-1,8.8831497943883759412E00,
|
|
9.3506656132177855979E01,5.9727027639480026226E02,
|
|
2.4945375852903726711E03,6.8481904505362823326E03,
|
|
1.1602651437647350124E04,9.8427148383839780218E03,
|
|
1.0765576773720192317E-8
|
|
};
|
|
const static double normal_cdf_d[8]=
|
|
{
|
|
2.2266688044328115691E01,2.3538790178262499861E02,
|
|
1.5193775994075548050E03,6.4855582982667607550E03,
|
|
1.8615571640885098091E04,3.4900952721145977266E04,
|
|
3.8912003286093271411E04,1.9685429676859990727E04
|
|
};
|
|
//--- coefficients for approximation in third interval
|
|
const static double normal_cdf_p[6]=
|
|
{
|
|
2.1589853405795699E-1,1.274011611602473639E-1,
|
|
2.2235277870649807E-2,1.421619193227893466E-3,
|
|
2.9112874951168792E-5,2.307344176494017303E-2
|
|
};
|
|
const static double normal_cdf_q[5]=
|
|
{
|
|
1.28426009614491121E00,4.68238212480865118E-1,
|
|
6.59881378689285515E-2,3.78239633202758244E-3,
|
|
7.29751555083966205E-5
|
|
};
|
|
|
|
//--- coefficients for p close to 0.5
|
|
const double normal_q_a0 = 3.3871328727963666080;
|
|
const double normal_q_a1 = 1.3314166789178437745E+2;
|
|
const double normal_q_a2 = 1.9715909503065514427E+3;
|
|
const double normal_q_a3 = 1.3731693765509461125E+4;
|
|
const double normal_q_a4 = 4.5921953931549871457E+4;
|
|
const double normal_q_a5 = 6.7265770927008700853E+4;
|
|
const double normal_q_a6 = 3.3430575583588128105E+4;
|
|
const double normal_q_a7 = 2.5090809287301226727E+3;
|
|
const double normal_q_b1 = 4.2313330701600911252E+1;
|
|
const double normal_q_b2 = 6.8718700749205790830E+2;
|
|
const double normal_q_b3 = 5.3941960214247511077E+3;
|
|
const double normal_q_b4 = 2.1213794301586595867E+4;
|
|
const double normal_q_b5 = 3.9307895800092710610E+4;
|
|
const double normal_q_b6 = 2.8729085735721942674E+4;
|
|
const double normal_q_b7 = 5.2264952788528545610E+3;
|
|
//--- coefficients for p not close to 0, 0.5 or 1
|
|
const double normal_q_c0 = 1.42343711074968357734;
|
|
const double normal_q_c1 = 4.63033784615654529590;
|
|
const double normal_q_c2 = 5.76949722146069140550;
|
|
const double normal_q_c3 = 3.64784832476320460504;
|
|
const double normal_q_c4 = 1.27045825245236838258;
|
|
const double normal_q_c5 = 2.41780725177450611770E-1;
|
|
const double normal_q_c6 = 2.27238449892691845833E-2;
|
|
const double normal_q_c7 = 7.74545014278341407640E-4;
|
|
const double normal_q_d1 = 2.05319162663775882187;
|
|
const double normal_q_d2 = 1.67638483018380384940;
|
|
const double normal_q_d3 = 6.89767334985100004550E-1;
|
|
const double normal_q_d4 = 1.48103976427480074590E-1;
|
|
const double normal_q_d5 = 1.51986665636164571966E-2;
|
|
const double normal_q_d6 = 5.47593808499534494600E-4;
|
|
const double normal_q_d7 = 1.05075007164441684324E-9;
|
|
//--- coefficients for p near 0 or 1.
|
|
const double normal_q_e0 = 6.65790464350110377720E0;
|
|
const double normal_q_e1 = 5.46378491116411436990E0;
|
|
const double normal_q_e2 = 1.78482653991729133580E0;
|
|
const double normal_q_e3 = 2.96560571828504891230E-1;
|
|
const double normal_q_e4 = 2.65321895265761230930E-2;
|
|
const double normal_q_e5 = 1.24266094738807843860E-3;
|
|
const double normal_q_e6 = 2.71155556874348757815E-5;
|
|
const double normal_q_e7 = 2.01033439929228813265E-7;
|
|
const double normal_q_f1 = 5.99832206555887937690E-1;
|
|
const double normal_q_f2 = 1.36929880922735805310E-1;
|
|
const double normal_q_f3 = 1.48753612908506148525E-2;
|
|
const double normal_q_f4 = 7.86869131145613259100E-4;
|
|
const double normal_q_f5 = 1.84631831751005468180E-5;
|
|
const double normal_q_f6 = 1.42151175831644588870E-7;
|
|
const double normal_q_f7 = 2.04426310338993978564E-15;
|
|
//+------------------------------------------------------------------+
|
|
//| Normal probability density function (PDF) |
|
|
//+------------------------------------------------------------------+
|
|
//| The function returns the probability density function |
|
|
//| of the Normal distribution with parameters mu and sigma. |
|
|
//| |
|
|
//| Arguments: |
|
|
//| x : Random variable |
|
|
//| mu : Mean |
|
|
//| sigma : Standard deviation (sigma>0) |
|
|
//| log_mode : Logarithm mode flag, if true it returns Log values |
|
|
//| error_code : Variable for error code |
|
|
//| |
|
|
//| Return value: |
|
|
//| The probability density evaluated at x. |
|
|
//+------------------------------------------------------------------+
|
|
double MathProbabilityDensityNormal(const double x,const double mu,const double sigma,const bool log_mode,int &error_code)
|
|
{
|
|
//--- check NaN
|
|
if(!MathIsValidNumber(x) || !MathIsValidNumber(mu) || !MathIsValidNumber(sigma))
|
|
{
|
|
error_code=ERR_ARGUMENTS_NAN;
|
|
return QNaN;
|
|
}
|
|
//--- check sigma
|
|
if(sigma<=0)
|
|
{
|
|
error_code=ERR_ARGUMENTS_INVALID;
|
|
return QNaN;
|
|
}
|
|
|
|
error_code=ERR_OK;
|
|
|
|
//--- prepare argument
|
|
double y=(x-mu)/sigma;
|
|
//--- check it
|
|
if(!MathIsValidNumber(y))
|
|
{
|
|
error_code=ERR_ARGUMENTS_INVALID;
|
|
return QNaN;
|
|
}
|
|
//--- check overflow
|
|
y=MathAbs(y);
|
|
if(y>=2*MathSqrt(DBL_MAX))
|
|
{
|
|
error_code=ERR_ARGUMENTS_INVALID;
|
|
return QNaN;
|
|
}
|
|
//--- return density
|
|
return TailLogValue(M_1_SQRT_2PI*MathExp(-0.5*y*y)/sigma,true,log_mode);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Normal probability density function (PDF) |
|
|
//+------------------------------------------------------------------+
|
|
//| The function returns the probability density function |
|
|
//| of the Normal distribution with parameters mu and sigma. |
|
|
//| |
|
|
//| Arguments: |
|
|
//| x : Random variable |
|
|
//| mu : Mean |
|
|
//| sigma : Standard deviation (sigma>0) |
|
|
//| error_code : Variable for error code |
|
|
//| |
|
|
//| Return value: |
|
|
//| The probability density evaluated at x. |
|
|
//+------------------------------------------------------------------+
|
|
double MathProbabilityDensityNormal(const double x,const double mu,const double sigma,int &error_code)
|
|
{
|
|
return MathProbabilityDensityNormal(x,mu,sigma,false,error_code);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Normal probability density function (PDF) |
|
|
//+------------------------------------------------------------------+
|
|
//| The function calculates the probability density function of |
|
|
//| the Normal distribution with parameters mu and sigma |
|
|
//| for values in x. |
|
|
//| |
|
|
//| Arguments: |
|
|
//| x : Array with random variables |
|
|
//| mu : Mean |
|
|
//| sigma : Standard deviation (sigma>0) |
|
|
//| log_mode : Logarithm mode flag, if true it returns Log values |
|
|
//| result : Array with calculated values |
|
|
//| |
|
|
//| Return value: |
|
|
//| true if successful, otherwise false. |
|
|
//+------------------------------------------------------------------+
|
|
bool MathProbabilityDensityNormal(const double &x[],const double mu,const double sigma,const bool log_mode,double &result[])
|
|
{
|
|
//--- check NaN
|
|
if(!MathIsValidNumber(mu) || !MathIsValidNumber(sigma))
|
|
return false;
|
|
//--- check sigma
|
|
if(sigma<=0)
|
|
return false;
|
|
|
|
int data_count=ArraySize(x);
|
|
if(data_count==0)
|
|
return false;
|
|
|
|
int error_code=0;
|
|
ArrayResize(result,data_count);
|
|
|
|
for(int i=0; i<data_count; i++)
|
|
{
|
|
double x_arg=x[i];
|
|
|
|
if(!MathIsValidNumber(x_arg))
|
|
return false;
|
|
|
|
//--- prepare argument and check it
|
|
double y=(x_arg-mu)/sigma;
|
|
if(!MathIsValidNumber(y))
|
|
return false;
|
|
|
|
//--- check overflow
|
|
y=MathAbs(y);
|
|
if(y>=2*MathSqrt(DBL_MAX))
|
|
return false;
|
|
|
|
//--- calculate density
|
|
result[i]=TailLogValue(M_1_SQRT_2PI*MathExp(-0.5*y*y)/sigma,true,log_mode);
|
|
}
|
|
return true;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Normal probability density function (PDF) |
|
|
//+------------------------------------------------------------------+
|
|
//| The function calculates the probability density function of |
|
|
//| the Normal distribution with parameters mu and sigma |
|
|
//| for values in x[] array. |
|
|
//| |
|
|
//| Arguments: |
|
|
//| x : Array with random variables |
|
|
//| mu : Mean |
|
|
//| sigma : Standard deviation (sigma>0) |
|
|
//| result : Array with calculated values |
|
|
//| |
|
|
//| Return value: |
|
|
//| true if successful, otherwise false. |
|
|
//+------------------------------------------------------------------+
|
|
bool MathProbabilityDensityNormal(const double &x[],const double mu,const double sigma,double &result[])
|
|
{
|
|
return MathProbabilityDensityNormal(x,mu,sigma,false,result);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Normal cumulative distribution function (CDF) |
|
|
//+------------------------------------------------------------------+
|
|
//| The function returns the probability that an observation |
|
|
//| from the Normal distribution with parameters mu and sigma |
|
|
//| is less than or equal to x. |
|
|
//| |
|
|
//| Arguments: |
|
|
//| x : The desired quantile |
|
|
//| mu : Mean |
|
|
//| sigma : Standard deviation (must be positive) |
|
|
//| tail : Flag to calculate lower tail |
|
|
//| log_mode : Logarithm mode, if true it calculates Log values |
|
|
//| error_code : Variable for error code |
|
|
//| |
|
|
//| Return value: |
|
|
//| The value of the Normal cumulative distribution function with |
|
|
//| parameters mu and sigma, evaluated at x. |
|
|
//+------------------------------------------------------------------+
|
|
//| Comment from original FORTRAN code |
|
|
//| https://www.netlib.org/toms-2014-06-10/639 |
|
|
//| https://www.netlib.org/toms-2014-06-10/715 |
|
|
//| |
|
|
//| This function evaluates the normal distribution function: |
|
|
//| |
|
|
//| / x |
|
|
//| 1 | -t*t/2 |
|
|
//| P(x) = ----------- | e dt |
|
|
//| sqrt(2 pi) | |
|
|
//| /-oo |
|
|
//| |
|
|
//| The main computation evaluates near-minimax approximations |
|
|
//| derived from those in "Rational Chebyshev approximations for |
|
|
//| the error function" by W. J. Cody, Math. Comp., 1969, 631-637. |
|
|
//| This transportable program uses rational functions that |
|
|
//| theoretically approximate the normal distribution function to |
|
|
//| at least 18 significant decimal digits. The accuracy achieved |
|
|
//| depends on the arithmetic system, the compiler, the intrinsic |
|
|
//| functions, and proper selection of the machine-dependent |
|
|
//| constants. |
|
|
//| |
|
|
//| Author: |
|
|
//| W. J. Cody, Mathematics and Computer Science Division |
|
|
//| Argonne National Laboratory, Argonne, IL 60439 |
|
|
//+------------------------------------------------------------------+
|
|
double MathCumulativeDistributionNormal(const double x,const double mu,const double sigma,const bool tail,const bool log_mode,int &error_code)
|
|
{
|
|
//--- check NaN
|
|
if(!MathIsValidNumber(x) || !MathIsValidNumber(mu) || !MathIsValidNumber(sigma))
|
|
{
|
|
error_code=ERR_ARGUMENTS_NAN;
|
|
return QNaN;
|
|
}
|
|
//--- check sigma
|
|
if(sigma<=0)
|
|
{
|
|
error_code=ERR_ARGUMENTS_INVALID;
|
|
return QNaN;
|
|
}
|
|
|
|
error_code=ERR_OK;
|
|
//--- prepare argument
|
|
double xx=(x-mu)/sigma;
|
|
//--- mathematical constants
|
|
//--- sqrpi = 1 / sqrt(2*pi), root32 = sqrt(32), and
|
|
//--- thrsh is the argument for which anorm = 0.75.
|
|
const double sqrpi=1.0/MathSqrt(2*M_PI);
|
|
const double thrsh = 0.66291e0;
|
|
const double root32= MathSqrt(32);
|
|
//--- machine-dependent constants
|
|
//--- data eps/5.96e-8/,xlow/-12.949e0/,xuppr/5.768e0/
|
|
const double eps=1.11e-16;
|
|
const double xlow=-37.519;
|
|
const double xuppr=8.572;
|
|
int k;
|
|
//---
|
|
double xsq=0.0;
|
|
double y=MathAbs(xx);
|
|
double xnum=0.0;
|
|
double xden=0.0;
|
|
double cdf=0.0;
|
|
double del=0.0;
|
|
//---
|
|
if(y<=thrsh)
|
|
{
|
|
//--- evaluate for |x| <= 0.66291
|
|
if(y>eps)
|
|
xsq=xx*xx;
|
|
|
|
xnum = normal_cdf_a[4] * xsq;
|
|
xden = xsq;
|
|
for(k=0; k<3; k++)
|
|
{
|
|
xnum=(xnum+normal_cdf_a[k])*xsq;
|
|
xden=(xden+normal_cdf_b[k])*xsq;
|
|
}
|
|
cdf = xx*(xnum+normal_cdf_a[3])/(xden+normal_cdf_b[3]);
|
|
cdf = 0.5 + cdf;
|
|
}
|
|
else
|
|
if(y<=root32)
|
|
{
|
|
//--- evaluate for 0.66291 <= |x| <= sqrt(32)
|
|
xnum = normal_cdf_c[8]*y;
|
|
xden = y;
|
|
for(k=0; k<7; k++)
|
|
{
|
|
xnum=(xnum+normal_cdf_c[k])*y;
|
|
xden=(xden+normal_cdf_d[k])*y;
|
|
}
|
|
cdf=(xnum+normal_cdf_c[7])/(xden+normal_cdf_d[7]);
|
|
xsq=int(y*16)/16;
|
|
del=(y-xsq)*(y+xsq);
|
|
cdf=MathExp(-xsq*xsq*0.5)*MathExp(-del*0.5)*cdf;
|
|
if(xx>0.0) cdf=1.0-cdf;
|
|
}
|
|
//--- evaluate for |x| > sqrt(32)
|
|
else
|
|
{
|
|
cdf=0.0;
|
|
if((xx>=xlow) && (xx<xuppr))
|
|
{
|
|
xsq=1.0/(xx*xx);
|
|
xnum = normal_cdf_p[5]*xsq;
|
|
xden = xsq;
|
|
for(k=0; k<3; k++)
|
|
{
|
|
xnum=(xnum+normal_cdf_p[k])*xsq;
|
|
xden=(xden+normal_cdf_q[k])*xsq;
|
|
}
|
|
cdf=xsq*(xnum+normal_cdf_p[4])/(xden+normal_cdf_q[4]);
|
|
cdf=(sqrpi-cdf)/y;
|
|
xsq=int(xx*16)/16;
|
|
del=(xx-xsq)*(xx+xsq);
|
|
cdf=MathExp(-xsq*xsq*0.5)*MathExp(-del*0.5)*cdf;
|
|
}
|
|
if(xx>0.0) cdf=1.0-cdf;
|
|
}
|
|
//--- take into account round-off errors for probability
|
|
return TailLogValue(MathMin(cdf,1.0),tail,log_mode);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Normal cumulative distribution function (CDF) |
|
|
//+------------------------------------------------------------------+
|
|
//| The function returns the probability that an observation |
|
|
//| from the Normal distribution with parameters mu and sigma |
|
|
//| is less than or equal to x. |
|
|
//| |
|
|
//| Arguments: |
|
|
//| x : The desired quantile |
|
|
//| mu : Mean |
|
|
//| sigma : Standard deviation (must be positive) |
|
|
//| error_code : Variable for error code |
|
|
//| |
|
|
//| Return value: |
|
|
//| The value of the Normal cumulative distribution function with |
|
|
//| parameters mu and sigma, evaluated at x. |
|
|
//+------------------------------------------------------------------+
|
|
double MathCumulativeDistributionNormal(const double x,const double mu,const double sigma,int &error_code)
|
|
{
|
|
return MathCumulativeDistributionNormal(x,mu,sigma,true,false,error_code);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Normal cumulative distribution function (CDF) |
|
|
//+------------------------------------------------------------------+
|
|
//| The function calculates the cumulative distribution function of |
|
|
//| the Normal distribution with parameters mu and sigma |
|
|
//| for values in x[] array. |
|
|
//| |
|
|
//| Arguments: |
|
|
//| x : Array with random variables |
|
|
//| mu : Mean |
|
|
//| sigma : Standard deviation (must be positive) |
|
|
//| tail : Flag to calculate lower tail |
|
|
//| log_mode : Logarithm mode, if true it calculates Log values |
|
|
//| result : Array with calculated values |
|
|
//| |
|
|
//| Return value: |
|
|
//| true if successful, otherwise false. |
|
|
//+------------------------------------------------------------------+
|
|
bool MathCumulativeDistributionNormal(const double &x[],const double mu,const double sigma,const bool tail,const bool log_mode,double &result[])
|
|
{
|
|
//--- check NaN
|
|
if(!MathIsValidNumber(mu) || !MathIsValidNumber(sigma))
|
|
return false;
|
|
//--- check sigma
|
|
if(sigma<=0)
|
|
return false;
|
|
|
|
int data_count=ArraySize(x);
|
|
if(data_count==0)
|
|
return false;
|
|
|
|
int error_code=0;
|
|
ArrayResize(result,data_count);
|
|
for(int i=0; i<data_count; i++)
|
|
{
|
|
double x_arg=x[i];
|
|
|
|
//--- prepare argument
|
|
double xx=(x_arg-mu)/sigma;
|
|
//--- mathematical constants
|
|
//--- sqrpi = 1 / sqrt(2*pi), root32 = sqrt(32), and
|
|
//--- thrsh is the argument for which anorm = 0.75.
|
|
const double sqrpi=1.0/MathSqrt(2*M_PI);
|
|
const double thrsh = 0.66291e0;
|
|
const double root32= MathSqrt(32);
|
|
//--- machine-dependent constants
|
|
//--- data eps/5.96e-8/,xlow/-12.949e0/,xuppr/5.768e0/
|
|
const double eps=1.11e-16;
|
|
const double xlow=-37.519;
|
|
const double xuppr=8.572;
|
|
int k;
|
|
//---
|
|
double xsq=0.0;
|
|
double y=MathAbs(xx);
|
|
double xnum=0.0;
|
|
double xden=0.0;
|
|
double cdf=0.0;
|
|
double del=0.0;
|
|
//---
|
|
if(y<=thrsh)
|
|
{
|
|
//--- evaluate for |x| <= 0.66291
|
|
if(y>eps)
|
|
xsq=xx*xx;
|
|
|
|
xnum = normal_cdf_a[4] * xsq;
|
|
xden = xsq;
|
|
for(k=0; k<3; k++)
|
|
{
|
|
xnum=(xnum+normal_cdf_a[k])*xsq;
|
|
xden=(xden+normal_cdf_b[k])*xsq;
|
|
}
|
|
cdf = xx*(xnum+normal_cdf_a[3])/(xden+normal_cdf_b[3]);
|
|
cdf = 0.5 + cdf;
|
|
}
|
|
else
|
|
if(y<=root32)
|
|
{
|
|
//--- evaluate for 0.66291 <= |x| <= sqrt(32)
|
|
xnum = normal_cdf_c[8]*y;
|
|
xden = y;
|
|
for(k=0; k<7; k++)
|
|
{
|
|
xnum=(xnum+normal_cdf_c[k])*y;
|
|
xden=(xden+normal_cdf_d[k])*y;
|
|
}
|
|
cdf=(xnum+normal_cdf_c[7])/(xden+normal_cdf_d[7]);
|
|
xsq=int(y*16)/16;
|
|
del=(y-xsq)*(y+xsq);
|
|
cdf=MathExp(-xsq*xsq*0.5)*MathExp(-del*0.5)*cdf;
|
|
if(xx>0.0) cdf=1.0-cdf;
|
|
}
|
|
//--- evaluate for |x| > sqrt(32)
|
|
else
|
|
{
|
|
cdf=0.0;
|
|
if((xx>=xlow) && (xx<xuppr))
|
|
{
|
|
xsq=1.0/(xx*xx);
|
|
xnum = normal_cdf_p[5]*xsq;
|
|
xden = xsq;
|
|
for(k=0; k<3; k++)
|
|
{
|
|
xnum=(xnum+normal_cdf_p[k])*xsq;
|
|
xden=(xden+normal_cdf_q[k])*xsq;
|
|
}
|
|
cdf=xsq*(xnum+normal_cdf_p[4])/(xden+normal_cdf_q[4]);
|
|
cdf=(sqrpi-cdf)/y;
|
|
xsq=int(xx*16)/16;
|
|
del=(xx-xsq)*(xx+xsq);
|
|
cdf=MathExp(-xsq*xsq*0.5)*MathExp(-del*0.5)*cdf;
|
|
}
|
|
if(xx>0.0) cdf=1.0-cdf;
|
|
}
|
|
//--- take into account round-off errors for probability
|
|
result[i]=TailLogValue(MathMin(cdf,1.0),tail,log_mode);
|
|
}
|
|
return true;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Normal cumulative distribution function (CDF) |
|
|
//+------------------------------------------------------------------+
|
|
//| The function calculates the cumulative distribution function of |
|
|
//| the Normal distribution with parameters mu and sigma |
|
|
//| for values in x[] array. |
|
|
//| |
|
|
//| Arguments: |
|
|
//| x : Array with random variables |
|
|
//| mu : Mean |
|
|
//| sigma : Standard deviation (must be positive) |
|
|
//| result : Array with calculated values |
|
|
//| |
|
|
//| Return value: |
|
|
//| true if successful, otherwise false. |
|
|
//+------------------------------------------------------------------+
|
|
bool MathCumulativeDistributionNormal(const double &x[],const double mu,const double sigma,double &result[])
|
|
{
|
|
return MathCumulativeDistributionNormal(x,mu,sigma,true,false,result);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Normal distribution quantile function (inverse CDF) |
|
|
//+------------------------------------------------------------------+
|
|
//| The function returns the inverse cumulative distribution |
|
|
//| function of the Normal distribution with parameters mu and sigma |
|
|
//| for the desired probability. |
|
|
//| |
|
|
//| Arguments: |
|
|
//| probability : The desired probability |
|
|
//| mu : Mean |
|
|
//| sigma : Standard deviation (must be positive) |
|
|
//| tail : Flag to calculate lower tail |
|
|
//| log_mode : Logarithm mode,if true it calculates for Log values|
|
|
//| error_code : Variable for error code |
|
|
//| |
|
|
//| Return value: |
|
|
//| The value of the inverse cumulative distribution function |
|
|
//| of the Normal distribution with parameters mu and sigma. |
|
|
//+------------------------------------------------------------------+
|
|
//| Comment from original FORTRAN code |
|
|
//| https://www1.fpl.fs.fed.us/ni241.f |
|
|
//| Produces the normal deviate Z corresponding to a given lower |
|
|
//| tail area of P; Z is accurate to about 1 part in 10**16. |
|
|
//| Wichura, M.J. (1988). Algorithm AS 241: The Percentage Points of |
|
|
//| the Normal Distribution. Applied Statistics, v.37, N3, 477-484. |
|
|
//+------------------------------------------------------------------+
|
|
double MathQuantileNormal(const double probability,const double mu,const double sigma,const bool tail,const bool log_mode,int &error_code)
|
|
{
|
|
//--- check NaN
|
|
if(!MathIsValidNumber(probability) || !MathIsValidNumber(mu) || !MathIsValidNumber(sigma))
|
|
{
|
|
error_code=ERR_ARGUMENTS_NAN;
|
|
return QNaN;
|
|
}
|
|
//--- check sigma
|
|
if(sigma<=0)
|
|
{
|
|
error_code=ERR_ARGUMENTS_INVALID;
|
|
return QNaN;
|
|
}
|
|
|
|
//--- calculate real probability
|
|
double prob=TailLogProbability(probability,tail,log_mode);
|
|
//--- check probability range
|
|
if(prob<0.0 || prob>1.0)
|
|
{
|
|
error_code=ERR_ARGUMENTS_INVALID;
|
|
return QNaN;
|
|
}
|
|
//--- f(0)=-infinity
|
|
if(prob==0.0)
|
|
{
|
|
error_code=ERR_RESULT_INFINITE;
|
|
return QNEGINF;
|
|
}
|
|
//--- f(1)=+infinity
|
|
if(prob==1.0)
|
|
{
|
|
error_code=ERR_RESULT_INFINITE;
|
|
return QPOSINF;
|
|
}
|
|
|
|
error_code=ERR_OK;
|
|
|
|
double q=prob-0.5;
|
|
double r=0;
|
|
double ppnd16=0.0;
|
|
//---
|
|
if(MathAbs(q)<=0.425)
|
|
{
|
|
r=0.180625-q*q;
|
|
ppnd16=q*(((((((normal_q_a7*r+normal_q_a6)*r+normal_q_a5)*r+normal_q_a4)*r+normal_q_a3)*r+normal_q_a2)*r+normal_q_a1)*r+normal_q_a0)/
|
|
(((((((normal_q_b7*r+normal_q_b6)*r+normal_q_b5)*r+normal_q_b4)*r+normal_q_b3)*r+normal_q_b2)*r+normal_q_b1)*r+1.0);
|
|
//---
|
|
error_code=ERR_OK;
|
|
return mu+sigma*ppnd16;
|
|
}
|
|
else
|
|
{
|
|
if(q<0.0)
|
|
r=prob;
|
|
else
|
|
r=1.0-prob;
|
|
//---
|
|
r=MathSqrt(-MathLog(r));
|
|
//---
|
|
if(r<=5.0)
|
|
{
|
|
r=r-1.6;
|
|
ppnd16=(((((((normal_q_c7*r+normal_q_c6)*r+normal_q_c5)*r+normal_q_c4)*r+normal_q_c3)*r+normal_q_c2)*r+normal_q_c1)*r+normal_q_c0)/
|
|
(((((((normal_q_d7*r+normal_q_d6)*r+normal_q_d5)*r+normal_q_d4)*r+normal_q_d3)*r+normal_q_d2)*r+normal_q_d1)*r+1.0);
|
|
}
|
|
else
|
|
{
|
|
r=r-5.0;
|
|
ppnd16=(((((((normal_q_e7*r+normal_q_e6)*r+normal_q_e5)*r+normal_q_e4)*r+normal_q_e3)*r+normal_q_e2)*r+normal_q_e1)*r+normal_q_e0)/
|
|
(((((((normal_q_f7*r+normal_q_f6)*r+normal_q_f5)*r+normal_q_f4)*r+normal_q_f3)*r+normal_q_f2)*r+normal_q_f1)*r+1.0);
|
|
}
|
|
//---
|
|
if(q<0.0)
|
|
ppnd16=-ppnd16;
|
|
}
|
|
//--- return rescaled/shifted value
|
|
return mu+sigma*ppnd16;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Normal distribution quantile function (inverse CDF) |
|
|
//+------------------------------------------------------------------+
|
|
//| The function returns the inverse cumulative distribution |
|
|
//| function of Normal distribution with parameters mu and sigma |
|
|
//| for the desired probability. |
|
|
//| |
|
|
//| Arguments: |
|
|
//| probability : The desired probability |
|
|
//| mu : Mean |
|
|
//| sigma : Standard deviation (must be positive) |
|
|
//| error_code : Variable for error code |
|
|
//| |
|
|
//| Return value: |
|
|
//| The value of the inverse cumulative distribution function |
|
|
//| of the Normal distribution with parameters mu and sigma. |
|
|
//+------------------------------------------------------------------+
|
|
double MathQuantileNormal(const double probability,const double mu,const double sigma,int &error_code)
|
|
{
|
|
return MathQuantileNormal(probability,mu,sigma,true,false,error_code);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Normal distribution quantile function (inverse CDF) |
|
|
//+------------------------------------------------------------------+
|
|
//| The function calculates the inverse cumulative distribution |
|
|
//| function of the Normal distribution with parameters mu and sigma |
|
|
//| for the probability values from array. |
|
|
//| |
|
|
//| Arguments: |
|
|
//| probability : Array with probabilities |
|
|
//| mu : Mean |
|
|
//| sigma : Standard deviation (must be positive) |
|
|
//| tail : Flag to calculate lower tail |
|
|
//| log_mode : Logarithm mode, if true it calculates Log values |
|
|
//| result : Array with calculated values |
|
|
//| |
|
|
//| Return value: |
|
|
//| true if successful, otherwise false. |
|
|
//+------------------------------------------------------------------+
|
|
bool MathQuantileNormal(const double &probability[],const double mu,const double sigma,const bool tail,const bool log_mode,double &result[])
|
|
{
|
|
//--- check NaN
|
|
if(!MathIsValidNumber(mu) || !MathIsValidNumber(sigma))
|
|
return false;
|
|
//--- check sigma
|
|
if(sigma<0)
|
|
return false;
|
|
|
|
int data_count=ArraySize(probability);
|
|
if(data_count==0)
|
|
return false;
|
|
|
|
int error_code=0;
|
|
ArrayResize(result,data_count);
|
|
|
|
//--- case sigma==0
|
|
if(sigma==0.0)
|
|
{
|
|
for(int i=0; i<data_count; i++)
|
|
result[i]=mu;
|
|
return true;
|
|
}
|
|
|
|
for(int i=0; i<data_count; i++)
|
|
{
|
|
//--- calculate real probability
|
|
double prob=TailLogProbability(probability[i],tail,log_mode);
|
|
//--- check probability range
|
|
if(prob<0.0 || prob>1.0)
|
|
return false;
|
|
|
|
//--- f(0)=-infinity, f(1)=+infinity
|
|
if(prob==0.0 || prob==1.0)
|
|
{
|
|
if(prob==0.0)
|
|
result[i]=QNEGINF;
|
|
else
|
|
result[i]=QPOSINF;
|
|
}
|
|
else
|
|
{
|
|
double q=prob-0.5;
|
|
double r=0;
|
|
double ppnd16=0.0;
|
|
//---
|
|
if(MathAbs(q)<=0.425)
|
|
{
|
|
r=0.180625-q*q;
|
|
ppnd16=q*(((((((normal_q_a7*r+normal_q_a6)*r+normal_q_a5)*r+normal_q_a4)*r+normal_q_a3)*r+normal_q_a2)*r+normal_q_a1)*r+normal_q_a0)/
|
|
(((((((normal_q_b7*r+normal_q_b6)*r+normal_q_b5)*r+normal_q_b4)*r+normal_q_b3)*r+normal_q_b2)*r+normal_q_b1)*r+1.0);
|
|
//--- set rescaled/shifted value
|
|
result[i]=mu+sigma*ppnd16;
|
|
}
|
|
else
|
|
{
|
|
if(q<0.0)
|
|
r=prob;
|
|
else
|
|
r=1.0-prob;
|
|
//---
|
|
r=MathSqrt(-MathLog(r));
|
|
//---
|
|
if(r<=5.0)
|
|
{
|
|
r=r-1.6;
|
|
ppnd16=(((((((normal_q_c7*r+normal_q_c6)*r+normal_q_c5)*r+normal_q_c4)*r+normal_q_c3)*r+normal_q_c2)*r+normal_q_c1)*r+normal_q_c0)/
|
|
(((((((normal_q_d7*r+normal_q_d6)*r+normal_q_d5)*r+normal_q_d4)*r+normal_q_d3)*r+normal_q_d2)*r+normal_q_d1)*r+1.0);
|
|
}
|
|
else
|
|
{
|
|
r=r-5.0;
|
|
ppnd16=(((((((normal_q_e7*r+normal_q_e6)*r+normal_q_e5)*r+normal_q_e4)*r+normal_q_e3)*r+normal_q_e2)*r+normal_q_e1)*r+normal_q_e0)/
|
|
(((((((normal_q_f7*r+normal_q_f6)*r+normal_q_f5)*r+normal_q_f4)*r+normal_q_f3)*r+normal_q_f2)*r+normal_q_f1)*r+1.0);
|
|
}
|
|
//---
|
|
if(q<0.0)
|
|
ppnd16=-ppnd16;
|
|
}
|
|
//--- set rescaled/shifted value
|
|
result[i]=mu+sigma*ppnd16;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Normal distribution quantile function (inverse CDF) |
|
|
//+------------------------------------------------------------------+
|
|
//| The function calculates the inverse cumulative distribution |
|
|
//| function of the Normal distribution with parameters mu and sigma |
|
|
//| for the probability values from array. |
|
|
//| |
|
|
//| Arguments: |
|
|
//| probability : Array with probabilities |
|
|
//| mu : Mean |
|
|
//| sigma : Standard deviation (must be positive) |
|
|
//| result : Array with calculated values |
|
|
//| |
|
|
//| Return value: |
|
|
//| true if successful, otherwise false. |
|
|
//+------------------------------------------------------------------+
|
|
bool MathQuantileNormal(const double &probability[],const double mu,const double sigma,double &result[])
|
|
{
|
|
return MathQuantileNormal(probability,mu,sigma,true,false,result);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Random variate from the Normal distribution |
|
|
//+------------------------------------------------------------------+
|
|
//| Compute the random variable from the Normal distribution |
|
|
//| with given mean mu and standard deviation sigma. |
|
|
//| |
|
|
//| Arguments: |
|
|
//| mu : Mean |
|
|
//| sigma : Standard deviation (must be positive) |
|
|
//| error_code : Variable for error code |
|
|
//| |
|
|
//| Return value: |
|
|
//| The random value with Normal distribution. |
|
|
//+------------------------------------------------------------------+
|
|
double MathRandomNormal(const double mu,const double sigma,int &error_code)
|
|
{
|
|
//--- check NaN
|
|
if(!MathIsValidNumber(mu) || !MathIsValidNumber(sigma))
|
|
{
|
|
error_code=ERR_ARGUMENTS_NAN;
|
|
return QNaN;
|
|
}
|
|
//--- check sigma
|
|
if(sigma<0)
|
|
{
|
|
error_code=ERR_ARGUMENTS_INVALID;
|
|
return QNaN;
|
|
}
|
|
|
|
error_code=ERR_OK;
|
|
//---
|
|
if(sigma==0.0)
|
|
return mu;
|
|
//--- generate random number
|
|
double rnd=MathRandomNonZero();
|
|
//--- return normal random using quantile
|
|
return MathQuantileNormal(rnd,mu,sigma,true,false,error_code);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Random variate from the Normal distribution |
|
|
//+------------------------------------------------------------------+
|
|
//| Generates random variables from the Normal distribution with |
|
|
//| parameters mu and sigma. |
|
|
//| |
|
|
//| Arguments: |
|
|
//| mu : Mean |
|
|
//| sigma : Standard deviation (must be positive) |
|
|
//| data_count : Number of values needed |
|
|
//| result : Output array with random values |
|
|
//| |
|
|
//| Return value: |
|
|
//| true if successful, otherwise false. |
|
|
//+------------------------------------------------------------------+
|
|
bool MathRandomNormal(const double mu,const double sigma,const int data_count,double &result[])
|
|
{
|
|
//--- check NaN
|
|
if(!MathIsValidNumber(mu) || !MathIsValidNumber(sigma))
|
|
return false;
|
|
//--- check sigma
|
|
if(sigma<0)
|
|
return false;
|
|
//--- prepare output array and calculate random values
|
|
ArrayResize(result,data_count);
|
|
if(sigma==0.0)
|
|
{
|
|
for(int i=0; i<data_count; i++)
|
|
result[i]=mu;
|
|
return true;
|
|
}
|
|
int err_code=0;
|
|
for(int i=0; i<data_count; i++)
|
|
result[i]=MathRandomNonZero();
|
|
//--- return normal random array using quantile
|
|
return MathQuantileNormal(result,mu,sigma,result);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Normal distribution moments |
|
|
//+------------------------------------------------------------------+
|
|
//| The function calculates 4 first moments of the Normal |
|
|
//| distribution with parameters mu and sigma. |
|
|
//| |
|
|
//| Arguments: |
|
|
//| mu : Mean |
|
|
//| sigma : Standard deviation (sigma>0) |
|
|
//| mean : Variable for mean value (1st moment) |
|
|
//| variance : Variable for variance value (2nd moment) |
|
|
//| skewness : Variable for skewness value (3rd moment) |
|
|
//| kurtosis : Variable for kurtosis value (4th moment) |
|
|
//| error_code : Variable for error code |
|
|
//| |
|
|
//| Return value: |
|
|
//| true if moments calculated successfully, otherwise false. |
|
|
//+------------------------------------------------------------------+
|
|
bool MathMomentsNormal(const double mu,const double sigma,double &mean,double &variance,double &skewness,double &kurtosis,int &error_code)
|
|
{
|
|
//--- default values
|
|
mean =QNaN;
|
|
variance=QNaN;
|
|
skewness=QNaN;
|
|
kurtosis=QNaN;
|
|
//--- check NaN
|
|
if(!MathIsValidNumber(mu) || !MathIsValidNumber(sigma))
|
|
{
|
|
error_code=ERR_ARGUMENTS_NAN;
|
|
return false;
|
|
}
|
|
//--- check sigma
|
|
if(sigma<=0)
|
|
{
|
|
error_code=ERR_ARGUMENTS_INVALID;
|
|
return false;
|
|
}
|
|
|
|
error_code=ERR_OK;
|
|
//--- calculate moments
|
|
mean =mu;
|
|
variance=MathPow(sigma,2);
|
|
skewness=0;
|
|
kurtosis=0;
|
|
//--- successful
|
|
return true;
|
|
}
|
|
//+------------------------------------------------------------------+
|