//+------------------------------------------------------------------+ //| ScanAllCalendarEvents.mq5 | //| 用于获取MT5所有财经日历事件ID| //+------------------------------------------------------------------+ #property copyright "www.eatrader.cn" #property link "https://www.eatrader.cn" #property version "1.00" #property description "使用方法:需要把本脚本放到Scripts文件夹下,放开加载,每次加载仅仅执行1次" #property description "存放路径 C:\Users\Administrator\AppData\Roaming\MetaQuotes\Terminal\Common\Files\Common\Files" #property description "主要显示:最重要的数据" #property description "作者:648555129" #property script_show_inputs //--- 输入参数:你可以根据需要修改起始时间 input int 过去n天 = 7; input int 未来n天 = 30; enum countname { us = 0, // 美国 cn = 1, // 中国 eu = 2, // 欧元区 jp = 3, // 日本 gb = 4, // 英国 ca = 5, // 加拿大 au = 6, // 澳大利亚 ch = 7, // 瑞士 nz = 8, // 新西兰 }; input countname 选择国家_单独显示 = us; input bool 显示所有9大主要经济体的最重要的数据 = true; input ENUM_CALENDAR_EVENT_IMPORTANCE 重要性级别_选择=CALENDAR_IMPORTANCE_HIGH; // 日志文件全局句柄 int g_logFileHandle = -1; string g_logFilePath = ""; //+------------------------------------------------------------------+ //| 输出到日志文件和控制台 | //+------------------------------------------------------------------+ void Log(string msg) { // 输出到控制台 Print(msg); // 输出到文件(如果文件已打开) if(g_logFileHandle != INVALID_HANDLE) FileWrite(g_logFileHandle, msg); } //+------------------------------------------------------------------+ //| 生成日志文件名(按日期时间) | //+------------------------------------------------------------------+ string GetLogFileName() { datetime now = TimeLocal(); MqlDateTime dt; TimeToStruct(now, dt); // 格式:CalendarEvents_2026-06-12_14-30-22.txt return StringFormat("CalendarEvents_%04d-%02d-%02d_%02d-%02d-%02d.txt", dt.year, dt.mon, dt.day, dt.hour, dt.min, dt.sec); } //+------------------------------------------------------------------+ //| 打开日志文件 | //+------------------------------------------------------------------+ bool OpenLogFile() { string fileName = GetLogFileName(); // 使用 Common 文件夹(所有终端共享,路径在:C:\Users\用户名\AppData\Roaming\MetaQuotes\Terminal\Common\Files) g_logFilePath = "Common\\Files\\" + fileName; g_logFileHandle = FileOpen(g_logFilePath, FILE_WRITE | FILE_TXT | FILE_COMMON | FILE_ANSI); if(g_logFileHandle == INVALID_HANDLE) { Print("错误:无法创建日志文件 ", g_logFilePath, " 错误码=", GetLastError()); Print("将只输出到控制台,不保存文件。"); return false; } // 写入文件头 Log("======================================================"); Log("MT5 财经日历事件记录 - 生成时间: " + TimeToString(TimeLocal(), TIME_DATE|TIME_MINUTES|TIME_SECONDS)); Log("======================================================"); Log(""); // 打印存放路径方便用户查找 Print("日志文件已保存到 Common 文件夹:", g_logFilePath); Print("你可以通过MT5菜单:文件 -> 打开数据文件夹 -> MQL5 -> Files 找到该文件。"); Print("存放路径:C:\Users\Administrator\AppData\Roaming\MetaQuotes\Terminal\Common\Files\Common\Files"); Print("如需桌面保存,请手动复制该文件到桌面。或创建快捷方式到桌面"); return true; } //+------------------------------------------------------------------+ //| 关闭日志文件 | //+------------------------------------------------------------------+ void CloseLogFile() { if(g_logFileHandle != INVALID_HANDLE) { FileClose(g_logFileHandle); g_logFileHandle = INVALID_HANDLE; } } //+------------------------------------------------------------------+ //| 脚本主函数 | //+------------------------------------------------------------------+ void OnStart() { // 打开日志文件 OpenLogFile(); switch(选择国家_单独显示) { case 0: PrintHighImportanceEvents("US"); break; case 1: PrintHighImportanceEvents("CN"); break; case 2: PrintHighImportanceEvents("EU"); break; case 3: PrintHighImportanceEvents("JP"); break; case 4: PrintHighImportanceEvents("GB"); break; case 5: PrintHighImportanceEvents("CA"); break; case 6: PrintHighImportanceEvents("AU"); break; case 7: PrintHighImportanceEvents("CH"); break; case 8: PrintHighImportanceEvents("NZ"); break; } string countries[] = {"EU", "JP", "CA", "AU", "CN", "US", "GB", "CH", "NZ"}; if(显示所有9大主要经济体的最重要的数据 == true) PrintSortedHighImportanceEvents(countries, true); // 关闭日志文件 CloseLogFile(); } //+------------------------------------------------------------------+ //| 打印指定国家的高重要性经济事件 | //+------------------------------------------------------------------+ void PrintHighImportanceEvents(string countryCode) { if(MQLInfoInteger(MQL_TESTER)) { Log("【错误】财经日历API不能在策略测试器中使用!请将此函数挂载到在线图表上运行。"); return; } datetime now = TimeTradeServer(); datetime from = now - 过去n天 * 86400; datetime to = now + 未来n天 * 86400; string country_chinese_name = ""; if(countryCode == "US") country_chinese_name = "美国"; if(countryCode == "EU") country_chinese_name = "欧盟"; if(countryCode == "JP") country_chinese_name = "日本"; if(countryCode == "GB") country_chinese_name = "英国"; if(countryCode == "AU") country_chinese_name = "澳洲"; if(countryCode == "NZ") country_chinese_name = "新西兰"; if(countryCode == "CN") country_chinese_name = "中国"; if(countryCode == "CA") country_chinese_name = "加拿大"; if(countryCode == "CH") country_chinese_name = "瑞士"; MqlCalendarValue values[]; int total = CalendarValueHistory(values, from, to, countryCode); if(total <= 0) { Log(StringFormat("未获取到 %s 的事件数据。错误码: %d", country_chinese_name, GetLastError())); return; } Log(StringFormat("===== %s 未来一个月(外加过去%d天)高重要性事件 =====", country_chinese_name, 过去n天)); Log("发布时间(服务器)\t\t事件名称\t\t公布值\t\t预期值\t\t上次值"); ulong printedEvents[]; for(int i = 0; i < total; i++) { MqlCalendarValue val = values[i]; MqlCalendarEvent ev; if(!CalendarEventById(val.event_id, ev)) continue; if(ev.importance < 重要性级别_选择) continue; string ev_chinese = (ev.importance == 2) ? "中MID" : ((ev.importance == 3) ? "高HIGH" : ""); bool alreadyPrinted = false; for(int j = 0; j < ArraySize(printedEvents); j++) { if(printedEvents[j] == val.event_id) { alreadyPrinted = true; break; } } if(alreadyPrinted) continue; int newSize = ArraySize(printedEvents); ArrayResize(printedEvents, newSize + 1); printedEvents[newSize] = val.event_id; if(val.time > TimeCurrent()) Log(""); string actual = (val.actual_value != LONG_MIN) ? DoubleToString((double)val.actual_value / 1000000.0, 2) : "未公布/未更新"; string forecast = (val.forecast_value != LONG_MIN) ? DoubleToString((double)val.forecast_value / 1000000.0, 2) : "—"; string previous = (val.prev_value != LONG_MIN) ? DoubleToString((double)val.prev_value / 1000000.0, 2) : "—"; string cmt = ""; if(val.actual_value != LONG_MIN && (double)val.actual_value > (double)val.forecast_value && (double)val.actual_value > (double)val.prev_value) cmt = " >>>>> 实际值大于>预期值,也大于前值,利好 ?利空 ?"; if(val.actual_value != LONG_MIN && (double)val.actual_value < (double)val.forecast_value && (double)val.actual_value < (double)val.prev_value) cmt = " <<<<< 实际值小于<预期值,也小于前值,利好 ?利空 ?"; Log(StringFormat("%s\t\t<%d_%s>\t\t%s :\t\t%s\t\t%s\t\t%s \t\t%s", TimeToString(val.time, TIME_DATE|TIME_MINUTES), ev.importance, ev_chinese, ev.name, actual, forecast, previous, cmt)); } if(ArraySize(printedEvents) == 0) Log(StringFormat("未找到 %s 未来一个月的高重要性事件", country_chinese_name)); else Log(StringFormat("===== 共找到 %d 条高重要性事件 =====", ArraySize(printedEvents))); Log(""); } //+------------------------------------------------------------------+ //| 事件结构体 | //+------------------------------------------------------------------+ struct SEventItem { datetime time; string country; string event_name; double forecast; double actual; double prev; ulong event_id; }; //+------------------------------------------------------------------+ //| 收集指定国家列表的高重要性事件 | //+------------------------------------------------------------------+ int CollectHighImportanceEvents(string &countries[], SEventItem &events[]) { ArrayResize(events, 0); if(MQLInfoInteger(MQL_TESTER)) { Log("【错误】财经日历API不能在策略测试器中使用!"); return 0; } datetime now = TimeTradeServer(); datetime from = now - 过去n天 * 86400; datetime to = now + 未来n天 * 86400; for(int c = 0; c < ArraySize(countries); c++) { string country = countries[c]; MqlCalendarValue values[]; int total = CalendarValueHistory(values, from, to, country); if(total <= 0) { if(GetLastError() != 0) Log(StringFormat("国家 %s 无事件或错误码: %d", country, GetLastError())); continue; } ulong processed_ids[]; for(int i = 0; i < total; i++) { MqlCalendarValue val = values[i]; MqlCalendarEvent ev; if(!CalendarEventById(val.event_id, ev)) continue; if(ev.importance < 重要性级别_选择) continue; bool already = false; for(int j = 0; j < ArraySize(processed_ids); j++) { if(processed_ids[j] == val.event_id) { already = true; break; } } if(already) continue; int sz = ArraySize(processed_ids); ArrayResize(processed_ids, sz + 1); processed_ids[sz] = val.event_id; SEventItem item; item.time = val.time; item.country = country; item.event_name = ev.name; item.event_id = val.event_id; item.forecast = (val.forecast_value != LONG_MIN) ? (double)val.forecast_value / 1000000.0 : -1; item.actual = (val.actual_value != LONG_MIN) ? (double)val.actual_value / 1000000.0 : -1; item.prev = (val.prev_value != LONG_MIN) ? (double)val.prev_value / 1000000.0 : -1; int idx = ArraySize(events); ArrayResize(events, idx + 1); events[idx] = item; } } return ArraySize(events); } //+------------------------------------------------------------------+ //| 排序事件数组 | //+------------------------------------------------------------------+ void SortEventsByTime(SEventItem &events[], bool ascending = true) { int n = ArraySize(events); if(n <= 1) return; for(int i = 0; i < n - 1; i++) { for(int j = 0; j < n - i - 1; j++) { bool needSwap = ascending ? (events[j].time > events[j+1].time) : (events[j].time < events[j+1].time); if(needSwap) { SEventItem temp = events[j]; events[j] = events[j+1]; events[j+1] = temp; } } } } //+------------------------------------------------------------------+ //| 打印并排序高重要性事件 | //+------------------------------------------------------------------+ void PrintSortedHighImportanceEvents(string &countries[], bool ascending = true) { SEventItem events[]; int count = CollectHighImportanceEvents(countries, events); if(count == 0) { Log("未获取到任何高重要性事件。"); return; } SortEventsByTime(events, ascending); Log(StringFormat("===== 主要国家的最高重要性事件列表 (%s) =====", ascending ? "时间升序" : "时间降序")); Log("发布时间(服务器)\t\t\t\t国家\t\t事件名称\t\t\t\t公布值\t\t预期值\t\t上次值"); for(int i = 0; i < count; i++) { string timeStr = TimeToString(events[i].time, TIME_DATE|TIME_MINUTES); string forecastStr = (events[i].forecast != -1) ? DoubleToString(events[i].forecast, 2) : "—"; string actualStr = (events[i].actual != -1) ? DoubleToString(events[i].actual, 2) : "未公布/更新"; string prevStr = (events[i].prev != -1) ? DoubleToString(events[i].prev, 2) : "—"; string cmt = ""; if(events[i].actual != -1 && events[i].actual > events[i].forecast && events[i].actual > events[i].prev) cmt = " >>>>> 实际值大于>预期值,也大于前值,利好 ?利空 ?"; if(events[i].actual != -1 && events[i].actual < events[i].forecast && events[i].actual < events[i].prev) cmt = " <<<<< 实际值小于<预期值,也小于前值,利好 ?利空 ?"; string country_chinese_name = ""; if(events[i].country == "US") country_chinese_name = "美国"; if(events[i].country == "EU") country_chinese_name = "欧盟"; if(events[i].country == "JP") country_chinese_name = "日本"; if(events[i].country == "GB") country_chinese_name = "英国"; if(events[i].country == "AU") country_chinese_name = "澳洲"; if(events[i].country == "NZ") country_chinese_name = "新西兰"; if(events[i].country == "CN") country_chinese_name = "中国"; if(events[i].country == "CA") country_chinese_name = "加拿大"; if(events[i].country == "CH") country_chinese_name = "瑞士"; if(events[i].time > GetTodayDate()) Log(""); Log(StringFormat("%s\t\t%s\t\t%s\t\t : %s\t\t%s\t\t%s \t\t%s", timeStr, events[i].country + country_chinese_name, events[i].event_name, actualStr, forecastStr, prevStr, cmt)); } Log(StringFormat("===== 共 %d 条事件 =====", count)); } //+------------------------------------------------------------------+ //| 获取今日起始时间 | //+------------------------------------------------------------------+ datetime GetTodayDate() { datetime now = TimeCurrent(); MqlDateTime dt; TimeToStruct(now, dt); dt.hour = 0; dt.min = 0; dt.sec = 0; return StructToTime(dt); } //+------------------------------------------------------------------+