使用MQL5经济日历进行交易(第二部分):创建新闻交易面板·进阶篇
(2/3)· 从函数检索到可视化面板,三步把高影响新闻摆上MT5桌面
「用 OBJ_RECTANGLE_LABEL 画可定位的信息框」
在 MT5 里用矩形标签(OBJ_RECTANGLE_LABEL)做 HUD 式提示框,比在图表上堆文字对象干净得多。它不绑定时间轴坐标,完全靠距边角像素定位,适合挂「小布盯盘」的 AIGC 信号浮层。 下面这段是创建函数的尾部属性设置,注意 OBJPROP_CORNER 设成 CORNER_LEFT_UPPER 后,XD/YD 就是从左上角往右、往下的像素偏移;OBJPROP_BACK 设 false 保证它浮在 K 线上方而不是被盖住。 边框只在 borderType 为 BORDER_FLAT 时才读 OBJPROP_STYLE / OBJPROP_WIDTH / OBJPROP_COLOR,若用 BORDER_NONE 传 clrNONE 即可,省一次重绘开销。最后 ChartRedraw(0) 触发刷新,函数返回 true 代表对象建好且属性落定。 别把定位角写死 代码里 OBJPROP_CORNER 被重复设了两次 LEFT_UPPER,属冗余。若你想让框贴右下角显示止损位,应改 CORNER_RIGHT_LOWER,并把 XD/YD 理解为距右、距下的像素,否则框会跑出可视区。
ObjectSetInteger(class="num">0, objName, OBJPROP_YSIZE, yS); class=class="str">"cmt">// Height of the rectangle ObjectSetInteger(class="num">0, objName, OBJPROP_CORNER, CORNER_LEFT_UPPER); class=class="str">"cmt">// Positioning corner ObjectSetInteger(class="num">0, objName, OBJPROP_BGCOLOR, clrBg); class=class="str">"cmt">// Rectangle background class="type">class="kw">color ObjectSetInteger(class="num">0, objName, OBJPROP_BORDER_TYPE, borderType); class=class="str">"cmt">// Border type ObjectSetInteger(class="num">0, objName, OBJPROP_STYLE, borderStyle); class=class="str">"cmt">// Border style(only if borderType is flat) ObjectSetInteger(class="num">0, objName, OBJPROP_WIDTH, widthBorder); class=class="str">"cmt">// Border width(only if borderType is flat) ObjectSetInteger(class="num">0, objName, OBJPROP_COLOR, clrBorder); class=class="str">"cmt">// Border class="type">class="kw">color (only if borderType is flat) ObjectSetInteger(class="num">0, objName, OBJPROP_BACK, false); class=class="str">"cmt">// Not a background object ObjectSetInteger(class="num">0, objName, OBJPROP_STATE, false); class=class="str">"cmt">// Not selectable ObjectSetInteger(class="num">0, objName, OBJPROP_SELECTABLE, false); class=class="str">"cmt">// Not selectable ObjectSetInteger(class="num">0, objName, OBJPROP_SELECTED, false); class=class="str">"cmt">// Not selected ObjectSetInteger(class="num">0, objName, OBJPROP_XDISTANCE, xD); class=class="str">"cmt">// X distance from the corner ObjectSetInteger(class="num">0, objName, OBJPROP_CORNER, CORNER_LEFT_UPPER); class=class="str">"cmt">// Positioning corner ChartRedraw(class="num">0); class=class="str">"cmt">// Redraw the chart class="kw">return (true); class=class="str">"cmt">// Return true if object creation and class="kw">property settings are successful class="type">bool createRecLabel(class="type">class="kw">string objName, class="type">int xD, class="type">int yD, class="type">int xS, class="type">int yS, class="type">class="kw">color clrBg, class="type">int widthBorder, class="type">class="kw">color clrBorder = clrNONE, ENUM_BORDER_TYPE borderType = BORDER_FLAT, ENUM_LINE_STYLE borderStyle = STYLE_SOLID) { ResetLastError(); class=class="str">"cmt">// Reset any previous error codes class=class="str">"cmt">// Create a rectangle label object if (!ObjectCreate(class="num">0, objName, OBJ_RECTANGLE_LABEL, class="num">0, class="num">0, class="num">0)) { Print(__FUNCTION__, ": failed to create rec label! Error code = ", _LastError); class="kw">return (false); class=class="str">"cmt">// Return false if object creation fails } class=class="str">"cmt">// Set properties for the rectangle label ObjectSetInteger(class="num">0, objName, OBJPROP_XDISTANCE, xD); class=class="str">"cmt">// X distance from the corner ObjectSetInteger(class="num">0, objName, OBJPROP_YDISTANCE, yD); class=class="str">"cmt">// Y distance from the corner ObjectSetInteger(class="num">0, objName, OBJPROP_XSIZE, xS); class=class="str">"cmt">// Width of the rectangle ObjectSetInteger(class="num">0, objName, OBJPROP_YSIZE, yS); class=class="str">"cmt">// Height of the rectangle
用 ObjectSetInteger 钉死 GUI 对象的锚点与边框
在 MT5 里画矩形或按钮,光靠 ObjectCreate 只是把对象挂上图表,真正决定它「长在哪、长什么样」的是后面一连串 ObjectSetInteger 调用。下面这段把矩形锚在左上角(CORNER_LEFT_UPPER),并指定背景色、边框类型与线型——边框相关的 OBJPROP_STYLE / OBJPROP_WIDTH / OBJPROP_COLOR 只有在 borderType 为 flat 时才生效,设错类型这些参数会被静默忽略。 ObjectSetInteger(0, objName, OBJPROP_CORNER, CORNER_LEFT_UPPER); // 锚点设为左上角 ObjectSetInteger(0, objName, OBJPROP_BGCOLOR, clrBg); // 矩形背景色 ObjectSetInteger(0, objName, OBJPROP_BORDER_TYPE, borderType); // 边框类型 ObjectSetInteger(0, objName, OBJPROP_STYLE, borderStyle); // 边框线型(仅 borderType=flat 时) ObjectSetInteger(0, objName, OBJPROP_WIDTH, widthBorder); // 边框宽度(仅 flat) ObjectSetInteger(0, objName, OBJPROP_COLOR, clrBorder); // 边框颜色(仅 flat) ObjectSetInteger(0, objName, OBJPROP_BACK, false); // 非背景层对象 ObjectSetInteger(0, objName, OBJPROP_STATE, false); // 不可选中状态 ObjectSetInteger(0, objName, OBJPROP_SELECTABLE, false); // 禁止鼠标选中 ObjectSetInteger(0, objName, OBJPROP_SELECTED, false); // 初始未选中 ChartRedraw(0); // 强制重绘图表 return (true); // 对象创建与属性设置成功返回 true 按钮的创建函数 createButton 也一样套路:先用 ResetLastError 清掉上次错误码,ObjectCreate 失败就打印 _LastError 并返回 false。成功后才用 OBJPROP_XDISTANCE / OBJPROP_YDISTANCE 定坐标——这两个值是相对锚点角的像素偏移,不是价格坐标。 ObjectSetInteger(0, objName, OBJPROP_XDISTANCE, xD); // 距锚点角水平像素 ObjectSetInteger(0, objName, OBJPROP_YDISTANCE, yD); // 距锚点角垂直像素 外汇与贵金属行情跳空频繁,GUI 对象坐标用像素偏移可能在极端波动后显得错位,开 MT5 把这段贴进 EA 的 OnCreate 里跑一遍,调 xD / yD 看锚点是否符合预期。
ObjectSetInteger(class="num">0, objName, OBJPROP_CORNER, CORNER_LEFT_UPPER); class=class="str">"cmt">// Positioning corner ObjectSetInteger(class="num">0, objName, OBJPROP_BGCOLOR, clrBg); class=class="str">"cmt">// Rectangle background class="type">class="kw">color ObjectSetInteger(class="num">0, objName, OBJPROP_BORDER_TYPE, borderType); class=class="str">"cmt">// Border type ObjectSetInteger(class="num">0, objName, OBJPROP_STYLE, borderStyle); class=class="str">"cmt">// Border style(only if borderType is flat) ObjectSetInteger(class="num">0, objName, OBJPROP_WIDTH, widthBorder); class=class="str">"cmt">// Border width(only if borderType is flat) ObjectSetInteger(class="num">0, objName, OBJPROP_COLOR, clrBorder); class=class="str">"cmt">// Border class="type">class="kw">color (only if borderType is flat) ObjectSetInteger(class="num">0, objName, OBJPROP_BACK, false); class=class="str">"cmt">// Not a background object ObjectSetInteger(class="num">0, objName, OBJPROP_STATE, false); class=class="str">"cmt">// Not selectable ObjectSetInteger(class="num">0, objName, OBJPROP_SELECTABLE, false); class=class="str">"cmt">// Not selectable ObjectSetInteger(class="num">0, objName, OBJPROP_SELECTED, false); class=class="str">"cmt">// Not selected ChartRedraw(class="num">0); class=class="str">"cmt">// Redraw the chart class="kw">return (true); class=class="str">"cmt">// Return true if object creation and class="kw">property settings are successful } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Function to create button | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">bool createButton(class="type">class="kw">string objName, class="type">int xD, class="type">int yD, class="type">int xS, class="type">int yS, class="type">class="kw">string txt = "", class="type">class="kw">color clrTxt = clrBlack, class="type">int fontSize = class="num">12, class="type">class="kw">color clrBg = clrNONE, class="type">class="kw">color clrBorder = clrNONE, class="type">class="kw">string font = "Arial Rounded MT Bold") { class=class="str">"cmt">// Reset any previous errors ResetLastError(); class=class="str">"cmt">// Attempt to create the button object if (!ObjectCreate(class="num">0, objName, OBJ_BUTTON, class="num">0, class="num">0, class="num">0)) { class=class="str">"cmt">// Print an error message if creation fails Print(__FUNCTION__, ": failed to create the button! Error code = ", _LastError); class="kw">return (false); } class=class="str">"cmt">// Set properties for the button ObjectSetInteger(class="num">0, objName, OBJPROP_XDISTANCE, xD); class=class="str">"cmt">// X distance from the corner ObjectSetInteger(class="num">0, objName, OBJPROP_YDISTANCE, yD); class=class="str">"cmt">// Y distance from the corner
◍ 用 ObjectSetInteger 给按钮定尺寸和坐标锚点
在 MT5 里用 OBJ_BUTTON 做自定义面板时,尺寸和锚点必须靠 ObjectSetInteger 逐个写进去,而不是在 ObjectCreate 时顺手带参。上面这段把宽度 xS、高度 yS 以及 CORNER_LEFT_UPPER 锚点一次性设好,按钮就会钉在图表左上角,不会随价格滚动乱跑。 逐行看这几个调用:OBJPROP_XSIZE / OBJPROP_YSIZE 控制像素级宽高;OBJPROP_CORNER 决定以哪个角为基准,写错常量按钮可能直接跑到屏幕外。OBJPROP_BACK 设 false 代表按钮浮在 K 线上方,设 true 才会沉到背景层,做半透明提示条时容易踩反。 最后那句 ChartRedraw(0) 不能省。实测不主动重绘时,新建对象在部分券商的 MT5 构建里可能延迟 1~2 个 tick 才显示,手动调参数验证时会被误判为代码失效。
ObjectSetInteger(class="num">0, objName, OBJPROP_XSIZE, xS); class=class="str">"cmt">// 设置按钮宽度(像素) ObjectSetInteger(class="num">0, objName, OBJPROP_YSIZE, yS); class=class="str">"cmt">// 设置按钮高度(像素) ObjectSetInteger(class="num">0, objName, OBJPROP_CORNER, CORNER_LEFT_UPPER); class=class="str">"cmt">// 锚定左上角 ObjectSetString(class="num">0, objName, OBJPROP_TEXT, txt); class=class="str">"cmt">// 按钮显示文字 ObjectSetInteger(class="num">0, objName, OBJPROP_COLOR, clrTxt); class=class="str">"cmt">// 文字颜色 ObjectSetInteger(class="num">0, objName, OBJPROP_FONTSIZE, fontSize); class=class="str">"cmt">// 字号 ObjectSetString(class="num">0, objName, OBJPROP_FONT, font); class=class="str">"cmt">// 字体名 ObjectSetInteger(class="num">0, objName, OBJPROP_BGCOLOR, clrBg); class=class="str">"cmt">// 背景色 ObjectSetInteger(class="num">0, objName, OBJPROP_BORDER_COLOR, clrBorder); class=class="str">"cmt">// 边框色 ObjectSetInteger(class="num">0, objName, OBJPROP_BACK, false); class=class="str">"cmt">// 不透明背景、浮于上层 ObjectSetInteger(class="num">0, objName, OBJPROP_STATE, false); class=class="str">"cmt">// 初始未按下 ObjectSetInteger(class="num">0, objName, OBJPROP_SELECTABLE, false); class=class="str">"cmt">// 禁止选中 ObjectSetInteger(class="num">0, objName, OBJPROP_SELECTED, false); class=class="str">"cmt">// 未选中态 class=class="str">"cmt">// 重绘图表以显示按钮 ChartRedraw(class="num">0); class="kw">return (true); class=class="str">"cmt">// 按钮创建成功
ObjectSetInteger(class="num">0, objName, OBJPROP_XSIZE, xS); class=class="str">"cmt">// Width of the button ObjectSetInteger(class="num">0, objName, OBJPROP_YSIZE, yS); class=class="str">"cmt">// Height of the button ObjectSetInteger(class="num">0, objName, OBJPROP_CORNER, CORNER_LEFT_UPPER); class=class="str">"cmt">// Positioning corner ObjectSetString(class="num">0, objName, OBJPROP_TEXT, txt); class=class="str">"cmt">// Text displayed on the button ObjectSetInteger(class="num">0, objName, OBJPROP_COLOR, clrTxt); class=class="str">"cmt">// Text class="type">class="kw">color ObjectSetInteger(class="num">0, objName, OBJPROP_FONTSIZE, fontSize); class=class="str">"cmt">// Font size ObjectSetString(class="num">0, objName, OBJPROP_FONT, font); class=class="str">"cmt">// Font name ObjectSetInteger(class="num">0, objName, OBJPROP_BGCOLOR, clrBg); class=class="str">"cmt">// Background class="type">class="kw">color ObjectSetInteger(class="num">0, objName, OBJPROP_BORDER_COLOR, clrBorder); class=class="str">"cmt">// Border class="type">class="kw">color ObjectSetInteger(class="num">0, objName, OBJPROP_BACK, false); class=class="str">"cmt">// Transparent background ObjectSetInteger(class="num">0, objName, OBJPROP_STATE, false); class=class="str">"cmt">// Button state(not pressed) ObjectSetInteger(class="num">0, objName, OBJPROP_SELECTABLE, false); class=class="str">"cmt">// Not selectable ObjectSetInteger(class="num">0, objName, OBJPROP_SELECTED, false); class=class="str">"cmt">// Not selected class=class="str">"cmt">// Redraw the chart to display the button ChartRedraw(class="num">0); class="kw">return (true); class=class="str">"cmt">// Button creation successful
「用矩形和标签搭出面板骨架」
在 MT5 里做自定义看板,第一步不是算数据,而是把图形对象的锚点和层级先钉死。上面这段把主面板、子面板和标题标签的创建逻辑拆得很直白:主矩形从坐标 (50,50) 起,宽 740、高 410,背景色用 SeaGreen;两个子矩形在主矩形内缩进 3~10 像素不等,分别用 White 和 Green 区分区块。 标签对象的关键属性全靠 ObjectSetInteger / ObjectSetString 逐条写:CORNER_LEFT_UPPER 锁定左上角锚点,OBJPROP_BACK 设 false 让标签浮在 K 线上方,OBJPROP_SELECTABLE 和 OBJPROP_SELECTED 都关掉,避免鼠标误选。最后 ChartRedraw(0) 强制重绘,否则对象可能不会立刻显示。 标题标签 HEADER_LABEL 放在 (58,55),字号 15,文字写死成 "MQL5 Economic Calendar"。列头用数组 array_calendar 存了 8 个字段名,buttons 数组则给了每列像素宽度:80/50/50/40/281/60/70/70,加起来正好 701,比子面板内宽略小,留了边距。 开 MT5 新建 EA,把 createRecLabel 和 createLabel 两个函数原样贴进代码,改一下坐标和颜色就能跑出空面板;外汇和贵金属行情波动剧烈,这类看板只做信息聚合,不构成任何方向建议。
ObjectSetInteger(class="num">0, objName, OBJPROP_CORNER, CORNER_LEFT_UPPER); class=class="str">"cmt">// 设定对象锚点为左上角 ObjectSetString(class="num">0, objName, OBJPROP_TEXT, txt); class=class="str">"cmt">// 设置标签显示的文字 ObjectSetInteger(class="num">0, objName, OBJPROP_COLOR, clrTxt); class=class="str">"cmt">// 设置文字颜色 ObjectSetInteger(class="num">0, objName, OBJPROP_FONTSIZE, fontSize); class=class="str">"cmt">// 设置字体大小 ObjectSetString(class="num">0, objName, OBJPROP_FONT, font); class=class="str">"cmt">// 设置字体名称 ObjectSetInteger(class="num">0, objName, OBJPROP_BACK, false); class=class="str">"cmt">// 背景透明,对象在前台 ObjectSetInteger(class="num">0, objName, OBJPROP_STATE, false); class=class="str">"cmt">// 标签状态非激活 ObjectSetInteger(class="num">0, objName, OBJPROP_SELECTABLE, false); class=class="str">"cmt">// 不可被选中 ObjectSetInteger(class="num">0, objName, OBJPROP_SELECTED, false); class=class="str">"cmt">// 当前未选中 class=class="str">"cmt">// 重绘图表以显示标签 ChartRedraw(class="num">0); class="kw">return (true); class=class="str">"cmt">// 标签创建成功 } class="macro">#define MAIN_REC "MAIN_REC" class="type">int OnInit(){ ... class="kw">return(INIT_SUCCEEDED); } createRecLabel(MAIN_REC,class="num">50,class="num">50,class="num">740,class="num">410,clrSeaGreen,class="num">1); class="macro">#define SUB_REC1 "SUB_REC1" class="macro">#define SUB_REC2 "SUB_REC2" createRecLabel(SUB_REC1,class="num">50+class="num">3,class="num">50+class="num">30,class="num">740-class="num">3-class="num">3,class="num">410-class="num">30-class="num">3,clrWhite,class="num">1); createRecLabel(SUB_REC2,class="num">50+class="num">3+class="num">5,class="num">50+class="num">30+class="num">50+class="num">27,class="num">740-class="num">3-class="num">3-class="num">5-class="num">5,class="num">410-class="num">30-class="num">3-class="num">50-class="num">27-class="num">10,clrGreen,class="num">1); class="macro">#define HEADER_LABEL "HEADER_LABEL" createLabel(HEADER_LABEL,class="num">50+class="num">3+class="num">5,class="num">50+class="num">5,"MQL5 Economic Calendar",clrWhite,class="num">15); class="type">class="kw">string array_calendar[] = {"Date","Time","Cur.","Imp.","Event","Actual","Forecast","Previous"}; class="type">int buttons[] = {class="num">80,class="num">50,class="num">50,class="num">40,class="num">281,class="num">60,class="num">70,class="num">70};
把财经日历铺到MT5面板上的写法
想在MT5图表上做个自用的财经日历面板,核心是先批量生成分类按钮,再拉取指定时段的新闻值。下面这段逻辑从坐标初始化开始,把数组里的日历分类逐个画成按钮,按钮间距固定留3像素,起始X是59、Y是132,单按钮高25。 循环里每画一个按钮就累加 startX,保证不重叠;随后用 CalendarValueHistory 拉取服务器时间前后各12小时(PERIOD_H12)的事件,country_code 写死 "US" 可只盯美元相关。Print 出来的 TOTAL VALUES 与 ArraySize(values) 能直接核对抓到了几条,外汇与贵金属受这类数据扰动大,属于高风险品种,实际跳空概率会随事件级别上升。 面板还补了两个文本标签:TIME_LABEL 在(70,85)显示服务器时间与新闻总数,IMPACT_LABEL 在(70,105)做表头。影响级别分 None/Low/Medium/High 四档,循环里按档上色——黄、橙、红分别对应低中高,None 用白字黑底,视觉上一眼能分出事件分量。
class="macro">#define ARRAY_CALENDAR "ARRAY_CALENDAR" class=class="str">"cmt">//--- class=class="str">"cmt">//--- Initialize starting x-coordinate for button positioning class="type">int startX = class="num">59; class=class="str">"cmt">//--- Loop through the array_calendar elements to create buttons for (class="type">int i=class="num">0; i<ArraySize(array_calendar); i++){ class=class="str">"cmt">//--- Create each button for calendar categories createButton(ARRAY_CALENDAR+IntegerToString(i),startX,class="num">132,buttons[i],class="num">25,array_calendar[i],clrWhite,class="num">13,clrGreen,clrNONE,"Calibri Bold"); startX += buttons[i]+class="num">3; class=class="str">"cmt">//--- Update x-coordinate for the next button } class=class="str">"cmt">//--- Declare variables for tracking news events and status class="type">int totalNews = class="num">0; class="type">bool isNews = false; MqlCalendarValue values[]; class=class="str">"cmt">//--- Array to store calendar values class=class="str">"cmt">//--- Define start and end time for calendar event retrieval class="type">class="kw">datetime startTime = TimeTradeServer() - PeriodSeconds(PERIOD_H12); class="type">class="kw">datetime endTime = TimeTradeServer() + PeriodSeconds(PERIOD_H12); class=class="str">"cmt">//--- Set a specific country code filter(e.g., "US" for USD) class="type">class="kw">string country_code = "US"; class="type">class="kw">string currency_base = SymbolInfoString(_Symbol,SYMBOL_CURRENCY_BASE); class=class="str">"cmt">//--- Retrieve historical calendar values within the specified time range class="type">int allValues = CalendarValueHistory(values,startTime,endTime,NULL,NULL); class=class="str">"cmt">//--- Print the total number of values retrieved and the array size Print("TOTAL VALUES = ",allValues," || Array size = ",ArraySize(values)); class="macro">#define TIME_LABEL "TIME_LABEL" class=class="str">"cmt">//--- class=class="str">"cmt">//--- Create label displaying server time and total number of news events found createLabel(TIME_LABEL,class="num">70,class="num">85,"Server Time: "+TimeToString(TimeCurrent(), TIME_DATE|TIME_SECONDS)+" ||| Total News: "+ IntegerToString(allValues),clrBlack,class="num">14,"Times new roman bold"); class="macro">#define IMPACT_LABEL "IMPACT_LABEL" class=class="str">"cmt">//--- class=class="str">"cmt">//--- Create label for displaying "Impact" category header createLabel(IMPACT_LABEL,class="num">70,class="num">105,"Impact: ",clrBlack,class="num">14,"Times new roman bold"); class=class="str">"cmt">//--- Define labels for impact levels and size of impact display areas class="type">class="kw">string impact_labels[] = {"None", "Low", "Medium", "High"}; class="type">int impact_size = class="num">100; class=class="str">"cmt">//--- Loop through impact levels to create buttons for each level for (class="type">int i=class="num">0; i<ArraySize(impact_labels); i++){ class="type">class="kw">color impact_color = clrBlack, label_color = clrBlack; class=class="str">"cmt">//--- Default colors for label and button class=class="str">"cmt">//--- Assign class="type">class="kw">color based on impact level if (impact_labels[i] == "None"){label_color = clrWhite;} else if (impact_labels[i] == "Low"){impact_color = clrYellow;} else if (impact_labels[i] == "Medium"){impact_color = clrOrange;} else if (impact_labels[i] == "High"){impact_color = clrRed;}