# 统计估计

8 一月 2014, 09:58
0
1 754

### 避免异常值

1. 中值；
2. 50% 四分位中心间距（中四分位距，MQR）；
3. 整个采样的算术平均值；
4. 50% 四分位距的算术平均值（四分位距平均值，IQM）；
5. 间距的中心（中列数）- 确定为采样中最大值和最小值的平均值。

```//----------------------------------------------------------------------------
//                                                                erremove.mq5
//                                   Copyright 2011, MetaQuotes Software Corp.
//                                                         https://www.mql5.com
//----------------------------------------------------------------------------
#property version   "1.00"

#import "shell32.dll"
bool ShellExecuteW(int hwnd,string lpOperation,string lpFile,
string lpParameters,string lpDirectory,int nShowCmd);
#import
//----------------------------------------------------------------------------
// Script program start function
//----------------------------------------------------------------------------
void OnStart()
{
int i;
double dat[100];
double y[];

srand(1);
for(i=0;i<ArraySize(dat);i++)dat[i]=rand()/16000.0;

dat[25]=3;           // Make Error !!!

erremove(dat,y,1);

}
//----------------------------------------------------------------------------
int erremove(const double &x[],double &y[],int visual=1)
{
int i,m,n;
double a[],b[5];
double dcen,kurt,sum2,sum4,gs,v,max,min;

if(!ArrayIsDynamic(y))                           // Error
{
Print("Function erremove() error!");
return(-1);
}
n=ArraySize(x);
if(n<4)                                          // Error
{
Print("Function erremove() error!");
return(-1);
}
ArrayResize(a,n);
ArrayCopy(a,x);
ArraySort(a);
b[0]=(a[0]+a[n-1])/2.0;                          // Midrange
m=(n-1)/2;
b[1]=a[m];                                       // Median
if((n&0x01)==0)b[1]=(b[1]+a[m+1])/2.0;
m=n/4;
b[2]=(a[m]+a[n-m-1])/2.0;                        // Midquartile range
b[3]=0;
for(i=m;i<n-m;i++)b[3]+=a[i];                    // Interquartile mean(IQM)
b[3]=b[3]/(n-2*m);
b[4]=0;
for(i=0;i<n;i++)b[4]+=a[i];                      // Mean
b[4]=b[4]/n;
ArraySort(b);
dcen=b[2];                                       // Distribution center
sum2=0; sum4=0;
for(i=0;i<n;i++)
{
a[i]=a[i]-dcen;
v=a[i]*a[i];
sum2+=v;
sum4+=v*v;
}
if(sum2<1.e-150)kurt=1.0;
kurt=((n*n-2*n+3)*sum4/sum2/sum2-(6.0*n-9.0)/n)*(n-1.0)/(n-2.0)/(n-3.0); // Kurtosis
if(kurt<1.0)kurt=1.0;
gs=(1.55+0.8*MathLog10((double)n/10.0)*MathSqrt(kurt-1))*MathSqrt(sum2/(n-1));
max=dcen+gs;
min=dcen-gs;
m=0;
for(i=0;i<n;i++)if(x[i]<=max&&x[i]>=min)a[m++]=x[i];
ArrayResize(y,m);
ArrayCopy(y,a,0,0,m);

if(visual==1)vis(x,dcen,min,max,n-m);

return(n-m);
}
//----------------------------------------------------------------------------
void vis(const double &x[],double dcen,double min,double max,int numerr)
{
int i;
double d,yma,ymi;
string str;

yma=x[0];ymi=x[0];
for(i=0;i<ArraySize(x);i++)
{
if(yma<x[i])yma=x[i];
if(ymi>x[i])ymi=x[i];
}
if(yma<max)yma=max;
if(ymi>min)ymi=min;
d=(yma-ymi)/20.0;
yma+=d;ymi-=d;
str="unset key\n";
str+="set title 'Sequence and error levels (number of errors = "+
(string)numerr+")' font ',10'\n";
str+="set yrange ["+(string)ymi+":"+(string)yma+"]\n";
str+="set xrange [0:"+(string)ArraySize(x)+"]\n";
str+="plot "+(string)dcen+" lt rgb 'green',";
str+=(string)min+ " lt rgb 'red',";
str+=(string)max+ " lt rgb 'red',";
str+="'-' with line lt rgb 'dark-blue'\n";
for(i=0;i<ArraySize(x);i++)str+=(string)x[i]+"\n";
str+="e\n";
if(!saveScript(str)){Print("Create script file error");return;}
if(!grPlot())Print("ShellExecuteW() error");
}
//----------------------------------------------------------------------------
bool grPlot()
{
string pnam,param;

pnam="GNUPlot\\binary\\wgnuplot.exe";
param="-p MQL5\\Files\\gplot.txt";
return(ShellExecuteW(NULL,"open",pnam,param,NULL,1));
}
//----------------------------------------------------------------------------
bool saveScript(string scr1="",string scr2="")
{
int fhandle;

fhandle=FileOpen("gplot.txt",FILE_WRITE|FILE_TXT|FILE_ANSI);
if(fhandle==INVALID_HANDLE)return(false);
FileWriteString(fhandle,"set terminal windows enhanced size 560,420 font 8\n");
FileWriteString(fhandle,scr1);
if(scr2!="")FileWriteString(fhandle,scr2);
FileClose(fhandle);
return(true);
}
//----------------------------------------------------------------------------```

