通过应用程序了解MQL5中的函数(基础篇)
📘

通过应用程序了解MQL5中的函数(基础篇)

第 1/2 篇

从 MT5 自带程序看清函数长相

打开 MT5 终端,进到「文件 → 打开数据文件夹 → MQL5 → Experts」,里面自带的 MACD Sample 这类 EA 就是现成的函数教科书。跑过一次回测的人会看到:同一段信号判断逻辑,被拆成 CheckForTrade() 这类独立函数反复调用,而不是堆在主过程里。 MQL5 里函数的基本骨架是「返回类型 函数名(参数类型 参数名)」,例如 double GetMA(int period) 表示传入周期、吐出双精度均线值。把常用计算封进函数,EA 在 1 分钟图上每秒重算也不会把主循环写成长毛怪物。 一个可验证现象:新建一个空 EA,只写 OnTick(){ Print(__FUNCTION__); },在 EURUSD 的 M1 上挂 10 分钟,专家日志里会刷出上百次 OnTick 字样——说明这个函数被报价驱动反复触发,外汇与贵金属杠杆高、跳空频繁,这种高频调用下函数若写得臃肿,实盘滑点风险会明显放大。

◍ 先把函数这件事拆开看

MQL5 里函数不是装饰品,而是把重复逻辑收口成单一入口的基本单元。一篇讲透函数用法的技术文,通常会按定义、结构、带参/不带参、默认值、参数传递、return、void、重载这条线走,最后落到几个可直接搬进 EA 的小工具上。 对交易者而言,函数最大的现实意义是:把「新闻提醒」「手数计算」「一键平掉所有单」这类动作封装好,主循环里一行调用就完事,不用每次都把逻辑重写一遍。 原文列出的落点包括新闻提醒程序、手数计算程序、关闭所有持仓程序,以及对应的函数重载与 void 类型用法。外汇与贵金属杠杆高、滑点突发,任何自动逻辑上线前都应在 MT5 策略测试器里用历史数据跑过,并清楚自己承担实盘风险。

「把重复逻辑收进一个函数里」

在 MT5 的 MQL5 编程里,函数就是一块带名字的代码,专门干一件明确的事,哪里要用就直接调用,不用把同一段逻辑抄得到处都是。语言自带的是内置函数,自己按需求写的是用户定义函数,实盘脚本里后者用得最多。 举个具体场景:当账户净值触及最大回撤阈值时,需要一键平掉所有未结订单。如果这个动作在 EA 的多个分支里都要触发,正确做法是把平仓逻辑封成一个函数,在需要的地方调一次就行;要是每处都重写一遍,代码很快就没法看了。 用户定义函数带来的直接好处有这几条可验证的点:落实 DRY(不要重复自己),同样的逻辑只写一次;随时可重用,改一处全生效;分而治之,复杂策略拆成小函数逐个击破;代码可读性上升,调试时定位错误更快。外汇与贵金属杠杆高、回撤失控风险大,用函数管平仓逻辑至少能让风控代码不混乱。 抽象和封装也算附赠价值:不用函数可能要多写几倍行数,而函数把数据和操作收在内部,比散代码更安全、好管。

MQL5 里函数怎么搭起来

写 EA 或指标时,先把函数拆成两步看:先声明或定义,再在需要的地方调用。定义时确定返回类型、函数名、参数列表和函数体;调用时只写函数名并填参数,MT5 就会在对应位置执行那段逻辑。 拿最直白的加法函数举例,返回 int、收两个 int 参数 val1 和 val2,函数体算完和之后用 Print 在「专家」标签页输出,并 return 结果。实盘或回测里调用 add(5,15),专家页会打出 20,这就是函数跑通的最小证据。 参数形态有三种常见写法。带参函数如 sayHello(string greeting, string name),参数类型随任务走;无参函数留空括号,像 sayHello() 内部写死 "Hello, " 和 "World!",调用后输出相同;带默认值函数 sayHello(string greeting="Hello, ", string name="World!") 允许调用时不传参用默认、传参则覆盖。连续调用 sayHello() 与 sayHello("Hi, ","Developer!") 能直接看出差异。 传参分值传递和引用传递。值传递时原始变量不变;引用传递在参数前加 &,如 updateNums(int &val1, int &val2),函数内 val1*=2 会直接改写外部变量。新建两个变量赋 10 和 20,调用前打印一次、调用后打印一次,第二次会看到被乘 2 后的更新值。外汇与贵金属杠杆高,任何代码先在策略测试器用历史数据验证再上真仓。 有返回值的函数必须带 return,且返回类型不能是数组,但可返回数组元素,或改用引用传数组间接改内容。不返回就用 void,例如 void updateNums(...) 不需要 return。同名不同参叫函数重载:两个 add 一个收两数、一个收三数,输入函数名时 MT5 编辑器会列出候选,按参数个数或类型选。这套结构摸清后,你开 MT5 新建 mq5 把上面代码贴进去编译,基本就能确认自己写的函数是否被识别。

