www.eatrader.cn/重要新闻事件脚本(MT5版本_260612_OK).mq5
2026-06-18 08:07:36 +00:00

400 lines
No EOL
16 KiB
MQL5

//+------------------------------------------------------------------+
//| 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);
}
//+------------------------------------------------------------------+