English Русский Español Deutsch 日本語 Português
preview
MQL5 简介(第 6 部分):MQL5 中的数组函数新手指南 (二)

MQL5 简介(第 6 部分):MQL5 中的数组函数新手指南 (二)

MetaTrader 5交易 | 18 十一月 2024, 10:04
552 0
Israel Pelumi Abioye
Israel Pelumi Abioye

概述

欢迎来到我们 MQL5 之旅的第六部分!我们将继续探讨 MQL5 编程的细节,为您提供成功驾驭自动化交易动态世界所需的知识和技能。 本章将进一步介绍数组函数。在前面的第 5 部分中,我们通过介绍一些数组函数奠定了基础。

现在,我们将在第 6 部分探讨其余的数组函数,这将确保你对这些有用的工具有一个全面的了解。我们的目标仍然是涵盖自动交易策略所需的基本思想,无论您作为开发人员的经验水平如何,也无论您对算法交易的熟悉程度如何。我们深入探讨这些函数的细微差别,目的是促进读者的全面理解,使他们能够胜任 MQL5 编程中不断变化的工作。

本文将介绍以下数组函数:

  • ArrayPrint
  • ArrayInsert
  • ArraySize
  • ArrayRange
  • ArrarRemove
  • ArraySwap
  • ArrayReverse
  • ArraySort

1.ArrayPrint

在 MQL5 中,您可以使用预定义函数 "ArrayPrint()" 打印数组中的元素。该函数常用于调试,因为它提供了一种快速实用的方法,可以在算法或脚本运行时查看数组中保存的值。为了帮助交易员和开发人员在代码中的不同点跟踪和验证数据,函数会将数组元素输出到控制台或日志中。

类比

假设您有一个专门存放书籍的书架。您可能偶尔会忘记哪本书在哪个书架上。现在,请把 "ArrayPrint()" 当作一个秘密短语,用它来查看书架上的每一本书,而不用亲自去看每一本书。每当您想查询自己拥有哪些书籍时,只要说 "ArrayPrint()",就能看到您书架上所有书名的整洁列表。这就好比快速扫描书架,确保所有你喜欢的书都在那里!

不过,这个工具并不局限于标准打印;当你想查看书名并对其进行专门整理时,可以将 "ArrayPrint()" 视为给智能书架下达的魔法指令。您可以使用该命令指定您想要的每本书的信息量,如作者和出版日期,或者只想查看书名。甚至连标题出现的顺序都可以自定义。"ArrayPrint()" 的功能远不止这些,我们稍后再讨论。它不仅限于显示书籍的标题。让我们满怀期待地等待魔法吧!

语法:
ArrayPrint(array[], digit , Separator, Start, Count, Flags);

参数:

  • array[]:这是要打印的数组。它可以是不同数据类型的数组,也可以是简单结构的数组。
  • Digits:要显示的数组中每个数字的小数位数由该参数设置。
  • Separator:该参数用于指定打印时数组每个元素之间的分隔符。
  • Start:它指定打印应从哪个元素开始的索引。
  • Count:指定要打印的元素个数。
  • Flags:用于修改输出。这是可选项,因为默认情况下已启用。ARRAYPRINT_HEADER(该标记用于打印结构数组的标题)、ARRAYPRINT_INDEX(在左侧打印索引)和 ARRAYPRINT_LIMIT(只打印前 100 个和后 100 个数组元素)。ARRAYPRINT_ALIGN(该标记启用打印值的对齐)和 ARRAYPRINT_DATE(打印日、月、年的日期)。

示例:

void OnStart()
  {

// Define an array of doubles
   double ThisArray[] = { 1.46647, 2.76628, 3.83367, 4.36636, 5.9393};

// Print the entire array using ArrayPrint with 2 decimal places and a single spacing between array elements
   ArrayPrint(Array,2," ",0,WHOLE_ARRAY);

  }

解释:

在此代码片段中,我们处理的是一个包含给定名称的 double 值数组。该数组有五个元素,每个元素包含一个十进制数。随后一行使用 "ArrayPrint()" 函数显示数组的全部内容。

让我们来分析一下 "ArrayPrint()" 函数中使用的参数:

  • "ThisArray":这是我们要打印的数组。
  • "2":指定要显示的数组中每个元素的小数位数。
  • " ":在数组元素之间设置一个空格作为分隔符。
  • "0":指定从数组的起始位置开始打印。
  • "WHOLE_ARRAY":指定打印整个数组。
输出:

图 1.MetaTrader5 中的代码输出

这直截了当地说明了 double 型数值 "ArrayPrint() "函数的作用。现在,让我们来看看更多使用结构的例子。当我们探索使用 "ArrayPrint()" 来组织和显示结构化数据的可能性时,请准备好迎接更复杂的情况。

示例:

void OnStart()
  {

// Define a structure for storing information about students
   struct StudentsDetails
     {
      string         name;
      int            age;
      string         address;
      datetime       time; // Add a time field
     };

// Create an array of Students structures
   StudentsDetails Students[3];

// Fill in details for each person
   Students[0].name = "Abioye";
   Students[0].age = 25;
   Students[0].address = "123 MQL5 St";
   Students[0].time = TimeCurrent();

   Students[1].name = "Israel";
   Students[1].age = 26;
   Students[1].address = "456 MQL4 St";
   Students[1].time = TimeCurrent();

   Students[2].name = "Pelumi";
   Students[2].age = 27;
   Students[2].address = "789 MetaQuotes St";
   Students[2].time = TimeCurrent();

// Print the details of each person using ArrayPrint
   ArrayPrint(Students, 0, " | ", 0, WHOLE_ARRAY);

  }