MQL5 / C++
returnedDataType functionName(param1, param2)
{
      bodyOfFunction
}
class=class="str">"cmt">//addition function
class=class="str">"cmt">// returned data type is an integer - the name of the function is add - parameters or arguments are two class="type">int variables val1 and val2
class="type">int add(class="type">int val1, class="type">int val2)
  {
   class=class="str">"cmt">//body of function that we need the function to perform when calling it
   class=class="str">"cmt">//create a result new variable to be assigned by the result of val1 and val2 addition
   class="type">int result = val1+val2;
   class=class="str">"cmt">//Print result in the experts tab
   Print(result);
   class=class="str">"cmt">//returning value
   class="kw">return result;
   }
   class=class="str">"cmt">//calling our defined function by its name and specifying arguments
   add(class="num">5,class="num">15);
class=class="str">"cmt">//sayHello function
class=class="str">"cmt">// returned data type is class="type">class="kw">string - name of function is sayHello - parameters or arguments are two class="type">class="kw">string variables greeting and name
class="type">class="kw">string sayHello(class="type">class="kw">string greeting, class="type">class="kw">string name)
  {
   class=class="str">"cmt">//body of function that we need the function to perform when calling it
   class=class="str">"cmt">//create a result new variable to be assigned by the result of greeting and name addition
   class="type">class="kw">string result = greeting+name;
   class=class="str">"cmt">//Print result in the experts tab
   Print(result);
   class=class="str">"cmt">//returning value
   class="kw">return result;
   }
class=class="str">"cmt">//sayHello function
class=class="str">"cmt">// returned data type is a class="type">class="kw">string - the name of the function is sayHello - no parameters
class="type">class="kw">string sayHello()
  {
   class=class="str">"cmt">//body of the function that we need the function to perform when calling it
   class=class="str">"cmt">//create a result new variable to be assigned by the result of greeting and name addition
   class="type">class="kw">string greeting= "Hello, ";
   class="type">class="kw">string name= "World!";
   class="type">class="kw">string result = greeting+name;
   class=class="str">"cmt">//Print the result in the experts&class="macro">#x27; tab
   Print(result);
   class=class="str">"cmt">//returning value
   class="kw">return result;
   }
sayHello();
class=class="str">"cmt">//defining function with class="kw">default values
class="type">class="kw">string sayHello(class="type">class="kw">string greeting= "Hello, ", class="type">class="kw">string name="World!")
  {
   class="type">class="kw">string result = greeting+name;
   Print(result);
   class="kw">return result;
   }
   sayHello();
   sayHello("Hi, ", "Developer!");
class=class="str">"cmt">//passing by reference
class="type">void updateNums(class="type">int &val1, class="type">int &val2)
  {
   val1*=class="num">2;

常见问题

带括号且前面有类型名(如void、int)的基本就是函数,重点看函数名和参数列表,自带程序里OnTick、OnInit都算标准函数。
把重复逻辑收进一个自定义函数,主程序里直接调用函数名,改只改一处就能全局生效。
小布可以帮你逐段解读自带程序里的函数结构和调用关系,把看不懂的代码块翻译成白话结论,省去自己硬啃。
写清返回类型、函数名、括号内参数,大括号里放执行语句,例如int Add(int a,int b){return a+b;}就是最基础形态。
能跑但难维护,拆函数后可读性高、复用强,调试时也能单独测某个块,大程序里这是基本素养。