```m=(n-1)/2;
median=a[m];
if((n&0x01)==0)b[1]=(median+a[m+1])/2.0;```

50% 四分位中心间距（中四分位矩，MQR）：

```m=n/4;
MQR=(a[m]+a[n-m-1])/2.0;               // Midquartile range```

50% 四分位距的算术平均值（四分位距平均值，IQM）。从采样的两个极端值中去除了 25% 的样本，剩余的 50% 用于计算算术平均值：

```m=n/4; IQM=0;
for(i=m;i<n-m;i++)IQM+=a[i];
IQM=IQM/(n-2*m);                       // Interquartile mean(IQM)```

### 可视化

图 1. 文件夹 \gnuplot 的放置

### 参数的估计

```struct statParam
{
double mean;
double median;
double var;
double stdev;
double skew;
double kurt;
};
//----------------------------------------------------------------------------
int dStat(const double &x[],statParam &sP)
{
int i,m,n;
double a,b,sum2,sum3,sum4,y[];

ZeroMemory(sP);                                      // Reset sP
n=ArraySize(x);
if(n<4)                                             // Error
{
Print("Function dStat() error!");
return(-1);
}
sP.kurt=1.0;
ArrayResize(y,n);
ArrayCopy(y,x);
ArraySort(y);
m=(n-1)/2;
sP.median=y[m];                                     // Median
if((n&0x01)==0)sP.median=(sP.median+y[m+1])/2.0;
sP.mean=0;
for(i=0;i<n;i++)sP.mean+=x[i];
sP.mean/=n;                                         // Mean
sum2=0;sum3=0;sum4=0;
for(i=0;i<n;i++)
{
a=x[i]-sP.mean;
b=a*a;sum2+=b;
b=b*a;sum3+=b;
b=b*a;sum4+=b;
}
if(sum2<1.e-150)return(1);
sP.var=sum2/(n-1);                                  // Variance
sP.stdev=MathSqrt(sP.var);                           // Standard deviation
sP.skew=n*sum3/(n-2)/sum2/sP.stdev;                 // Skewness
sP.kurt=((n*n-2*n+3)*sum4/sum2/sum2-(6.0*n-9.0)/n)*
(n-1.0)/(n-2.0)/(n-3.0); // Kurtosis

return(1);
```

### 直方图

