MQL4:数组和循环

你好,亲爱的外汇程序员们!

在今天的课程中,根据您的要求,我们将详细介绍如何使用MQL4数组和循环。

循环用于重复代码段,数组用于存储无限数量的数据结构,然后在循环中进行处理。

让我们开始循环。由于数组元素通常使用循环来访问,所以我们首先学习如何使用它们,然后再访问数组。

MQL4中的while循环语法如下:

while(<条件>){“循环体”;}

在这种情况下,循环体将在括号中的真实条件下运行。如果这个条件在循环完成时被证明是错误的,则循环体不会执行一次。举个例子,在终端日志从1到5的整数,每个从新行开始。代码将是这样的:

int i = 1;while (i <= 5){Print( i );i++;}

根据问题的条件,我们首先定义了整数变量i,并将其设置为1。循环算子while检查变量是否小于或等于5i如果是,则执行循环体:将值打印到日志中并增加1。第一次迭代后,数字“1”出现在日志中,变量的值出现在日志中i 等于2。经过几次迭代,变量i等于6,条件i<=5错了因此,循环体将不再运行。

循环for

这种循环的工作原理与已经考虑过的相同。while在这里,只要一个条件是真的,循环体就存在。但是,在运算符中,可以指定在循环开始前执行的操作(例如,初始化计数器变量),在每个迭代完成后(增加或减少计数器)。这种循环主要用于我们事先知道迭代次数的情况。MQL4中for循环的语法如下:

for(表达式1;表达式2;表达式3){“循环体”;}
  • 表达–周期初始化通常是迭代计数器的声明和初始化;
  • 表达-循环持续的条件,只要它是真的,循环体就完成了;
  • 表达–每次迭代后计算的表达式通常会更改迭代计数器。

看看循环for在下面的例子中,我们可以找到1到1000之间的整数和。

int sum=0; // 数和变量for(int i=1; i<=1000; i++) sum+=i; // 再加上当前金额打印(“1到100的和:”,i);

我们宣布了一个变量sum为了将当前数和写入其中,并将其与零值进行指数化。

在for变量语句中i它是一个迭代计数器。我们将其宣布为初始值“1”。我们需要循环执行1000次,也就是说,只要一个变量i小于或等于1000。循环延续条件为i<=1000每次迭代后,我们必须将计数器放大1。用分号写i++.

循环体只有一个算子sum+=i,相当于记录sum=sum+i因此,这里不需要运算符括号“{}”。在循环体中,sum变量的值增加到变量的值。i,在当前迭代中包含从1到1000的另一个数字。经过一千次循环后,变量sum它将包含从1到1000的所有整数之和。

运算符中的任何三个或所有表达式for(表达式1;表达式2;表达式3)可能缺席。不能只省略分号分隔表达式,这意味着必须始终包含两个字符“;». 例如,记录for(;;)这是一个无限的循环。表达表达可以由逗号运算符“,”组合的多个表达式组成。

让我们解决这个问题。让我们在一个循环中同时打印1到5和5到1的数字。循环体只能由一个函数调用组成。Print().

for(int i=1, j=5; i<=5; i++, j--)Print(i," ",j);

如你所见,循环体执行5次,其中变量 i 从1到5,变量j从5到1。执行结果如下:

5 14 23 32 41 5

请注意,随着增量,即增加变量i在这里,我们使用减法,也就是说,把变量减少一个j.

让我们在日志中记录从1到5的五个整数循环的输出如下:

int n=1;  for(;n<=5;){Print(n);n++;}

在这里,我们宣布了一个变量-计数器到循环运算符,并将其增量放在循环体中。

循环计数器for可以增加或减少任何值,而不仅仅是1。这样就可以一步一步地实现循环。例如,在日志中打印从1到10的所有奇数。为此,我们将每次迭代后的计数器增加2,从1开始:

for(int i=1; i<=10; i+=2)Print(i);

