MQL5 酷宝书 宏观经济事件数据库·综合运用
(3/3)· 26 个原生函数配上自写 CDatabase 类,外汇贵金属事件流终于不再散落一地
- 从国家序号看 EURUSD 关联市场的排序逻辑
- 分组统计与去重查询的输出差异
- 去重查询里大洲与币种的排列差异
- 从货币清单反推查询函数的输出结构
- 从查询回显看数据集的字段结构
- 国家维度表在 EURUSD 回测里的实际落库
- 正文
- Replace 漏了非空约束字段就报错
- CSV 调试输出里能直接看到的国别映射
- 用 SQL 把洲际国家表拆成两张子集
- 用 CREATE TABLE AS 切出欧系国家子集
- 用 SQL 视图裁剪货币属性表
- 把宏观事件拆成三张关系表
- 日历库的三表关联与查询实战
- 把财经日历国家列表落库的实现片段
- 用 GROUP BY 数出各国事件密度
- 用子查询和CTE给国家归并事件数
- 正文
- 按国家统计事件与高影响事件的分布
- 用 SQL 把财经事件按国家拆开看
- 按国家聚合财经事件命中率
- 用 EXCEPT 揪出零事件国家
- 用 SQL 反查无事件国与 GDP 季环比覆盖
- 用子查询拉取指定周期的GDP数据
- EURUSD-H1 请求样本与事件值提取
- 抓取二季度 GDP 季环比的跨市场快照
- 把 GDP 季率事件拼回国家名
- 跨市场新闻冲击在 EURUSD H1 上的区域分化
- 画得少,看得清
「从国家序号看 EURUSD 关联市场的排序逻辑」
上面这组输出来自一个按数字序号排布的查询函数,标的锁定 EURUSD 的 H1 周期,函数名里带 _select_some_sorted_columns,说明它只挑了部分列做排序展示。 行首的序号 9 到 23 并不是随机值,而是 ISO 3166 国家数字码:印度 356、意大利 380、日本 392、韩国 410、墨西哥 484、新西兰 554、挪威 578、新加坡 702、南非 710、西班牙 724、瑞典 752、瑞士 756、英国 826、美国 840、欧盟 999。同一大洲的条目在排序里是聚拢的,亚洲从 356 排到 702,欧洲从 380 一直拉到 999。 如果你在 MT5 里跑同类脚本,可以直接拿这些数字码去校验自己数据库里的 country 表有没有漏行。外汇和贵金属杠杆高,这类关联市场排序只帮你定位数据,不预示任何汇率方向,EURUSD 的波动仍可能受流动性突变冲击。
◍ 分组统计与去重查询的输出差异
在 MT5 用 CDatabase::SelectFromGroupBy() 跑 EURUSD H1 时,按 CONTINENT 分组会得到 7 行聚合结果:欧洲 9 条、亚洲 6 条、北美 3 条、大洋洲 2 条,非洲/南美/全球各 1 条。这反映样本货币所属经济体的分布偏态,欧洲系货币对出现频率明显最高。 紧接着的 DISTINCT 查询列出 19 个不重复货币代码:从 NZD、EUR 到 ALL(阿尔巴尼亚列克),说明底层表 NAME 字段覆盖了主要 G10 与部分新兴市场币种。 两者对照看,分组计数告诉你「每类有多少」,去重告诉你「有哪些类」。实盘前建议在 MT5 终端打开对应脚本,把 H1 换成你想验证的周期,看分组行数会不会因数据窗口长度而变。外汇与贵金属波动剧烈,这类统计只描述历史样本结构,不代表后续走势概率。
去重查询里大洲与币种的排列差异
在 MT5 用 CDatabase 做跨时段统计时,SelectDistinctFrom() 对 CONTINENT 字段去重返回 7 行:Australia/Oceania、Europe、Asia、North America、South America、Africa、World,顺序与未分组全量列出的 7 个大洲并不一致,后者按 Africa、Asia、Australia/Oceania、Europe、North America、South America、World 排。 紧接的按币种去重排序(_select_sorted_distinct_columns)在 EURUSD,H1 上吐出 14 种 CURRENCY:ALL、AUD、BRL、CAD、CNY、EUR、HKD、INR、JPY、KRW、MXN、NZD、NOK、SGD,编号 1 到 14。 这种顺序错位说明底层查询返回的是去重后的逻辑集合,不是原表物理行序;写回测或因子库时若直接按行号映射大洲含义会踩坑。外汇与贵金属属高风险品种,任何统计结论都只是概率倾向,开 MT5 跑一遍上述两个方法就能验证你本地数据是否同序。
「从货币清单反推查询函数的输出结构」
在 EURUSD,H1 图表上跑排序去重查询,终端会先吐出第 15~19 行:ZAR、SEK、CHF、GBP、USD。这五条是 distinct 后的货币代码,顺序由排序规则决定,并非按字母或体量排列。 紧接着的带 where 条件查询,输出 11 行国家维度记录。字段依次是 COUNTRY_ID、NAME、CODE、CONTINENT、CURRENCY,例如 392 Japan JP Asia JPY、710 South Africa ZA Africa ZAR、756 Switzerland CH Europe CHF。 这类输出说明:查询函数把底层表当关系型数据扫,EURUSD 品种名只是命名空间前缀,不影响返回列的逻辑。 开 MT5 把同样的查询挂到 XAUUSD,H1 上,若返回行数或货币集合不同,就能确认数据表是按品种分区的。外汇与贵金属杠杆交易高风险,验证结果仅作策略参考,不预示任何方向。
◍ 从查询回显看数据集的字段结构
在 MT5 终端跑出的一组诊断回显里,两条 SQL 风格查询揭示了底层数据表的实际列布局。第一条 _select_some_columns_where 只捞回 12 行、840 对应的 United States 单条,说明 where 过滤在 H1 周期数据集上直接生效。
第二条 _select_some_sorted_columns_where 按 COUNTRY_ID 升序返回了 12 个国家:从 710 南非到 840 美国,覆盖非洲、亚洲、欧洲、北美、大洋洲。注意排序键不是名称而是数字 ID,日本 392 排第 2、西班牙 724 排第 7,这种隐式主键在写 EA 读取国别表时不能想当然按字母序处理。
第三条 _update_some_columns 的表头比前两条多了 CURRENCY_SYMBOL 和 URL_NAME 两列,意味着更新操作会回填符号与链接字段。外汇与贵金属交易依托这类基础表做国别映射时波动剧烈、风险偏高,建议直接开 MT5 调出同结构诊断脚本核对自己的环境字段数是否一致。
国家维度表在 EURUSD 回测里的实际落库
跑 _update_some_columns 时把 EURUSD 的 H1 数据按国家维度补全,日志里直接吐出 11 行记录。每行左侧的序号是行号,紧跟的数字是内部 country_id,后面依次是国家名、ISO 代码、所在洲、货币代码、符号和 slug。
留意几个硬数据:欧盟 country_id=999 挂 EUR/€,新西兰 554 用 NZD/$,日本 392 的货币与符号字段是 None,中国 156 同样 None,而巴西 76 是 BRL/R$。这说明维度表对无独立外汇符号的经济体留了空位,后续做洲际波动率归类时得自己补映射。
外汇和贵金属本身杠杆高、滑点跳空频繁,这类维度补齐只是给 AIGC 特征工程打底,不代表任何方向判断。开 MT5 把这段日志跑出来,核对你本地 country_id 是否和上面一致,不一致就说明维度源被改过。
「正文」
<span class="number">12</span>_update_some_columns (EURUSD,H1) <span class="number">12</span>| <span class="number">484</span> Mexico MX North America MXN Mex$ mexico <span class="number">12</span>_update_some_columns (EURUSD,H1) <span class="number">13</span>| <span class="number">710</span> South Africa ZA Africa ZAR R south-africa <span class="number">12</span>_update_some_columns (EURUSD,H1) <span class="number">14</span>| <span class="number">344</span> Hong Kong HK Asia None None hong-kong <span class="number">12</spa
◍ Replace 漏了非空约束字段就报错
在 MT5 用 CDatabase::Replace 改表时,若只传部分列名,数据库会按 NOT NULL 约束校验整行。上面那段只给 NAME 和 CURRENCY_SYMBOL 两列赋值的写法,直接触发了 COUNTRIES.COUNTRY_ID 的非空约束失败,错误码 5619,Replace 调用返回 false。
日志里 11_replace_some_rows 打印出 database error, NOT NULL constraint failed: COUNTRIES.COUNTRY_ID,说明 Mexico 这一行缺了主键 COUNTRY_ID 就无法落库。外汇与贵金属相关的数据表操作同样面临这类底层约束风险,MT5 数据库报错不会自动回滚,需自行 Close 后处理。
修正办法是把整行非空字段都填全:下面代码补齐 COUNTRY_ID(484)、CODE('MX')、CONTINENT('North America')、CURRENCY('MXN')、URL_NAME('mexico') 等 7 个字段,Replace 才成功。替换前后日志对比可见,CURRENCY_SYMBOL 由 Mex$ 变成了 Peso mexicano,其余列保持不变。
开 MT5 跑这段时,先确认表结构里哪些列标了 NOT NULL,否则少传一个就白忙。
class="type">class="kw">string col_names[]= { "COUNTRY_ID", "NAME", "CODE", "CONTINENT", "CURRENCY", "CURRENCY_SYMBOL", "URL_NAME" }; class="type">class="kw">string col_vals[class="num">7]; col_vals[class="num">0]=::StringFormat("%I64u", class="num">484); col_vals[class="num">1]=::StringFormat("&class="macro">#x27;%s&class="macro">#x27;", "Mexico"); col_vals[class="num">2]=::StringFormat("&class="macro">#x27;%s&class="macro">#x27;", "MX"); col_vals[class="num">3]=::StringFormat("&class="macro">#x27;%s&class="macro">#x27;", "North America"); col_vals[class="num">4]=::StringFormat("&class="macro">#x27;%s&class="macro">#x27;", "MXN"); col_vals[class="num">5]=::StringFormat("&class="macro">#x27;%s&class="macro">#x27;", "Peso mexicano"); col_vals[class="num">6]=::StringFormat("&class="macro">#x27;%s&class="macro">#x27;", "mexico"); if(!db_obj.Replace(col_names, col_vals)) { db_obj.Close(); class="kw">return; }
CSV 调试输出里能直接看到的国别映射
在 MT5 用自定义脚本跑 _delete_some_rows 这类数据清洗函数时,终端里打印的调试行会带出原始 CSV 的整行内容。上面这段 EURUSD,H1 下的 12 行输出,就是典型的国别基础表:每行第一列是内部序号,第二列是 ISO 数字码,后面依次跟国家名、双字母代码、所在洲、货币码、货币符号和 slug。
注意数字码和货币并不总是一一对应。比如序号 2 的 European Union 用 999 这个非真实 ISO 码占位,货币是 EUR;序号 5/6/7 的意大利、德国、法国数字码分别是 380、276、250,但货币同为 EUR。做跨市场宏观相关性脚本时,若按数字码硬切货币组,可能把欧盟聚合实体和成员国重复计入。
外汇与贵金属交易本身高风险,这类基础表只是给 AIGC 辅助筛选基本面因子用。开 MT5 按 F4 编译一段读 CSV 的脚本,把 Print 行原样丢进专家日志,就能复现上面这 12 行,核对你的映射表有没有漏掉挪威(578/NOK)或南非(710/ZAR)这类非美系流动性来源。
「用 SQL 把洲际国家表拆成两张子集」
在 MT5 的 MQL5 数据库对象里,可以先从 COUNTRIES 总表按洲筛选,把数据落进两张物理表。上面日志里能看到,原始表含 Switzerland(CHF)、Spain(EUR)、Sweden(SEK) 等欧洲条目,以及 Mexico(MXN) 等北美条目,国家 ID 从 724 到 756 不等。 下面这段代码干了两件事:建 NORTH_AMERICAN_COUNTRIES 和 EUROPEAN_COUNTRIES。CreateTableAs 的第三个参数传 true,表示表已存在就覆盖,避免重复跑脚本报错。 跑完后在专家日志里调 _union_some_columns,能看到子集已生效:Canada(124/CAD)、France(250/EUR)、Germany(276/EUR)、Italy(380/EUR)、Mexico(484/MXN) 被干净地分到两个洲的表里。外汇贵金属品种关联这类基础数据时,注意宏观事件对不同洲货币影响路径不同,杠杆交易高风险,别把洲际分类当方向信号直接用。
class=class="str">"cmt">//--- create class="num">2 tables class="type">class="kw">string table1_name, table2_name, sql_request; table1_name="EUROPEAN_COUNTRIES"; table2_name="NORTH_AMERICAN_COUNTRIES"; sql_request="SELECT COUNTRY_ID AS id, NAME AS name, CURRENCY " "as currency FROM COUNTRIES " "WHERE CONTINENT=&class="macro">#x27;North America&class="macro">#x27;"; if(!db_obj.CreateTableAs(table2_name, sql_request, true)) { db_obj.Close(); class="kw">return; } db_obj.FinalizeSqlRequest(); sql_request="SELECT COUNTRY_ID AS id, NAME AS name, CURRENCY " "as currency FROM COUNTRIES " "WHERE CONTINENT=&class="macro">#x27;Europe&class="macro">#x27;"; if(!db_obj.CreateTableAs(table1_name, sql_request, true)) { db_obj.Close(); class="kw">return; } db_obj.FinalizeSqlRequest();
◍ 用 CREATE TABLE AS 切出欧系国家子集
在 MT5 的 SQL 引擎里跑 16_union_some_columns 时,输出第 6~12 行给出的是 COUNTRY_ID 从 578(挪威)到 999(欧盟)的记录,说明 WHERE 过滤落在了北欧与西欧经济体上;而 18_except_some_columns 的反选结果只保留澳、巴、加、墨、新西兰、南非与美,欧元区和瑞郎、英镑被剔除。
临时表的做法很直接:把 COUNTRIES 里 COUNTRY_ID<=578 的行用 CREATE TABLE AS 落盘成 Table1,字段重命名为 id / name / currency。下面这段代码就是实际建表与打印的动作,复制进 EA 的 OnStart 就能在 Experts 日志看到 Table1 的内容。
外汇与贵金属交易涉及高杠杆高风险,这类数据库操作仅用于本地品种属性管理,不预示任何价格方向。
建完表别忘 FinalizeSqlRequest,否则后续 SELECT 会挂在未释放的句柄上;这是很多人第一次跑 MQL5 SQLite 封装时踩的坑。
class=class="str">"cmt">//--- create temporary tables class="type">class="kw">string table1_name, table2_name, sql_request; table1_name="Table1"; table2_name="Table2"; sql_request="SELECT COUNTRY_ID AS id, NAME AS name, CURRENCY " "as currency FROM COUNTRIES " "WHERE COUNTRY_ID<=class="num">578"; if(!db_obj.CreateTableAs(table1_name, sql_request, true, true)) { db_obj.Close(); class="kw">return; } db_obj.FinalizeSqlRequest(); class=class="str">"cmt">//--- print the temporary table class="type">class="kw">string temp_col_names[]= {"*"}; if(db_obj.SelectTable(table1_name, true)) if(db_obj.SelectFrom(temp_col_names)) { ::Print(" \nTable #class="num">1: "); db_obj.PrintSqlRequest(); db_obj.FinalizeSqlRequest(); } sql_request="SELECT COUNTRY_ID AS id, NAME AS name, CURRENCY "
用 SQL 视图裁剪货币属性表
在 MT5 的 CDatabase 环境里,可以把国家维度表按 COUNTRY_ID 阈值切成临时结果集。下面这段把 COUNTRY_ID>=392 的经济体捞出来建表,跑完能在日志里看到 5 行记录:日本(392/JPY)、韩国(410/KRW)、墨西哥(484/MXN)、新西兰(554/NZD)、挪威(578/NOK)。 建表后若直接 SelectTable + SelectFrom 打印,终端会原样吐出表头和行;这一步常用来肉眼核对交集字段有没有截错。外汇与贵金属品种受宏观消息冲击大,这类映射表只解决数据准备,不预示任何价格波动方向。 删视图时有个坑:第一次循环 if_exists=0 试图 DropView("European1"),因为视图不存在直接报 5601 错误;第二次 if_exists=1 对 European2 走「存在才删」,日志才打成功。用 idx 控制 if_exists 是避免脚本中断的实用写法。
class="type">class="kw">string sql_request="SELECT name, currency FROM COUNTRIES " "WHERE COUNTRY_ID>=class="num">392"; if(!db_obj.CreateTableAs(table2_name, sql_request, true, true)) { db_obj.Close(); class="kw">return; } db_obj.FinalizeSqlRequest(); class=class="str">"cmt">//--- print the temporary table if(db_obj.SelectTable(table2_name, true)) if(db_obj.SelectFrom(temp_col_names)) { ::Print(" \nTable #class="num">2: "); db_obj.PrintSqlRequest(); db_obj.FinalizeSqlRequest(); } class=class="str">"cmt">//--- drop a view class="type">class="kw">string table_name="COUNTRIES"; if(db_obj.SelectTable(table_name)) for(class="type">int idx=class="num">0; idx<class="num">2; idx++) { class="type">class="kw">string view_name=::StringFormat("European%d", idx+class="num">1); class="type">bool if_exists=idx; if(db_obj.DropView(view_name, if_exists)) ::PrintFormat("A view \"%s\" has been successfully dropped!", view_name); db_obj.FinalizeSqlRequest(); }
「把宏观事件拆成三张关系表」
做价格行为分析时,宏观事件往往是跳空和瞬时波动的触发点。想在 MT5 里用程序筛事件,第一步不是抓数据,而是先把结构定清楚。 这里建议直接建一个关系库,源表只留三张:COUNTRIES 存国家主体,EVENTS 存事件元数据,EVENT_VALUES 存每次发布的实际值、预期值和前值。三表通过外键关联,事件归国家、数值挂事件,查询时按国家+事件类型拉历史就很干净。 MQL5 酷宝书里讲过财经日历的字段结构,照着那套字段映射过来建表成本很低。图例 10 展示的关联方式就是 EVENTS.country_id → COUNTRIES.id、EVENT_VALUES.event_id → EVENTS.id,没有多余中间表。 实盘接这套库时记住:外汇和贵金属对非农、CPI 类事件反应剧烈,属于高风险品种,事件驱动的滑点和点差扩张可能吞掉策略优势,先用历史表回测再上实盘。
◍ 日历库的三表关联与查询实战
COUNTRIES 是 EVENTS 的父表,EVENTS 又是 EVENT_VALUES 的父表,三者靠主键外键串成一对多(1..*)结构。COUNTRIES 主键为 COUNTRY_ID(带“+”标记),EVENTS 主键 EVENT_ID、外键 COUNTRY_ID(带“#”标记),EVENT_VALUES 主键 VALUE_ID、外键 EVENT_ID。这种键约束不是为了好看,是来保证库里宏观数据不出现孤儿记录。 建 EVENTS 表时,外键段写法是硬约束点:FOREIGN KEY (COUNTRY_ID) REFERENCES COUNTRIES(COUNTRY_ID) 把子表国家字段锁死到父表;ON UPDATE CASCADE / ON DELETE CASCADE 意味着父表改或删一国,子表相关事件自动跟着动。下面这段建表 SQL 可直接丢进 MT5 脚本验证。 [CODE] CREATE TABLE IF NOT EXISTS EVENTS ( EVENT_ID [UNSIGNED BIG INT] PRIMARY KEY NOT NULL, TYPE TEXT, SECTOR TEXT, FREQUENCY TEXT, TIME_MODE TEXT, COUNTRY_ID [UNSIGNED BIG INT] NOT NULL, UNIT TEXT, IMPORTANCE TEXT, MULTIPLIER TEXT, DIGITS [UNSIGNED INT], SOURCE TEXT, CODE TEXT, NAME TEXT, FOREIGN KEY (COUNTRY_ID) REFERENCES COUNTRIES (COUNTRY_ID) ON UPDATE CASCADE ON DELETE CASCADE ) //--- Table 1 MqlCalendarCountry calendar_countries[]; table_name="COUNTRIES"; if(db_obj.SelectTable(table_name)) if(db_obj.EmptyTable()) { db_obj.FinalizeSqlRequest(); string col_names[]= { "COUNTRY_ID", // 1 "NAME", // 2 填表阶段也有套路:SelectTable 类似持仓函数 PositionSelect,先选中才能操作;EmptyTable 清掉旧数据,再循环塞入 COUNTRY_ID、COUNTRY_NAME、CURRENCY 等列,每行用 InsertSingleRow 落库。整批写入包在 DatabaseTransactionBegin/Commit 里,避免半截中断。 跑完脚本得到实打实的数字:COUNTRIES 23 行、EVENTS 1500 行、EVENT_VALUES 158696 行。拿 EVENTS 做按国统计,美国事件 247 个排第一;重要事件(IMPORTANCE='High')美国 20、英国 13、欧盟 11、日本 7,意大利和西班牙为 0。 复合查询能少写重复代码。比如 GDP 季度值取样,先筛出 21 国有 q/q 指标(印度不用全球值),再 JOIN 事件 ID,未分组时 EU 因多读数出现 2-4 条重复,取样 36 行;改成分组取 value_id 最大的一条后,只剩 21 行。外汇与贵金属受宏观事件驱动明显,这类数据完整性直接影响信号质量,实操前请在 MT5 用样本库自测关联逻辑。
CREATE TABLE IF NOT EXISTS EVENTS( EVENT_ID [UNSIGNED BIG INT] PRIMARY KEY NOT NULL, TYPE TEXT, SECTOR TEXT, FREQUENCY TEXT, TIME_MODE TEXT, COUNTRY_ID [UNSIGNED BIG INT] NOT NULL, UNIT TEXT, IMPORTANCE TEXT, MULTIPLIER TEXT, DIGITS [UNSIGNED INT], SOURCE TEXT, CODE TEXT, NAME TEXT, FOREIGN KEY(COUNTRY_ID) REFERENCES COUNTRIES(COUNTRY_ID) ON UPDATE CASCADE ON DELETE CASCADE ) class=class="str">"cmt">//--- Table class="num">1 MqlCalendarCountry calendar_countries[]; table_name="COUNTRIES"; if(db_obj.SelectTable(table_name)) if(db_obj.EmptyTable()) { db_obj.FinalizeSqlRequest(); class="type">class="kw">string col_names[]= { "COUNTRY_ID", class=class="str">"cmt">// class="num">1 "NAME", class=class="str">"cmt">// class="num">2
把财经日历国家列表落库的实现片段
这段逻辑负责把 MT5 内置财经日历里的国家元数据写进本地数据库,字段对齐 7 列:id、name、code、continent、currency、currency_symbol、url_name。 先通过 CiCalendarInfo 初始化并调用 GetCountries 拿到 MqlCalendarCountry 数组,再用 db_obj.TransactionBegin() 开事务,遍历 ArraySize(calendar_countries) 个国家逐行拼 col_vals。 continent 字段默认写 NULL,只有当 SCountryByContinent 对该国 code 初始化成功,才用 ContinentDescription() 覆盖;其余货币、符号、url 直接取自结构体字符串。 任意一行 InsertSingleRow 失败就 TransactionRollback 并 Close 退出,避免半量写入。外汇与贵金属受宏观数据扰动大、杠杆风险高,这类日历落库仅用于本地筛选,不代表任何方向判断。
"CODE", class=class="str">"cmt">// class="num">3 "CONTINENT", class=class="str">"cmt">// class="num">4 "CURRENCY", class=class="str">"cmt">// class="num">5 "CURRENCY_SYMBOL", class=class="str">"cmt">// class="num">6 "URL_NAME" class=class="str">"cmt">// class="num">7 }; CiCalendarInfo calendar_info; if(calendar_info.Init()) { if(calendar_info.GetCountries(calendar_countries)) { if(db_obj.TransactionBegin()) for(class="type">int c_idx=class="num">0; c_idx<::ArraySize(calendar_countries); c_idx++) { MqlCalendarCountry curr_country=calendar_countries[c_idx]; class="type">class="kw">string col_vals[]; ::ArrayResize(col_vals, class="num">7); col_vals[class="num">0]=::StringFormat("%I64u", curr_country.id); col_vals[class="num">1]=::StringFormat("&class="macro">#x27;%s&class="macro">#x27;", curr_country.name); col_vals[class="num">2]=::StringFormat("&class="macro">#x27;%s&class="macro">#x27;", curr_country.code); col_vals[class="num">3]="NULL"; SCountryByContinent curr_country_continent_data; if(curr_country_continent_data.Init(curr_country.code)) col_vals[class="num">3]=::StringFormat("&class="macro">#x27;%s&class="macro">#x27;", curr_country_continent_data.ContinentDescription()); col_vals[class="num">4]=::StringFormat("&class="macro">#x27;%s&class="macro">#x27;", curr_country.currency); col_vals[class="num">5]=::StringFormat("&class="macro">#x27;%s&class="macro">#x27;", curr_country.currency_symbol); col_vals[class="num">6]=::StringFormat("&class="macro">#x27;%s&class="macro">#x27;", curr_country.url_name); if(!db_obj.InsertSingleRow(col_names, col_vals)) { db_obj.TransactionRollback(); db_obj.Close(); class="kw">return; } db_obj.FinalizeSqlRequest();
「用 GROUP BY 数出各国事件密度」
在 MT5 里用 CDatabase 做宏观事件统计时,最实用的落点是按国家维度聚合事件数。下面这段逻辑先指定表名 EVENTS,再声明要选取的两列:COUNTRY_ID 起别名为 id,COUNT(EVENT_ID) 起别名为 events_num,分组键只放 COUNTRY_ID。 代码通过 SelectFromGroupBy 下发 GROUP BY 查询,若返回失败直接 Close 并 return,避免脏句柄残留;随后 PrintSqlRequest 把实际 SQL 打到日志,方便你核对 MT5 终端里跑的到底是不是预期语句。 实际在 EURUSD,H1 品种上跑出来的样本显示:id=2 的国家累计 36 条事件、events_num 85;id=11 高达 events_num 124,是密度峰值;而 id=1 仅有 7 条。外汇与贵金属受宏观事件驱动明显,此类聚合仅作概率参考,实盘仍属高风险。 你在策略里若想过滤低样本国家,可直接在 gr_names 之外加 HAVING events_num>20 之类的条件,MT5 内置 SQLite 语法都支持。
class="type">class="kw">string table_name="EVENTS"; if(db_obj.SelectTable(table_name)) { class="type">class="kw">string col_names_to_select[]= { "COUNTRY_ID AS id", "COUNT(EVENT_ID) AS events_num" }; class="type">class="kw">string gr_names[]= { "COUNTRY_ID" }; if(!db_obj.SelectFromGroupBy(col_names_to_select, gr_names)) { db_obj.Close(); class="kw">return; } class=class="str">"cmt">//--- print the SQL request if(db_obj.PrintSqlRequest()<class="num">0) ::PrintFormat("Failed to print the SQL request, error %d", ::GetLastError()); db_obj.FinalizeSqlRequest();
◍ 用子查询和CTE给国家归并事件数
在 MT5 的 SQL 数据库接口里,把 EVENTS 表按 COUNTRY_ID 聚合后再和 COUNTRIES 做连接,有两种常见写法:派生表(子查询)与 CTE(WITH 子句)。上面 EURUSD,H1 的调试输出里能看到 sRequest1 在 18~23 根 K 线处分别打出 724/752/756/826/840/999 的基准值,以及 39/59/40/115/247/82 的附属计数,说明这类请求在回测打印时会产生明确的分段数据。 子查询写法先把 COUNT(EVENT_ID) GROUP BY COUNTRY_ID 塞进 JOIN 的括号里,起别名为 ev,再用 c.COUNTRY_ID = ev.id 关联国家名。CTE 写法则用 WITH ev_cnt AS (...) 把同一段聚合逻辑提出来,后续 SELECT 直接 INNER JOIN ev_cnt,可读性倾向更好。 下面这段 MQL5 展示了两种请求是怎么拼出来并执行的:先拿 db_obj.SqlRequest() 取子查询文本,用 StringFormat 拼成完整 SQL,再 Select 执行并打印。外汇与贵金属相关的数据库回测涉及杠杆与滑点,属于高风险操作,结果只代表历史数据聚合,不预示未来。
class=class="str">"cmt">//--- class="num">2) group events number by country name class="kw">using a subquery ::Print("\nGroup events number by country name class="kw">using a subquery:\n"); class="type">class="kw">string subquery=db_obj.SqlRequest(); class="type">class="kw">string new_sql_request=::StringFormat("SELECT c.NAME AS country," "ev.events_num AS events_number FROM COUNTRIES c " "JOIN(%s) AS ev " "ON c.COUNTRY_ID=ev.id", subquery); if(!db_obj.Select(new_sql_request)) { db_obj.Close(); class="kw">return; } class=class="str">"cmt">//--- print the SQL request if(db_obj.PrintSqlRequest()<class="num">0) ::PrintFormat("Failed to print the SQL request, error %d", ::GetLastError()); db_obj.FinalizeSqlRequest(); class=class="str">"cmt">//--- class="num">3) group events number by country name class="kw">using CTE ::Print("\nGroup events number by country name class="kw">using CTE:\n"); new_sql_request=::StringFormat("WITH ev_cnt AS(%s)" "SELECT c.NAME AS country," "ev.events_num AS events_number FROM COUNTRIES c " "INNER JOIN ev_cnt AS ev ON c.COUNTRY_ID=ev.id", subquery); if(!db_obj.Select(new_sql_request)) { db_obj.Close(); class="kw">return; } class=class="str">"cmt">//--- print the SQL request if(db_obj.PrintSqlRequest()<class="num">0) ::PrintFormat("Failed to print the SQL request, error %d", ::GetLastError()); db_obj.FinalizeSqlRequest();
正文
sRequest1 (EURUSD,H1) <span class="number">1</span>| Worldwide <span class="number">7</span> sRequest1 (EURUSD,H1) <span class="number">2</span>| Australia <span class="number">85</span> sRequest1 (EURUSD,H1) <span class="number">3</span>| Brazil <span class="number">55</span> sRequest1 (EURUSD,H1) <span class="number">4</span>| Canada <span class="number">74</span> sRequest1 (EURUSD,H1) <span class="number">5</span>| China <span class="number">40</span> sRequest1 (EURUSD,H1) <span class="number">6</span>| France <span class="number">43</span> sRequest1 (EURUSD,H1) <span class="number">7</span>| Germany &
「按国家统计事件与高影响事件的分布」
在 MT5 里做宏观事件量化时,常需要把原始事件表按国家聚合,看清哪些经济体贡献了高频数据、哪些又集中释放高影响事件。下面这段 SQL 拼接逻辑就是干这个的:先用子查询拿到高影响事件子集,再 JOIN 主表做 GROUP BY。 代码里 subquery 是前面已构建好的高影响事件筛选 SQL,StringFormat 把它嵌进主查询,按 COUNTRY_ID 分组输出 events_num(总事件数)与 imp_events_num(高影响事件数)。若 Select 执行失败直接关库返回,避免后续空指针。 实际在 EURUSD H1 上跑出来的样本里,id=10 的国家总事件 392、高影响 7;id=4 总事件 124、高影响 10,高影响占比明显更陡。这种分布差异,可能提示你某些货币对的跳空风险集中在少数经济体发布日。 外汇与贵金属受事件冲击的高波动特性意味着,这类统计只帮你定位风险窗口,不等于方向判断,实操仍需结合价格行为确认。
subquery=db_obj.SqlRequest(); class="type">class="kw">string new_sql_request4=::StringFormat("SELECT ev.COUNTRY_ID AS id, COUNT(EVENT_ID) AS events_num," "imp.high AS imp_events_num " "FROM EVENTS ev JOIN(%s) AS imp " "ON ev.COUNTRY_ID=imp.id GROUP BY COUNTRY_ID", subquery); if(!db_obj.Select(new_sql_request4)) { db_obj.Close(); class="kw">return; } class=class="str">"cmt">//--- print the SQL request if(db_obj.PrintSqlRequest()<class="num">0) ::PrintFormat("Failed to print the SQL request, error %d", ::GetLastError()); db_obj.FinalizeSqlRequest();
◍ 用 SQL 把财经事件按国家拆开看
上面那几行 sRequest1 的输出是 EURUSD H1 周期下,14 到 21 点(小时桶)的请求统计:第 19 小时总请求 826、重要请求 13,第 20 小时总请求 840、重要请求 20,说明晚间美盘重叠段的新闻敏感度明显跳升。这类原始计数只是引子,真要横向比各国事件密度,得直接查内置经济日历库。 下面这段 SQL 做了三件事:先按 COUNTRY_ID 聚合出每国事件总数,再嵌套子查询算出各国 High 重要性事件数,最后用 COUNTRIES 表做 JOIN 并按重要事件数降序排列。你在 MT5 的数据库对象里跑它,能直接拿到“哪国央行/数据最该盯”的排序表。 MQL5 侧用 SqlRequest() 取回结果,StringFormat 拼出 new_sql_request5 字符串,Print 打头注释标明这是第 6 类查询:分组统计各国事件数与重要事件数。外汇和贵金属受此类宏观事件驱动明显,杠杆品种波动可能瞬间放大,验证前先开模拟盘跑一遍。
SELECT c.NAME AS country,
ev.events_num AS events_number,
ev.imp_events_num AS imp_events_number
FROM COUNTRIES c
JOIN(
SELECT ev.COUNTRY_ID AS id,
COUNT(EVENT_ID) AS events_num,
imp.high AS imp_events_num
FROM EVENTS ev
JOIN(
SELECT COUNTRY_ID AS id,
COUNT(IMPORTANCE) AS high
FROM EVENTS
WHERE IMPORTANCE = &class="macro">#x27;High&class="macro">#x27;
GROUP BY COUNTRY_ID
)
AS imp ON ev.COUNTRY_ID = imp.id
GROUP BY COUNTRY_ID
)
AS ev ON c.COUNTRY_ID = ev.id
ORDER BY imp_events_number DESC
class=class="str">"cmt">//--- class="num">6) important events - countries, events number and important events number
::Print("\nGroup events number and important events number by country:\n");
subquery=db_obj.SqlRequest();
class="type">class="kw">string new_sql_request5=::StringFormat("SELECT c.NAME AS country,"
"ev.events_num AS events_number,"
"ev.imp_events_num AS imp_events_number "
"FROM COUNTRIES c "按国家聚合财经事件命中率
在 MT5 里用 CDatabase 跑 SQL 子查询,可以把某品种周期下的新闻事件按国家分组,并统计总事件数与重要事件数。下面这段拼接逻辑先把子查询结果 JOIN 到国家表,再按重要事件数倒序排,方便一眼看出哪些经济体对 EURUSD 的 H1 波动贡献最大。
[CODE]
"JOIN(%s) AS ev "
"ON c.COUNTRY_ID=ev.id "
"ORDER BY imp_events_number DESC", subquery);
if(!db_obj.Select(new_sql_request5))
{
db_obj.Close();
return;
}
//--- print the SQL request
if(db_obj.PrintSqlRequest()<0)
::PrintFormat("Failed to print the SQL request, error %d", ::GetLastError());
db_obj.FinalizeSqlRequest();
[/CODE]
代码逐行拆解:前 three 行字符串拼出 JOIN 与 ORDER BY,把子查询别名 ev 按国家 ID 关联,并以 imp_events_number 降序;if(!db_obj.Select(...)) 执行失败就关库返回;PrintSqlRequest() 小于 0 时打印错误码;最后 FinalizeSqlRequest() 释放语句句柄。
实际在 EURUSD H1 上跑出来的前排结果是:美国总事件 247、重要 20;英国 115/13;欧盟 82/11;加拿大 74/10。外汇与贵金属受宏观事件驱动明显,这类统计只说明历史分布,不代表未来波动概率,实盘仍需控仓。
"JOIN(%s) AS ev " "ON c.COUNTRY_ID=ev.id " "ORDER BY imp_events_number DESC", subquery); if(!db_obj.Select(new_sql_request5)) { db_obj.Close(); class="kw">return; } class=class="str">"cmt">//--- print the SQL request if(db_obj.PrintSqlRequest()<class="num">0) ::PrintFormat("Failed to print the SQL request, error %d", ::GetLastError()); db_obj.FinalizeSqlRequest();
「用 EXCEPT 揪出零事件国家」
上面那串 sRequest1 输出是 EURUSD H1 周期下,部分国家宏观事件数的快照:印度 57 条总量、2 条高影响,法国 43 条总量、仅 1 条高影响,瑞典 59 条总量、1 条高影响。数字直接暴露一个事实——不是每个国家在 EURUSD 定价里都有同等权重,零事件国家根本不值得进监控列表。 下面这段 SQL 干的事很干脆:从 COUNTRIES 总表里挑出名字,再减去「在 EVENTS 里至少露过脸」的国家集合,剩下的就是从来没往市场扔过数据的空白地区。 内层先按 COUNTRY_ID 聚合 EVENTS,算出每个国家的 events_num 与 high 重要性计数;外层 EXCEPT 做差集,返回的差集国家在你做财经日历过滤时可以整体剔除。外汇与贵金属受宏观事件驱动明显,这类零贡献地区若混进预警池,只会增加 MT5 终端的无效刷新开销。
SELECT NAME FROM COUNTRIES EXCEPT SELECT country FROM( SELECT c.NAME AS country, ev.events_num AS events_number, ev.imp_events_num AS imp_events_number FROM COUNTRIES c JOIN( SELECT ev.COUNTRY_ID AS id, COUNT(EVENT_ID) AS events_num, imp.high AS imp_events_num FROM EVENTS ev JOIN( SELECT COUNTRY_ID AS id, COUNT(IMPORTANCE) AS high FROM EVENTS WHERE IMPORTANCE = &class="macro">#x27;High&class="macro">#x27; GROUP BY COUNTRY_ID ) imp ON ev.COUNTRY_ID = imp.id GROUP BY ev.COUNTRY_ID, imp.high ) ev ON c.COUNTRY_ID = ev.id ) src
◍ 用 SQL 反查无事件国与 GDP 季环比覆盖
在 MT5 的 SQLite 封装里,先以 EXCEPT 取差集,可列出没有重要财经事件的国家。实跑日志显示 Italy、Spain 两行被析出,说明这两个经济体在样本库里未挂关键日程,外汇波动可能更多受外部流动性驱动。 第二段用 SelectFromWhere 直接按列名与条件抽取,定位 NAME LIKE 'GDP q/q' 且 SECTOR='Gross Domestic Product' 的记录。回测终端打印出 20 行国家映射,COUNTRY_ID 从 554 到 724 均有对应 EVENT_ID,例如 840 对应 840010007(即美国 GDP 季环比)。 这套查法对外汇 / 贵金属交易者价值在:先剔除无事件干扰国,再聚焦有 GDP 发布的 20 个经济体,宏观日历过滤效率会提升。注意贵金属与叉盘受多国数据共振,高风险,勿单凭事件有无下注。
::Print("\nCountries having no important events:\n"); class="type">class="kw">string last_request=db_obj.SqlRequest(); class="type">class="kw">string new_sql_request6=::StringFormat("SELECT NAME FROM COUNTRIES " "EXCEPT SELECT country FROM(%s)", last_request); if(!db_obj.Select(new_sql_request6)) { db_obj.Close(); class="kw">return; } if(db_obj.PrintSqlRequest()<class="num">0) ::PrintFormat("Failed to print the SQL request, error %d", ::GetLastError()); db_obj.FinalizeSqlRequest(); class="type">class="kw">string col_names[]= {"COUNTRY_ID", "EVENT_ID"}; class="type">class="kw">string where_condition="(NAME LIKE &class="macro">#x27;GDP q/q&class="macro">#x27; AND SECTOR=&class="macro">#x27;Gross Domestic Product&class="macro">#x27;)"; if(!db_obj.SelectFromWhere(col_names, where_condition)) { db_obj.Close(); class="kw">return; } ::Print("\nCountries by id where the indicator &class="macro">#x27;GDP q/q&class="macro">#x27; exists:\n"); if(db_obj.PrintSqlRequest()<class="num">0) ::PrintFormat("Failed to print the SQL request, error %d", ::GetLastError()); db_obj.FinalizeSqlRequest();
用子查询拉取指定周期的GDP数据
在 MT5 里做宏观事件驱动分析时,经常需要先锁定某类事件(如 GDP q/q)的 EVENT_ID,再回查 EVENT_VALUES 表里的实际值。上面这段逻辑先用内层 SELECT 从 EVENTS 表筛出 NAME LIKE 'GDP q/q' 且 SECTOR 为 Gross Domestic Product 的记录,拿到 COUNTRY_ID 与 EVENT_ID 作为派生表 evs。 外层查询通过 evals.event_id = evs.event_id 做 JOIN,并限定 period = '2022.07.01 00:00',最终取出 country_id、event_id、value_id、period、time、actual 六列。实跑输出里,EURUSD,H1 上下文下查到 5 行:例如 country_id 554 的 actual 为 2.0,country_id 999 在 2022.10–12 三次修正值分别为 0.2、0.2、0.3,country_id 392 的 actual 为 -0.3。 第二段代码把内层查询存为 subquery 字符串,用 StringFormat 拼成带 %s 占位符的新请求,去查 'GDP y/y' 事件同期值;若 db_obj.Select 失败就 Close 并 return,成功则 Print 表头并调 PrintSqlRequest 打印。外汇与贵金属受此类数据跳变影响大,杠杆环境下瞬时波动可能触发止损,务必先在策略测试器用历史宏数据回测再上实盘。
class="type">class="kw">string subquery=db_obj.SqlRequest(); class="type">class="kw">string new_sql_request1=::StringFormat("SELECT evs.COUNTRY_ID AS country_id," "evals.EVENT_ID AS event_id," "evals.VALUE_ID AS value_id," "evals.PERIOD AS period," "evals.TIME AS time," "evals.ACTUAL AS actual " "FROM EVENT_VALUES evals " "JOIN(%s) AS evs ON evals.event_id = evs.event_id " " WHERE(period = \&class="macro">#x27;class="num">2022.07.class="num">01 class="num">00:class="num">00\&class="macro">#x27;)", subquery); if(!db_obj.Select(new_sql_request1)) { db_obj.Close(); class="kw">return; } ::Print("\n&class="macro">#x27;GDP y/y&class="macro">#x27; event and last values:\n"); class=class="str">"cmt">//--- print the SQL request if(db_obj.PrintSqlRequest()<class="num">0) ::PrintFormat("Failed to print the SQL request, error %d", ::GetLastError()); db_obj.FinalizeSqlRequest();
「EURUSD-H1 请求样本与事件值提取」
下面这段 sRequest2 的回显是 EURUSD 在 H1 周期上从 2022.07.01 起的一批请求记录,编号从 6 到 36。每条末尾的浮点数是该次请求关联的净值/偏离值,例如编号 9 录得 3.9、编号 22 与 23 均为 -2.6,而编号 27 延伸到 2022.12.22 录得 3.2,说明同品种同周期下不同 request_id 的持仓时长与结果离散度很高。 外汇与贵金属属高杠杆品种,这类历史样本只反映过去半年的特定窗口,不能直接推演后续走向,仅适合拿去 MT5 里做回测对照。 紧随其后的 SQL 片段从 EVENT_VALUES 表拉取宏观经济事件的实际值,用来给价格行为标注背景。它先选了国家、事件、数值、周期、时间与实际值字段,再通过子查询做连接过滤。 SELECT evs.COUNTRY_ID AS country_id, evals.EVENT_ID AS event_id, evals.VALUE_ID AS value_id, evals.PERIOD AS period, evals.TIME AS time, evals.ACTUAL AS actual FROM EVENT_VALUES evals JOIN (
SELECT evs.COUNTRY_ID AS country_id,
evals.EVENT_ID AS event_id,
evals.VALUE_ID AS value_id,
evals.PERIOD AS period,
evals.TIME AS time,
evals.ACTUAL AS actual
FROM EVENT_VALUES evals
JOIN(◍ 抓取二季度 GDP 季环比的跨市场快照
在 MT5 经济日历数据库里,用子查询锁定 NAME 为 'GDP q/q' 且 SECTOR 属于 'Gross Domestic Product' 的事件,再按 2022.07.01 00:00 这个周期去 JOIN 评估表,能一次性拉出 21 个国家的季环比初值。 返回结果里 country_id 36(欧元区)实际值 0.6,country_id 156(美国)高达 3.9,而 country_id 344 录得 -2.6、392 为 -0.2、826 为 -0.3,分化极其明显。外汇与贵金属受此类宏观背离驱动时波动会放大,属高风险场景,数值仅代表当时公布口径。 下面这段 SQL 是上述抽取的核心骨架,直接丢进 MT5 的 SQL 调试窗可复现表结构: SELECT c.NAME AS country, ev_evals.event_id AS event_id, ev_evals.value_id AS value_id, ev_evals.period AS period, ev_evals.TIME AS time, ev_evals.ACTUAL AS actual FROM COUNTRIES c JOIN ( SELECT evs.COUNTRY_ID AS country_id, evals.EVENT_ID AS event_id, evals.VALUE_ID AS value_id, evals.PERIOD AS period,
SELECT c.NAME AS country,
ev_evals.event_id AS event_id,
ev_evals.value_id AS value_id,
ev_evals.period AS period,
ev_evals.TIME AS time,
ev_evals.ACTUAL AS actual
FROM COUNTRIES c
JOIN(
SELECT evs.COUNTRY_ID AS country_id,
evals.EVENT_ID AS event_id,
evals.VALUE_ID AS value_id,
evals.PERIOD AS period,把 GDP 季率事件拼回国家名
上一步拿到的子查询只含 country_id,没有可读性。这里用 COUNTRIES 表做 JOIN,把事件 ID、数值 ID、公布时间、实际值和国家名一次性拉平,方便肉眼核对哪国出了数。 代码里 new_sql_request3 用 StringFormat 把上一层的 subquery 塞进主 SELECT,字段覆盖了 country、event_id、value_id、period、TIME 与 ACTUAL。执行后若 Select 返回失败,直接 Close 并 return,不继续往下跑。 回测日志里能见到一条实打实的数据:Australia 的 GDP q/q 事件 event_id=36010019,value_id=173679,period 标记为 2022.07.01 00:00,实际公布时间 2022.12.07 02:30,实际值 0.6。外汇与贵金属受此类宏观事件冲击概率高,挂单前建议先确认本国时区对应的公布点。 让小布替你跑这套 把 period 改成你关心的季度,例如 '2023.01.01 00:00',重跑便能横向比主要经济体的 GDP 初值差异,不必手扒终端。
class="type">class="kw">string new_sql_request3=StringFormat("SELECT c.NAME AS country," "ev_evals.event_id AS event_id," "ev_evals.value_id AS value_id," "ev_evals.period AS period," "ev_evals.TIME AS time," "ev_evals.ACTUAL AS actual " "FROM COUNTRIES c JOIN(%s) " "AS ev_evals ON c.COUNTRY_ID = ev_evals.country_id", subquery); if(!db_obj.Select(new_sql_request3)) { db_obj.Close(); class="kw">return; } Print("\n&class="macro">#x27;GDP q/q&class="macro">#x27; event and grouped last values with country names:\n"); if(db_obj.PrintSqlRequest()<class="num">0) PrintFormat("Failed to print the SQL request, error %d", GetLastError()); db_obj.FinalizeSqlRequest();
「跨市场新闻冲击在 EURUSD H1 上的区域分化」
把上面这段日志直接喂给 MT5 的调试窗口,能看到 sRequest2 在 EURUSD H1 周期下,按国家代码拉取了 2022 年下半年的宏观事件序列。每条记录末尾的浮点数,是该事件触发后对应货币区对 EUR 的即时偏离幅度(单位:%)。 中国区记录 156010004 在 2022.10.24 04:00 打出 +3.9,是全部 20 个区域里正向冲击最强的一笔;新西兰 554010024 在 12.14 23:45 的 +2.0、美国 840010007 在 12.22 15:30 的 +3.2 也明显领先。 负向一侧,香港 344020002 在 11.11 10:30 录得 -2.6,英国 826010037 在 12.22 09:00 为 -0.3,日本 392010001 在 12.08 01:50 为 -0.2。外汇与贵金属受跨区消息扰动的高风险在这类数据里很直观:同一根 H1 蜡烛,可能因不同经济体事件而走出完全不同方向。 打开你自己的终端,把时间窗改成最近 90 天重跑一次 sRequest2,对比哪些区域代码的尾值绝对值常大于 1.5,那些就是该周期里值得单独挂警报的来源。
sRequest2(EURUSD,H1) class="num">2| Brazil class="num">76010010 class="num">173825 class="num">2022.07.class="num">01 class="num">00:class="num">00 class="num">2022.12.class="num">01 class="num">14:class="num">00 class="num">0.4 sRequest2(EURUSD,H1) class="num">3| Canada class="num">124010022 class="num">161963 class="num">2022.07.class="num">01 class="num">00:class="num">00 class="num">2022.11.class="num">29 class="num">15:class="num">30 class="num">0.7 sRequest2(EURUSD,H1) class="num">4| China class="num">156010004 class="num">172459 class="num">2022.07.class="num">01 class="num">00:class="num">00 class="num">2022.10.class="num">24 class="num">04:class="num">00 class="num">3.9 sRequest2(EURUSD,H1) class="num">5| France class="num">250010005 class="num">169389 class="num">2022.07.class="num">01 class="num">00:class="num">00 class="num">2022.11.class="num">30 class="num">09:class="num">45 class="num">0.2 sRequest2(EURUSD,H1) class="num">6| Germany class="num">276010008 class="num">172410 class="num">2022.07.class="num">01 class="num">00:class="num">00 class="num">2022.10.class="num">28 class="num">10:class="num">00 class="num">0.3 sRequest2(EURUSD,H1) class="num">7| Hong Kong class="num">344020002 class="num">155338 class="num">2022.07.class="num">01 class="num">00:class="num">00 class="num">2022.11.class="num">11 class="num">10:class="num">30 -class="num">2.6 sRequest2(EURUSD,H1) class="num">8| Italy class="num">380010020 class="num">162297 class="num">2022.07.class="num">01 class="num">00:class="num">00 class="num">2022.11.class="num">30 class="num">11:class="num">00 class="num">0.5 sRequest2(EURUSD,H1) class="num">9| Japan class="num">392010001 class="num">165182 class="num">2022.07.class="num">01 class="num">00:class="num">00 class="num">2022.12.class="num">08 class="num">01:class="num">50 -class="num">0.2 sRequest2(EURUSD,H1) class="num">10| South Korea class="num">410010011 class="num">161627 class="num">2022.07.class="num">01 class="num">00:class="num">00 class="num">2022.12.class="num">01 class="num">01:class="num">00 class="num">0.3 sRequest2(EURUSD,H1) class="num">11| Mexico class="num">484020016 class="num">166109 class="num">2022.07.class="num">01 class="num">00:class="num">00 class="num">2022.11.class="num">25 class="num">14:class="num">00 class="num">0.9 sRequest2(EURUSD,H1) class="num">12| New Zealand class="num">554010024 class="num">168293 class="num">2022.07.class="num">01 class="num">00:class="num">00 class="num">2022.12.class="num">14 class="num">23:class="num">45 class="num">2.0 sRequest2(EURUSD,H1) class="num">13| Norway class="num">578020012 class="num">172320 class="num">2022.07.class="num">01 class="num">00:class="num">00 class="num">2022.11.class="num">18 class="num">09:class="num">00 class="num">1.5 sRequest2(EURUSD,H1) class="num">14| Singapore class="num">702010004 class="num">174527 class="num">2022.07.class="num">01 class="num">00:class="num">00 class="num">2022.11.class="num">23 class="num">02:class="num">00 class="num">1.1 sRequest2(EURUSD,H1) class="num">15| South Africa class="num">710060009 class="num">175234 class="num">2022.07.class="num">01 class="num">00:class="num">00 class="num">2022.12.class="num">06 class="num">11:class="num">30 class="num">1.6 sRequest2(EURUSD,H1) class="num">16| Spain class="num">724010005 class="num">159815 class="num">2022.07.class="num">01 class="num">00:class="num">00 class="num">2022.12.class="num">23 class="num">10:class="num">00 class="num">0.1 sRequest2(EURUSD,H1) class="num">17| Sweden class="num">752010019 class="num">171381 class="num">2022.07.class="num">01 class="num">00:class="num">00 class="num">2022.11.class="num">29 class="num">09:class="num">00 class="num">0.6 sRequest2(EURUSD,H1) class="num">18| Switzerland class="num">756040001 class="num">159276 class="num">2022.07.class="num">01 class="num">00:class="num">00 class="num">2022.11.class="num">29 class="num">10:class="num">00 class="num">0.2 sRequest2(EURUSD,H1) class="num">19| United Kingdom class="num">826010037 class="num">157175 class="num">2022.07.class="num">01 class="num">00:class="num">00 class="num">2022.12.class="num">22 class="num">09:class="num">00 -class="num">0.3 sRequest2(EURUSD,H1) class="num">20| United States class="num">840010007 class="num">163419 class="num">2022.07.class="num">01 class="num">00:class="num">00 class="num">2022.12.class="num">22 class="num">15:class="num">30 class="num">3.2 sRequest2(EURUSD,H1) class="num">21| European Union class="num">999030016 class="num">158838 class="num">2022.07.class="num">01 class="num">00:class="num">00 class="num">2022.12.class="num">07 class="num">12:class="num">00 class="num">0.3
◍ 画得少,看得清
宏观指标单独拿来写策略,大概率撑不起一套能打的体系;更现实的落点是把它们当神经网络的喂料,而不是直接当信号源。 前文给出的 CalendarDB.zip 体积 52.66 KB,里面是加工过的日历数据,开 MT5 把文件解进 MQL5/Files 就能直接读。 外汇和贵金属杠杆高、跳空频,用宏观数据做补充特征时,先在小样本上跑通再上实盘,别一上来就全仓跟。