```struct statParam
{
double mean;
double median;
double var;
double stdev;
double skew;
double kurt;
};
//----------------------------------------------------------------------------
int dHist(const double &x[],double &histo[],const statParam &sp)
{
int i,k,n,nbar;
double a[],max,s,xmin;

if(!ArrayIsDynamic(histo))                           // Error
{
Print("Function dHist() error!");
return(-1);
}
n=ArraySize(x);
if(n<4)                                             // Error
{
Print("Function dHist() error!");
return(-1);
}
nbar=(sp.kurt+1.5)*MathPow(n,0.4)/6.0;
if((nbar&0x01)==0)nbar--; if(nbar<5)nbar=5;          // Number of bars
ArrayResize(a,n);
ArrayCopy(a,x);
max=0.0;
for(i=0;i<n;i++)
{
a[i]=(a[i]-sp.mean)/sp.stdev;                     // Normalization
if(MathAbs(a[i])>max)max=MathAbs(a[i]);
}
xmin=-max;
s=2.0*max*n/nbar;
ArrayResize(histo,nbar+2);
ArrayInitialize(histo,0.0);
histo[0]=0.0;histo[nbar+1]=0.0;
for(i=0;i<n;i++)
{
k=(a[i]-xmin)/max/2.0*nbar;
if(k>(nbar-1))k=nbar-1;
histo[k+1]++;
}
for(i=0;i<nbar;i++)histo[i+1]/=s;

return(1);
}```

### 正态概率图

```struct statParam
{
double mean;
double median;
double var;
double stdev;
double skew;
double kurt;
};
//----------------------------------------------------------------------------
int dRankit(const double &x[],double &resp[],double &xscale[],const statParam &sp)
{
int i,n;
double np;

if(!ArrayIsDynamic(resp)||!ArrayIsDynamic(xscale))    // Error
{
Print("Function dHist() error!");
return(-1);
}
n=ArraySize(x);
if(n<4)                                            // Error
{
Print("Function dHist() error!");
return(-1);
}
ArrayResize(resp,n);
ArrayCopy(resp,x);
ArraySort(resp);
for(i=0;i<n;i++)resp[i]=(resp[i]-sp.mean)/sp.stdev;
ArrayResize(xscale,n);
xscale[n-1]=MathPow(0.5,1.0/n);
xscale[0]=1-xscale[n-1];
np=n+0.365;
for(i=1;i<(n-1);i++)xscale[i]=(i+1-0.3175)/np;
for(i=0;i<n;i++)xscale[i]=ltqnorm(xscale[i]);

return(1);
}
//----------------------------------------------------------------------------

double A1 = -3.969683028665376e+01, A2 =  2.209460984245205e+02,
A3 = -2.759285104469687e+02, A4 =  1.383577518672690e+02,
A5 = -3.066479806614716e+01, A6 =  2.506628277459239e+00;
double B1 = -5.447609879822406e+01, B2 =  1.615858368580409e+02,
B3 = -1.556989798598866e+02, B4 =  6.680131188771972e+01,
B5 = -1.328068155288572e+01;
double C1 = -7.784894002430293e-03, C2 = -3.223964580411365e-01,
C3 = -2.400758277161838e+00, C4 = -2.549732539343734e+00,
C5 =  4.374664141464968e+00, C6 =  2.938163982698783e+00;
double D1 =  7.784695709041462e-03, D2 =  3.224671290700398e-01,
D3 =  2.445134137142996e+00, D4 =  3.754408661907416e+00;
//----------------------------------------------------------------------------
double ltqnorm(double p)
{
int s=1;
double r,x,q=0;

if(p<=0||p>=1){Print("Function ltqnorm() error!");return(0);}
if((p>=0.02425)&&(p<=0.97575))    // Rational approximation for central region
{
q=p-0.5; r=q*q;
x=(((((A1*r+A2)*r+A3)*r+A4)*r+A5)*r+A6)*q/(((((B1*r+B2)*r+B3)*r+B4)*r+B5)*r+1);
return(x);
}
if(p<0.02425)                    // Rational approximation for lower region
{
q=sqrt(-2*log(p));
s=1;
}
else      //if(p>0.97575)          // Rational approximation for upper region
{
q = sqrt(-2*log(1-p));
s=-1;
}
x=s*(((((C1*q+C2)*q+C3)*q+C4)*q+C5)*q+C6)/((((D1*q+D2)*q+D3)*q+D4)*q+1);
return(x);
}```

