为 MetaTrader 打造的高级 EA 构造器 - botbrains·综合运用
📘

为 MetaTrader 打造的高级 EA 构造器 - botbrains·综合运用

第 3/3 篇

EA 模块化的函数骨架长这样

把一套 MT5 自动交易逻辑拆成小块函数,是降低维护成本的直接办法。下面这段从实盘机器人里抽出的代码,每个 block_ 函数对应一个动作节点:打印快线数值、翻倍手数、发 TG 截图、平掉持仓,彼此用函数调用串起来。 比如 block_bQMre45Bd 里先算前一根 K 的快线 SMA:moving_average(..., 1) 取 shift=1,再连调五个子块去刷新界面文字、跑后续判断。手数控制分两路:block_bPlXoF1uA 把 __full_lot 设成 __lot * 2,block_bYUS6GLT0 则原样赋值,意味着加仓和首仓可以走不同仓位逻辑。 截图推送的参数是写死的:2160×720 像素发往 __admin_id,回测时若没填这个 ID,电报块会静默失效。外汇与贵金属波动剧烈,这类市价单模块上线前务必在策略测试器跑至少 3 个月 Tick 数据。

MQL5 / C++
class="type">void block_bO7LNEs4m(){
  print_debug_info(( to_string(to_double("ma_fast = ")) + DoubleToString(__ma_fast, class="num">2) ));
}
class=class="str">"cmt">//Function of the block bPlXoF1uA(set_complex_variable_value):
class="type">void block_bPlXoF1uA(){
  vset(__full_lot, ( __lot * to_double("class="num">2") ));
}
class=class="str">"cmt">//Function of the block bQ4zsFoIh(log):
class="type">void block_bQ4zsFoIh(){
  log_to_file("Open class="type">long!");
  block_bMgaVnT74();
}
class=class="str">"cmt">//Function of the block bQMre45Bd(set_complex_variable_value):
class="type">void block_bQMre45Bd(){
  vset(__ma_fast_prev, ( moving_average(to_string(__symbol), PERIOD_CURRENT, (class="type">int)__fast_ma_period, MODE_SMA, PRICE_CLOSE, class="num">1) ));
  block_bRUr8MnXh();
  block_b1VYatoxs();
  block_b3UJfY74N();
  block_bofgi9HOT();
}
class=class="str">"cmt">//Function of the block bRUr8MnXh(interface_element_modify):
class="type">void block_bRUr8MnXh(){
  modify_text("bj6MtjhZF", DoubleToString(__ma_fast_prev, class="num">2) );
}
class=class="str">"cmt">//Function of the block bS1JODjZj(print_debug_info):
class="type">void block_bS1JODjZj(){
  print_debug_info(( to_string(to_double("ma_slow_prev = ")) + DoubleToString(__ma_slow_prev, class="num">2) ));
}
class=class="str">"cmt">//Function of the block bT8xv0qGj(buy_signal_sound):
class="type">void block_bT8xv0qGj(){
  play_sound("buy_signal");
  block_bPlXoF1uA();
}
class=class="str">"cmt">//Function of the block bTonyumSN(print_debug_info):
class="type">void block_bTonyumSN(){
  print_debug_info(( to_string(to_double("ma_slow = ")) + DoubleToString(__ma_slow, class="num">2) ));
}
class=class="str">"cmt">//Function of the block bTs8fZtAO(telegram_send_chart_screenshot):
class="type">void block_bTs8fZtAO(){
  telegram_send_chart_screenshot(to_string(__symbol), class="num">2160, class="num">720, (class="type">int)__admin_id);
}
class=class="str">"cmt">//Function of the block bUySCvh6M(place_market_order):
class="type">void block_bUySCvh6M(){
  place_market_order(to_string(__symbol), "BUY", __full_lot);
  block_bfrp6ajWk();
  block_bjBTLJMym();
  block_boX0sSwri();
  block_bQ4zsFoIh();
}
class=class="str">"cmt">//Function of the block bWkG0nSQa(telegram_send_message):
class="type">void block_bWkG0nSQa(){
  telegram_send_message("Open class="type">class="kw">short!", (class="type">int)__admin_id);
}
class=class="str">"cmt">//Function of the block bX2tY0y68(terminal_print):
class="type">void block_bX2tY0y68(){
  terminal_print("Open class="type">class="kw">short!");
}
class=class="str">"cmt">//Function of the block bXRrICVna(close_position):
class="type">void block_bXRrICVna(){
  close_position(to_string(__symbol));
}
class=class="str">"cmt">//Function of the block bYGEhpZDM(place_market_order):
class="type">void block_bYGEhpZDM(){
  place_market_order(to_string(__symbol), "SELL", __lot);
}
class=class="str">"cmt">//Function of the block bYUS6GLT0(set_complex_variable_value):
class="type">void block_bYUS6GLT0(){
  vset(__full_lot, ( __lot ));
}
class=class="str">"cmt">//Function of the block bYi6ikfde(terminal_print):
class="type">void block_bYi6ikfde(){
  terminal_print("Робот запущен!");
}
class=class="str">"cmt">//Function of the block bfrp6ajWk(terminal_print):
class="type">void block_bfrp6ajWk(){
  terminal_print("Open class="type">long!");
}
class=class="str">"cmt">//Function of the block biLE3RJAD(sell_signal_sound):
class="type">void block_biLE3RJAD(){
  play_sound("sell_signal");
  block_bPlXoF1uA();
}
class=class="str">"cmt">//Function of the block bjBTLJMym(telegram_send_message):
class="type">void block_bjBTLJMym(){
  telegram_send_message("Open class="type">long!", (class="type">int)__admin_id);
}
class=class="str">"cmt">//Function of the block boHVNlqnO(set_complex_variable_value):
class="type">void block_boHVNlqnO(){
  vset(__ma_slow, ( moving_average(to_string(__symbol), PERIOD_CURRENT, (class="type">int)__slow_ma_period, MODE_SMA, PRICE_CLOSE, class="num">0) ));
  block_b0Wkfq6OD();
}
class=class="str">"cmt">//Function of the block boX0sSwri(telegram_send_chart_screenshot):
class="type">void block_boX0sSwri(){
  telegram_send_chart_screenshot(to_string(__symbol), class="num">2160, class="num">720, (class="type">int)__admin_id);
}
class=class="str">"cmt">//Function of the block bofgi9HOT(interface_element_modify):
class="type">void block_bofgi9HOT(){

◍ 慢快线死叉触发卖单的分块逻辑

这段 MQL5 把「慢快均线死叉」拆成了四个互相调用的函数块,核心判定在 block_bvIvs7SMe 里:当快线跌破慢线、且上一根 K 线还是快线在上的状态,同时同品种当前无卖出持仓,才去跑下单流程。 下单函数 block_bugmLdNsU 先以 SELL 方向、整手数开市价单,随后连续调用四个后缀块(bX2tY0y68 / bWkG0nSQa / bTs8fZtAO / b3crj4ayK),这些块大概率负责挂止损、改注释、刷面板等收尾动作,原文未展开。 死叉条件用 __ma_fast_prev > __ma_slow_prev 做「上一根反向」过滤,能砍掉一部分本根内反复穿插的假信号;pause(1000) 在 bzVyOb4tW 里硬等 1 秒再回流 biLE3RJAD,避免同 tick 内高频重判。外汇与贵金属波动剧烈,这种裸方向市价单在高滑点时段可能直接吃亏,上 MT5 把 __full_lot 调小到 0.01 先跑一周模拟再谈实盘。

MQL5 / C++
  modify_text("bLcIIkYqO", DoubleToString(__ma_slow, class="num">2) );
}
class=class="str">"cmt">//Function of the block bugmLdNsU(place_market_order):
class="type">void block_bugmLdNsU(){
  place_market_order(to_string(__symbol), "SELL", __full_lot);
  block_bX2tY0y68();
  block_bWkG0nSQa();
  block_bTs8fZtAO();
  block_b3crj4ayK();
}
class=class="str">"cmt">//Function of the block bvIvs7SMe(condition):
class="type">void block_bvIvs7SMe(){
  if (( __ma_fast < __ma_slow ) && ( __ma_fast_prev > __ma_slow_prev ) && ( get_position_info(to_string(__symbol), "POSITION_DIRECTION") != SELL_DIRECTION )){
    block_bugmLdNsU();
  }
}
class=class="str">"cmt">//Function of the block bzVyOb4tW(pause):
class="type">void block_bzVyOb4tW(){
  pause(class="num">1000);
  block_biLE3RJAD();
}

