//+------------------------------------------------------------------+ //| NoncentralF.mqh | //| Copyright 2000-2025, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #include "Math.mqh" #include "F.mqh" #include "Gamma.mqh" #include "NoncentralBeta.mqh" //+------------------------------------------------------------------+ //| Noncentral-F probability density function (PDF) | //+------------------------------------------------------------------+ //| The function returns the probability density function | //| of the Noncentral-F distribution with parameters nu1,nu2,sigma. | //| | //| Arguments: | //| x : Random variable | //| nu1 : Numerator degrees of freedom | //| nu2 : Denominator degrees of freedom | //| sigma : Noncentrality parameter | //| 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 MathProbabilityDensityNoncentralF(const double x,const double nu1,const double nu2,const double sigma,const bool log_mode,int &error_code) { //--- return F if sigma==0 if(sigma==0.0) return MathProbabilityDensityF(x,nu1,nu2,error_code); //--- check NaN if(!MathIsValidNumber(x) || !MathIsValidNumber(nu1) || !MathIsValidNumber(nu2) || !MathIsValidNumber(sigma)) { error_code=ERR_ARGUMENTS_NAN; return QNaN; } //--- check arguments if(nu1!=MathRound(nu1) || nu2!=MathRound(nu2) || nu1<=0 || nu2<=0) { error_code=ERR_ARGUMENTS_INVALID; return QNaN; } error_code=ERR_OK; if(x<=0.0) return TailLog0(true,log_mode); //--- factors double nu1_half=nu1*0.5; double nu2_half=nu2*0.5; double nu12_half=nu1_half+nu2_half; double lambda=sigma*0.5; double coef_lambda=MathExp(-lambda); double nu_coef=nu1/nu2; double g=x*nu_coef; double pwr_g=MathExp((nu1_half-1)*MathLog(g)); double g1=g+1.0; double pwr_g1=MathExp(-nu12_half*MathLog(g1)); double pwr_lambda=1.0; double fact_mult=1.0; //--- initial value for recurrent calculation double r_beta=MathBeta(nu1_half,nu2_half); //--- direct calculation of the sum int max_terms=100; int j=0; double pdf=0; while(j0) { pwr_g*=g; pwr_lambda*=lambda; fact_mult/=j; pwr_g1/=g1; double jm1=j-1; r_beta*=((nu1_half+jm1)/(nu12_half+jm1)); } double dp=pwr_g*pwr_g1*coef_lambda*pwr_lambda*fact_mult/r_beta; pdf+=dp; if(dp/(pdf+10E-10)<10E-14) break; j++; } //--- check convergence if(j0) { pwr_g*=g; pwr_lambda*=lambda; fact_mult/=j; pwr_g1/=g1; double jm1=j-1; r_beta*=((nu1_half+jm1)/(nu12_half+jm1)); } double dp=pwr_g*pwr_g1*coef_lambda*pwr_lambda*fact_mult/r_beta; pdf+=dp; if(dp/(pdf+10E-10)<10E-14) break; j++; } //--- check convergence if(j1.0) { error_code=ERR_ARGUMENTS_INVALID; return QNaN; } if(prob==1.0) { error_code=ERR_RESULT_INFINITE; return QPOSINF; } error_code=ERR_OK; if(prob==0.0) return 0.0; //--- int max_iterations=50; int iterations=0; //--- initial values double h=1.0; double h_min=10E-10; 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=MathProbabilityDensityNoncentralF(x,nu1,nu2,sigma,err_code); double cdf=MathCumulativeDistributionNoncentralF(x,nu1,nu2,sigma,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; if(prob==1.0) result[i]=QPOSINF; else if(prob==0.0) result[i]=0.0; else { int max_iterations=50; int iterations=0; //--- initial values double h=1.0; double h_min=10E-10; 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=MathProbabilityDensityNoncentralF(x,nu1,nu2,sigma,err_code); double cdf=MathCumulativeDistributionNoncentralF(x,nu1,nu2,sigma,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(iterations2) mean=nu2*(nu1+sigma)/(nu1*(nu2-2)); //--- variance if(nu2>4) variance=2*MathPow(nu2/nu1,2)*((nu2-2)*(nu1+2*sigma)+MathPow(nu1+sigma,2))/((nu2-4)*MathPow(nu2-2,2)); //--- factors double sigma_sqr=MathPow(sigma,2); double sigma_cube=sigma_sqr*sigma; double nu12m2=(nu1+nu2-2); double nu2p10=(nu2+10); //--- skewness if(nu2>6) { skewness=2*M_SQRT2*MathSqrt(nu2-4); skewness*=(nu12m2*(6*sigma_sqr+(2*nu1+nu2-2)*(3*sigma+nu1))+2*sigma_cube); skewness/=(nu2-6); skewness/=MathPow(nu12m2*(2*sigma+nu1)+sigma_sqr,1.5); } //--- kurtosis if(nu2>8) { double coef=nu2p10*(MathPow(nu1,2)+nu1*(nu2-2))+4*MathPow(nu2-2,2); kurtosis=1; kurtosis=3*(nu2-4); kurtosis*=(nu12m2*(coef*(4*sigma+nu1)+nu2p10*(4*sigma_cube+2*sigma_sqr*(3*nu1+2*nu2-4)))+nu2p10*MathPow(sigma,4)); kurtosis/=(nu2-8)*(nu2-6); kurtosis/=MathPow((nu12m2*(2*sigma+nu1)+sigma_sqr),2); kurtosis-=3; } //--- successful return true; } //+------------------------------------------------------------------+