第一个程序

让我们试着在脚本中添加一些简单但具有说明性的内容,以演示脚本的运行。我们将修改后的脚本重命名为 HelloChart.mq5

在许多编程教材中,第一个例子都是打印经典的 "Hello, world"。在 MQL5 中,类似的问候语如下所示:

void OnStart()
{
  Print("Hello, world");
}

但我们会让它的信息量更丰富:

void OnStart()
{
  Print("Hello, "Symbol());
}

因此,我们只添加了一个字符串,但包含多个语言结构。

此处,Print 是嵌入在终端的函数的名称,用于在 EA 交易日志中显示消息(工具窗口中的选项卡 EA 交易;尽管此选项卡名为 EA 交易,但会收集所有 MQL 程序类型的消息)。与我们单独定义的 OnStart 函数不同,Print 函数是预先为我们定义的,并且是永久性的。 Print 是构建 MQL5 API(应用程序编程接口)的多个嵌入式函数之一。

代码中新增的代码行表示调用 Print 函数的语句,用于向函数发送自变量列表(圆括号中),这些自变量将打印在日志中。列表中的自变量用逗号分隔。本例中有两个自变量,分别是:代码行 "Hello " 以及对另一个嵌入式函数 Symbol 的调用,后者返回当前图表上活动金融工具的名称(从中获得的值将立即被传入 Print 函数自变量列表中,即调用 Symbol 函数的位置)。

Symbol 函数没有任何参数,因此不会向圆括号中传送任何内容。

例如,如果是对 "EURUSD" 图表运行脚本,那么调用 Symbol() 函数将返回 "EURUSD",对于正在执行的程序,调用 Print 函数的语句将有所不同,如下所示:Print("Hello, ", "EURUSD")。当然,从用户的角度来看,所有这些对函数的调用和中间结果的动态替换都是无缝且即时完成。不过对于程序员来说,充分认识到程序的逐步执行过程至关重要,这样既能避免逻辑错误,又能确保代码严格符合预期设想。

双引号内的 "Hello " 行被称为字面量,也就是被计算机按原样识别为文本的固定字符序列(与在程序源代码中的形式完全一致)。

因此,上述打印语句必须在日志中逐个打印这两个自变量,这应导致将两行合并,得到 "Hello, EURUSD"。

重要的是,引号内的逗号将作为该行的一部分在日志中打印,不会进行任何特殊处理。与此不同的是,右引号之后且 Symbol() 调用之前的逗号是自变量列表中的分隔字符,会影响程序行为。如果省略第一个逗号,程序仍然是正确的,只是在打印的文字 "Hello" 后面没有逗号。但如果省略第二个逗号,程序将停止编译,因为函数自变量列表的语法将被破坏:其中的所有值(本例中有两行)必须用逗号分隔。

编译器错误如下所示:

'Symbol' - some operator expected        HelloChart.mq5        16        19

编译器会报错,提示在引用 Symbol 之前缺少关键内容。这将中断编译,也不会创建程序的可执行文件。因此,我们要把逗号放回原处。

这个例子向我们展示了严格遵循语言语法的重要性。同样的字符,在程序中的位置不同,作用也会有所不同。可以说是失之毫厘,谬以千里。例如,注意调用 Print 的代码行结尾的分号。分号在这里表示语句结束。如果我们忘记输入这个分号,可能会出现奇怪的编译器错误。

要验证这一点,我们尝试移除这个分号并重新编译脚本。这将导致出现新错误,其中包含有关问题的说明以及在源代码中的位置。

MetaEditor 日志中的编译错误

MetaEditor 日志中的编译错误

 

'}' - semicolon expected        HelloChart.mq5        17        1
'}' - unexpected end of program        HelloChart.mq5        17        1

第一个错误明确指出缺少编译器所期望的分号。第二个错误是传播性的:在当前语句结束之前,检测到了表示程序结束的右花括号。在编译器看来,它将继续编译,因为它还没有遇到分号。修复这类错误的方法很明显:必须将分号放回语句中的正确位置。

我们来进行编译并启动修复后的脚本。它执行速度非常快,几乎从图表中瞬间消失,同时在 EA 交易日志中显示一条记录,确认脚本运行。

HelloChart (EURUSD,H1)        Hello, EURUSD