MQL5 简介(第 7 部分):在 MQL5 中构建 EA 交易和使用 AI 生成代码的初级指南·进阶篇
「让 AI 写 MQL5 前先把伪代码拆细」
AI 写 MQL5 确实能把重复性编码压缩掉一大块,但现阶段它生成的代码只是“指导性模型”,不是交付终版。实测中,若你不直接给项目背景,AI 返回的变量定义常常漏掉外部依赖;先写详尽伪代码再喂给模型,回应的准确率会明显提升。 以一个简单的交易语音提醒 EA 为例,伪代码要拆到四步:初始化变量、用户设提醒时间和声音、持续比对本地与提醒时间、到点播声音文件。每一步都逼你回答具体问题,比如“提醒时间用什么格式”“声音文件存哪”。这些问题就是给 AI 的精确路线图。 AI 对“EA 需要哪些变量”的典型回应会列出:datetime 型提醒时间、string 型声音路径、datetime 型当前时间等。它给的代码并不完美,但你能从中抽出下一轮问题,例如用户怎么输入参数。用 input string 声音乐件名,用户就能在 EA 属性里填,而不是写死在代码里。 到第三步监控时区,AI 给出的核心逻辑是在 OnTick 里用 TimeLocal() 取本地时间,StringToTime() 转提醒时间,相等就 PlaySound()。这一步越往后,AI 的解释越贴项目,说明分阶段喂伪代码比一次性丢需求靠谱得多。 第四步把 WAV 丢进 MT5 安装目录的 Sounds 文件夹,代码里直接引文件名播。重点:AI 不是替你干完,而是和你来回碰,把项目复杂度摊开。外汇和贵金属波动剧烈、高风险,这类提醒 EA 只解决“别漏看时间”,下单决策还得你自己扛。
在 MT5 里用 EA 挂多时段声音闹钟
做外汇或贵金属盯盘,固定时间点容易漏看,用 EA 在终端本地挂几个声音闹钟比人工记表更稳。下面这段 MQL5 代码演示了如何声明 3 个闹钟时间、对应声音文件,并在 OnTick 里比对本地时间触发播放,外汇与贵金属波动受消息面影响大,属于高风险品种,闹钟只作提醒、不构成交易依据。 代码里先定义了 Alarm1~Alarm3 三个 datetime 变量和 Sound1~Sound3 字符串,默认声音文件名为 alert1.wav 等;NumberOfAlarms 写死为 3,表示最多同时挂 3 个提醒点。input 层的 Alarm1/Alarm2/Alarm3 默认都是 "00:00:00",你在 EA 参数里改成 "08:30:00" 这类字符串即可生效。 OnTick 中通过 TimeLocal() 取本机时间,再用 StringToTime() 把输入字符串转成 datetime 做相等比较。注意原文用了 currentTime == StringToTime(AlarmX) 的精确相等判断,Tick 频率若错过那一秒就可能不响,实盘建议改成区间判断(如差值小于 1 秒)。PlaySound(Sound) 负责播放在 input 里指定的声音文件,声音需放在 MT5 的 Sounds 目录下。 OnInit 与 OnDeinit 这里是空壳,初始化直接 return 0,去初始化没做资源回收。若你要在闹钟触发时同时发手机推送,可在相等判断里补 SendNotification,但先确认 MetaQuotes ID 已绑定。
class=class="str">"cmt">// Define variables for alarm times class="type">class="kw">datetime Alarm1; class="type">class="kw">datetime Alarm2; class="type">class="kw">datetime Alarm3; class=class="str">"cmt">// Define variables for sound selection class="type">class="kw">string Sound1 = "alert1.wav"; class="type">class="kw">string Sound2 = "alert2.wav"; class="type">class="kw">string Sound3 = "alert3.wav"; class=class="str">"cmt">// Define variables for current time and notification message class="type">class="kw">datetime CurrentTime; class="type">class="kw">string NotificationMessage; class=class="str">"cmt">// Define other configuration variables class="type">int NumberOfAlarms = class="num">3; class="kw">input class="type">class="kw">string Alarm1 = "class="num">00:class="num">00:class="num">00"; class="kw">input class="type">class="kw">string Alarm2 = "class="num">00:class="num">00:class="num">00"; class="kw">input class="type">class="kw">string Alarm3 = "class="num">00:class="num">00:class="num">00"; class="kw">input class="type">class="kw">string Sound = ""; class=class="str">"cmt">// User-selected sound filename class=class="str">"cmt">// Inside the OnTick() function class=class="str">"cmt">// Get the current time class="type">class="kw">datetime currentTime = TimeLocal(); class=class="str">"cmt">// Check if the current time matches any of the alarm times if(currentTime == StringToTime(Alarm1) || currentTime == StringToTime(Alarm2) || currentTime == StringToTime(Alarm3)) { class=class="str">"cmt">// Trigger the audio alert PlaySound(Sound); } PlaySound("alert.wav"); class=class="str">"cmt">// Define class="kw">input variables class="kw">input class="type">class="kw">string Alarm1 = "class="num">00:class="num">00:class="num">00"; class=class="str">"cmt">// Default value for first alarm class="kw">input class="type">class="kw">string Alarm2 = "class="num">00:class="num">00:class="num">00"; class=class="str">"cmt">// Default value for second alarm class="kw">input class="type">class="kw">string Alarm3 = "class="num">00:class="num">00:class="num">00"; class=class="str">"cmt">// Default value for third alarm class="kw">input class="type">class="kw">string Sound = "alert.wav"; class=class="str">"cmt">// Default sound file class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Expert initialization function | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">int OnInit() { class=class="str">"cmt">// Initialization function, executed once when the EA is launched class="kw">return class="num">0; class=class="str">"cmt">// Return class="num">0 to indicate successful initialization } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Expert deinitialization function | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnDeinit(const class="type">int reason) { class=class="str">"cmt">// Deinitialization function, executed before the EA is removed class=class="str">"cmt">// Perform any cleanup or necessary actions here } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Expert tick function | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnTick() { class=class="str">"cmt">// Convert alarm strings to class="type">class="kw">datetime objects class="type">class="kw">datetime first_Alarm = StringToTime(Alarm1); class="type">class="kw">datetime second_Alarm = StringToTime(Alarm2); class="type">class="kw">datetime third_Alarm = StringToTime(Alarm3); class=class="str">"cmt">// Get current local time
◍ 用本地时间触发三段式声音提醒
在 MT5 里做定时提醒,核心是把输入的字符串时间转成 datetime 再做等值比对。下面这段逻辑放在 OnTick 里,每次报价到来都会取一次本地时间,若命中任一时点就播声音文件。 输入参数给了三个 alarm 字符串,默认全是 00:00:00,Sound 默认 alert.wav。实际用的时候把 Alarm1~Alarm3 改成你的关键时点,比如伦敦开盘 08:00:00、美盘重叠 13:30:00,就能靠声音防漏单。外汇与贵金属波动剧烈,定时提醒只解决「不在屏前」的问题,不替代风控。 注意 TimeLocal() 返回的是终端所在机器的系统时间,不是服务器时间。若 VPS 时区设错,提醒会偏移到奇怪的时刻——这是实盘里最容易踩的坑。 代码逐行看:StringToTime 把 'HH:HH:SS' 文本解析为 datetime;TimeLocal 抓当前本地钟;if 里用 == 直接比,命中即 PlaySound。OnInit 仅返回 0 表示加载成功,OnDeinit 留空可做清理,OnStart 里的 Print 则方便你手动跑脚本确认本地时间格式。
class="type">class="kw">datetime Time = TimeLocal(); class=class="str">"cmt">// Check if current time matches any of the alarm times if(first_Alarm == Time || second_Alarm == Time || third_Alarm == Time) { class=class="str">"cmt">// Play sound if any alarm time is reached PlaySound(Sound); } } class="type">void OnStart() { class=class="str">"cmt">// Get the current local time class="type">class="kw">datetime localTime = TimeLocal(); class=class="str">"cmt">// Print the local time to the console Print("Current Local Time: ", localTime); } class=class="str">"cmt">// Define class="kw">input variables class="kw">input class="type">class="kw">string Alarm1 = "class="num">00:class="num">00:class="num">00"; class=class="str">"cmt">// Default value for first alarm class="kw">input class="type">class="kw">string Alarm2 = "class="num">00:class="num">00:class="num">00"; class=class="str">"cmt">// Default value for second alarm class="kw">input class="type">class="kw">string Alarm3 = "class="num">00:class="num">00:class="num">00"; class=class="str">"cmt">// Default value for third alarm class="kw">input class="type">class="kw">string Sound = "alert.wav"; class=class="str">"cmt">// Default sound file class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Expert initialization function | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">int OnInit() { class=class="str">"cmt">// Initialization function, executed once when the EA is launched class="type">class="kw">datetime localTime = TimeLocal(); class="kw">return class="num">0; class=class="str">"cmt">// Return class="num">0 to indicate successful initialization } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Expert deinitialization function | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnDeinit(const class="type">int reason) { class=class="str">"cmt">// Deinitialization function, executed before the EA is removed class=class="str">"cmt">// Perform any cleanup or necessary actions here } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Expert tick function | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnTick() { class=class="str">"cmt">// Convert alarm strings to class="type">class="kw">datetime objects class="type">class="kw">datetime first_Alarm = StringToTime(Alarm1); class="type">class="kw">datetime second_Alarm = StringToTime(Alarm2); class="type">class="kw">datetime third_Alarm = StringToTime(Alarm3); class=class="str">"cmt">// Get current local time class="type">class="kw">datetime Time = TimeLocal(); class=class="str">"cmt">// Check if current time matches any of the alarm times if(first_Alarm == Time || second_Alarm == Time || third_Alarm == Time) { class=class="str">"cmt">// Play sound if any alarm time is reached PlaySound(Sound); } }
「记住这一条就够了」
把复杂语法拆成小项目练手,配合 AI 辅助写伪代码和迭代测试,是摸熟 MQL5 最务实的路径。前面附带的报警 EA 片段里,OnInit 只做一次 StringToTime 转换,比在每个 tick 里重复转三次更省资源。
但这段代码的触发逻辑有硬伤:OnTick 里的 first_Alarm == Time 用等号比对本地时间,tick 到达时刻很难精确命中秒级报警点,漏报概率偏高。真要落地,得改用时间区间判断或 OnTimer 配合状态变量。
外汇与贵金属自带高杠杆风险,任何自动化脚本先在策略测试器跑历史数据,再上模拟盘验证。开 MT5 把上面代码贴进新 EA,改几个报警字符串,你能立刻看到漏触发的现象。
class="kw">input class="type">class="kw">string Alarm1 = "class="num">00:class="num">00:class="num">00"; class=class="str">"cmt">// 第一个警报的默认值 class="kw">input class="type">class="kw">string Alarm2 = "class="num">00:class="num">00:class="num">00"; class=class="str">"cmt">// 第二次警报的默认值 class="kw">input class="type">class="kw">string Alarm3 = "class="num">00:class="num">00:class="num">00"; class=class="str">"cmt">// 第三警报的默认值 class="kw">input class="type">class="kw">string Sound = "alert.wav"; class=class="str">"cmt">// 默认声音文件 class=class="str">"cmt">// 为持久值定义全局项 class="type">class="kw">datetime first_Alarm, second_Alarm, third_Alarm; class="type">int OnInit() { class=class="str">"cmt">// 初始化函数,启动 EA 时执行一次 class=class="str">"cmt">// 每个输入只进行一次转换 first_Alarm = StringToTime(Alarm1); second_Alarm = StringToTime(Alarm2); third_Alarm = StringToTime(Alarm3); class="kw">return class="num">0; class=class="str">"cmt">// 返回 class="num">0 表示初始化成功 } class="type">void OnTick() { class=class="str">"cmt">// 获取当前当地时间 class="type">class="kw">datetime Time = TimeLocal(); class=class="str">"cmt">// 检查当前时间是否与任何警报时间一致 if(first_Alarm == Time || second_Alarm == Time || third_Alarm == Time) class=class="str">"cmt">// 这里还有一个逻辑错误(见下文) { class=class="str">"cmt">// 达到任何闹钟时间时播放声音 PlaySound(Sound); } }