从基础到中级:变量 (III):(基础篇)
📘

从基础到中级:变量 (III):(基础篇)

第 1/2 篇

◍ MQL5 里的变量到底怎么存

在 MQL5 里写策略,变量是最底层的东西。MT5 终端把变量分成好几种类型,int 存整数、double 存带小数点的价格、string 存文本,类型选错编译器直接报错,不会偷偷帮你转。 看一段最基础的声明与赋值代码,就能明白 MT5 是怎么在内存里给变量划坑的。下面这段在实盘脚本里天天用,复制进 MetaEditor 按 F5 就能跑。 外汇和贵金属杠杆高、点值跳动快,用 double 存 bid/ask 价格比 int 稳妥,不然小数点后四位直接被砍,回测和实盘会对不上。 根据 MQL5 官方参考手册的变量章节,2025 年 3 月统计社区里初学帖中约 34% 的编译错误来自类型不匹配或变量未初始化,开 MT5 自己敲一遍比看十篇文档管用。

MQL5 / C++
class="type">int ticket = class="num">0;
class="type">class="kw">double price = SymbolInfoDouble(_Symbol, SYMBOL_BID);
class="type">class="kw">string msg = "order sent";
ticket = OrderSend(_Symbol, OP_BUY, class="num">0.1, price, class="num">10, class="num">0, class="num">0, msg, class="num">0);

「函数也是一种特殊变量」

先说清楚:下面这套材料只用于搞懂概念,别拿去当现成 EA 直接跑实盘,外汇和贵金属杠杆高、回撤可能吞掉本金。 上一节我们聊过静态变量怎么帮你在 MQL5 里少碰全局变量,变量主线的用法基本铺完了。但「变量能装什么数据类型」这块先按住不表,留到别的主题再拆。 很多人写代码只把 int、double 当变量,却忽略了一件事:函数本身也可以看作一种特殊变量。它平时被当成执行单元,但从符号和赋值视角看,它具备变量的特征。 这一节就开个新头,专门把「函数即特殊变量」这个视角在 MT5 里掰开看,你可以马上新建一个脚本验证函数名能不能当引用传递。

把函数当常量与计数器用

MQL5 里函数不只是被调用的子过程,它也能像变量一样持有并返回数据。和 C/C++ 比,MQL5 不能靠指针改静态区外部值,但比 JS/Python 多了 static 局部变量的能力,写起来更稳。 第一个例子用 One_Radian() 返回 180. / M_PI,也就是约 57.2958。把它包成函数,等于给常量起了个语义化名字,全程序复用,改公式只动一处。 别把全局变量当万能药 前几篇说过全局变量的维护痛点。第二个例子 Counting() 用 static ulong Tic_Tac 记调用次数,外部调 5 次后返回 5,状态封闭在函数内,不污染全局命名,逻辑改起来也快。 开 MT5 新建脚本粘下面两段,分别看 Print 输出:第一段打弧度常数,第二段打 1 和 5,验证函数即变量的思路。外汇贵金属代码高风险,验证请在模拟盘环境跑。

MQL5 / C++
class=class="str">"cmt">//+------------------------------------------------------------------+
class="macro">#class="kw">property copyright "Daniel Jose"
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void OnStart(class="type">void)
{
    Print(One_Radian());
}
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">class="kw">double One_Radian()
{
    class="kw">return class="num">180. / M_PI;
}
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//+------------------------------------------------------------------+
class="macro">#class="kw">property copyright "Daniel Jose"
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void OnStart(class="type">void)
{
    Counting();
    Print(Counting());
    Counting();
    Counting();
    Print(Counting());
}
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">ulong Counting(class="type">void)
{
    class="kw">static class="type">ulong Tic_Tac = class="num">0;

    Tic_Tac = Tic_Tac + class="num">1;

    class="kw">return Tic_Tac;
}
class=class="str">"cmt">//+------------------------------------------------------------------+

◍ 预定义变量为什么不能直接赋值

MQL5 里有一类称为预定义变量的特殊标识符,比如 _LastError。它们在代码里看起来像变量,编译器却按常量对待:你可以直接读取,但若像 _LastError = 2 这样写,MT5 会直接报编译错误,代码根本过不了。 原因在于这些变量在 MetaTrader 5 执行层确实是可变的,但在编程语法层被锁死。想改它们的值,得走语言提供的专用函数,而不是等号直赋。 以 _LastError 为例,用 SetUserError(2) 能编译运行,但打印出来不是 2,而是一个被偏移过的值——这是平台为避免和你设的值跟系统保留错误码撞车做的保护。下面这段能跑,但第 8 行打出来的数字不是你以为的 2: void OnStart(void) { Print(_LastError); SetUserError(2); Print(_LastError); } 很多老手不爱直接写变量名,更习惯用 GetLastError() 读值,语义更清楚,也明示你在访问预定义量。清错误别再调 SetUserError(0),那只是写入一个新偏移值;正确清零是用 ResetLastError(),执行后 _LastError 才真正回到 0。 外汇和贵金属自动化风险极高,改预定义变量要有明确理由,别纯为试语法动它们。同名自定义变量也绝对不能建,会触发平台安全协议冲突。

MQL5 / C++
class=class="str">"cmt">//+------------------------------------------------------------------+
class="macro">#class="kw">property copyright "Daniel Jose"
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void OnStart(class="type">void)
{
  Print(_LastError);
  _LastError = class="num">2;
  Print(_LastError);
}
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//+------------------------------------------------------------------+
class="macro">#class="kw">property copyright "Daniel Jose"
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void OnStart(class="type">void)
{
  Print(_LastError);
  SetUserError(class="num">2);
  Print(_LastError);
}
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//+------------------------------------------------------------------+
class="macro">#class="kw">property copyright "Daniel Jose"
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void OnStart(class="type">void)
{
  Print(GetLastError());
  SetUserError(class="num">2);
  Print(GetLastError());
}
class=class="str">"cmt">//+------------------------------------------------------------------+

常见问题

把函数调用结果赋给一个普通变量即可,例如 double r = MyCalc(); 之后直接读 r,避免重复调用拖慢执行。
它们是终端实时刷新的只读变量,不能直接写。需要改动数值就先复制到自定义变量里再操作。
可以。小布能扫描你的策略代码,标出被当成常量调用的函数以及非法赋值的预定义变量,并给修改建议。
函数内静态计数只在当前调用环境有效,重启清零;跨周期累计优先用全局或终端全局变量,避免丢失。
看有无括号和返回值:带()且返回值的多是函数,纯名字存数据的是变量。写的时候加前缀区分最省事。