解释:

struct StudentsDetails
{
   string         name;
   int            age;
   string         address;
   datetime       time; // Add a time field
};

  • 为存储学生数据,定义了一个名为 "StudentsDetails" 的结构。
  • 姓名、年龄、地址以及当天的时间和日期都会作为结构成员添加进来。
StudentsDetails Students[3];

  • 创建一个名为 Students 的数组,类型为 "StudentsDetails",大小为 3,允许存储三个学生。

Students[0].name = "Abioye";
Students[0].age = 25;
Students[0].address = "123 MQL5 St";
Students[0].time = TimeCurrent();

Students[1].name = "Israel";
Students[1].age = 26;
Students[1].address = "456 MQL4 St";
Students[1].time = TimeCurrent();

Students[2].name = "Pelumi";
Students[2].age = 27;
Students[2].address = "789 MetaQuotes St";
Students[2].time = TimeCurrent();

  • 填写每个学生的详细信息。例如,为姓名、年龄、地址和时间字段赋值,"Students[0]" 代表第一个学生。
ArrayPrint(Students, 0, " | ", 0, WHOLE_ARRAY);
  • 要显示数组中的所有学生信息,需要使用 "ArrayPrint()" 函数。打印数组,字段分隔符设置为"|"。
输出:

图 2.MetaTrader5 中的代码输出

我们利用 "ArrayPrint()" 函数在输入每个学生的所有必要详细信息后显示学生信息。上图显示的是默认输出,显示了在没有任何额外格式标志的情况下如何显示详细信息。使用指定的分隔符"|",每个学生的姓名、年龄、地址以及当前时间和日期都会清晰地显示出来。这是第一个表示方法;我们将研究如何添加更多格式化选项,以进一步自定义输出。  

要知道,在 "ArrayPrint()" 函数中添加特定的格式标志,计算机就会应用该格式标志,而忽略其他格式标志,这一点至关重要。为了说明 "ARRAYPRINT_HEADER" 标志对结果的影响,我们将在示例中加入该标志。

示例:

ArrayPrint(Students, 0, " | ", 0, WHOLE_ARRAY,ARRAYPRINT_HEADER);

输出:

图 3.MetaTrader5 中的代码输出


为了便于识别每个字段,标志指示函数为结构数组添加标题([name] [age] [address] [time])。"ARRAYPRINT_INDEX" 是本例中特意省略的标志之一,以突出每个标志的单独功能。

在对比图片中,请注意第二个输出与第一个输出不同,因为我们引入了 "ARRAYPRINT_HEADER" 标记。该标志指示 "ArrayPrint" 函数为每个字段添加标题,为显示的信息提供了清晰的标签。值得注意的是,第二次输出中没有索引信息。这就强调了一个问题,即每个格式化标记都是独立运行的,包含一个特定的标记会相应地修改输出。 为了展示根据自己的喜好调整输出的多功能性,我们还将尝试各种标志组合。

值得注意的是,在处理时间数据时,"ArrayPrint" 函数可以提供更多功能。可以使用 "ARRAYPRINT_MINUTES" 和 "ARRAYPRINT_SECONDS" 等标志来调整时间格式。通过这些标志,您可以调整所显示时间信息的详细程度,从而根据自己的喜好定制显示内容。 如果选择 "ARRAYPRINT_MINUTES" 标志,函数将只输出当前的小时和分钟,而省略日期和秒钟。另一方面,使用 "ARRAYPRINT_SECONDS" 标记可以进一步细化输出,只显示时、分、秒。这些标记可对时间表示法进行细化控制,确保输出结果与您的要求精确匹配,而不会包含不必要的细节。

示例:

ArrayPrint(Students, 0, " | ", 0, WHOLE_ARRAY,ARRAYPRINT_MINUTES);

输出:

图 4.MetaTrader5 中的代码输出

这些标志并不相互排斥。您可以将多个标志组合在一起,以更精确地定制输出。例如,如果同时应用 ARRAYPRINT_HEADER 和 ARRAYPRINT_MINUTES 标志,函数将包含列标题,并以只显示当前小时和分钟的格式显示时间。

示例:

ArrayPrint(Students,0," | ",0,WHOLE_ARRAY,ARRAYPRINT_HEADER | ARRAYPRINT_MINUTES);

输出:

图 5.MetaTrader5 中的代码输出

这展示了这些标志如何无缝协作,提供定制化的信息输出。


2.ArrayInsert

使用 "ArrayInsert()" 函数可以将元素从一个数组插入另一个数组。将源数组中的元素排列在指定位置,可以增加目标数组的大小。把它想象成把一块新的拼图整合到现有的拼图中,而不对拼图的整体设计造成任何破坏。

ArrayInsert 和 ArrayCopy 的区别:

