//+------------------------------------------------------------------+ //| T.mqh | //| Copyright 2000-2025, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #include "Math.mqh" #include "Gamma.mqh" //+------------------------------------------------------------------+ //| T probability density function (PDF) | //+------------------------------------------------------------------+ //| The function returns the probability density function | //| of the T-distribution with parameter nu. | //| | //| Arguments: | //| x : Random variable | //| nu : Degrees of freedom | //| log_mode : Logarithm mode, if true it calculates Log values | //| error_code : Variable for error code | //| | //| Return value: | //| The probability density evaluated at x. | //+------------------------------------------------------------------+ double MathProbabilityDensityT(const double x,const double nu,const bool log_mode,int &error_code) { //--- check NaN if(!MathIsValidNumber(x) || !MathIsValidNumber(nu)) { error_code=ERR_ARGUMENTS_NAN; return QNaN; } //--- check nu if(nu!=MathRound(nu) || nu<=0.0) { error_code=ERR_ARGUMENTS_INVALID; return QNaN; } error_code=ERR_OK; //--- calculate T density double pdf=MathExp(MathGammaLog((nu+1.0)*0.5)-MathGammaLog(nu*0.5)); pdf=pdf/(MathSqrt(nu*M_PI)*MathPow(1+x*x/nu,(nu+1.0)*0.5)); //--- return density return TailLogValue(pdf,true,log_mode); } //+------------------------------------------------------------------+ //| T probability density function (PDF) | //+------------------------------------------------------------------+ //| The function returns the probability density function | //| of the T-distribution with parameter nu. | //| | //| Arguments: | //| x : Random variable | //| nu : Degrees of freedom | //| error_code : Variable for error code | //| | //| Return value: | //| The probability density evaluated at x. | //+------------------------------------------------------------------+ double MathProbabilityDensityT(const double x,const double nu,int &error_code) { return MathProbabilityDensityT(x,nu,false,error_code); } //+------------------------------------------------------------------+ //| T probability density function (PDF) | //+------------------------------------------------------------------+ //| The function calculates the probability density function of | //| the T distribution with parameter nu for values in x[] array. | //| | //| Arguments: | //| x : Array with random variables | //| nu : Degrees of freedom | //| log_mode : Logarithm mode flag, if true it returns Log values | //| result : Array with calculated values | //| | //| Return value: | //| true if successful, otherwise false. | //+------------------------------------------------------------------+ bool MathProbabilityDensityT(const double &x[],const double nu,const bool log_mode,double &result[]) { //--- check NaN if(!MathIsValidNumber(nu)) return false; //--- check nu if(nu!=MathRound(nu) || nu<=0.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; i0.0) cdf=1.0-cdf; //--- take into account round-off errors for probability return TailLogValue(MathMin(cdf,1.0),tail,log_mode); } //+------------------------------------------------------------------+ //| T cumulative distribution function (CDF) | //+------------------------------------------------------------------+ //| The function returns the probability that an observation from | //| T-distribution with parameter nu is less than or equal to x. | //| | //| Arguments: | //| x : The desired quantile | //| nu : Degrees of freedom | //| error_code : Variable for error code | //| | //| Return value: | //| The value of T cumulative distribution function with parameter | //| nu, evaluated at x. | //+------------------------------------------------------------------+ double MathCumulativeDistributionT(const double x,const double nu,int &error_code) { return MathCumulativeDistributionT(x,nu,true,false,error_code); } //+------------------------------------------------------------------+ //| T cumulative distribution function (CDF) | //+------------------------------------------------------------------+ //| The function calculates the cumulative distribution function of | //| the T distribution with parameter nu for values in x. | //| | //| Arguments: | //| x : Array with random variables | //| nu : Degrees of freedom | //| 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 MathCumulativeDistributionT(const double &x[],const double nu,const bool tail,const bool log_mode,double &result[]) { //--- check NaN if(!MathIsValidNumber(nu)) return false; //--- check nu (must be positive integer) if(nu!=MathRound(nu) || nu<=0.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; i0.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; } //+------------------------------------------------------------------+ //| T cumulative distribution function (CDF) | //+------------------------------------------------------------------+ //| The function calculates the cumulative distribution function of | //| the T distribution with parameter nu for values in x[] array. | //| | //| Arguments: | //| x : Array with random variables | //| nu : Degrees of freedom | //| result : Array with calculated values | //| | //| Return value: | //| true if successful, otherwise false. | //+------------------------------------------------------------------+ bool MathCumulativeDistributionT(const double &x[],const double nu,double &result[]) { return MathCumulativeDistributionT(x,nu,true,false,result); } //+------------------------------------------------------------------+ //| T distribution quantile function (inverse CDF) | //+------------------------------------------------------------------+ //| The function returns the inverse cumulative distribution | //| function of the T distribution with parameter nu for the desired | //| probability. | //| | //| Arguments: | //| probability : The desired probability | //| nu : Degrees of freedom | //| 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 inverse cumulative distribution function | //| of the T-distribution with parameter nu. | //+------------------------------------------------------------------+ double MathQuantileT(const double probability,const double nu,const bool tail,const bool log_mode,int &error_code) { //--- check NaN if(!MathIsValidNumber(probability) || !MathIsValidNumber(nu)) { error_code=ERR_ARGUMENTS_NAN; return QNaN; } //--- check nu if(nu!=MathRound(nu) || nu<0.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; } //--- check cases when probability==0 or 1 if(prob==0.0 || prob==1.0) { error_code=ERR_RESULT_INFINITE; //--- if(prob==0.0) return(QNEGINF); else return(QPOSINF); } error_code=ERR_OK; //--- special case nu=1 if(nu==1.0) return MathTan(M_PI*(prob-0.5)); //--- special case if(prob==0.5) return 0.0; //--- int max_iterations=50; int iterations=0; //--- initial values double h=1.0; double h_min=10E-20; double x=0.5; int err_code=0; //--- Newton iterations while(iterationsh_min && MathAbs(h)>MathAbs(h_min*x))==false) break; //--- calculate pdf and cdf double pdf=MathProbabilityDensityT(x,nu,err_code); double cdf=MathCumulativeDistributionT(x,nu,err_code); //--- calculate ratio h=(cdf-prob)/pdf; //--- double x_new=x-h; //--- check x if(x_new<0.0) x_new=x*0.1; else if(x_new>1.0) x_new=1.0-(1.0-x)*0.1; x=x_new; iterations++; } //--- check convergence if(iterations1.0) return false; //--- special case p=0.5 if(prob==0.5) result[i]=0.0; else if(prob==0.0) result[i]=QNEGINF; else if(prob==1.0) result[i]=QPOSINF; else { //--- special case nu=1 if(nu==1.0) result[i]=MathTan(M_PI*(prob-0.5)); else { int max_iterations=50; int iterations=0; //--- initial values double h=1.0; double h_min=10E-18; double x=0.5; int err_code=0; //--- Newton iterations while(iterationsh_min && MathAbs(h)>MathAbs(h_min*x))==false) break; //--- calculate pdf and cdf double pdf=MathProbabilityDensityT(x,nu,err_code); double cdf=MathCumulativeDistributionT(x,nu,err_code); //--- calculate ratio h=(cdf-prob)/pdf; //--- double x_new=x-h; //--- check x if(x_new<0.0) x_new=x*0.1; else if(x_new>1.0) x_new=1.0-(1.0-x)*0.1; if (MathAbs(x_new-x)<10E-15) break; x=x_new; iterations++; } //--- check convergence if(iterations=1.0 || r2==0.0); //--- generate normal and gamma random variables double rnd_normal=x2*MathSqrt(-2.0*MathLog(r2)/r2); double rnd_gamma=MathRandomGamma(nu*0.5,1,error_code); //--- calculate ratio double result=0; if(rnd_gamma!=0) result=MathSqrt(nu*0.5)*rnd_normal/MathSqrt(rnd_gamma); return(result); } //+------------------------------------------------------------------+ //| Random variate from the T distribution | //+------------------------------------------------------------------+ //| Generates random variables from the T distribution with | //| parameter nu. | //| | //| Arguments: | //| nu : Degrees of freedom | //| data_count : Number of values needed | //| result : Output array with random values | //| | //| Return value: | //| true if successful, otherwise false. | //+------------------------------------------------------------------+ bool MathRandomT(const double nu,const int data_count,double &result[]) { //--- check NaN if(!MathIsValidNumber(nu)) return false; //--- check arguments if(nu!=MathRound(nu) || nu<=0.0) return false; int error_code=0; //--- prepare output array and calculate random values ArrayResize(result,data_count); for(int i=0; i=1.0 || r2==0.0); //--- generate normal and gamma random variables double rnd_normal=x2*MathSqrt(-2.0*MathLog(r2)/r2); double rnd_gamma=MathRandomGamma(nu*0.5,1,error_code); //--- calculate ratio double rnd=0; if(rnd_gamma!=0) rnd=MathSqrt(nu*0.5)*rnd_normal/MathSqrt(rnd_gamma); result[i]=rnd; } return true; } //+------------------------------------------------------------------+ //| T distribution moments | //+------------------------------------------------------------------+ //| The function calculates 4 first moments of the T distribution | //| with parameter nu. | //| | //| Arguments: | //| nu : Degrees of freedom | //| 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. | //+------------------------------------------------------------------+ double MathMomentsT(const double nu,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(nu)) { error_code=ERR_ARGUMENTS_NAN; return QNaN; } //--- check nu if(nu!=MathRound(nu) || nu<0.0) { error_code=ERR_ARGUMENTS_INVALID; return QNaN; } error_code=ERR_OK; //--- calculate moments mean=0; if(nu>2) variance=nu/(nu-2); skewness=0; if(nu>4) kurtosis=6/(nu-4); //--- successful return true; } //+------------------------------------------------------------------+