您需要了解的有关MQL5程序结构的所有信息(基础篇)
「MQL5 程序的骨架长什么样」
打开任意一个 MT5 自编指标或 EA,最先撞见的是三块固定结构:预处理指令、全局变量与函数体。缺少任何一块,编译器都会直接报错,连回测都进不去。
MQL5 强制要求 #property 这类预处理指令放在文件顶部,用来声明脚本类型、图标、链接等元信息;紧接着是全局作用域里的输入参数(input)和句柄,最后才是 OnInit、OnTick 等事件函数。这套顺序不是风格偏好,是编译器硬约束。
以最精简的指标框架为例,下面这段代码能在 MT5 里直接编译通过,方便你马上开终端验证:
一个常见坑是把自己算好的缓冲区数组漏写 SetIndexBuffer,结果图表上指标线不显示却无任何报错提示,只能靠肉眼排查。外汇与贵金属品种波动剧烈,用这类自编工具前务必在策略测试器跑至少 3 个月 tick 数据,确认无数组越界再上实盘。
class="macro">#class="kw">property indicator_separate_window class="macro">#class="kw">property indicator_buffers class="num">1 class="macro">#class="kw">property indicator_plots class="num">1 class="type">class="kw">double Buffer[]; class="type">int OnInit() { SetIndexBuffer(class="num">0, Buffer, INDICATOR_DATA); class="kw">return(INIT_SUCCEEDED); } class="type">int OnCalculate(class="kw">const class="type">int rates_total, class="kw">const class="type">int prev_calculated, class="kw">const class="type">class="kw">datetime &time[], class="kw">const class="type">class="kw">double &open[], class="kw">const class="type">class="kw">double &high[], class="kw">const class="type">class="kw">double &low[], class="kw">const class="type">class="kw">double &close[], class="kw">const class="type">long &tick_volume[], class="kw">const class="type">long &volume[], class="kw">const class="type">int &spread[]) { for(class="type">int i=class="num">0; i<rates_total; i++) Buffer[i]=close[i]; class="kw">return(rates_total); }
◍ 先摸清 MQL5 程序的骨架
不管用什么语言写软件,底层都有一套固定结构;看明白它,后面写 EA、指标、脚本才不会卡壳。MQL5 也不例外,它把程序拆成了若干必须认识的部件,开发者按这套骨架填内容,才能把项目目标落地。 这一节先列出一份清单,后面会逐个拆开讲:预处理器、宏替换(#define)、程序属性(#property)、包含文件(#include)、导入函数(#import)、条件编译(#ifdef / #ifndef / #else / #endif)、输入与全局变量、函数与类、事件处理函数,以及一个完整的 MQL5 程序示例。 把上面这些节点吃透,你基本就能在 MT5 里照着结构起一个空模板,再往里填自己的逻辑。外汇与贵金属杠杆高、波动剧烈,拿这套结构做回测或实盘前,先在小资金或模拟账户验证,风险自担。
MT5 编译前的预处理指令怎么落地
在 MT5 里写 EA 或指标,源码真正交给编译器之前会先过一道预处理。所有预处理指令都以 # 开头,它们不是语言语句,结尾不能加分号;若误写分号,会依指令类型报出编译错误。 预处理主要做五类事:宏替换(#define)、程序属性(#property)、包含文件(#include)、导入函数(#import)、条件编译(#ifdef / #ifndef / #else / #endif)。其中 #define 可定义无参常量,也支持带参宏,最多允许 8 个参数。 看一段可直接贴进 MT5 测试的片段:INTEGER 被替换为 10,DOUBLE 为 10.50,STRING_VALUE 为字符串;MUL(a,b) 是带参宏,c=MUL(A,B) 中 A=2+3、B=5-1,展开后 c=((2+3)*(5-1))=20?实际代码里 c 打印为 41,因为 A、B 宏直接文本替换成 2+3 与 5-1 参与 MUL 展开为 ((2+3)*(5-1)) 等于 20,但示例注释写 c=41,系原文示例将 A、B 另作他算,复制时以你本地 Print 输出为准。 #property 必须写在主 mql5 文件顶部,不能放 include 里,否则被忽略。它决定的版权、链接、版本会出现在 EA 运行后“常用”选项卡。#include 通常置顶,尖括号格式让编译器去标准库 Include 目录找,引号格式去当前文件同目录找。#import 用来引入已编译的 ex5 或系统 dll 函数。条件编译能按宏是否定义来跳过整段代码,#else 和 #endif 后可跟多行,不受单行限制。 外汇与贵金属杠杆高、波动剧烈,用预处理组织代码只是降低人为出错概率,不预示任何收益。开 MT5 新建脚本,把下方代码原样粘入,调用 defValues() 就能看到各宏的真实替换结果。
class="macro">#define 标识符 替换值 class="macro">#define 标识符(参数1,参数2,…参数5) class=class="str">"cmt">//Parameter-free format class="macro">#define INTEGER class="num">10 class=class="str">"cmt">//class="type">int class="macro">#define DOUBLE class="num">10.50 class=class="str">"cmt">//class="type">class="kw">double class="macro">#define STRING_VALUE "MetaQuotes Software Corp." class=class="str">"cmt">//str class="macro">#define INCOMPLETE_VALUE INTEGER+DOUBLE class=class="str">"cmt">//Incomlete class="macro">#define COMPLETE_VALUE(INTEGER+DOUBLE) class=class="str">"cmt">//complete class=class="str">"cmt">//Parametic format class="macro">#define A class="num">2+class="num">3 class="macro">#define B class="num">5-class="num">1 class="macro">#define MUL(a, b) ((a)*(b)) class="type">class="kw">double c=MUL(A,B); class=class="str">"cmt">//function to print values class="type">void defValues() { Print("INTEGER Value, ",INTEGER); class=class="str">"cmt">//result: INTEGER Value, class="num">10 Print("DOUBLE Value, ",DOUBLE); class=class="str">"cmt">//result: DOUBLE Value, class="num">10.50 Print("STRING Value, ",STRING_VALUE); class=class="str">"cmt">//result: STRING Value, MetaQuotes Software Corp. Print("INCOMPLETE Value, ",INCOMPLETE_VALUE*class="num">2); class=class="str">"cmt">//result: INCOMPLETE Value, class="num">31 Print("COMPLETE Value, ",COMPLETE_VALUE*class="num">2); class=class="str">"cmt">//result: STRING Value, class="num">41 Print("c= ",c); class=class="str">"cmt">//result: c= class="num">41 } class="macro">#class="kw">property copyright "Copyright class="num">2023, MetaQuotes Software Corp." class="macro">#class="kw">property link "[MQL5官方文档] class="macro">#class="kw">property version "class="num">1.00"
「用预处理指令拼装你的 EA 模块」
MQL5 的预处理指令能在编译期决定代码如何组装,而不是运行时。掌握 #include、#import 和 #ifdef 这套组合,可以把通用函数库和平台原生 DLL 接口拆开维护,EA 主文件只管调度。
class="macro">#class="kw">property description "Property preprocessor" class="macro">#include <File_Name.mqh> class="macro">#include "File_Name.mqh" class="macro">#class="kw">import "File_Name" func1 define; func2 define; ... funcN define; class="macro">#class="kw">import class="macro">#ifdef identifier class=class="str">"cmt">//If the identifier has been defined, the code here will be compiled. class="macro">#endif class="macro">#ifndef identifier class=class="str">"cmt">// If the identifier is not defined, the code here will be compiled. class="macro">#endif
class="macro">#class="kw">property description "Property preprocessor" class="macro">#include <File_Name.mqh> class="macro">#include "File_Name.mqh" class="macro">#class="kw">import "File_Name" func1 define; func2 define; ... funcN define; class="macro">#class="kw">import class="macro">#ifdef identifier class=class="str">"cmt">//If the identifier has been defined, the code here will be compiled. class="macro">#endif class="macro">#ifndef identifier class=class="str">"cmt">// If the identifier is not defined, the code here will be compiled. class="macro">#endif