MQL5 细则手册:MetaTrader 5 交易事件的声音通知(基础篇)
◍ 用 MQL5 给交易事件挂声音提醒
MT5 客户端本身支持事件声音,但想按自定义逻辑触发提醒,得靠 MQL5 的 OnTradeTransaction 钩子。比如持仓成交、挂单触发这类事件,都可以用 PlaySound 直接播本地 wav,不必盯盘也能知道发生了什么。 下面这段是最小可用骨架:在每次交易事务回调里,判断事务类型为成交后播放提示音。注意 wav 文件要放在 MT5 的 Sounds 目录,否则返回 false。
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"); } }
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 再判盈亏出声。外汇和贵金属波动剧烈,这类提示只辅助盯盘,不替代风控。
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 个按钮占位生成,外汇与贵金属波动提醒的高频误触风险也随之上升,实盘前先关掉自动播放。
"::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 才能把按钮精确摆在想要的位置。
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