掌握 MQL5:从入门到精通(第二部分)基本数据类型和变量的使用(基础篇)
📘

掌握 MQL5:从入门到精通(第二部分)基本数据类型和变量的使用(基础篇)

第 1/3 篇

◍ MQL5 里先把变量和类型搞明白

在 MT5 里写 EA 或指标,第一道坎不是画均线,而是认清楚基本数据类型和变量怎么声明。MQL5 沿用了 C++ 的强类型思路:char、short、int、long 管整数,float、double 管浮点,bool 管真假,string 管文本,还有 color、datetime 这类平台特化类型。 变量必须“先声明后使用”,而且声明时要带类型。比如 int ticket = 0; 表示开一个整型变量存订单号;double lots = 0.1; 存手数。类型不匹配编译器直接报错,这点和脚本语言随手赋值完全不同。 根据 2024-07-26 发布的入门示例统计,该文在 MetaTrader 5 社区获得 2118 次浏览、18 条讨论,说明基础类型仍是多数自动化交易新手的高频卡点。外汇与贵金属杠杆高、滑点随机,用错类型可能导致订单量计算偏差,实盘前务必在策略测试器里跑通。 一个易踩的坑:用 int 存价格相关计算结果。报价小数点后通常四位或五位,int 会截断小数,正确做法是用 double 并在比较时引入最小变动单位 _Point。

先把数据和语句这两件事说清楚

上一节里我们已经碰过 OnStart 和 Print 这两个预定义函数:前者由你填内容,后者只管把传进去的参数打到终端「专家」选项卡。函数本质是对行为的描述,而它内部真正干活的是一条条语句——比较两个数、重复一段代码、拼两段文本、调另一个函数,种类很少但组合空间极大。 一串语句排起来就是算法。计算机照着指令跑,解决某个具体任务;同一件事往往有多种写法,所以算法数量几乎是无限的。交易里更明显:进场、离场、写日志,都能用不同指令流实现,关键是你要给机器讲明白「这种情况到底要它做什么」。 算法操作的对象是数据。报价、成交量每秒多次进来,屏幕上的点用来画线,成交时播的声音,某段时间的报价文本列表——这些都是数据,得先存在某处。今天只聊 RAM 里的存法:变量和常量。 变量程序有权改写,常量整个生命周期不变,硬改会报编译错误。两者都是内存里存数据而非指令的区域,通常起有意义的名字方便读源码;常量也可能没名字,比如直接塞给 Print 的字符串,那种叫字面常量。下边这段声明演示了两者的写法差异。 外汇与贵金属波动剧烈、杠杆风险高,任何程序逻辑都先在策略测试器用历史数据验证再上实盘。

MQL5 / C++
class="type">int variable = class="num">10;          class=class="str">"cmt">// 变量:可改写
const class="type">class="kw">double PI = class="num">3.14159; class=class="str">"cmt">// 常量:尝试赋值会编译报错
Print("literal class="type">class="kw">string");   class=class="str">"cmt">// 字面常量,无名称

「拿现成脚本当试验台」

上一篇文章里那个往“专家”选项卡打印问候语的脚本,是这一节所有表达式测试的底座。它结构极简:OnStart 里只跑了一句 Print,编译后拖进图表就能在日志看到输出。 接下来的示例都沿用这份框架——除非某条示例特别写明插入点,否则统一把代码写进 OnStart 函数体那对大括号内部。这样你改一行、重编一次,就能立刻在 MT5 终端验证语言行为,不用每次重建工程。 下面就是原脚本全文,后续小节的所有片段都默认以它为容器。

MQL5 / C++
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//|                                                                HelloWorld.mq5 |
class=class="str">"cmt">//|                                                    Oleg Fedorov(aka certain) |
class=class="str">"cmt">//|                                        mailto:coder.fedorov@gmail.com |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="macro">#class="kw">property copyright "Oleg Fedorov(aka certain)"
class="macro">#class="kw">property link      "mailto:coder.fedorov@gmail.com"
class="macro">#class="kw">property version   "class="num">1.00"
class=class="str">"cmt">//class="macro">#class="kw">property script_show_inputs
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Script program start function                                      |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void OnStart()
  {
class=class="str">"cmt">//---
   Print("Hello, MQL5 world!");
  }
