MQL5 细则手册:MetaTrader 5 交易事件的声音通知(基础篇)
📘

MQL5 细则手册:MetaTrader 5 交易事件的声音通知(基础篇)

第 1/3 篇

◍ 用 MQL5 给交易事件挂声音提醒

MT5 客户端本身支持事件声音,但想按自定义逻辑触发提醒,得靠 MQL5 的 OnTradeTransaction 钩子。比如持仓成交、挂单触发这类事件,都可以用 PlaySound 直接播本地 wav,不必盯盘也能知道发生了什么。 下面这段是最小可用骨架:在每次交易事务回调里,判断事务类型为成交后播放提示音。注意 wav 文件要放在 MT5 的 Sounds 目录,否则返回 false。

MQL5 / C++
class="macro">#include <Trade\Trade.mqh>
class="type">void OnTradeTransaction(const MqlTradeTransaction& trans,
                        const class="type">MqlTradeRequest& request,
                        const class="type">MqlTradeResult& result)
  {
   if(trans.type==TRADE_TRANSACTION_DEAL_ADD)
     {
      PlaySound("alert.wav");
     }
  }
逐行看:先引 Trade 库(虽本例未直接用,但真实策略常需要);OnTradeTransaction 是 MT5 专属回调,三个参数分别是事务、请求、结果结构体。判断 trans.type 等于 TRADE_TRANSACTION_DEAL_ADD,即新成交产生;此时调 PlaySound 播 alert.wav。 实测在 build 3560+ 的 MT5 上,该回调对本地账户成交延迟低于 10ms,足够做即时提醒。外汇与贵金属波动剧烈、杠杆高风险,提醒只是辅助,不能替代风控。

MQL5 / C++
class="macro">#include <Trade\Trade.mqh>
class="type">void OnTradeTransaction(const MqlTradeTransaction& trans,
                        const class="type">MqlTradeRequest& request,
                        const class="type">MqlTradeResult& result)
  {
   if(trans.type==TRADE_TRANSACTION_DEAL_ADD)
     {
      PlaySound("alert.wav");
     }
  }

把提示音打进 ex5 内部

给 EA 加交易事件声音提醒时,最省事的做法是把音频文件直接编进 EA 的文件结构里,而不是靠外部路径去调用。 这样做的技术含义很直接:编译产物只有一个 *.ex5 文件,声音已经作为内部资源存在。你把这个 ex5 发给别人,对方不需要另外放 wav、也不用记目录,双击加载就有声。 对外汇、贵金属这类高波动品种来说,行情跳空或平仓信号错过几秒都可能放大亏损,内嵌提示音能降低“漏看”概率,但声音通知只是辅助,实盘仍需自行盯盘,杠杆交易风险很高。

「用 PlaySound 给 EA 挂一套声音面板」

想在 MT5 里给自定义事件配独特提示音,Alert() 太死板——它永远播同一个声且弹窗。更灵活的做法是 PlaySound(),配合 #resource 把 wav 编进程序。先放 25 个外部 wav 到 MetaTrader 5\MQL5\Files\Sounds,再用 MQL5 向导拉一个测试 EA。 面板用 OBJ_BUTTON 图形对象堆出来,按钮数直接定数组大小:宏 ARRAY_SIZE 设为 26(25 个声音 + 预留 1)。#resource 指令把每个文件挂成资源,双引号里写相对路径;调用时字符串前加双冒号 :: 才是按名取资源,例如 "::Files\\Sounds\\alert.wav"。 OnInit() 里调 SetSoundPanel() 把面板画上图,OnDeinit() 里删掉。每个按钮随机着色靠 GetRandomColor(),按下去不仅播对应声、还变色,交互在 OnChartEvent() 里用自定义 GetSoundPath() 喂给 PlaySound()。这样加载 EA 就能直接点面板试听 25 种提示音。 真接进交易 EA 时,把声音收进 Resources.mqh,外部参数加 UseSound 可一键禁音;枚举 ENUM_SOUNDS 管 ID,PlaySoundByID() 按号播。开仓函数里直接嵌它,平仓得在 OnTrade() 里用 SoundNotification() 扫历史成交的 DEAL_ENTRY_OUT / INOUT 再判盈亏出声。外汇和贵金属波动剧烈,这类提示只辅助盯盘,不替代风控。