"ArrayInsert()" 和 "ArrayCopy()" 的主要区别在于如何处理已经存在的元素。"ArrayCopy()" 可以修改原始数组,用另一个数组中的元素替换指定位置上的元素。而 "ArrayInsert()" 则通过移动当前元素为新元素腾出空间来保留数组的结构和顺序。从本质上讲,"ArrayInsert() "提供了一种在 MQL5 中操作数组的通用方法,类似于在序列中添加一个新元素,而不会导致任何其他元素移动。了解了这一区别,您就能在编程过程中精确地操作数组。

请注意,对于静态数组,如果要插入的元素数等于或超过数组大小,"ArrayInsert()" 将不会将源数组中的元素添加到目标数组中。在这种情况下,插入只能从目标数组的索引 0 开始。在这种情况下,目标数组实际上被源数组完全取代。

类比

想象一下,你有两组积木(数组),每组都有自己独特的排列方式。现在,假设您想在不破坏现有结构的情况下将这些数据集组合起来。"ArrayInsert()" 就像一个神奇的工具,能让你顺利地将一个集合中的新块插入另一个集合的特定位置,从而扩展整个集合。

现在,比较一下 "ArrayInsert()" 和 "ArrayCopy()":当你使用 "ArrayCopy()" 时,这有点像重新排列原始数据集,用另一个数据集中的新数据块替换一些数据块。而 "ArrayInsert()" 则更为精细。它通过移动区块来为新来者腾出空间,从而确保现有顺序保持不变。这就像有一个一丝不苟的助手,他知道该把每个块准确地放在哪里,从而保持了集合的原始设计。

对于静态集合(数组),有一条重要规则。如果新区块的数量过多,集合无法处理,"ArrayInsert()" 就不会强制插入。但是,如果从数据集的起点(索引 0)开始插入,则可以有效地用新数据块替换整个数据集。了解这些概念有助于您成为 MQL5 编程领域的编程大师!

语法:

ArrayInsert(DestinationArray[],SourceArray[],DestinationIndexStart,SourceIndexStart,count);

参数:

  • DestinationArray[]:从源数组接收元素并插入其中的数组。
  • SourceArray[]:要插入目标数组的数组称为源数组。
  • DestinationIndexStart:目标数组中开始插入的索引。
  • SourceIndexStart:源数组中的索引,用于复制插入元素。
  • Count:从源数组插入目标数组的元素个数。
示例:
void OnStart()
  {

// Declare two dynamic arrays
   int SourceArray[];
   int DestinationArray[];

// Resizing the dynamic arrays to have 5 elements each
   ArrayResize(SourceArray, 5);
   ArrayResize(DestinationArray, 5);

// Assigning values to dynamic array elements
   SourceArray[0] = 1;
   SourceArray[1] = 3;
   SourceArray[2] = 5;
   SourceArray[3] = 7;
   SourceArray[4] = 9;

// Assigning different values to DestinationArray
   DestinationArray[0] = 15;
   DestinationArray[1] = 20;
   DestinationArray[2] = 25;
   DestinationArray[3] = 30;
   DestinationArray[4] = 35;

// Print the elements of SourceArray before ArrayInsert/ArrayCopy
   Print("Elements of SourceArray before ArrayInsert/ArrayCopy: ");
   ArrayPrint(SourceArray, 2, " ", 0, WHOLE_ARRAY);

// Print the elements of DestinationArray before ArrayInsert/ArrayCopy
   Print("Elements of DestinationArray before ArrayInsert/ArrayCopy: ");
   ArrayPrint(DestinationArray, 2, " ", 0, WHOLE_ARRAY);

// Using ArrayInsert to insert SourceArray into DestinationArray at index 2
   ArrayInsert(DestinationArray, SourceArray, 2, 0, WHOLE_ARRAY);

// Print the modified DestinationArray after ArrayInsert
   Print("Elements of DestinationArray after using ArrayInsert: ");
   ArrayPrint(DestinationArray, 2, " ", 0, WHOLE_ARRAY);

// Reset DestinationArray to demonstrate ArrayCopy
   ArrayFree(DestinationArray);
   ArrayResize(DestinationArray, 5);

   DestinationArray[0] = 15;
   DestinationArray[1] = 20;
   DestinationArray[2] = 25;
   DestinationArray[3] = 30;
   DestinationArray[4] = 35;

// Using ArrayCopy to copy elements from SourceArray to DestinationArray
   ArrayCopy(DestinationArray, SourceArray, 2, 0, WHOLE_ARRAY);

// Print the modified DestinationArray after ArrayCopy
   Print("Elements of DestinationArray after using ArrayCopy: ");
   ArrayPrint(DestinationArray, 2, " ", 0, WHOLE_ARRAY);

  }
解释:

int SourceArray[];
int DestinationArray[];

  • 这里声明了 "SourceArray" 和 "DestinationArray" 这两个动态数组。整数值将保存在这些数组中。

ArrayResize(SourceArray, 5);
ArrayResize(DestinationArray, 5);

  • 这些代码行将动态数组的大小调整为每个数组包含五个元素。为此,我们使用了 "ArrayResize()" 函数。

SourceArray[0] = 1;
SourceArray[1] = 3;
SourceArray[2] = 5;
SourceArray[3] = 7;
SourceArray[4] = 9;

  • "SourceArray" 元素是给定值。
DestinationArray[0] = 15;
DestinationArray[1] = 20;
DestinationArray[2] = 25;
DestinationArray[3] = 30;
DestinationArray[4] = 35;
  • "DestinationArray" 元素是给定值。