在这种情况下,计数器变量依次为1、3、5、7、9、11,并在日志中显示1、3、5、7、9。

循环do while

如前所述,如果循环条件为c(while)最初是假的,然后循环体永远不会完成。然而,有些任务至少需要一次循环。为此,有一个循环,无论条件如何,身体至少会运行一次。循环语法do while或者,正如人们所说,MQL4中的后条件循环有以下形式:

do{“循环体”;}while(<条件]);

使用循环从1到5输出整数来完成相同的任务do while:

int i=1;do{Print(i);i++;}while(i<=5);

首先,我们宣布了一个变量-计数器i并根据任务条件将其值1初始化。然后,循环体立即完成。在日志中显示变量的值i,当时等于1,然后是变量的值i增加了一个,然后检查了条件。i<=5因为2小于5,所以循环一直持续到变量的值i不等于六。请注意,我们在将计数器的值输入日志后生成循环体中计数器的增量。如果我们在日志中显示之前这样做,则必须降低计数器的初始值并更改条件。在这种情况下,循环将是这样的:

int i=0;do{i++;Print(i);}while(i<5);

在MQL4语言中,增量操作可以直接在函数调用中执行,并且必须记住后缀增量(i++)在表达式中使用变量后立即将变量值增加1,前缀增量(++i)在表达式中使用变量之前,将变量值增加一个。现在我们的例子可以写得更紧凑:

int i=1;doPrint(i++);while(i<=5);

这里的功能Print()在日志中显示变量的值i接下来是放大。i每单位(增量):

int i=0;doPrint(++i);while(i<5);

调用函数时Print()首先,变量增加i一个,然后一个值i出现在杂志上。

让我们把这个例子更难。参赞,将其附加到图表后,它不会立即开始处理输入的抽签,而是在我们在几秒钟内指定的一段时间后开始处理。同时参赞我必须用图表上的注释告诉你还有多少秒才能运行。显然,这种延迟必须放在处理程序内部。OnInit(),因为此功能在初始化顾问时执行。

//+------------------------------------------------------------------+//| Expert initialization function                                   |//+------------------------------------------------------------------+int OnInit(){uint begin=gettickcount(),//记住gettickcount()函数的值passed_seconds,//秒过去了pause=10;            // 秒间歇Comment("");              // 清除图形上的注释,输出一个空字符串do{passed_seconds=(GetTickCount()-begin)/1000;// 发射几秒钟后comment(“顾问将通过:”,passed_seconds开始工作);}while(passed_seconds<pause);// 循环体在数量上运行//过去的秒数少于秒数Comment("");              // 清除图形上的注释,输出一个空字符串return(INIT_SUCCEEDED);}

在这个代码中,我们实现了延迟输出的剩余时间,以秒为单位的循环开始do while功能GetTickCount()返回系统启动后的毫秒数。我们用它来计算过去和现在的秒数。

操作员breakcontinue

操作员breakcontinue可用于任何类型的循环体。

在操作员的帮助下break你可以立即停止循环体的运行,而不需要任何额外的条件。它将控制传递给循环后的第一个操作员。考虑我们熟悉的在终端日志中输出1到5整数的问题的实现:

int i=1;while(true){Print(i);i++;if(i>5) break;}

在这里,我们有一个无限的循环。while,因为括号中的条件总是真的。循环体将当前变量值输出到日志中i和它的增殖。一旦意义i6,算子break停止循环。这里有一个重要的看法。如果一个循环涉及大量迭代,或者一个错误导致循环无限,程序可能不会响应“挂起”。为了避免这种情况,在循环的条件下添加函数调用IsStopped()真理的回归(true)如果终端发出命令以完成MQL4程序(例如,在运行MQL4时单击“停止”按钮)测试仪). 考虑到这一点,我们的例子可以这样写:

while(!IsStopped){Print(i);i++;if(i>5) break;}

这仍然是相同的无限循环,但它一直运行,直到被运算符打断。break或者直到终端的命令来完成程序。