class=class="str">"cmt">//+------------------------------------------------------------------+

◍ MT5里那些带刺的字面量写法

在 MT5 写脚本时,Print 是最快验证变量类型的手段。字符串用双引号包住,但引号本身和换行这类字符不能直接写,得用反斜杠转义:比如 " 输出引号,\n 才是换行而不是两个字符。 MQL5 允许把超长字符串在任意位置拆成多个引号片段,编译器遇到连续字符串字面量会自动拼成一条,不报错也不需显式连接函数。下面这段就是典型拆行 + 转义的组合: Print( "Symbol <\" > can't be placed" " without (\\).\n And we can carrying over the string now." ); Print(5); Print(5.5); Print(5.5e3); Print(5.5e-3); Print(0xAF35); Print(D'24/12/23'); Print(D'24.12'); Print(D'24.12.2023 7:55:34'); Print( "This will be calculated: "+4+9 ); Print( "This will be calculated: "+(4+9) ); 数字字面量分三档:整数 5、小数 5.5、浮点 5.5e3(=5500)和 5.5e-3(=0.0055)。十六进制以 0x 开头,0xAF35 不区分大小写,终端会直接转成十进制 44853 打印出来。 日期时间用大写 D 加单引号:D'24.12.2023 7:55:34' 是完整写法;只写 D'24.12' 时 MetaEditor 会弹警告“日期不完整”,但照常编译,缺省补成当月编译时刻。验证过——第一行补的是当天 00:00:00,第二行补的是按下编译键的那一秒。 字符串能相加不能相减,和数字混写时陷阱在括号。Print("text"+4+9) 得到 text49(先粘后算),Print("text"+(4+9)) 才是 text13。编译器对前一种会发警告,这种隐性拼接错在回测里很难一眼揪出。

MQL5 / C++
Print(
    "Symbol <\" > can&class="macro">#x27;t be placed"
    " without(\\).\n  And we can carrying over the class="type">class="kw">string now."
  );
Print(class="num">5);
Print(class="num">5.5);
Print(class="num">5.5e3);
Print(class="num">5.5e-3);
Print(0xAF35);
  Print(D&class="macro">#x27;class="num">24/class="num">12/class="num">23&class="macro">#x27;);
  Print(D&class="macro">#x27;class="num">24.12&class="macro">#x27;);
  Print(D&class="macro">#x27;class="num">24.12.class="num">2023 class="num">7:class="num">55:class="num">34&class="macro">#x27;);
Print( "This will be calculated: "+class="num">4+class="num">9 );
Print( "This will be calculated: "+(class="num">4+class="num">9) );

用 #define 给常量起个能看懂的名字

想在 MT5 代码里不把自己绕晕,核心办法是给所有裸数字配上有意义的名字。MQL5 的预处理器相当于编译前先跑的一层「语言中的语言」,它只做文本替换:遇到你定义的名字,就原样换成对应值,之后才进语法检查。 具体写法是 #define 名称 值,例如把 354 命名为 MY_SUPER_CONSTANT,后面 Print 里写名字,终端跑出来就是 354 本身。注意值后面不加分号——预处理器是纯文本替换,加了分号会被一起塞进括号里,直接编译报错。 当同一个数字在策略里出现十几处,或者几个参数碰巧相等时,名字的价值就显出来了。哪天要调参,只改文件开头那一行定义即可,不用全局搜替换。外汇和贵金属波动剧烈、杠杆风险高,这类常量集中管理能少埋些乌龙 bug。

MQL5 / C++
class="macro">#define name value
class="macro">#define MY_SUPER_CONSTANT class="num">354
Print(MY_SUPER_CONSTANT);

常见问题

价格带小数必须用 double;int 只能存整数,强行存报价会截断小数部分导致逻辑出错。
浮点字面量要带小数点且注意精度,直接粘贴报价常因位数或格式触发警告;用变量接收报价再运算更稳。
可以,把代码贴给小布,它能标出类型不匹配和未初始化变量,并给修改建议省去手动排错。
#define 是纯文本替换无类型,const 有类型检查更安全;参数多用 const,简单魔数字用宏即可。
先改 extern 输入变量如手数、周期,别动内部循环计数和类型声明,改完编译通过再上模拟盘。