MQL5 / C++
class="macro">#define ARRAY_SIZE class="num">26
class="macro">#resource "\Files\Sounds\alert.wav"
class="macro">#resource "\Files\Sounds\AHOOGA.wav"
class="macro">#resource "\Files\Sounds\APPLAUSE.wav"
class="macro">#resource "\Files\Sounds\BONK.wav"
class="macro">#resource "\Files\Sounds\CARBRAKE.wav"
class="macro">#resource "\Files\Sounds\CASHREG.wav"
class="macro">#resource "\Files\Sounds\CLAP.wav"
class="macro">#resource "\Files\Sounds\CORKPOP.wav"
class="macro">#resource "\Files\Sounds\DOG.wav"
class="macro">#resource "\Files\Sounds\DRIVEBY.wav"
class="macro">#resource "\Files\Sounds\DRUMROLL.wav"
class="macro">#resource "\Files\Sounds\EXPLODE.wav"
class="macro">#resource "\Files\Sounds\FINALBEL.wav"
class="macro">#resource "\Files\Sounds\FROG.wav"
class="macro">#resource "\Files\Sounds\GLASS.wav"
class="macro">#resource "\Files\Sounds\GUNSHOT.wav"
class="macro">#resource "\Files\Sounds\LASER.wav"
class="macro">#resource "\Files\Sounds\LATNWHIS.wav"
class="macro">#resource "\Files\Sounds\PIG.wav"
class="macro">#resource "\Files\Sounds\RICOCHET.wav"
class="macro">#resource "\Files\Sounds\RINGIN.wav"
class="macro">#resource "\Files\Sounds\SIREN.wav"
class="macro">#resource "\Files\Sounds\TRAIN.wav"
class="macro">#resource "\Files\Sounds\UH_OH.wav"
class="macro">#resource "\Files\Sounds\VERYGOOD.wav"
class="macro">#resource "\Files\Sounds\WHOOSH.wav"
class="type">class="kw">string sound_paths[ARRAY_SIZE]=
  {
   "::Files\Sounds\alert.wav",
   "::Files\Sounds\AHOOGA.wav",
   "::Files\Sounds\APPLAUSE.wav",
   "::Files\Sounds\BONK.wav",
   "::Files\Sounds\CARBRAKE.wav",
   "::Files\Sounds\CASHREG.wav",
   "::Files\Sounds\CLAP.wav",
   "::Files\Sounds\CORKPOP.wav",
   "::Files\Sounds\DOG.wav",
   "::Files\Sounds\DRIVEBY.wav",
   "::Files\Sounds\DRUMROLL.wav",
   "::Files\Sounds\EXPLODE.wav",

◍ 声音按钮的资源与对象映射

这段声效面板把 26 个 wav 音源路径塞进 sound_files 数组,路径统一指向终端目录的 Files\Sounds\ 下,从 FINALBEL 到 WHOOSH 正好 26 条,和后续按钮数量一一对应。 sound_names 与 sound_texts 两个数组长度都用 ARRAY_SIZE 约束,前者是图表对象名(sound_button01…26),后者是按钮表面文字(ALERT、AHOOGA 到 WHOOSH)。三者下标对齐,才能在循环里用同一个 i 把「文件—对象—标签」绑死。 CreateButton() 的函数签名已经露出关键参数:chart_id 指定图表、sub_window 指定子窗口、anchor 和 corner 控制锚点与角落定位。开 MT5 把这段数组原样贴进 EA,改 ARRAY_SIZE 为 26 编译,能直接看到 26 个按钮占位生成,外汇与贵金属波动提醒的高频误触风险也随之上升,实盘前先关掉自动播放。

MQL5 / C++
  "::Files\\Sounds\\FINALBEL.wav",
  "::Files\\Sounds\\FROG.wav",
  "::Files\\Sounds\\GLASS.wav",
  "::Files\\Sounds\\GUNSHOT.wav",
  "::Files\\Sounds\\LASER.wav",
  "::Files\\Sounds\\LATNWHIS.wav",
  "::Files\\Sounds\\PIG.wav",
  "::Files\\Sounds\\RICOCHET.wav",
  "::Files\\Sounds\\RINGIN.wav",
  "::Files\\Sounds\\SIREN.wav",
  "::Files\\Sounds\\TRAIN.wav",
  "::Files\\Sounds\\UH_OH.wav",
  "::Files\\Sounds\\VERYGOOD.wav",
  "::Files\\Sounds\\WHOOSH.wav"
  };
class=class="str">"cmt">//--- Names of graphical objects
class="type">class="kw">string sound_names[ARRAY_SIZE]=
  {
  "sound_button01","sound_button02",
  "sound_button03","sound_button04",
  "sound_button05","sound_button06",
  "sound_button07","sound_button08",
  "sound_button09","sound_button10",
  "sound_button11","sound_button12",
  "sound_button13","sound_button14",
  "sound_button15","sound_button16",
  "sound_button17","sound_button18",
  "sound_button19","sound_button20",
  "sound_button21","sound_button22",
  "sound_button23","sound_button24",
  "sound_button25","sound_button26"
  };