需要注意的是,MQL4允许函数内部的循环被运算符打断。return例如:

void PrintNumber(){int i=1;while(!IsStopped){Print(i);i++;if(i>5) return;}}

在这种情况下,操作员return中断循环并将控制转移到调用函数的程序位置PrintNumber().

算子continue中断当前循环迭代并开始新循环。循环体中跟随算子的所有算子continue,不会执行。为了说明操作员的工作,我们稍微修改了我们的问题,将1到5个整数输入日志。所有的数字,除了2。

for(int i=1; i<=5; i++){if(i==2) continue;Print(i);}
12345

数字“2”的输出将被忽略。

算子continue如果循环体足够大,则使用方便。您可以跳过所有后续运算符并进行新的迭代。

地块

数组几乎存在于所有编程语言中,MQL4也不例外。从本质上讲,数组是一组具有相同名称的变量,但每个变量都有自己的唯一编号。例如,我们需要三个整数变量。我们可以这样宣布:

int Var1, Var2, Var3;

在这种情况下,每个变量都可以用其唯一的名称访问。例如,给变量分配值:

Var1=35;Var2=8;Var3=21;

另一方面,变量可以指定为一个由三个元素组成的数组:

int Var[3];

这些变量的名称和数组中的编号应该是:

Var[0]=35;Var[1]=8;Var[2]=21;

数组中变量的编号称为索引(来自拉丁语)index食指)。在声明数组时,方括号中表示数组的大小(元素数),在访问变量时,表示元素索引。

请注意,数组中的元素编号从零开始,而不是从1开始。这种情况通常会导致错误和问题,特别是在初学者中。数组与普通变量一样,是一个以地址开头的内存区域。在数组的情况下,对索引中每个元素的访问指定为从开始的偏移。然后,第一个元素的地址与整个数组的地址相同,即偏移量为零。第二个元素的地址是第一个元素的地址加上第一个元素大小的偏移量。第二个地址是两个位移,等等。D.其他事项

静态和动态数组

静态数组的大小在编译阶段设置,并且在程序执行过程中不会更改较大的数组。静态数组声明示例:

int Array[10];

在这里,我们宣布了一个由10个整数元素组成的数组,编译器将为其分配内存。

在执行过程中可以调整大小的数组称为动态数组。随着数组大小的变化,内存要么被分配,要么被动态释放。动态数组声明示例:

int Array[];

因此,如果在方括号中没有指定数组的大小,则它将声明为动态数组。在这种情况下,我们宣布了一个动态的整数元素数组。要使用数组,必须使用函数指定数组的大小。ArrayResize():

ArrayResize(Array,10);

现在数组Array它由10个元素组成,索引从0到9。

此函数有第三个可选参数reserveu size。您可以使用它指定“带备用”数组的大小。例如,函数的第一个调用形式为ArrayResize(Array, 10, 1000)将数组大小增加到10个元素,但物理内存将分配给数组,就像它包含1010个元素一样。也就是说,1000个元素下的内存被存储在储备中。现在,如果数组大小在1010范围内增减,则不会有物理内存分配。如果将大小增加到1011,则会分配额外的1000个备用项,以此类推。由于物理内存分配是一个相当缓慢的过程,如果程序中的阵列大小经常变化,则函数的第三个参数ArrayResize()这将是非常有用的。

在MQL4中,数组的所有元素在声明为零时初始化:数字数组为零,字符串为空。对于逻辑值数组,这是false但是,在某些情况下,数组必须用特定的值进行同化。对于静态数组,可以在声明数组时按以下方式进行:

int Numbers[5] = {3, 21, 72, 1, 8};

在这里,索引为0到4的五个元素中的每个元素在大括号中按顺序分配值。您可以以类似的方式将数组的所有元素同化为一个值:

int Numbers[5] = {82};

所有五个元素的值都为82。

不能以这种方式初始化动态数组。即使您声明数组:

int Numbers[] = {3, 21, 72, 1, 8};