Print("Elements of SourceArray before ArrayInsert/ArrayCopy: ");
ArrayPrint(SourceArray, 2, " ", 0, WHOLE_ARRAY);
  • 这一行使用 "ArrayPrint()" 函数打印 "SourceArray" 中的元素,然后向控制台打印一条信息。空格用作分隔符,格式中显示两位小数。
Print("Elements of DestinationArray before ArrayInsert/ArrayCopy: ");
ArrayPrint(DestinationArray, 2, " ", 0, WHOLE_ARRAY);
  • 与上一行类似,该行打印一条信息,然后打印 "DestinationArray" 中的元素。
ArrayInsert(DestinationArray, SourceArray, 2, 0, WHOLE_ARRAY);
  • 这一行使用 "ArrayInsert()" 函数从索引 2 开始将 "SourceArray" 中的元素插入 "DestinationArray"。
Print("Elements of DestinationArray after using ArrayInsert: ");
ArrayPrint(DestinationArray, 2, " ", 0, WHOLE_ARRAY);
  • 在执行 "ArrayInsert()" 操作后,会打印一条信息,然后是 "DestinationArray" 中被修改的元素。
ArrayFree(DestinationArray);
ArrayResize(DestinationArray, 5);
  • 释放内存后,这些行将 "DestinationArray" 的大小调整为再次包含五个元素。
DestinationArray[0] = 15;
DestinationArray[1] = 20;
DestinationArray[2] = 25;
DestinationArray[3] = 30;
DestinationArray[4] = 35;
  • 再次为 "DestinationArray" 元素赋值。
ArrayCopy(DestinationArray, SourceArray, 2, 0, WHOLE_ARRAY);
  • 这一行使用 ArrayCopy 函数从索引 2 开始将 SourceArray 中的元素复制到 DestinationArray 中。
Print("Elements of DestinationArray after using ArrayCopy: ");
ArrayPrint(DestinationArray, 2, " ", 0, WHOLE_ARRAY);
  • 这将打印一条信息,然后打印 "ArrayCopy()" 操作后 "DestinationArray" 中修改过的元素。

输出:

图 6.MetaTrader5 中的代码输出

本代码示例旨在演示 MQL5 的 "ArrayInsert()" 和 "ArrayCopy()" 函数之间的区别。虽然操作数组元素是这两个函数的共同用途,但它们的功能是不同的。本例中使用了两个动态数组 - "SourceArray" 和 "DestinationArray"。在执行任何操作之前,脚本都会显示这些数组中包含的元素。然后,利用 ArrayInsert 将 "SourceArray" 中的元素插入到 "DestinationArray" 中的指定位置。然后,重置数组,并使用 "ArrayCopy()" 将 "SourceArray" 中的元素复制到 "DestinationArray" 中。它们的行为是区别最大的地方:在目标数组的特定位置插入元素时,"ArrayInsert()" 会移动现有元素,为新元素腾出空间。它有助于将元素放在所需的索引处。通过 "ArrayCopy()",源数组中的元素会被复制并替换为目标数组中的任何现有元素。可在数组间高效复制元素,而不会影响已设置的值。


3.ArraySize

MQL5 函数 "ArraySize()" 用于确定一维数组中包含多少个元素。返回一个表示指定数组中元素总数的整数,使确定数组大小的过程变得更简单。

类比

假设你有一个书架,上面摆满了不同的书,每本书都代表数组中的一个元素。就像图书管理员一样,"ArraySize()" 函数会告诉你书架上书籍的精确数量。同样,使用 "ArraySize()" 可以更有效地管理和排列数据,当应用到数组时,它会告诉你数组包含的元素总数。程序员可以将其作为一种有用的工具来了解数组的大小,并确保他们在编码时拥有适当数量的 "书籍"。

语法:
ArraySize( array[]);

参数:

  • array[]:该参数表示要查找大小的数组。
示例:

void OnStart()
  {

// Declare an array
   int array[5];

// Get the size of the array using ArraySize
   int arraySize = ArraySize(array);

// Print the array size
   Print("The size of array is: ", arraySize); // Output will be 5

  }

解释:

"int array[5];"

  • 这一行声明了一个名称为 "array"、大小为 "5" 的整数数组。

"int arraySize = ArraySize(array);"

  • 这一行创建了一个名为 "arraySize" 的新整数变量,并使用赋值操作符 "=" 将其值设置为 "ArraySize"(数组)的结果。由于数组的大小总是整数,因此使用了 "int" 类型。MQL5 提供的用于确定数组大小的函数称为 "ArraySize"(大写),我们声明用于存储结果的变量称为 "arraySize"(小写)。必须注意编程语言的大小写敏感性。大写的 ArraySize 表示内置数组,小写的 arraySize 表示我们的特定变量。

“Print("The size of array is: ", arraySize);”:

  • 这一行使用 "Print" 函数向控制台打印一条信息。它显示了数组的大小,该大小来自于 "arraySize" 变量。

在深入探索 MQL5 编程的神奇世界时,您必须慢慢学习我们遇到的每个函数的复杂性。这就像在工匠的车间里学习如何使用工具来理解 ArraySize、ArrayInsert 和 ArrayPrint 等函数一样,每个函数都有特定的用途。慢慢学习,了解其中的奥妙;不要急于求成。我们将在后面的文章中介绍的更复杂的想法都将以这些函数为基础。


