Articles on MQL4
Work with arrays

Work with arrays


for example, forex

There are two pieces of news – bad and good. The bad news – it is impossible to forecast the market.
The good news – to earn money you don’t need to forecast the market.
Bruce Babcock



Many of you must have heard this saying in one or another interpretation. There are supporters and opponents of the efficient market hypothesis. Some consider that the process is random and it is impossible to earn money on markets, other think that prices are predictable and this gives opportunities to make a profit from the market’s behavior.

In each joke there is a grain of joke. But joke continues. From time to time we can hear that one can make a profit on random movement of price, and there is no need in developing a trading system, but only knowledge of mathematic to the extent of the first courses of University is required. The results of trading systems that work on random quotes are provided, the testing results confirm – it is possible to make a profit on a random market in a random way. I created a table in Excel, which models 100 transactions on prices with increments according to the normal distribution law, and created 7 columns, each of which shows total profit out of 20 series of 100 transactions from preset StopLoss(SL) and TakeProfit(TP).

 
 


We can see that profit when TP/SL=3 proved to be maximum (472), and in case of inverse ratio loss is maximum (-492). You may perform your testing series in order to compare your results with mine. For this you should change settings and write 20 times the value of «Total» in the correspondent cells.

 
 


Perhaps your results will be somewhat different from mine, but what if they prove to be close at least by half? What to do in such a case, to start at once trading following the principle of random opening of transaction with ratio TP/SL=3 of at first make sure whether market prices are normally distributed?

Normal distributions are considered to be the most important among methods of mathematical statistics, I advise you to read the book by S.V. Bulashev « Statistics for Traders». I will try to explain in my own words what normal distribution is. Let us assume that there are two sportsmen shooters, each of which performs 100 shots at a target. We will measure how far from the centre the bullet deviates. For example in centimeters. Having counted all the 100 shots we will get such a table.

 
 


It is seen that the distribution of hits frequency is bell-shaped with the peak near 0. For normal distributions the center coincides with mathematical expectation (arithmetic mean). Besides the bell can have flat edges or steeper edges. It is characterized by dispersion of random value around the average. The criterion of this dispersion is standard deviation (σ - sigma), which we already know how to find. Out of the two shooters in the general case the better will be the one with the smaller standard deviation.

One of the important features of standard deviation is the fact that in the interval of 3 sigmas from mathematical expectation there are 99,73% values, in the interval +- 2 sigmas - 95,45 %, and in the interval +- sigmas – 68.27 % . We will try to study the distribution of closing prices for any instrument with the help of a script.

The script will fill in the array CloseArray[] with values Close[i]-Close[i+N], where N I called shift. I.e. we will watch how distribution of increments will change depending on N, with N = from 1 to 10. Each such filling of the array I called selection, each selection will have such characteristics as average value (mathematical expectation), standard deviation (sigma), maximum and minimum value, and percentage of hits in one, two or three sigmas. These characteristics will be output in a *.csv file, so that later we can construct diagrams of distributions using them.

For writing the main features array Stat[8] is used:

 
 


Thus we can process values Close[i]-Close[i+1] on time frame D1. So to process Close[i]-Close[i+2] we have either to create a new array Stat2[] or to clear the values of array Stat[] and fill them over again. Such a way is not universal, and for such cases multidimensional arrays are used. We’d rather declare array Stat[10][8], where we will save for each shift from 1 to 10 their own characteristics.

 
 


Now we have a two-dimensional array. But there is one more moment – perhaps we will have to get statistics not only for daily bars (D1), but for other time frames as well. We will add universality with the help of one more dimension:

 
 


Arrays in MQL-4 can be no more than four-dimensional, and that is enough for most tasks. Now we can process in the cycle 7 time frames (from PERIOD_M1 to PERIOD_D1) and 10 shifts. As indexes in the first dimension can take on values from 0 to 6, I created a function that returns according to the number of time frame the value of time frame in minutes, so that this can be used in standard functions.

 
 


The formulas themselves are very simple, but the code is a little bit long.