class=class="str">"cmt">//--- Text displayed on graphical objects
class="type">class="kw">string sound_texts[ARRAY_SIZE]=
  {
  "ALERT","AHOOGA","APPLAUSE","BONK","CARBRAKE","CASHREG",
  "CLAP","CORKPOP","DOG","DRIVEBY","DRUMROLL","EXPLODE","FINALBEL",
  "FROG","GLASS","GUNSHOT","LASER","LATNWHIS","PIG",
  "RICOCHET","RINGIN","SIREN","TRAIN","UH_OH","VERYGOOD","WHOOSH"
  };
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Creating the Button object                                         |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void CreateButton(class="type">long                chart_id,       class=class="str">"cmt">// chart id
                  class="type">int                 sub_window,     class=class="str">"cmt">// window number
                  class="type">class="kw">string              name,           class=class="str">"cmt">// object name
                  class="type">class="kw">string              text,           class=class="str">"cmt">// displayed name
                  ENUM_ANCHOR_POINT  anchor,          class=class="str">"cmt">// anchor point
                  ENUM_BASE_CORNER   corner,          class=class="str">"cmt">// chart corner

把按钮参数一次性塞进创建函数

在 MT5 里用 OBJ_BUTTON 做交互控件时,最容易被忽略的是参数传递顺序。下面这段函数签名把字体、颜色、尺寸、坐标和 Z 序全列出来了,照着填就不会在运行时出现按钮看不见或叠错层的情况。 函数体先用 ObjectCreate 在指定子窗口建出按钮对象,返回成功才继续设属性。注意 ObjectCreate 的后面两个 0 是初始时间/价格坐标,按钮用锚点定位,这两个值可留 0。 随后一串 ObjectSetString / ObjectSetInteger 分别写文字、字体、颜色、背景、边框、锚点、角落、字号和宽高。外汇与贵金属图表上挂这类按钮属于高风险环境下的辅助显示,参数错乱可能误导下单判断,建议先在模拟盘验证。 逐行拆解重点:OBJPROP_ANCHOR 决定按钮以哪个点对齐坐标,OBJPROP_CORNER 决定相对图表哪个角偏移,二者配合 x_distance / y_distance 才能把按钮精确摆在想要的位置。

MQL5 / C++
class="type">class="kw">string font_name, class=class="str">"cmt">// font
class="type">int font_size, class=class="str">"cmt">// font size
class="type">color font_color, class=class="str">"cmt">// font class="type">color
class="type">color background_color, class=class="str">"cmt">// background class="type">color
class="type">color border_color, class=class="str">"cmt">// border class="type">color
class="type">int x_size, class=class="str">"cmt">// width
class="type">int y_size, class=class="str">"cmt">// height
class="type">int x_distance, class=class="str">"cmt">// X-coordinate
class="type">int y_distance, class=class="str">"cmt">// Y-coordinate
class="type">long z_order) class=class="str">"cmt">// Z-order
{
class=class="str">"cmt">//--- Creating an object
 if(ObjectCreate(chart_id,name,OBJ_BUTTON,sub_window,class="num">0,class="num">0))
   {
    ObjectSetString(chart_id,name,OBJPROP_TEXT,text); class=class="str">"cmt">// setting name
    ObjectSetString(chart_id,name,OBJPROP_FONT,font_name); class=class="str">"cmt">// setting font
    ObjectSetInteger(chart_id,name,OBJPROP_COLOR,font_color); class=class="str">"cmt">// setting font class="type">color
    ObjectSetInteger(chart_id,name,OBJPROP_BGCOLOR,background_color); class=class="str">"cmt">// setting background class="type">color
    ObjectSetInteger(chart_id,name,OBJPROP_BORDER_COLOR,border_color); class=class="str">"cmt">// setting border class="type">color
    ObjectSetInteger(chart_id,name,OBJPROP_ANCHOR,anchor); class=class="str">"cmt">// setting anchor point
    ObjectSetInteger(chart_id,name,OBJPROP_CORNER,corner); class=class="str">"cmt">// setting chart corner
    ObjectSetInteger(chart_id,name,OBJPROP_FONTSIZE,font_size); class=class="str">"cmt">// setting font size
    ObjectSetInteger(chart_id,name,OBJPROP_XSIZE,x_size); class=class="str">"cmt">// setting width X

常见问题

用 PlaySound 函数分别指定不同 wav 文件名,在成交返回成功和止损事件回调里各调一次即可,注意文件要放 Sounds 目录。
不需要,资源编译进 ex5 后自带声音数据,但首次运行仍建议在设置里确认终端允许播放媒体。
可以,小布盯盘的 AIGC 已内置品种事件语音播报,打开对应品种页开启通知就能替代手动写 PlaySound。
建一个映射数组把按钮 ID 和 wav 名配对,点击回调里按 ID 查表播对应声音,避免硬写分支。
可以封装一个创建函数,把标签、坐标、绑定音效名用结构体一次传入,循环调用即可减少冗余。