4.ArrayRange

MQL5 编程中的 "ArrayRange()" 函数对于计算多维数组中指定维数的元素个数至关重要。对于处理复杂数组的开发人员来说,它是一个非常有用的工具,可以为他们提供多维数组中给定层级或维度上有多少元素的准确信息。该函数无需处理计算所有维度共有多少元素的复杂问题,只需专注于特定维度,就能提供深入的见解。

ArrayRange 与 ArraySize 的区别

现在我们来区分一下 "ArraySize()" 和 "ArrayRange()"。虽然这两个函数都能提供对数组维度的洞察力,但它们各自的范围不同。使用 "ArraySize()" 可以找到一维数组的全部元素数。 

一维数组和多维数组在数据排列和结构方面各不相同。元素按一行排列的简单列表类似于一维数组。可以通过参照元素在线性结构中的位置来访问它们。

不过,多维数组增加了更多的结构层次。它们的组件按行和列排列,就像矩阵或表格。要访问多维数组中的元素,必须指定行和列索引,这提供了一种结构更合理的数据组织和检索方法。一维数组本质上是简单的线性序列,而多维数组则通过更像网格一样排列元素来增加复杂性。

类比

想象一下,你有一个巨大的书架,代表一个多维数组,每个书架都有不同的维度。MQL5 中的 "ArrayRange()" 函数就像一个神奇的放大镜,可以让您专注于一个特定的书架,显示该书架上书籍(元素)的确切数量。在处理复杂的信息库时,该工具非常方便。

现在让我们对比一下 "ArraySize()" 和 "ArrayRange()"。如果书籍是线性排列的,类似于一维数组,那么 "ArraySize()" 表示整个书架上书籍的总数。另外,您也可以使用 "ArrayRange()" 来放大书柜的某一部分,以精确计算书柜中的书籍数量。

语法:

ArrayRange(array[], dimensionIndex);

参数:

  • array[]:您要验证的数组的范围。
  • dimensionIndex: 需要确定范围的维度索引,从 0 开始。
示例:

void OnStart()
  {

// Declare a three-dimensional array
   double my3DArray[][2][4];

// Get the range of the first dimension (index 0)
   int dimension1Index = ArrayRange(my3DArray, 0);

// Get the range of the second dimension (index 1)
   int dimension2Index = ArrayRange(my3DArray, 1);

// Get the range of the third dimension (index 2)
   int dimension3Index = ArrayRange(my3DArray, 2);

   Print("Number of elements in dimension 1: ", dimension1Index);
   Print("Number of elements in dimension 2: ", dimension2Index);
   Print("Number of elements in dimension 3: ", dimension3Index);

  }

解释:

double my3DArray[][2][4];
  • 这一行声明了一个名为 "my3DArray" 的三维数组。

int dimension1Index = ArrayRange(my3DArray, 0);
  • 在这种情况下,可以使用 "ArrayRange()" 函数确定 my3DArray 的第一个维度(索引 0)中的范围(元素数量)。变量 "dimension1Index" 保存结果。
int dimension2Index = ArrayRange(my3DArray, 1);
  • 同样,该行获取并在变量 "dimension2Index" 中存储 "my3DArray" 的第二个维度(索引 1)的范围。

int dimension3Index = ArrayRange(my3DArray, 2);

  • 这一行将变量 "dimension3Index" 的值赋值给 "my3DArray" 的第三个维度(索引 2)的范围。

Print("Number of elements in dimension 1: ", dimension1Index);
Print("Number of elements in dimension 2: ", dimension2Index);
Print("Number of elements in dimension 3: ", dimension3Index);

  • 最后,我们使用 Print 函数显示结果和每个维度的元素数量。三维阵列尺寸的第一、第二和第三维都包含在打印信息中。
输出:

图 7.MetaTrader5 中的代码输出



5.ArrayRemove

"ArrayRemove()" 函数是一种有效的工具,可让程序员从数组中移除特定元素。数组的大小和结构会自动调整,以适应删除的需要,确保无缝删除过程。开发人员可以灵活地操作数组,因为他们可以指定起始索引和希望删除的元素数量。在处理必须随程序条件变化而动态修改的数组时,该函数尤其有用。

但说到 "ArrayRemove()",其行为会因使用的是静态数组还是动态数组而有所不同。对于动态数组,该功能可有效移除指定的一个或多个元素,并平滑调整数组大小,从而确保移除过程简化。另一方面,在处理静态数组时,"ArrayRemove()" 会删除指定的元素并保持数组的原始大小。但为了克服静态数组的固定性,该函数会复制数组末尾之后的元素来填补空缺。该方法允许在保持大小固定的情况下删除元素,使 "ArrayRemove()" 对各种数组情况的理解更加细致入微。在本节的学习过程中,更多的示例和见解将帮助我们更深入地理解 "ArrayRemove()",以及它在不同的数组场景中是如何工作的。

类比

把我们的数组看成一个书架,每本书都代表着信息位。现在,MQL5 为我们提供了一个类似于书架整理工具的独特工具,名为 "ArrayRemove()"。我们可以使用这个整理器将书架上的特定书籍移走,然后整齐地摆放剩余的书籍,填补空白。

