从头开始开发智能交易系统(第 29 部分):谈话平台·综合运用
📘

从头开始开发智能交易系统(第 29 部分):谈话平台·综合运用

第 3/3 篇

给EA接上两套声音警报

不盯盘也想知道盘面发生了什么,声音警报是最直接的方式——它能在事件发生的瞬间抓住注意力,老手甚至听一声就知道该不该动手查终端。这里的核心思路是把声音系统单独封成一个类,既隔离逻辑又方便后续扩展,而不必在主线代码里到处塞 PlaySound。 类里重写了两个同名 PlayAlert 函数,这是刻意做的:第一个版本按交易服务器返回的数字错误码去播放外部 wav 文件(路径形如 NanoEA-SIMD\RET_CODE\%d.wav),你随时替换目录里的音频,EA 运行时也能生效,不用重新编译;第二个版本把声音作为 EA 内部资源编译进去,对应三种固定事件——算法交易未开启、挂单转持仓、持仓在价格线归零时平仓。 外部文件方案适合报错和故障提醒:你录一个以服务器返回值命名的 wav,EA 自动找文件播报,连“订单被拒”都能用语音讲清楚。内部资源方案则绑死在 exe 里,换环境不用带音频包,但想改声得重编。 落地时有个坑:附件里的 SOUNDS 文件夹不能放在代码同目录,否则不响。跑一下配套脚本,工具栏会打印出目标目录;把 WARRING、BEGIN、END 三个 wav 拷进去,若要把它们编进 EA,则 MQL5 的 SOUND 目录里也得有同名文件,否则集成不进去。外汇与贵金属波动剧烈,声音提醒只降低漏看概率,不消除高风险。

MQL5 / C++
class C_Sounds
{
			class="kw">protected:
				enum eTypeSound {TRADE_ALLOWED, OPERATION_BEGIN, OPERATION_END};
		class="kw">public:
class=class="str">"cmt">//+------------------------------------------------------------------+
class="kw">inline class="type">bool PlayAlert(class="kw">const class="type">int arg)
			{
				class="kw">return PlaySound(StringFormat("NanoEA-SIMD\RET_CODE\%d.wav", arg));
			}
class=class="str">"cmt">//+------------------------------------------------------------------+
class="kw">inline class="type">bool PlayAlert(class="kw">const eTypeSound arg)
			{
				class="type">class="kw">string str1;
		