「BotBrains 里能直接拖的 140 多个积木」

BotBrains 编辑器内置超过 140 个可用模块,按功能被切成了事件、条件、循环、趋势指标、振荡器、比尔·威廉姆斯、图表分析、业务、变量、声音、信心、枚举、历史、Telegram、其它、界面元素、数学与逻辑运算符、调试等近二十类。做可视化策略时,先认清楚每类模块触发时机和输出类型,比硬背文档更高效。 事件类里最常用的是 New tick(新报价触发)和 Timer(按秒周期触发),前者适合做即时价行为判断,后者适合做固定频率扫描。条件只用「If」一个块,1 进 2 出,真走绿色分支、假走红色分支。 循环和枚举容易踩坑:列举有效限价或停损订单前,必须先放 Request active orders list;拉历史成交前必须先用 Request history。跳过这一步,循环里读到的票据大概率是上一轮的残留数据。 趋势与振荡器覆盖了 Adaptive MA、布林带、Ichimoku、MACD、RSI、Stochastic 等三十余个指标,比尔·威廉姆斯系单独成类(Alligator、Fractals、AO 等)。业务类直接挂 Market order / Limit order / Stop order 和下单后平仓、删单模块,配合「信心」类读账户与持仓信息,就能在 MT5 里拼出一条完整闭环。 数学运算符含 + - * / √ ^ % 及比较符,逻辑只有 AND / OR / NOT 三种。调试用 Print debug info 把变量值和模块返回值打到终端日志,是排查可视化逻辑错乱的最快手段。外汇与贵金属波动剧烈、杠杆风险高,模块拼出来的策略未经历史回测和实盘验证前,实盘触发概率和滑点损耗都只是推测。