想象一下,你有一个动态书架,可以轻松添加或删除书籍。在这种情况下,整理器可以在取出书籍后顺利调整书架,不会出现任何问题。然而,如果你的书架更像是一个固定大小的显示器,你无法改变它的大小(静态数组),那么在使用静态数组时,"ArrayRemove()" 就无法改变书架的大小,因此它会巧妙地复制数组末尾的书来填补空缺。这就好比把书架上最后一本书复制一份,然后放在被拿走的书的空隙里。这样,固定尺寸的书架就能保持完整,不会浪费空间。

因此,如果你从书架中间移走一本书,"ArrayRemove()" 会确保复制书架的末端来填补空缺,从而保留数组的结构。当你有特定数量的插槽(元素)需要维护时,这就特别方便了,它提供了一种在不改变书架大小的情况下整理书架的方法。

 

语法:
ArrayRemove(array[],start_index,count);
参数:

  • array[]:这是将被删除元素的数组。储藏区或书架是您要进行改动的地方。
  • start_index:它表示数组内移除的起点。例如,要删除从第三个书架开始的图书,您可以将索引设置为 3。
  • count:要从数组中删除的元素个数。如果您想删除三本书,您可以将计数设置为 3。
示例:
void OnStart()
  {

// Declare fixed-size array
   int fixedSizeArray[5] = {11, 13, 17, 21, 42};

// Declare dynamic array
   int dynamicArray[];
   ArrayResize(dynamicArray, 5);
   dynamicArray[0] = 11;
   dynamicArray[1] = 13;
   dynamicArray[2] = 17;
   dynamicArray[3] = 21;
   dynamicArray[4] = 42;

// Print initial arrays
   Print("Initial fixedSizeArray: ");
   ArrayPrint(fixedSizeArray, 0, " ", 0, WHOLE_ARRAY);

   Print("Initial dynamicArray: ");
   ArrayPrint(dynamicArray, 0, " ", 0, WHOLE_ARRAY);

// Remove two elements at index 2 from both arrays
   ArrayRemove(fixedSizeArray, 2, 2);
   ArrayRemove(dynamicArray, 2, 2);

// Print arrays after removal
   Print("After removing 3 elements at index 2 - fixedSizeArray: ");
   ArrayPrint(fixedSizeArray, 0, " ", 0, WHOLE_ARRAY);

   Print("After removing 3 elements at index 2 - dynamicArray: ");
   ArrayPrint(dynamicArray, 0, " ", 0, WHOLE_ARRAY);

  }
解释:

// Declare fixed-size array
   int fixedSizeArray[5] = {11, 13, 17, 21, 42};

// Declare dynamic array
   int dynamicArray[];
   ArrayResize(dynamicArray, 5);
   dynamicArray[0] = 11;
   dynamicArray[1] = 13;
   dynamicArray[2] = 17;
   dynamicArray[3] = 21;
   dynamicArray[4] = 42;

  • 声明一个固定大小为 5 的整数静态数组,名为 "fixedSizeArray",并使用 11、13、17、21 和 42 的值初始化数组。
  • 声明一个名为 "dynamicArray" 的整数动态数组,但未指定初始大小。使用 "ArrayResize" 将 "dynamicArray" 的大小调整为 5。

Print("Initial fixedSizeArray: ");
ArrayPrint(fixedSizeArray, 0, " ", 0, WHOLE_ARRAY);

Print("Initial dynamicArray: ");
ArrayPrint(dynamicArray, 0, " ", 0, WHOLE_ARRAY);

  • 使用 "ArrayPrint" 打印 "fixedSizeArray" 和 "dynamicArray" 的初始元素
ArrayRemove(fixedSizeArray, 2, 2);
ArrayRemove(dynamicArray, 2, 2);
  • 使用 "ArrayRemove",从索引 2 开始,从 "fixedSizeArray" 和 "dynamicArray" 中删除两个元素。
Print("After removing 3 elements at index 2 - fixedSizeArray: ");
ArrayPrint(fixedSizeArray, 0, " ", 0, WHOLE_ARRAY);

Print("After removing 3 elements at index 2 - dynamicArray: ");
ArrayPrint(dynamicArray, 0, " ", 0, WHOLE_ARRAY);
  • 删除过程结束后,使用 "ArrayPrint" 打印 "fixedSizeArray" 和 "dynamicArray" 中的元素。
输出:

 

图 8.MetaTrader5 中的代码输出

所给代码的输出如上图所示,显示了 "ArrayRemove()" 函数在静态和动态数组中的表现。动态数组的操作步骤非常简单:只需删除指定索引处的元素即可。为了填补移除后产生的空白,静态数组的函数会复制数组结束后出现的元素。这种微妙的行为展示了 "ArrayRemove()" 适应各种数组类型的方式。

当我们阅读完这些文章并进入实际示例后,"ArrayRemove()" 的概念将变得更加清晰。请不要犹豫,提出更多问题;我们将一起继续探索和理解这些概念。


6.ArraySwap

在 MQL5 编程中,"ArraySwap()" 函数的目的是切换两个动态数组的全部内容。借助该函数,两个数组之间的所有元素都可以更轻松地交换。它提供了一种在数组之间切换整个数据集的简单方法,从而加快了 MQL5 重新排列数组内容的过程。

类比