				class="kw">switch (arg)
				{
					case TRADE_ALLOWED   : str1 = def_Sound00; class="kw">break;
					case OPERATION_BEGIN : str1 = def_Sound01; class="kw">break;
					case OPERATION_END   : str1 = def_Sound02; class="kw">break;
					class="kw">default : class="kw">return false;
				}
				PlaySound("::" + str1);
			}

「路由类与下单失败的告警分支」

这段 C_Router 类把下单动作收口到 inline bool Send(void) 里,用 OrderSend 把封装好的 MqlTradeRequest 发出去,结果写进 MqlTradeResult。若返回 false,先尝试用 Sound.PlayAlert 按 retcode 播报警声,播不出再走 Terminal.MsgError 把「Error Number: %d」打到日志,函数返回 false;成功则直接 return true。 OnInit 里先查 TERMINAL_TRADE_ALLOWED,若终端禁止交易,会触发 Sound.PlayAlert(TRADE_ALLOWED) 并返回 INIT_FAILED,EA 起不来。这一道闸能避免在无交易权限的 MT5 终端上白跑逻辑。 CreateIndicator 按枚举挂不同颜色的指标对象:IT_TAKE 用绿系(clrForestGreen/clrDarkGreen),IT_STOP 用砖红系(clrFireBrick/clrMaroon),IT_PENDING 用蓝黄系并额外建一个状态按钮 m_BtnCheck 且默认置 true。外汇与贵金属杠杆高,这类自动挂单对象若颜色或按钮状态误设,盘面误读概率会明显上升,建议开 MT5 把宏里的 clr 常量逐一对一遍。

MQL5 / C++
class C_Router
{
   class="kw">protected:
   class="kw">private  :
      class="type">MqlTradeRequest TradeRequest;
      class="type">MqlTradeResult  TradeResult;
class=class="str">"cmt">//+------------------------------------------------------------------+
   class="kw">inline class="type">bool Send(class="type">void)
      {
         if (!OrderSend(TradeRequest, TradeResult))
         {
            if (!Sound.PlayAlert(TradeResult.retcode)) Terminal.MsgError(C_Terminal::FAILED_ORDER, StringFormat("Error Number: %d", TradeResult.retcode));
            class="kw">return false;
         }
         class="kw">return true;
      }
class=class="str">"cmt">// ... The rest of the class code....
class="type">int OnInit()
{
   if (!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED))
   {
      Sound.PlayAlert(C_Sounds::TRADE_ALLOWED);
      class="kw">return INIT_FAILED;
   }
   Terminal.Init();
class=class="str">"cmt">// ... The rest of the code...
class="type">void CreateIndicator(class="type">class="kw">ulong ticket, eIndicatorTrade it)
{
   class="type">class="kw">string sz0;
   class="kw">switch (it)
   {
      case IT_TAKE     : macroCreateIndicator(it, clrForestGreen, clrDarkGreen, clrNONE); class="kw">break;
      case IT_STOP     : macroCreateIndicator(it, clrFireBrick, clrMaroon, clrNONE); class="kw">break;
      case IT_PENDING:
         macroCreateIndicator(it, clrCornflowerBlue, clrDarkGoldenrod, def_ColorVolumeEdit);
         m_BtnCheck.Create(ticket, sz0 = macroMountName(ticket, it, EV_CHECK), def_BtnCheckEnabled, def_BtnCheckDisabled);
         m_BtnCheck.SetStateButton(sz0, true);
         macroInfoBase(IT_PENDING);

◍ 成交与撤单时的图形与声音联动

上面这段逻辑处理的是交易指令在图表上的落地与清理。当分支进入 IT_RESULT,系统用 clrSlateBlue 画指标线,同时播 OPERATION_BEGIN 提示音,并把 ExistOpenPosition 标为真,说明此时持仓已经实际存在。 RemoveIndicator 负责反向清理:先关掉 CHART_EVENT_OBJECT_DELETE 避免误触,再按 ticket 和类型删对象;若 RESULT 线价格大于 0,额外播 OPERATION_END。删除完把选择票号归零、鼠标光标恢复、重绘图表。 OnStart 里只打了一行 TerminalInfoString(TERMINAL_PATH),你开 MT5 跑这段,能在专家日志直接看到终端安装路径,用来核对指标文件是否丢对目录。外汇和贵金属波动剧烈,这类自动提示只能降低漏看信号的概率,不保证胜率。

MQL5 / C++
            class="kw">break;
            case IT_RESULT  :
               macroCreateIndicator(it, clrSlateBlue, clrSlateBlue, def_ColorVolumeResult);
               macroInfoBase(IT_RESULT);
               Sound.PlayAlert(C_Sounds::OPERATION_BEGIN);
               m_InfoSystem.ExistOpenPosition = true;
               class="kw">break;
         }
         m_BtnClose.Create(ticket, macroMountName(ticket, it, EV_CLOSE), def_BtnClose);
}
class="kw">inline class="type">void RemoveIndicator(class="type">class="kw">ulong ticket, eIndicatorTrade it = IT_NULL)
{
         ChartSetInteger(Terminal.Get_ID(), CHART_EVENT_OBJECT_DELETE, false);
         if ((it == IT_NULL) || (it == IT_PENDING) || (it == IT_RESULT))
         {
            if (macroGetPrice(ticket, IT_RESULT, EV_LINE) > class="num">0) Sound.PlayAlert(C_Sounds::OPERATION_END);
            ObjectsDeleteAll(Terminal.Get_ID(), StringFormat("%s%c%llu%c", def_NameObjectsTrade, def_SeparatorInfo, ticket, (ticket > class="num">1 ? &class="macro">#x27;*&class="macro">#x27; : def_SeparatorInfo)));
         } else ObjectsDeleteAll(Terminal.Get_ID(), StringFormat("%s%c%llu%c%c", def_NameObjectsTrade, def_SeparatorInfo, ticket, def_SeparatorInfo, (class="type">char)it));
         ChartSetInteger(Terminal.Get_ID(), CHART_EVENT_OBJECT_DELETE, true);
         m_Selection.ticket = class="num">0;
         Mouse.Show();
         ChartRedraw();
}
class="macro">#class="kw">property copyright "Daniel Jose"
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void OnStart()
{
         Print(TerminalInfoString(TERMINAL_PATH));
}
class=class="str">"cmt">//+------------------------------------------------------------------+

把这条线请下神坛

语音报警的思路说穿了很简单:用 PlaySound 或自定义 wav 触发,把 EA、指标、脚本里的关键事件变成人声提示,而不是盯着日志看文字。前面演示的这套方案只是最小骨架,实际你完全可以把开仓理由、风控阈值录成一段十几秒的语音,挂在 OnTradeTransaction 里播。 MetaTrader 5 的声音系统不挑宿主,EA 之外指标和脚本都能调,限制你的只有愿不愿意自己录素材。外汇和贵金属波动快、滑点凶,语音提醒能缩短反应延迟,但绝不替代你对仓位和风险的判断,信号漏播或延迟都可能发生。 真要验证,把附件里 EA_-_h_Parte_29_6.zip 的例程拖进 MT5 回测一遍,改一个 wav 路径就能听到效果。剩下的玩法,是你自己往里塞什么话。

常见问题

在告警模块里建两个独立声音分支,分别绑定不同事件源与音频文件,运行时按事件触发对应声道即可。
在路由类的失败回调里加图形标记加声音告警,把错误码写进日志并弹窗,方便立刻排查。
小布可接管图形与声音联动的监控,成交或撤单时自动推送提醒,你不用一直守着终端。
把图形绘制与声音调用放进同一事件处理函数末尾,用状态锁避免重复执行,回测时可关声音。
会。告警只是辅助,外汇贵金属高风险,信号延迟或环境异常都可能漏报,别完全依赖自动化线。