更好的程序员(第 06 部分):9 个导致有效编码的习惯·进阶篇
「网格里怎么抓最新那张单和总单数」
做网格策略时,EA 必须随时知道「当前同魔法码同品种下,某一类持仓里最新开的那张单价是多少」,以及「这类持仓到底开了几张」。下面两段 CGrid 成员函数就是干这个的,直接塞进你的网格类里就能用。 LastPositionOpenPrice 从 PositionsTotal()-1 倒序遍历,用 TimeMsc() 比较成交时间,只保留时间更大的那张,返回其 PriceOpen();若一类单子都没有,返回 -1。 CountPositions 逻辑更简单,同样按魔法码、品种、类型三重过滤,命中就 counter++,最后把累计数交回去。实盘里这两值一结合,就能判断加仓间距是否够、是否触到层数上限。 外汇与贵金属杠杆高,网格在单边行情中可能连续放大风险敞口,参数请先在策略测试器跑历史数据验证。
class="type">class="kw">double CGrid::LastPositionOpenPrice(class="type">ENUM_POSITION_TYPE type) { class="type">class="kw">double LastPrice = -class="num">1; class="type">class="kw">ulong LastTime = class="num">0; for (class="type">int i=PositionsTotal()-class="num">1; i>=class="num">0; i--) if (m_position.SelectByIndex(i)) if (m_position.Magic() == MagicNumber && m_position.Symbol()==Symbol() && m_position.PositionType()==type) { class="type">class="kw">ulong positionTime = m_position.TimeMsc(); if ( positionTime > LastTime ) class=class="str">"cmt">//FInd the latest position { LastPrice = m_position.PriceOpen(); LastTime = m_position.TimeMsc(); } } class="kw">return LastPrice; } class="type">int CGrid::CountPositions(class="type">ENUM_POSITION_TYPE type) { class="type">int counter = class="num">0; class=class="str">"cmt">//variable to store our positions number for (class="type">int i=PositionsTotal()-class="num">1; i>=class="num">0; i--) if (m_position.SelectByIndex(i)) class=class="str">"cmt">// Select position by its index if (m_position.Magic() == MagicNumber && m_position.Symbol() == Symbol() && m_position.PositionType() == type) { counter++; } class="kw">return counter; }
◍ 把编码变成生物钟
很多 MQL5 新手卡在“想写但坐不下来”,本质是缺一个固定触发点。把编码窗口钉死,比如每天上午 8:00–11:00,连续坚持几周,大脑会在那个时段自动进入兴奋状态,这比靠意志力硬撑效率高得多。 外汇与贵金属 EA 开发本身高风险,策略逻辑写错可能放大实盘亏损;但先能稳定坐下来写代码,才有机会谈回测与风控。 时间表没有标准答案,按你自己精力曲线排。有人夜盘后清醒,有人开盘前思路最干净,选能连续执行 21 天以上的那段就行。
给编码留出整块不受扰时段
写 MQL5 策略最怕中途被打断。实测里,大脑进入高度专注通常要连续 undisturbed 工作 90 分钟以上,之后才可能冒出能用的算法结构;碎片化 20 分钟写一段,往往隔天就得返工。 多数人一天里只有 2~3 小时处在能啃硬骨头的状态,其余时间更适合做回测参数微调、日志整理这类机械活。把深度编码压进这几个窗口,效率差出几倍。 外汇和贵金属 EA 开发高风险,逻辑漏洞会直接反映到实盘回撤。建议每周固定留 2~3 个整天只做核心代码,不回消息、不切图表,把艰苦的底层模块一次写完。
「把脏活拆进单用途函数」
在 MT5 里写 EA,最容易被坑的就是把循环和判断全塞进 OnTick。主线函数一旦堆满逻辑,调试时就像口袋里拔手榴弹保险针,随时炸在自己手上。 强迫简单算法挤在一个地方,是制造隐性 bug 的高效手法,代价往往是真金白银和大量排查时间。外汇与贵金属杠杆高、跳空频繁,这类错误触发后亏损可能快速放大。 每个函数只干一件事,名字直白到不用看实现就能猜到用途。下面这段按类型统计持仓的函数就是例子,光看 CountPositions 就知道它在数什么。
<span class="keyword">class="type">int</span> CGrid::CountPositions(<span class="macro">class="type">ENUM_POSITION_TYPE</span> type) { <span class="keyword">class="type">int</span> counter = <span class="number">class="num">0</span>; <span class="comment">class=class="str">"cmt">//variable to store our positions number</span> <span class="keyword">for</span> (<span class="keyword">class="type">int</span> i=<span class="functions">PositionsTotal</span>()-<span class="number">class="num">1</span>; i>=<span class="number">class="num">0</span>; i--) <span class="keyword">if</span> (m_position.SelectByIndex(i)) <span class="comment">class=class="str">"cmt">// Select position by its index</span> <span class="keyword">if</span> (m_position.Magic() == MagicNumber && m_position.<span class="functions">Symbol</span>() == <span class="functions">Symbol</span>() && m_position.PositionType() == type) { counter++; } <span class="keyword">class="kw">return</span> counter; } <span class="comment">class=class="str">"cmt">//+------------------------------------------------------------------+</span> <span class="comment">class=class="str">"cmt">//| |</span> <span class="comment">class=class="str">"cmt">//+------------------------------------------------------------------+</span>
<span class="keyword">class="type">int</span> CGrid::CountPositions(<span class="macro">class="type">ENUM_POSITION_TYPE</span> type) { <span class="keyword">class="type">int</span> counter = <span class="number">class="num">0</span>; <span class="comment">class=class="str">"cmt">//variable to store our positions number</span> <span class="keyword">for</span> (<span class="keyword">class="type">int</span> i=<span class="functions">PositionsTotal</span>()-<span class="number">class="num">1</span>; i>=<span class="number">class="num">0</span>; i--) <span class="keyword">if</span> (m_position.SelectByIndex(i)) <span class="comment">class=class="str">"cmt">// Select position by its index</span> <span class="keyword">if</span> (m_position.Magic() == MagicNumber && m_position.<span class="functions">Symbol</span>() == <span class="functions">Symbol</span>() && m_position.PositionType() == type) { counter++; } <span class="keyword">class="kw">return</span> counter; } <span class="comment">class=class="str">"cmt">//+------------------------------------------------------------------+</span> <span class="comment">class=class="str">"cmt">//| |</span> <span class="comment">class=class="str">"cmt">//+------------------------------------------------------------------+</span>
◍ 注释、盲打与版本控制的实战落点
写 MQL5 时给变量和函数加中文或英文注释,不是写给新手看的摆设。MetaEditor 会在你调用时浮出参数说明,几周后再看那段 ATR 过滤逻辑,没注释就只能从头读代码,效率直接腰斩。 盲打这件事被很多交易者忽略。在 keybr.com 免费练几周,形成肌肉记忆后,眼睛只盯屏幕写 EA,改一处止损逻辑不用低头找键位,连续编码 1 小时也不打断思路。外汇与贵金属杠杆高,复盘时间本就紧,打字卡顿也是在浪费你的盘后时间。 版本控制别只靠脑子记。Git 适合多文件工程;单文件 EA 可用土办法:每次大改后另存一个带版本号和改动说明的 txt,和 .mq5 一起开着,Windows 下按 CTRL+F7 让 MetaEditor 顺手编译全部打开文件,报错只管来自 txt 的忽略掉即可。下面这段输入参数就是一个该加注释的样本: 代码里的 InitialLots=0.01 是初始仓位,EquityUse=50 代表占用权益 50% 上限,AtrBarSignal=1 指明 ATR 取第 1 根 K 线。开 MT5 把这段贴进新 EA 输入区,编译后到属性框看注释是否随参数浮现,就能验证注释习惯值不值。
class="kw">input group "Money management" class="kw">input class="type">class="kw">double InitialLots = class="num">0.01; class=class="str">"cmt">//Initial position volume class="kw">input class="type">int EquityUse = class="num">50; class=class="str">"cmt">// Percentage of equity to be used in all trading operations class="kw">input group "Average True Range"; class="kw">input class="type">int AtrBarSignal = class="num">1; class=class="str">"cmt">//Atr value will be calculation taken from this candle
别急着下结论
这套受 Python 启发的 MQL5 模块写到这儿就收住了,但能不能直接搬进实盘脚本,还得你自己跑一遍才知道。文后附的 gridmodule.mqh 只有 3.58 KB,轻量到可以随手 include 进 EA 做网格逻辑验证。 外汇和贵金属杠杆高、滑点跳空频繁,模块再顺手也只解决工程封装,不替你扛回撤风险。 真要确认它值不值,开 MT5 建个测试品种,把头文件挂上跑两周模拟,比看任何结语都实在。