假设您有两个装满书的书柜。通过 "ArraySwap()" 函数,你可以将一个书架上的每本书与其他书进行交换,就像巫师的咒语一样。如果 "书架 A" 上有一些书,而 "书架 B" 上有其他书,那么要想让 "书架 A" 上的所有书都移到 "书架 B" 上,或者让 "书架 B" 上的所有书都移到 "书架 A" 上,可以使用 "ArraySwap()" 咒语。这是一种轻松的方法,可以将两个书架上的每本书进行交换,而不必担心任何特定的书籍。

语法:
ArraySwap(dynamic_array1, dynamic_array2);

参数:

假设您有两个装满书的书柜。通过 "ArraySwap()" 函数,你可以将一个书架上的每本书与其他书进行交换,就像巫师的咒语一样。如果 "书架 A" 上有一些书,而 "书架 B" 上有其他书,那么要想让 "书架 A" 上的所有书都移到 "书架 B" 上,或者让 "书架 B" 上的所有书都移到 "书架 A" 上,可以使用 "ArraySwap()" 咒语。这是一种轻松的方法,可以将两个书架上的每本书进行交换,而不必担心任何特定的书籍。

示例:

void OnStart()
  {

// Declare dynamic arrays
   int dynamic_array1[];
   int dynamic_array2[];

// Resize dynamic arrays to have 5 elements each
   ArrayResize(dynamic_array1, 5);
   ArrayResize(dynamic_array2, 5);

// Assign values to dynamic arrays
   dynamic_array1[0] = 1;
   dynamic_array1[1] = 3;
   dynamic_array1[2] = 5;
   dynamic_array1[3] = 7;
   dynamic_array1[4] = 9;

   dynamic_array2[0] = 11;
   dynamic_array2[1] = 13;
   dynamic_array2[2] = 15;
   dynamic_array2[3] = 17;
   dynamic_array2[4] = 19;

// Print initial dynamic arrays
   Print("Initial dynamic_array1: ");
   ArrayPrint(dynamic_array1, 0, " ", 0, WHOLE_ARRAY);

   Print("Initial dynamic_array2: ");
   ArrayPrint(dynamic_array2, 0, " ", 0, WHOLE_ARRAY);

// Swap the contents of dynamic_array1 and dynamic_array2
   ArraySwap(dynamic_array1, dynamic_array2);

// Print dynamic arrays after swapping
   Print("After swapping - dynamic_array1: ");
   ArrayPrint(dynamic_array1, 0, " ", 0, WHOLE_ARRAY);

   Print("After swapping - dynamic_array2: ");
   ArrayPrint(dynamic_array2, 0, " ", 0, WHOLE_ARRAY);
  }

解释:

// Declare dynamic arrays
   int dynamic_array1[];
   int dynamic_array2[];

// Resize dynamic arrays to have 5 elements each
   ArrayResize(dynamic_array1, 5);
   ArrayResize(dynamic_array2, 5);

  • 在这几行中声明了动态整数数组 "dynamic_array1" 和 "dynamic_array2"。 使用 "ArrayResize" 函数将每个动态数组的大小设置为 5。

// Assign values to dynamic arrays
   dynamic_array1[0] = 1;
   dynamic_array1[1] = 3;
   dynamic_array1[2] = 5;
   dynamic_array1[3] = 7;
   dynamic_array1[4] = 9;

   dynamic_array2[0] = 11;
   dynamic_array2[1] = 13;
   dynamic_array2[2] = 15;
   dynamic_array2[3] = 17;
   dynamic_array2[4] = 19;

  • 这两行为 "dynamic_array1" 和 "dynamic_array2" 中的每个元素赋予一个特定值。
// Print initial dynamic arrays
   Print("Initial dynamic_array1: ");
   ArrayPrint(dynamic_array1, 0, " ", 0, WHOLE_ARRAY);

   Print("Initial dynamic_array2: ");
   ArrayPrint(dynamic_array2, 0, " ", 0, WHOLE_ARRAY);
  • 这两行会将 "dynamic_array1" 和 "dynamic_array2" 的初始值打印到控制台。
// Swap the contents of dynamic_array1 and dynamic_array2
   ArraySwap(dynamic_array1, dynamic_array2);
  • 要使用 "ArraySwap()" 函数将 "dynamic_array1" 中的所有内容替换为 "dynamic_array2"。
// Print dynamic arrays after swapping
   Print("After swapping - dynamic_array1: ");
   ArrayPrint(dynamic_array1, 0, " ", 0, WHOLE_ARRAY);

   Print("After swapping - dynamic_array2: ");
   ArrayPrint(dynamic_array2, 0, " ", 0, WHOLE_ARRAY);
  • 交换过程结束后,这两行会将 "dynamic_array1" 和 "dynamic_array2" 的更新值打印到控制台。
输出:

图 9.MetaTrader5 中的代码输出



7.ArrayReverse

使用 "ArrayReverse()" 函数可以重新排列数组元素,或翻转其顺序。借助这一功能,开发人员可以快速翻转序列中的元素,使最后一个元素成为第一个元素,反之亦然。这种操作提供了一种灵活有效的方法,可以改变包含各种数据类型的数组中元素的排列。在编程过程中,如果需要颠倒元素的顺序,"ArrayReverse()" 会使这一过程变得更容易,并产生更简洁、可读性更强的代码。

类比

