从基础到中级:定义(一)·综合运用
(3/3)· 递归与 include 之后,收尾篇带你把宏、常量与跨语言导入玩成可控的实验台
很多交易者写 EA 时直接改硬编码参数,回测一次换一个数,版本乱到自己也分不清哪版用了什么止损。定义的价值正在于把这类微调收拢成一行指令,改一处全网生效,却少有人把它当成日常调试的默认习惯。
◍ 用宏切换斐波那契的迭代与递归实现
在 MT5 脚本里通过预处理器宏控制编译分支,可以同一份源码切换两种斐波那契算法。定义 DEF_INTERACTIVE 时走迭代,未定义时走递归,运行时由编译器裁掉另一半代码。 第一段示例里默认元素数设为 6,迭代循环用 c、i、v 三个变量步进:c 从 0 起每次加 2,i 与 v 交替累加,返回第 6 项时得到数值 8(序列 0,1,1,2,3,5,8)。 第二段把默认元素数改成 11,并新增 def_OPERATION 宏拼接日志前缀。此时若保留 DEF_INTERACTIVE,终端会打印 "Result of Interactive operation of element 11 : 89";注释掉该宏则走递归分支,输出 "Recursive" 前缀且同样返回 89。 别把宏当运行时开关 宏在编译期就定死分支,想在线切换算法必须改代码重编译,不适合做参数面板里的实时选项。真要对比性能,分别编译两次用 Print 计时更直观。
class="macro">#class="kw">property copyright "Daniel Jose" class=class="str">"cmt">//+------------------------------------------------------------------+ class="macro">#define DEF_INTERACTIVE "Interactive" class=class="str">"cmt">//+----------------+ class="macro">#define def_Fibonacci_Element_Default class="num">6 class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnStart(class="type">void) { Print("Result to ", class="macro">#ifdef DEF_INTERACTIVE DEF_INTERACTIVE, " : " class="macro">#else "Recursive : " class="macro">#endif , Fibonacci()); } class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">uint Fibonacci(class="type">uint arg = def_Fibonacci_Element_Default) { class="macro">#ifdef DEF_INTERACTIVE class="type">uint v, i, c; for (c = class="num">0, i = class="num">0, v = class="num">1; c < arg; i += v, c += class="num">2) v += i; class="kw">return (c == arg ? i : v); class="macro">#else if (arg <= class="num">1) class="kw">return arg; class="kw">return Fibonacci(arg - class="num">1) + Fibonacci(arg - class="num">2); class="macro">#endif } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//+------------------------------------------------------------------+ class="macro">#class="kw">property copyright "Daniel Jose" class=class="str">"cmt">//+------------------------------------------------------------------+ class="macro">#define DEF_INTERACTIVE class=class="str">"cmt">//+----------------+ class="macro">#ifdef DEF_INTERACTIVE class="macro">#define def_OPERATION "Interactive" class="macro">#else class="macro">#define def_OPERATION "Recursive" class="macro">#endif class=class="str">"cmt">//+----------------+ class="macro">#define def_Fibonacci_Element_Default class="num">11 class=class="str">"cmt">//+----------------+ class="macro">#define def_MSG_TERMINAL "Result of " + def_OPERATION + " operation of element" class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnStart(class="type">void) { Print(def_MSG_TERMINAL, " ", def_Fibonacci_Element_Default, " : ", Fibonacci()); } class=class="str">"cmt">//+------------------------------------------------------------------+
斐波那契的迭代与递归两套实现
这段 MQL5 代码给出了同一个 Fibonacci 函数的两种编译路径,由 DEF_INTERACTIVE 宏决定走哪条。默认不定义该宏时,走的是第 34–37 行的递归版本,直接 return Fibonacci(arg-1)+Fibonacci(arg-2),逻辑直观但重复计算严重。 若放开第 04 行的 // #define DEF_INTERACTIVE 注释,则启用第 25–30 行的迭代版:用 c、i、v 三个变量在 for 里滚动累加,循环步长 c+=2,最终按 c==arg 返回 i 或 v。实测 arg=11(即 def_Fibonacci_Element_Default 默认值)时,递归与迭代都给出 89 这个第 11 项斐波那契数。 代码后半段的宏封装(BEGIN_PROC、ENTER_POINT、Z_SET_NUMBERS 等)把语法糖到近乎伪代码,例如 ENTER_POINT 展开就是 void OnStart(void),MINOR 等价于 <。开 MT5 把这段贴进脚本,注释/取消第 04 行各跑一次,能从终端输出里直接比对两种算法的耗时差异。外汇与贵金属交易用这类数列做周期测算时,需注意杠杆品种的高风险,数列本身不预示价格方向。
class="type">uint Fibonacci(class="type">uint arg = def_Fibonacci_Element_Default) { class="macro">#ifdef DEF_INTERACTIVE class="type">uint v, i, c; for (c = class="num">0, i = class="num">0, v = class="num">1; c < arg; i += v, c += class="num">2) v += i; class="kw">return (c == arg ? i : v); class="macro">#else if (arg <= class="num">1) class="kw">return arg; class="kw">return Fibonacci(arg - class="num">1) + Fibonacci(arg - class="num">2); class="macro">#endif } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//+------------------------------------------------------------------+ class="macro">#class="kw">property copyright "Daniel Jose" class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">// class="macro">#define DEF_INTERACTIVE class=class="str">"cmt">//+----------------+ class="macro">#ifdef DEF_INTERACTIVE class="macro">#define def_OPERATION "Interactive" class="macro">#else class="macro">#define def_OPERATION "Recursive" class="macro">#endif class=class="str">"cmt">//+----------------+ class="macro">#define def_Fibonacci_Element_Default class="num">11 class=class="str">"cmt">//+----------------+ class="macro">#define def_MSG_TERMINAL "Result of " + def_OPERATION + " operation of element" class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//+------------------------------------------------------------------+ class="macro">#class="kw">property copyright "Daniel Jose" class=class="str">"cmt">//+------------------------------------------------------------------+ class="macro">#define BEGIN_PROC { class="macro">#define END_PROC } class="macro">#define RETURN class="kw">return class="macro">#define ENTER_POINT class="type">void OnStart(class="type">void) class="macro">#define Z_SET_NUMBERS class="type">long class="macro">#define EQUAL == class="macro">#define IS = class="macro">#define MINOR < class="macro">#define OR ||
「用宏切换斐波那契的两种算法」
这段脚本用预编译宏把同一套斐波那契计算切成了交互迭代和递归两套实现,编译期靠 DEF_INTERACTIVE 是否定义来决定走哪条路。默认元素序号定在 11,终端会打印出「Result of Interactive operation of element 11 : 」这样的前缀,方便你直接看当前跑的是哪种模式。 交互分支里用了 for 循环做累加:c 从 0 计步、i 初值 0、v 初值 1,每次 v 累加 i、c 自增 2,直到 c 不小于目标序号;最后用三目运算返回第 11 项,实际算出来是 89(Fib(11)=89)。递归分支则是经典双递归,arg 小于等于 1 直接返回,否则返回前两项之和,代码短但重复计算多。 把第 15 行注释掉再编译,def_OPERATION 会变成 "Recursive",打印前缀随之改变,你能直观对比两种路径在 MT5 里的输出差异。外汇与贵金属波动剧烈,这类算法仅用于指标逻辑验证,实盘前务必充分回测,高风险。
class="macro">#define MORE += class=class="str">"cmt">//+------------------------------------------------------------------+ class="macro">#define DEF_INTERACTIVE class=class="str">"cmt">//+----------------+ class="macro">#ifdef DEF_INTERACTIVE class="macro">#define def_OPERATION "Interactive" class="macro">#else class="macro">#define def_OPERATION "Recursive" class="macro">#endif class=class="str">"cmt">//+----------------+ class="macro">#define def_Fibonacci_Element_Default class="num">11 class=class="str">"cmt">//+----------------+ class="macro">#define def_MSG_TERMINAL "Result of " + def_OPERATION + " operation of element" class=class="str">"cmt">//+------------------------------------------------------------------+ ENTER_POINT BEGIN_PROC Print(def_MSG_TERMINAL, " ", def_Fibonacci_Element_Default, " : ", Fibonacci()); END_PROC class=class="str">"cmt">//+------------------------------------------------------------------+ Z_SET_NUMBERS Fibonacci(Z_SET_NUMBERS arg IS def_Fibonacci_Element_Default) BEGIN_PROC class="macro">#ifdef DEF_INTERACTIVE Z_SET_NUMBERS v, i, c; for (c IS class="num">0, i IS class="num">0, v IS class="num">1; c MINOR arg; i MORE v, c MORE class="num">2) v MORE i; RETURN(c EQUAL arg ? i : v); class="macro">#else if ((arg EQUAL class="num">1) OR(arg MINOR class="num">1)) RETURN arg; RETURN Fibonacci(arg - class="num">1) + Fibonacci(arg - class="num">2); class="macro">#endif END_PROC class=class="str">"cmt">//+------------------------------------------------------------------+
◍ 收束
这一节把前面拆开的五个 MQL5 示例都收进了随附的 Anexo.zip(2.65 KB),你解压后能在 MT5 的 MQEditor 里直接打开跑一遍,重点不是背语法,而是借这些奇怪的小例子把语言结构摸熟。 下一篇会转到 #define 的第二种用法——宏定义,和今天这五个例子用的是同一套练习程序,所以现在不练熟,后面很容易混淆。 外汇和贵金属杠杆高、回撤快,拿这些代码做实验务必先在策略测试器里用模拟品种跑,别直接上真实账户。