编译器将其定义为静态,并根据大括号中的值数自动设置大小。

可以使用函数初始化动态数组ArrayInitialize()或者ArrayFill()第一个值填充整个数组,第二个值只能填充数组的一部分。但这样就可以初始化或只填充简单类型的数组,例如字符串需要在循环中填充。在索引中搜索所有元素并为每个元素分配所需的值。如何做到这一点,我们将在下一节讨论。

在数组中使用循环

由于数组元素是按顺序编号的,因此使用循环处理数组非常方便:对数组的所有元素或其部分执行操作,搜索具有所需特征的元素,根据某些标准对数组中的元素进行排序。最常见的应用于数组的操作是其值循环中的过度,称为数组迭代。

让我们解决这个问题。

有一个单词列表:记忆, 汽车,比萨饼,水,剪刀,猫,电池,鱼竿,雷声,桌子,旗帜,电话,雨伞,文件搜索所有超过五个字符的单词,并在日志中显示所有这些单词以及这些单词的总数。

要处理单词,请创建一个字符串数组并将单词写入其中:

字符串[]={“机器”、“比萨饼”、“水”、“剪刀”、“猫”、“电池”、“鱼竿”、“雷霆”、“桌子”、“旗帜”、“电话”、“雨伞”、“文档”};int size=ArraySize(Words);int n=0;for(int i=0; i<size; i++){if(StringLen(Words[i])>5){Print(Words[i]);n++;}}if(n>0)print(字数大于5:“,n);

在这个例子中,我们需要一个额外的变量size,我们将用函数找到的ArraySize()数组大小。在每次迭代中调用函数将其值与计数器进行比较是不合理的。在这种情况下,绕过数组元素的方向并不重要。因此,您可以通过按相反的顺序遍历数组来避免额外的变量:

int n=0;for(int i=ArraySize(Words)-1; i>=0; i--)if(StringLen(Words[i])>5){Print(Words[i]);n++;}if(n>0)print(字数大于5:“,n);

下一步任务:从动态整数数组中删除具有指定索引的元素。

double Array[]; // 准备数组来演示算法的工作原理int size=21; // 让我们把它设置为21个元素。int removed_element=17; // 删除项目索引打印(“新大小”,arrayresize(array,size));for(int i=0;i<size;i++)//用100到120的数字填充数组Array[i]=i+100.0;if(removedu element<size)//要删除的元素的索引不超出数组范围{print(“将删除索引元素”,removedu element,“value”,array[removedu element]);for(int i=removed_element+1;i<size;i++)//将删除的所有元素向左移动一个Array[i-1]=Array[i];size=ArrayResize(Array,size-1); // 将数组大小减少1,从而消除不必要的最后一个元素打印(“新数组大小:”,大小);for(int i=size-1;i>=0;i——)//将数组的所有元素记录在日志中{Print("Array[",i,"]=",Array[i]);}}elseprint(“要删除的元素的索引位于数组之外”);

数组传递到函数

数组只能通过引用传递到函数,这意味着只将现有数组的地址传递给函数,而不是其副本。函数不能返回数组本身。它只对整个数组或其单个元素执行操作。因此,如果函数的参数是数组,则必须在其名称之前写一个字符。«&»(ampersand)表示参数是通过引用传递的,名称后面有空的方括号“[]”,表示参数是数组。

让我们使用一个函数来解决上一个问题,该函数将从引用的数组中删除具有指定索引的元素。