关于这套可视化编程思路的延伸阅读

BotBrains 这套可视化搭建思路在读者反馈里争议挺明显:2022 年 12 月 Ivan Titov 就指出,普通人用不了,因为它本质还是要懂 MQL5 编程,界面繁琐程度不比直接写 EA 低。2023 年 1 月 vbymrf 更直接——纯可视化代码和语言编程一样难学,因为语言构造绕不掉。 想继续深挖概率与组合数学在交易里的落地,同作者还有几篇连贯文章可对照看:伯努利逻辑那篇讲如何用 Bernoulli 方案描述交易数据数组并做自适应系统;回归模型续篇用三种动态暂态函数印证价格变化形态;曲线分析篇则把多状态系统往双状态系统化简,给可伸缩算法打底。 对程序员来说,这类自动模块生成界面仍有参考价值,但别指望零基础拼出能跑的机器人。外汇和贵金属波动极快,任何可视化策略未经 MT5 历史回测验证,实盘都只是概率游戏。

常见问题

可以用可视化积木搭,把均线模块和订单触发模块拖到一起连好逻辑就行,不用手写代码。
至少拆成信号计算、条件判断、下单执行、风控退出四块,各自封装成函数方便后期改。
可以,小布能读你导出的策略描述并提示死叉判定周期错配、漏掉止损等常见坑,省去人工复查。
内置 140 多个积木,均线、突破、网格、部分指标组合都能拼,常规散户策略基本够用。
逻辑简单时差异可忽略;模块调用层多或高频触发时略慢,实盘前用历史数据跑一遍更稳。