### 四张图表

```//----------------------------------------------------------------------------
// Script program start function
//----------------------------------------------------------------------------
void OnStart()
{
int i;
double dat[128],histo[],rankit[],xrankit[];
statParam sp;

MathSrand(1);
for(i=0;i<ArraySize(dat);i++) dat[i]=MathRand();

if(dStat(dat,sp)==-1)return;
if(dHist(dat,histo,sp)==-1)return;
if(dRankit(dat,rankit,xrankit,sp)==-1)return;

vis4plot(dat,histo,rankit,xrankit,sp,6);
}```

### 伪随机序列生成器

```//-----------------------------------------------------------------------------------
//                                                                      RNDXor128.mqh
//                                                                      2011, victorg
//                                                                https://www.mql5.com
//-----------------------------------------------------------------------------------

#include <Object.mqh>
//-----------------------------------------------------------------------------------
// Generation of pseudo-random sequences. The Xorshift RNG algorithm
// (George Marsaglia) with the 2**128 period of initial sequence is used.
//          uint rand_xor128()
//            {
//            static uint x=123456789,y=362436069,z=521288629,w=88675123;
//            uint t=(x^(x<<11));x=y;y=z;z=w;
//            return(w=(w^(w>>19))^(t^(t>>8)));
//            }
// Methods:
//  Rand()      - even distribution withing the range [0,UINT_MAX=4294967295].
//  Rand_01()   - even distribution within the range [0,1].
//  Rand_Norm() - normal distribution with zero mean and dispersion one.
//  Rand_Exp()  - exponential distribution with the parameter 1.0.
//  Rand_Laplace() - Laplace distribution with the parameter 1.0
//  Reset()     - resetting of all basic values to initial state.
//  SRand()     - setting new basic values of the generator.
//-----------------------------------------------------------------------------------
#define xor32  xx=xx^(xx<<13);xx=xx^(xx>>17);xx=xx^(xx<<5)
#define xor128 t=(x^(x<<11));x=y;y=z;z=w;w=(w^(w>>19))^(t^(t>>8))
#define inidat x=123456789;y=362436069;z=521288629;w=88675123;xx=2463534242

class RNDXor128:public CObject
{
protected:
uint      x,y,z,w,xx,t;
uint      UINT_half;
public:
RNDXor128()       {UINT_half=UINT_MAX>>1;inidat;};
double    Rand()            {xor128;return((double)w);};
int       Rand(double& a[],int n)
{int i;if(n<1)return(-1);
if(ArraySize(a)<n)return(-2);
for(i=0;i<n;i++){xor128;a[i]=(double)w;}
return(0);};
double    Rand_01()         {xor128;return((double)w/UINT_MAX);};
int       Rand_01(double& a[],int n)
{int i;if(n<1)return(-1);
if(ArraySize(a)<n)return(-2);
for(i=0;i<n;i++){xor128;a[i]=(double)w/UINT_MAX;}
return(0);};
double    Rand_Norm()       {double v1,v2,s,sln;static double ra;static uint b=0;
if(b==w){b=0;return(ra);}
do{
xor128;v1=(double)w/UINT_half-1.0;
xor128;v2=(double)w/UINT_half-1.0;
s=v1*v1+v2*v2;
}
while(s>=1.0||s==0.0);
sln=MathLog(s);sln=MathSqrt((-sln-sln)/s);
ra=v2*sln;b=w;
return(v1*sln);};
int       Rand_Norm(double& a[],int n)
{int i;if(n<1)return(-1);
if(ArraySize(a)<n)return(-2);
for(i=0;i<n;i++)a[i]=Rand_Norm();
return(0);};
double    Rand_Exp()        {xor128;if(w==0)return(DBL_MAX);
return(-MathLog((double)w/UINT_MAX));};
int       Rand_Exp(double& a[],int n)
{int i;if(n<1)return(-1);
if(ArraySize(a)<n)return(-2);
for(i=0;i<n;i++)a[i]=Rand_Exp();
return(0);};
double    Rand_Laplace()    {double a;xor128;
a=(double)w/UINT_half;
if(w>UINT_half)
{a=2.0-a;
if(a==0.0)return(-DBL_MAX);
return(MathLog(a));}
else
{if(a==0.0)return(DBL_MAX);
return(-MathLog(a));}};
int       Rand_Laplace(double& a[],int n)
{int i;if(n<1)return(-1);
if(ArraySize(a)<n)return(-2);
for(i=0;i<n;i++)a[i]=Rand_Laplace();
return(0);};
void      Reset()           {inidat;};
void      SRand(uint seed)  {int i;if(seed!=0)xx=seed;
for(i=0;i<16;i++){xor32;}
xor32;x=xx;xor32;y=xx;
xor32;z=xx;xor32;w=xx;
for(i=0;i<16;i++){xor128;}};
int       SRand(uint xs,uint ys,uint zs,uint ws)
{int i;if(xs==0&&ys==0&&zs==0&&ws==0)return(-1);
x=xs;y=ys;z=zs;w=ws;
for(i=0;i<16;i++){xor128;}
return(0);};
};
//-----------------------------------------------------------------------------------```