reference http:www.statsoft.ru/home/portal/glossary/GlossaryTwo/N/NormalDistribution.htm
#property copyright "MetaQuotes" #property link "http://www.alpari-idc.ru/ru/experts/articles/"
int FileHandle;
int init() { string FileName; Print("Execute init()"); // form the name of file, for example , FileName=Symbol()+"CloseStat.csv"; //open the file FileName (we’ll create a handle at it) FileHandle=FileOpen(FileName,FILE_WRITE | FILE_CSV,";"); if (FileHandle<1) { Print("Не удалось открыть файл, ошибка ",GetLastError()); return; } return(0); } int deinit() { Print("Execute deinit()");
//close the file (release the handle, so that the file can be //open for editing by other programs) if(FileHandle>0) FileClose(FileHandle); return(0); } int start() { double CloseArray[]; double Stat[7,10,8]; // 7 time frames, 10 shifts, 8 characteristics // 0 – Number of records for the period and shift // 1 – Average in points // 2 - Max in points // 3 - Min in points // 4 – Standard deviation in points // 5 – percentage of hits in interval +- sigma 6 - ------ +- 2 sigma 7 - ------ +- 3 sigma string rangeDescription[14]; double range[13]; int freequency[14]; int curPeriod; double Summ,Average,StDev,begin; int MaxOnArray,MinOnArray; int i_period,shift,m,z,t; double sigma,sigma_2,sigma_3; int BarsPeriod;
for (i_period=0;i_period<7;i_period++) // run on time frames { curPeriod=PeriodNumber(i_period); BarsPeriod=iBars(NULL,curPeriod); for (shift=1;shift<=10;shift++) // run on shifts { ArrayResize(CloseArray,BarsPeriod-shift); ArraySetAsSeries(CloseArray,true); MaxOnArray=-10000; MinOnArray=10000; Summ=0.0; StDev=0.0; for (m=0;m<BarsPeriod-shift;m++) // run on bars { CloseArray[m]=(iClose(NULL,curPeriod,m)-iClose(NULL,curPeriod,m+shift))/Point; if (CloseArray[m]>MaxOnArray) MaxOnArray=CloseArray[m]; if (CloseArray[m]<MinOnArray) MinOnArray=CloseArray[m]; Summ+=CloseArray[m]; StDev+=MathPow(CloseArray[m],2); } // run on bars
StDev=StDev/(BarsPeriod-shift); // quadratic mean Average=Summ/(BarsPeriod-shift);// simple average StDev=MathPow(StDev-MathPow(Average,2),0.5); // standard deviation sigma Average=NormalizeDouble(Average,1); StDev=NormalizeDouble(StDev,1); MaxOnArray=NormalizeDouble(MaxOnArray,1); MinOnArray=NormalizeDouble(MinOnArray,1);
Stat[i_period][shift-1][0]=BarsPeriod-shift; Stat[i_period][shift-1][1]=Average; Stat[i_period][shift-1][2]=MaxOnArray; Stat[i_period][shift-1][3]=MinOnArray; Stat[i_period][shift-1][4]=StDev; begin=Average-3.0*StDev; for(t=0;t<13;t++) { range[t]=begin; begin+=0.5*StDev; if (GetLastError()==4002) Print("Имеем выход за пределы массива в блоке for (t=1;t<13;t++) range[t]"); } //if (GetLastError()==4002) Print("We have array overrun in block for (t=1;t<13;t++) range[t]"); rangeDescription[0]="less "+DoubleToStr(range[0],1); for (t=1;t<13;t++) { rangeDescription[t]="от "+DoubleToStr(range[t-1],1)+" до "+DoubleToStr(range[t],1); }
rangeDescription[13]="more "+DoubleToStr(range[12],1); if (GetLastError()==4002) Print("We have array overrun in block for (t=1;t<13;t++) rangeDescription[t]");
ArrayInitialize(freequency,0); for(m=0;m<BarsPeriod-shift;m++) { if (CloseArray[m]<=range[0]) freequency[0]++; for (z=0;z<12;z++) { if ((range[z]<CloseArray[m])&&(CloseArray[m]<=range[z+1])) freequency[z+1]++; } if (range[12]<=CloseArray[m]) freequency[13]++; if (GetLastError()==4002) Print("We have an array overrun in block for(m=0;m); } //Print("Тайм-фрейм ",curPeriod,"M shift ",shift," Average=",Average, //" StOff=",StDev," Max=",MaxOnArray," Min=",MinOnArray);
if (FileWrite(FileHandle,"Тайм-фрейм ",curPeriod,"M shift ",shift," Среднее=",Average, " StOff=",StDev," Max=",MaxOnArray," Min=",MinOnArray)<0) Print("Writing in file error ",GetLastError());
for(z=0;z<14;z++) { //Print("in range ",rangeDescription[z]," it is found ",freequency[z]," of values"); FileWrite(FileHandle,z,rangeDescription[z],freequency[z]); if (GetLastError()==4002) Print("We have array overrun in block for(z=0;z<14;z++)"); } sigma=freequency[5]+freequency[6]+freequency[7]+freequency[8]; // number of hits in interval +-1 st.deviation sigma_2=sigma+freequency[3]+freequency[4]+freequency[9]+freequency[10]; // -/- in interval +-2 st. deviations sigma_3=sigma_2+freequency[1]+freequency[2]+freequency[11]+freequency[12]; // -/- in interval +-3 st. deviations sigma=NormalizeDouble(100*sigma/(BarsPeriod-shift),1); // percentage of hits in the interval from -1 to +1 st. deviations sigma_2=NormalizeDouble(100*sigma_2/(BarsPeriod-shift),1); // percentage of hits in the interval from -2 to +2 sigma_3=NormalizeDouble(100*sigma_3/(BarsPeriod-shift),1); // percentage of hits in the interval from -3 to +3
Stat[i_period][shift-1][5]=sigma; Stat[i_period][shift-1][6]=sigma_2; Stat[i_period][shift-1][7]=sigma_3;
FileWrite(FileHandle,sigma,"% within the range of standard deviation "); FileWrite(FileHandle,sigma_2,"% within the range of two standard deviations "); FileWrite(FileHandle,sigma_3,"% within the range of three standard deviations "); FileWrite(FileHandle,"---"); }// run on shifts }// run on time frames //---- return(0); }
int PeriodNumber(int number) { int per_min; switch (number) { case 0: per_min=PERIOD_M1;break; case 1: per_min=PERIOD_M5;break; case 2: per_min=PERIOD_M15;break; case 3: per_min=PERIOD_M30;break; case 4: per_min=PERIOD_H1;break; case 5: per_min=PERIOD_H4;break; default: per_min=PERIOD_D1;break; } return(per_min); }

I selected blocks for better understanding of the algorithm.

 
 
 
 


Please note the numerous usage of the construction.
 
 

The point is that when arrays of dynamic sizes are processed or two arrays of different sizes are processed it easy to make a mistake, which lies in array overrun. For example I declared array
double Array[100]
and tried to address to element Array[101](or Array[100]). In this case an error with code 4002 will be generated. It won’t cause a program stoppage but the code of this error will be stored until GetLastError() is called (then the value of the internal variable containing the error code will become equal zero) or until another error takes place. It is this mistake that I have in my script and to find where exactly it takes place I had to trap all the loops. There is no other reliable way to localize the place of mistake.

After the script is launched file SymbolNameCloseDist.csv will be created. We open it, select necessary data according to distribution frequencies and press «Graph Wizard» button.

 
 


We can see that the check confirms correctness of the script’s work – the sum of selected cells is equal to the number of values with preset time frame and shift.

 
 


We choose the type of diagram and press «Next».

 
 


Everything suits us we press again «Next».

 
 


If you wish – we fill in other fields and press again «Next». The last dialog window.


 
 


We press «Ready» and place the diagram window more convenient.

 
 


Now we have the chart of increment distribution for EURUSD M15. We can see that in 10 bars with a probability of 79% the price will be not further than 23 points (1 sigma ) from the current price, with a probability of 94.4% not further than 45 points (2 sigmas) from the current price, and with a probability of 98.2% not further than 67 points (3 sigmas). You should make yourself a conclusion whether this chart corresponds to the normal distribution chart.

The script is correct, but we can refine it using technical indicators on arrays. We will call the new script CloseDist2.mq4 . Besides I introduced a new function – ArrayCopySeries(). Please note that there is no need to set the size of array temp, in which allegedly closing prices are copied.

 
 


In fact with the help of this function we get access to the time-series of closing prices (MODE_CLOSE), though we address to array temp. In case of address to the data of another time frame or symbol a situation is possible when the history of quotes is absent, in this case mistake 4066 is generated. In the second script processing of error 4006 is added, but you should note that this example is wrong:

 
 


The point is that error 4066 is generated only once when the history is updated, for the second time it may appear only on another time frame or symbol.

Comparative analysis of slightly different scripts, implementing the same task, will help to understand better the functions that are used. The training scripts themselves I hope will be also useful. You may download scripts and files Microsoft Excel here .


Go to article «The tester».

+7 (495) 710-76-76
© 1998—2008 «Alpari»

close

Your Personal Area

For alpari.classic enter your account number (a letter and 4 figures) and the code word for the Personal Area.

For alpari.micro account: enter your login (6 figures) and the password for MT.

Open an account!Forgotten your password?