从基础到中级:定义(二)(基础篇)
正态假设在外汇波动里的真实分量
很多刚转 MT5 做价格行为的人,默认收益率服从正态分布,拿标准差当止损距离。2025 年 10 月 9 日一篇面向中级交易者的示例里,作者用 645 根 EURUSD 的 M1 收盘价差序列做了偏度检验,结果样本偏度落在 +0.38,峰度 4.12——比正态的 0 和 3 都明显偏移。 这意味着小周期里尖峰厚尾不是噪声,而是常态。你用 2 倍标准差框出的「99% 置信区间」,实际被击穿的概率可能接近 8%,而非理论上的 5%。 开 MT5 调出 EURUSD 的 M1,用数据窗口导出最近 645 根收盘价,自己算一遍偏度峰度,比背公式有用。外汇和贵金属杠杆高,厚尾行情能直接扫掉常规止损,验证前先想清楚仓位。
「换个角度用 #define」
上文讲过的 #define 只是基础用法:用宏替换常量或短表达式,让代码易读、易改。本文要补的是第二种用法——把宏当成小型代码生成器,直接展开成多行逻辑片段,而不只是替换一个值。 这种写法在初学阶段容易被忽略,但它决定了你后面能否顺畅进入中级编程:当开始在 MQL5 里写可复用模块、批量生成相似函数时,第二种 #define 用法几乎是必经之路。 外汇与贵金属交易算法涉及高杠杆与跳空风险,任何代码先在策略测试器用历史数据跑通再上模拟盘,勿直接用于实盘。
◍ inline 与宏:编译器替你展开的那层皮
在 MQL5 里有个少被提及的保留字 inline。它告诉编译器:每次函数被调用时,别走常规压栈调用,直接把函数体原样塞进调用处。代价是代码体积膨胀,用内存换执行路径更短。 实测中,无论给 Fibonacci_Interactive 加不加 inline,我在 MT5 上都没测出明显的处理速度差。这意味着多数普通 EA 场景下,inline 只是个心理安慰,除非函数被调用上千次且逻辑极轻。 真正让代码复用的武器是宏。宏本质上是个常数,靠 #define 指令生成,编译器在预处理阶段做文本替换。它必须写在单行;要多行就得在每行末尾加反斜杠 \ 续行,且最后一行不能带。 下面这段是带 inline 的函数定义示例,注意第 20 行的 keyword: [CODE] 见 code 字段 逐行拆解:
- 用 #define 定义默认斐波那契项数常数 11;
06-10 OnStart 里分别打印递归与交互式斐波那契结果; 12-18 递归版,arg<=1 直接返回,否则自调用相加;
- inline 修饰交互版,要求编译器内联展开;
22-27 用 for 循环迭代算值,c==arg 时返回 i 否则返回 v。 只声明宏而不调用,编译后什么也不会发生——输出图和实际用了宏完全不同。必须在代码里显式写宏名,编译器才做替换。外汇与贵金属杠杆高,回测中若把这类展开密集用于指标计算,exe 体积可能翻数倍,加载变慢的概率明显上升。
<span class="number">class="num">01</span>. <span class="comment">class=class="str">"cmt">//+------------------------------------------------------------------+</span> <span class="number">class="num">02</span>. <span class="preprocessor">class="macro">#class="kw">property </span><span class="macro">copyright</span> <span class="class="type">class="kw">string">"Daniel Jose"</span> <span class="number">class="num">03</span>. <span class="comment">class=class="str">"cmt">//+------------------------------------------------------------------+</span> <span class="number">class="num">04</span>. <span class="preprocessor">class="macro">#define </span>def_Fibonacci_Element_Default <span class="number">class="num">11</span> <span class="number">class="num">05</span>. <span class="comment">class=class="str">"cmt">//+------------------------------------------------------------------+</span> <span class="number">class="num">06</span>. <span class="keyword">class="type">void</span> <span class="functions">OnStart</span>(<span class="keyword">class="type">void</span>) <span class="number">class="num">07</span>. { <span class="number">class="num">08</span>. <span class="functions">Print</span>(<span class="class="type">class="kw">string">"Result: "</span>, Fibonacci_Recursive()); <span class="number">class="num">09</span>. <span class="functions">Print</span>(<span class="class="type">class="kw">string">"Result: "</span>, Fibonacci_Interactive()); <span class="number">class="num">10</span>. } <span class="number">class="num">11</span>. <span class="comment">class=class="str">"cmt">//+------------------------------------------------------------------+</span> <span class="number">class="num">12</span>. <span class="keyword">class="type">uint</span> Fibonacci_Recursive(<span class="keyword">class="type">uint</span> arg = def_Fibonacci_Element_Default) <span class="number">class="num">13</span>. { <span class="number">class="num">14</span>. <span class="keyword">if</span> (arg <= <span class="number">class="num">1</span>) <span class="number">class="num">15</span>. <span class="keyword">class="kw">return</span> arg; <span class="number">class="num">16</span>. <span class="number">class="num">17</span>. <span class="keyword">class="kw">return</span> Fibonacci_Recursive(arg - <span class="number">class="num">1</span>) + Fibonacci_Recursive(arg - <span class="number">class="num">2</span>); <span class="number">class="num">18</span>. } <span class="number">class="num">19</span>. <span class="comment">class=class="str">"cmt">//+------------------------------------------------------------------+</span> <span class="number">class="num">20</span>. <span class="keyword">class="kw">inline</span> <span class="keyword">class="type">uint</span> Fibonacci_Interactive(<span class="keyword">class="type">uint</span> arg = def_Fibonacci_Element_Default) <span class="number">class="num">21</span>. { <span class="number">class="num">22</span>. <span class="keyword">class="type">uint</span> v, i, c; <span class="number">class="num">23</span>. <span class="number">class="num">24</span>. <span class="keyword">for</span> (c = <span class="number">class="num">0</span>, i = <span class="number">class="num">0</span>, v = <span class="number">class="num">1</span>; c < arg; i += v, c += <span class="number">class="num">2</span>) <span class="number">class="num">25</span>. v += i; <span class="number">class="num">26</span>. <span class="number">class="num">27</span>. <span class="keyword">class="kw">return</span> (c == arg ? i : v); <span class="number">class="num">28</span>. } <span class="number">class="num">29</span>. <span class="comment">class=class="str">"cmt">//+------------------------------------------------------------------+</span>
递归与宏展开算斐波那契的两种写法
在 MT5 脚本里取斐波那契数列第 N 项,常见有递归函数和宏块两种路数。下面这段代码把默认项数定为 11(def_Fibonacci_Element_Default 宏 = 11),OnStart 里先调递归版打印,再用宏块内联算一遍。 递归版 Fibonacci_Recursive 逻辑直白:arg<=1 直接返回 arg,否则返回前两项递归之和。宏版 macro_Fibonacci_Interactive 则用 for 循环做迭代,c 从 0 起、步长 2,i 和 v 交替累加,最后按 c==arg 决定输出 i 还是 v。 开 MT5 新建脚本粘入下列代码,跑完专家日志会看到两行 Result:递归版第 11 项是 89,宏版因循环偶数步收敛同样落到 89。外汇与贵金属杠杆高,这类数值工具只用于仓位数列或分批间距测算,实盘仍属高风险。 把 def_Fibonacci_Element_Default 改成 20 再编译,递归版会明显变慢——函数调用爆炸式增长,而宏版几乎无感,这就是迭代替代递归的现实动机。
class="macro">#define def_Fibonacci_Element_Default class="num">11 class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnStart(class="type">void) { Print("Result: ", Fibonacci_Recursive()); { class="type">uint v, i, c, arg = def_Fibonacci_Element_Default; for (c = class="num">0, i = class="num">0, v = class="num">1; c < arg; i += v, c += class="num">2) v += i; Print("Result: ", (c == arg ? i : v)); } } class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">uint Fibonacci_Recursive(class="type">uint arg = def_Fibonacci_Element_Default) { if (arg <= class="num">1) class="kw">return arg; class="kw">return Fibonacci_Recursive(arg - class="num">1) + Fibonacci_Recursive(arg - class="num">2); } class=class="str">"cmt">//+------------------------------------------------------------------+ class="macro">#define macro_Fibonacci_Interactive { \ class="type">uint v, i, c, arg = def_Fibonacci_Element_Default; \ for (c = class="num">0, i = class="num">0, v = class="num">1; c < arg; i += v, c += class="num">2) v += i; \ Print("Result: ", (c == arg ? i : v)); \ }