### 序列示例

```#include "RNDXor128.mqh"
RNDXor128 Rnd;
//----------------------------------------------------------------------------
void OnStart()
{
int i;
double dat[512];

for(i=0;i<ArraySize(dat);i++) dat[i]=Rnd.Rand_01();
...
}```

```#include "RNDXor128.mqh"
RNDXor128 Rnd;
//----------------------------------------------------------------------------
void OnStart()
{
int i;
double dat[512];

for(i=0;i<ArraySize(dat);i++) dat[i]=Rnd.Rand_Norm();
...
}```

```#include "RNDXor128.mqh"
RNDXor128 Rnd;
//----------------------------------------------------------------------------
void OnStart()
{
int i;
double dat[512];

for(i=0;i<ArraySize(dat);i++) dat[i]=Rnd.Rand_Exp();
...
}```

```#include "RNDXor128.mqh"
RNDXor128 Rnd;
//----------------------------------------------------------------------------
void OnStart()
{
int i;
double dat[512];

for(i=0;i<ArraySize(dat);i++) dat[i]=Rnd.Rand_Laplace();
...
}```

```//----------------------------------------------------------------------------
void OnStart()
{
int i;
double dat[512];

for(i=0;i<ArraySize(dat);i++) dat[i]=MathSin(2*M_PI/4.37*i);
...
}```

```#include "RNDXor128.mqh"
RNDXor128 Rnd;
//----------------------------------------------------------------------------
void OnStart()
{
int i;
double dat[512],a;

for(i=0;i<ArraySize(dat);i++) {a+=Rnd.Rand_Laplace();dat[i]=a;}
...
}```

### 文件

• erremove.mq5 – 从采样中排除错误的脚本示例。
• function_dstat.mq5 – 用于计算统计参数的函数。
• function_dhist.mq5 - 用于计算直方图的值的函数。
• function_drankit.mq5 – 用于计算在绘制带有正态分布刻度的图表时所用值的函数。
• s4plot.mq5 – 在一张图纸上绘制四张图表的脚本示例。
• RNDXor128.mqh – 随机序列生成器类。
• xorshift.zip - George Marsaglia. 的"Xorshift RNGs"。

erremove.mq5 (4.53 KB)
function_dhist.mq5 (1.21 KB)
xorshift.zip (38.35 KB)
function_dstat.mq5 (1.35 KB)
s4plot.mq5 (10.52 KB)
rndxor128.mqh (12.01 KB)

MetaTrader 5 客户端提供了各种机会来优化 EA 交易的参数。除了策略测试程序中包含的优化标准以外，开发人员还有机会创建自己的标准。这样一来，EA 交易的测试和优化便具有了无限的可能性。本文介绍了创建此类标准的实用方法，既适用于复杂标准，也适用于简单标准。