double Array[]; // 让我们准备一个数组来演示我们未来的功能。int size=21;ArrayResize(Array,size);for(int i=0;i<size;i++)//用100到120的数字填充数组Array[i]=i+100.0;if( RemoveFromArray(Array, 17) )for(int i=ArraySize(Array)-1; i>=0; i--)//将数组的所有元素记录在日志中Print("Array[",i,"]=",Array[i]);让我们写一个函数来删除指定的元素。//+------------------------------------------------------------------+//^删除具有指定索引的动态数组元素›//如果删除成功,则返回“true”,否则。//返回false。//+------------------------------------------------------------------+bool RemoveFromArray(double &array[], int index){int size=ArraySize(array);if(index<size)//要删除的项目的索引不超出数组范围{for(int i=index+1;i<size;i++)//将删除的所有元素向左移动一个array[i-1]=array[i];size=ArrayResize(array,size-1); // 将数组大小减少1,从而消除不必要的最后一个元素return(true); // 返回真理,因为删除成功}else{print(“要删除的元素的索引位于数组之外”);return(false);// 返回错误,因为删除失败}}

如果出于某种原因,您不想更改源数组,并且要使用数组的副本执行所有操作,则可以使用arraycopy()函数。它将一个数组的内容复制到另一个数组。接收器数组自然必须声明,并且与源数组具有相同的类型。由于复制操作需要一段时间,请在任务中真正需要时尝试使用此功能。

多维数组

每个元素都有一个索引的数组称为一维数组。在此之前,我们只考虑一维数组。如果数组的每个元素都有一个以上的索引,那么我们正在处理一个多维数组。

视图记录:

int Numbers[5][4];

声明一个二维数组,换句话说,一个由四个元素组成的五个数组的数组。在视觉上,二维数组可以表示为表,在这种情况下,由五行和四列组成。二维数组的元素可以表示为表的单元格。单元格相交的字符串和列是数组元素的索引。例如,表达式Numbers[2][1]=48可以这样解释:数字“48”被写入第二列第三行表的单元格中(请记住,每个数组维度的索引都从零开始)。

因为每个数组元素Numbers两个索引必须通过两个循环来执行,一个循环嵌套在另一个循环中。例如,以下代码将数组中的所有元素设置为“10”,但元素除外。Numbers[2][1]将其设置为“48”:

for(int i=0; i<5; i++)for(int j=0; j<4; j++){if(i==2 && j==1)Numbers[i][j]=48;elseNumbers[i][j]=10;}

MQL4最多支持四个数组维度:

double prices[8][2][5]//一个三维数组的例子double levels[4][3][1][6]//四维数组

多维数组也可以是静态的或动态的。MQL4中多维动态数组的一个重要特征是,它们只能在第一个维度中动态,以下所有维度都是静态的。它们的大小必须在声明数组时显式指定。

double Prices[][2][5]; // 正确声明三维动态数组double Prices[][][5]; // 错误公告

因此,通过函数ArrayResize()只能更改数组第一维度的大小:

double Prices[][2][5];int new_size = ArrayResize(Prices,10);

需要注意的是,在这种情况下,函数ArrayResize()返回数组元素的总大小,即new_size等于100(10*2*5)。

实际上,您必须面对的大多数任务不太可能需要超过2的数组。例如,二维动态数组非常适合处理表数据,因此比其他多维数组更常见。然而,有时需要能够在两个维度中更改二维数组的大小。例如,在执行程序时,我们可能需要数组Numbers[Rows][Columns]哪里RowsColumns-这些是变量,但我们只能用变量指定第一维度的大小。您可以使用一个简单的技巧来绕过此限制:将数组的两个维度折叠为一个。也就是说,宣布一维动态数组并将其大小设置为乘积Rows*Columns,第二个维度用一个简单的公式来定义row*Columns+column哪里rowcolumn–虚拟表中单元格的坐标,并且Columns这是第二维度的大小(列的数量)。

为了更方便地使用一维动态数组作为二维数组,让我们写一个“包装”作为一个结构,我们将存储数组本身及其属性。以及使用两个索引访问数组元素的方法。