想象一下,书架上有一排书,每本书上都有一个编号。就好像这些书被 "ArrayReverse()" 函数神奇地重新排列了,最右边的书现在在最左边,反之亦然。这是一种改变书架上书籍顺序的简单方法。不仅如此,它在编程中也能发挥类似的作用,您可以使用 "ArrayReverse()" 来翻转列表或数组中的项目顺序,从最后一个项目开始,直到第一个项目。这就像在你的数组上向后施法,毫不费力地将其翻转过来。

语法:
ArrayReverse(array[], start, count);

参数:

  • array[]:该参数表示要反转的数组。
  • start:您希望开始反转的数组中的索引。
  • count:数组中应该反转的元素个数。

例子:
void OnStart()
  {

// Declare and initialize a 10-element array
   int array[10] = {1, 3, 5, 7, 9, 11, 13, 15, 17, 19};

// Print the original array
   Print("Original Array: ");
   ArrayPrint(array, 0, " ", 0, WHOLE_ARRAY);

// Reverse the array starting from index 4
   ArrayReverse(array, 4, WHOLE_ARRAY);

// Print the array after reversal
   Print("Array after reversal from index 4: ");
   ArrayPrint(array, 0, " ", 0, WHOLE_ARRAY);

  }

这段代码用指定元素初始化数组,打印原始数组,从索引 4 开始反转数组,然后打印结果。


输出:

图 10.MeterTrader5 中的代码输出



8.ArraySort

要对数组元素进行升序排序,"ArraySort()" 函数是一个非常有用的工具。通过使用该函数,您可以快速按顺序排列数组中的元素,从最小值开始,依次排列到最大值。在处理包含数值的数组时,这一功能尤其方便。

类比

想象一下,您希望将一组混杂的数字从小到大排列整齐。在 "ArraySort()" 函数的帮助下,您可以快速地将这些数字排序到适当的顺序,该函数就像一个魔法咒语。因此,您只需使用一条简单明了的命令,就能轻松识别列表中最小和最大的数字,并很好地对数字进行排序。有了 "ArraySort()" 函数的神奇功能,你就能以易于理解和结构化的方式看到这些数字!

语法:

ArraySort(array[]); // array[] 是要升序排序的数组

示例:
void OnStart()
  {

// Declare an array of numbers
   double array[5] = {9.5, 2.1, 7.8, 1.3, 5.6};

// Print the array before sorting
   Print("Array before sorting: ");
   ArrayPrint(array, 1, " ", 0, WHOLE_ARRAY);

// Use ArraySort to arrange the array in ascending order
   ArraySort(array);

// Print the array after sorting
   Print("Array after sorting: ");
   ArrayPrint(array, 1, " ", 0, WHOLE_ARRAY);

  }
输出:

图 11.MetaTrader5 中的代码输出


结论

现在,我们已经介绍了 MQL5 中数组管理的许多关键思路,包括 ArrayPrint、ArrayInsert、ArraySize、ArrayRange、ArrarRemove、ArraySwap、ArrayReverse 和 ArraySort。我们的目标是在本系列文章中涵盖作为交易策略自动化基础的各种基本思路。了解这些数组函数至关重要,尤其是在使用历史数据创建 EA 交易的时候。无论读者的经验水平如何,我都会确保每位读者都能掌握这些基本概念,为进入 MQL5 编程和算法交易之旅奠定基础。 

在结束本文时,我呼吁大家以耐心和好奇心来对待每一个想法,因为这些基本构件在今后的文章中将会非常重要,并将使开发可靠的自动交易系统变得既有价值又易于操作。您的理解是我的首要任务,因此,如果您需要帮助或澄清本文的任何部分,请随时联系我并提出问题。我们将在下一篇文章中通过视频全面介绍第 5 部分和第 6 部分中讨论的数组函数的各个方面。为了消除您的疑虑,该视频提供了一份可视化手册,帮助您更好地理解这些重要的 MQL5 编程思想。

本文由MetaQuotes Ltd译自英文
原文地址: https://www.mql5.com/en/articles/14407

一种采用纯MQL5语言实现的基于能量学习的特征选择算法 一种采用纯MQL5语言实现的基于能量学习的特征选择算法
本文介绍了一种在学术论文《FREL:一种稳定的特征选择算法》中描述的特征选择算法的实现,该算法被称为基于正则化能量的特征加权学习。
您应当知道的 MQL5 向导技术(第 12 部分):牛顿多项式 您应当知道的 MQL5 向导技术(第 12 部分):牛顿多项式
牛顿多项式,其依据一组少量点创建二次方程,是一种古老但有趣的时间序列观察方式。在本文中,我们尝试探讨这种方式在哪些方面对交易者有用,并解决其局限性。
一步步学习如何利用公允价值缺口(FVG)或市场不平衡性来交易的策略:一种“聪明资金”的交易方法 一步步学习如何利用公允价值缺口(FVG)或市场不平衡性来交易的策略:一种“聪明资金”的交易方法
基于公允价值缺口(FVG)交易策略的MQL5自动化交易算法创建与分步实施指南。这一教程旨在为无论是初学者还是经验丰富的交易者提供一个实用的EA创建指南。
群体优化算法:抵抗陷入局部极值(第二部分) 群体优化算法:抵抗陷入局部极值(第二部分)
我们将继续我们的实验,它的目标是研究群体优化算法在群体多样性较低时有效摆脱局部最小值并达到全局最大值的能力。提供了研究的结果。