struct int2DArray{private:int               rows;                                                                // 行数int               columns;                                                             // 列数int               Values[];                                                            // 一维动态数组int               GetIndex(int row, int col) {return(row*columns+col);};               // 返回数组中单元格的索引public:int               Create(int row, int col);                                            // 设置存储单元所需的数组大小int               Get(int row, int col) {return(Values[GetIndex(row,col)]);};          // 返回单元格内容(行,col)void              Set(int row, int col, int value) {Values[GetIndex(row,col)]=value;}; // 将值写入单元格(row,col)int               AddRows(int amount);                                                 // 将字符串添加到二维数组int               Rows() {return(rows);};                                              // 返回数组中的行数int               Columns() {return(columns);};                                        // 返回数组中的行数};//+------------------------------------------------------------------+//|                                                                  |//+------------------------------------------------------------------+int int2DArray::Create(int row, int col){int size=row*col;if(size<=0)return(EMPTY);rows=row;columns=col;ArrayFree(Values);ArrayResize(Values,size);ArrayInitialize(Values,0);return(size);}//+------------------------------------------------------------------+//|                                                                  |//+------------------------------------------------------------------+int int2DArray::AddRows(int amount){int new_size=ArrayResize(Values,ArraySize(Values)+amount*columns);rows+=amount;return(new_size);}//+------------------------------------------------------------------+//| Expert initialization function                                   |//+------------------------------------------------------------------+int OnInit(){//宣布结构变量:int2DArray Array;//将数组大小设置为10行和5列:int size=Array.Create(10,5);//所有单元格均为零,其总数为50:print(“数组大小=”,size);//用非零值填充单元格(0;3),(5;0),(8;4)Array.Set(0,3,9);Array.Set(5,0,18);Array.Set(8,4,3);//确保我们在set方法中指定索引的单元格已填充:for(int i=0; i<Array.Rows(); i++)for(int j=0; j<Array.Columns(); j++){PrintFormat("Array[%d,%d]=%d",i,j,Array.Get(i,j));}//在数组中添加2行。因为我们有五列的总数,所以在物理上,2*5=10个元素将添加到一维数组的末尾。Array.AddRows(2);//用一些非零值填充单元格(10;3),(11;4)Array.Set(10,3,4);Array.Set(11,4,31);//确保我们在set方法中指定索引的单元格已填充:for(int i=0; i<Array.Rows(); i++)for(int j=0; j<Array.Columns(); j++){PrintFormat("Array[%d,%d]=%d",i,j,Array.Get(i,j));}return(INIT_SUCCEEDED);}

这种结构也可以用于其他类型的数组。不幸的是,无法创建适合任何类型数组的通用结构。

“一个错误”

循环中最常见的错误之一for或者,如果他们使用计数器,则称为“未计算单位错误”或“每单位错误”。这是由于不正确地使用比较运算符造成的。例如,循环

for(int i=1; i<=5; i++)Print(i);

5次,循环

for(int i=1; i<5; i++)Print(i);

只做了4次。在第二种情况下,值为5的变量i条件i<5它将是虚假的,这意味着循环的身体将不满足这个值。重要的是要记住,一个循环只有当它的持续条件是真的时才会发生。“未计算单位错误”在数组上下文中是最大的危险。由于数组元素索引从零开始,因此最后一个元素的索引比数组本身小1。如果由于“未计数单位”的原因,数组迭代循环比所需的迭代循环多执行一次,则程序将因严重错误而停止工作。这就是所谓的“超越数组”:

int Numbers[];int size=ArrayResize(Numbers,100);for(int i=0;i<=size;i++)//必须使用严格的i<size条件Print(Numbers[i]);

这里有变量size相当于数组的大小,即100。在循环的最后一次迭代中,计数器i它将设置为100,但数组中没有索引元素,后者的索引为99。因此,循环的条件必须是严格的——i<size.

使用链接数组快速排序复合数据

考虑使用数组以数据库风格构建索引的一个有趣的例子。MQL4有一个功能ArraySort()在第一维度上对数组进行排序。例如,使用函数对结构或对象的数组进行排序ArraySort()你不能。似乎唯一的解决方案是编写一个排序函数,与结构数组元素的物理交换位置。但是你可以创建一个二维动态数组,将所需的值复制到该数组中即可进行排序,并创建一个元素索引,这些数据在源数组中所属。通过按第一维度对这样的数组进行排序,我们可以通过第二维度中的索引访问源数组中所需的元素。不会对源数组进行物理排序。让我们以一个具体的例子来考虑这种排序。只有我们才不会对结构数组进行排序,而是对打开的订单信息进行排序,甚至不将其复制到数组中。

我们将排序标准定义为列表:

enum field{forderopenttime,//开放时间fordertype,//类型forderlots,//体积forderopenprice,//开盘价格fOrderStopLoss,   // S/LfOrderTakeProfit, // T/Pfordercommission,//委员会forderswap,//交换利润};

让我们写一个函数,它根据传递的排序标准构建索引:

//+------------------------------------------------------------------+//|                                                                  |//+------------------------------------------------------------------+void BuildIndex(field criterion, int &out[]){double Index[][2];int size=OrdersTotal(); // 订单总数ArrayResize(Index,size);for(int i=size-1;i>=0;i——)//搜索所有订单if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)){Index[i][1]=OrderTicket();switch(criterion){case fOrderOpenTime:Index[i][0]=double(OrderOpenTime());break;case fOrderType:Index[i][0]=OrderType();break;case fOrderLots:Index[i][0]=OrderLots();break;case fOrderOpenPrice:Index[i][0]=OrderOpenPrice();break;case fOrderStopLoss:Index[i][0]=OrderStopLoss();break;case fOrderTakeProfit:Index[i][0]=OrderTakeProfit();break;case fOrderCommission:Index[i][0]=OrderCommission();break;case fOrderSwap:Index[i][0]=OrderSwap();break;case fOrderProfit:Index[i][0]=OrderProfit();break;}}ArraySort(Index);// 按第一维度排序ArrayResize(out,size);//按排序顺序将票证复制到传输的数组for(int i=0; i<size; i++)out[i]=int(Index[i][1]);}//+------------------------------------------------------------------+//| Expert initialization function                                   |//+------------------------------------------------------------------+int OnInit(){ /*在调用函数之前,必须声明一个数组,该数组将按排序顺序放置对命令的引用。很明显,这些链接将使用票证-唯一的订单ID。int Tickets[];/*调用函数。作为标准,我们指定订单利润,也就是说,我们将根据订单从最小到最大的当前利润进行排序:*/BuildIndex(fOrderProfit, Tickets);//我们将按利润排序的未平仓订单信息输入日志。//搜索票证数组for(int i = ArraySize(Tickets) -1; i>=0; i--){//选择带有指定票证的订单if(OrderSelect(Tickets[i],SELECT_BY_TICKET)){int digits=int(SymbolInfoInteger(OrderSymbol(),SYMBOL_DIGITS));//创建一个包含所选订单信息的字符串并在日志中显示Print(OrderTicket()," | ",TimeToString(OrderOpenTime())," | ",(OrderType()==OP_BUY)?"buy":"sell"," | ",DoubleToStr(OrderLots(),2)," | ",OrderSymbol()," | ",DoubleToStr(OrderOpenPrice(),digits)," | ",DoubleToStr(OrderStopLoss(),digits)," | ",DoubleToStr(OrderTakeProfit(),digits)," | ",DoubleToStr(OrderCommission(),2)," | ",DoubleToStr(OrderSwap(),2)," | ",DoubleToStr(OrderProfit(),2));}}return(INIT_SUCCEEDED);}

带结果的日志片段:

分隔符后的最右边数字是当前利润。订单如您所见,字符串是按此值排序的。

结论

在本教程中,我们讨论了循环在数组中的使用。同时,他们还记得并巩固了数组和循环本身的基本信息,研究了MQL4语言中实现数组和循环的特性,分析了数组和循环编程的典型例子和方法。

论坛主题

尊敬的尤里·洛塞夫AKA LSV107
Tlap.com

MQL4教程 ,,,