利用 MQL5 和 MQL4 实现的选择和导航工具: 把数据添加到图表中·进阶篇
📊

利用 MQL5 和 MQL4 实现的选择和导航工具: 把数据添加到图表中·进阶篇

(2/3)· 日内交易找不准进场背景?用 MQL5 把昨日趋势差、开盘线与整数位直接铺在图上

案例拆解新手友好 第 2/3 篇
很多人在 M5 上盯盘时,根本分不清今天是从哪根 K 线开始的,昨高昨低混成一团。把不同交易日的波动背景当同质噪声看,进场点自然飘忽。这篇接着上篇,把能直接铺在图表上的背景层一个个拆给你。

「用水平线画出整数关口网格」

这段脚本在 MT5 图表上以 tmpPrice 为基准,向上按 0.5 步长批量铺设水平参考线。外汇与贵金属价格常在区间边缘出现停顿,这类 0.5 / 1.0 间隔的虚线能帮肉眼快速定位潜在反应区,但汇价是否真在此受阻仍属概率事件,杠杆品种波动剧烈,需自行评估风险。 代码先对 _round_line_00_1 设了置底属性,随后连续创建 _round_line_05_1(tmpPrice+0.5)、_round_line_00_2(tmpPrice+1.0)、_round_line_05_2(tmpPrice+1.5)三条水平线,颜色统一用 clrCadetBlue、线型 STYLE_DASH,且全部禁止选中、置于背景。 逐行看:ObjectCreate 的第三参 OBJ_HLINE 指定水平线类型,时间参填 0 表示贯穿整个可视区域;ObjectSetInteger 里 OBJPROP_BACK 设 true 让线不挡 K 线,OBJPROP_SELECTABLE 设 false 避免误拖。复制进 EA 的绘图模块,改 exprefix 就能避免与已有对象重名。

MQL5 / C++
ObjectSetInteger(currChart,exprefix+"_round_line_00_1",OBJPROP_BACK,true);
ObjectCreate(currChart, exprefix+"_round_line_05_1", OBJ_HLINE, class="num">0, class="num">0, (class="type">class="kw">double) tmpPrice+class="num">0.5 );
ObjectSetInteger(currChart,exprefix+"_round_line_05_1",OBJPROP_COLOR,clrCadetBlue);
ObjectSetInteger(currChart,exprefix+"_round_line_05_1",OBJPROP_STYLE, STYLE_DASH);
ObjectSetInteger(currChart,exprefix+"_round_line_05_1",OBJPROP_SELECTABLE,false);
ObjectSetInteger(currChart,exprefix+"_round_line_05_1",OBJPROP_BACK,true);
ObjectCreate(currChart, exprefix+"_round_line_00_2", OBJ_HLINE, class="num">0, class="num">0, (class="type">class="kw">double) tmpPrice+class="num">1 );
ObjectSetInteger(currChart,exprefix+"_round_line_00_2",OBJPROP_COLOR,clrCadetBlue);
ObjectSetInteger(currChart,exprefix+"_round_line_00_2",OBJPROP_STYLE, STYLE_DASH);
ObjectSetInteger(currChart,exprefix+"_round_line_00_2",OBJPROP_SELECTABLE,false);
ObjectSetInteger(currChart,exprefix+"_round_line_00_2",OBJPROP_BACK,true);
ObjectCreate(currChart, exprefix+"_round_line_05_2", OBJ_HLINE, class="num">0, class="num">0, (class="type">class="kw">double) tmpPrice+class="num">1.5 );
ObjectSetInteger(currChart,exprefix+"_round_line_05_2",OBJPROP_COLOR,clrCadetBlue);
ObjectSetInteger(currChart,exprefix+"_round_line_05_2",OBJPROP_STYLE, STYLE_DASH);
ObjectSetInteger(currChart,exprefix+"_round_line_05_2",OBJPROP_SELECTABLE,false);
ObjectSetInteger(currChart,exprefix+"_round_line_05_2",OBJPROP_BACK,true);

break;

◍ 把最近四个小时收盘线钉在图上

顺着自然支撑阻力往下说,小时级别的收盘边界在更小周期里也可能构成临时的支撑或阻挡。笔者实盘里没明显体会到它的决定性作用,但作为参考线放上图表,至少能帮眼睛校准时段切换的节点。 下面这段逻辑只干一件事:在当前图表拉出最近四个小时的结束位置,用黄色竖线标出来。它从 M30 周期取 9 根 K 线(覆盖约 4.5 小时),倒序排列后逐个找分钟数为 0 的柱顶时间,偏移量自增定位到整点边界。 [CODE] /* 在图表上显示最后四小时 currChart - 图表 id */ void showCloseHour(long currChart){ MqlDateTime tmpTime; int tmpOffset=0; MqlRates rates[]; ArraySetAsSeries(rates, true); if(CopyRates(ChartSymbol(currChart), PERIOD_M30, 0, 9, rates)>0){ tmpOffset=0; TimeToStruct(rates[tmpOffset].time, tmpTime); if(tmpTime.min!=0){ tmpOffset++; } ObjectCreate(currChart, exprefix+"_hour_0", OBJ_VLINE, 0, rates[tmpOffset].time, 0); ObjectSetInteger(currChart,exprefix+"_hour_0",OBJPROP_SELECTABLE,false); ObjectSetInteger(currChart,exprefix+"_hour_0",OBJPROP_STYLE,STYLE_DOT); ObjectSetInteger(currChart,exprefix+"_hour_0",OBJPROP_RAY,true); ObjectSetInteger(currChart,exprefix+"_hour_0",OBJPROP_COLOR,clrYellow); ObjectSetInteger(currChart,exprefix+"_hour_0",OBJPROP_BACK,true); tmpOffset++; TimeToStruct(rates[tmpOffset].time, tmpTime); if(tmpTime.min!=0){ tmpOffset++; } ObjectCreate(currChart, exprefix+"_hour_1", OBJ_VLINE, 0, rates[tmpOffset].time, 0); ObjectSetInteger(currChart,exprefix+"_hour_1",OBJPROP_SELECTABLE,false); ObjectSetInteger(currChart,exprefix+"_hour_1",OBJPROP_STYLE,STYLE_DOT); ObjectSetInteger(currChart,exprefix+"_hour_1",OBJPROP_RAY,true); ObjectSetInteger(currChart,exprefix+"_hour_1",OBJPROP_COLOR,clrYellow); ObjectSetInteger(currChart,exprefix+"_hour_1",OBJPROP_BACK,true); tmpOffset++; TimeToStruct(rates[tmpOffset].time, tmpTime); if(tmpTime.min!=0){ tmpOffset++; } ObjectCreate(currChart, exprefix+"_hour_2", OBJ_VLINE, 0, rates[tmpOffset].time, 0); ObjectSetInteger(currChart,exprefix+"_hour_2",OBJPROP_SELECTABLE,false); ObjectSetInteger(currChart,exprefix+"_hour_2",OBJPROP_STYLE,STYLE_DOT); ObjectSetInteger(currChart,exprefix+"_hour_2",OBJPROP_RAY,true); ObjectSetInteger(currChart,exprefix+"_hour_2",OBJPROP_COLOR,clrYellow); [/CODE] 逐行看:ArraySetAsSeries 让 rates[0] 是最新柱;CopyRates 取 M30 的 9 根,足够向后推 4 个整点。每次用 TimeToStruct 看分钟,不是整点就 tmpOffset++ 跳到前一根,直到分钟为 0 才画 OBJ_VLINE。线设为黄点、不可选中、向右延伸、衬在背景,避免挡住价格。 外汇和贵金属波动受时段流动性影响大,这类整点参考线仅作视角辅助,实际触碰后的反转或突破倾向需结合量价判断,杠杆品种高风险。

MQL5 / C++
class=class="str">"cmt">/*
在图表上显示最后四小时
currChart - 图表 id
*/
class="type">void showCloseHour(class="type">long currChart){
  class="type">MqlDateTime tmpTime;
  class="type">int tmpOffset=class="num">0;
  class="type">MqlRates rates[];
  ArraySetAsSeries(rates, true);
  if(CopyRates(ChartSymbol(currChart), PERIOD_M30, class="num">0, class="num">9, rates)>class="num">0){
    tmpOffset=class="num">0;
    TimeToStruct(rates[tmpOffset].time, tmpTime);
    if(tmpTime.min!=class="num">0){
       tmpOffset++;
    }
    ObjectCreate(currChart, exprefix+"_hour_0", OBJ_VLINE, class="num">0, rates[tmpOffset].time, class="num">0);
    ObjectSetInteger(currChart,exprefix+"_hour_0",OBJPROP_SELECTABLE,false);
    ObjectSetInteger(currChart,exprefix+"_hour_0",OBJPROP_STYLE,STYLE_DOT);
    ObjectSetInteger(currChart,exprefix+"_hour_0",OBJPROP_RAY,true);
    ObjectSetInteger(currChart,exprefix+"_hour_0",OBJPROP_COLOR,clrYellow);
    ObjectSetInteger(currChart,exprefix+"_hour_0",OBJPROP_BACK,true);
    tmpOffset++;
    TimeToStruct(rates[tmpOffset].time, tmpTime);
    if(tmpTime.min!=class="num">0){
       tmpOffset++;
    }
    ObjectCreate(currChart, exprefix+"_hour_1", OBJ_VLINE, class="num">0, rates[tmpOffset].time, class="num">0);
    ObjectSetInteger(currChart,exprefix+"_hour_1",OBJPROP_SELECTABLE,false);
    ObjectSetInteger(currChart,exprefix+"_hour_1",OBJPROP_STYLE,STYLE_DOT);
    ObjectSetInteger(currChart,exprefix+"_hour_1",OBJPROP_RAY,true);
    ObjectSetInteger(currChart,exprefix+"_hour_1",OBJPROP_COLOR,clrYellow);
    ObjectSetInteger(currChart,exprefix+"_hour_1",OBJPROP_BACK,true);
    tmpOffset++;
    TimeToStruct(rates[tmpOffset].time, tmpTime);
    if(tmpTime.min!=class="num">0){
       tmpOffset++;
    }
    ObjectCreate(currChart, exprefix+"_hour_2", OBJ_VLINE, class="num">0, rates[tmpOffset].time, class="num">0);
    ObjectSetInteger(currChart,exprefix+"_hour_2",OBJPROP_SELECTABLE,false);
    ObjectSetInteger(currChart,exprefix+"_hour_2",OBJPROP_STYLE,STYLE_DOT);
    ObjectSetInteger(currChart,exprefix+"_hour_2",OBJPROP_RAY,true);
    ObjectSetInteger(currChart,exprefix+"_hour_2",OBJPROP_COLOR,clrYellow);

用竖线把整点切进图表背景

这段逻辑紧接前一小时线的绘制,继续往图表上叠参考线。它先给上一条线设了 OBJPROP_BACK 为 true,让线沉到 K 线后面不挡视野,再把 tmpOffset 自增 1 准备取下一根 bar 的时间。 TimeToStruct 把 rates[tmpOffset].time 拆成结构,若分钟字段不等于 0,说明这根 bar 不是整点开盘,就再 tmpOffset++ 跳到下一根,确保抓到的是整点时刻。外汇与贵金属市场跳空常见,这种偏移处理能避免把非整点线误画成小时分割线,属于高风险品种下的细节防错。 随后 ObjectCreate 用 OBJ_VLINE 在当前图表画一条名为 exprefix+"_hour_3" 的竖线,时间锚定在修正后的 rates[tmpOffset].time。接着一口气设了不可选中、点线样式、向右延伸射线、黄色、置底背景——跑起来你会在 MT5 上看到一条从整点向右点状延伸的黄色参考线。

MQL5 / C++
   ObjectSetInteger(currChart,exprefix+"_hour_2",OBJPROP_BACK,true);
   tmpOffset++;
   TimeToStruct(rates[tmpOffset].time, tmpTime);
   if(tmpTime.min!=class="num">0){
      tmpOffset++;
   }
   ObjectCreate(currChart, exprefix+"_hour_3", OBJ_VLINE, class="num">0, rates[tmpOffset].time, class="num">0);
   ObjectSetInteger(currChart,exprefix+"_hour_3",OBJPROP_SELECTABLE,false);
   ObjectSetInteger(currChart,exprefix+"_hour_3",OBJPROP_STYLE,STYLE_DOT);
   ObjectSetInteger(currChart,exprefix+"_hour_3",OBJPROP_RAY,true);
   ObjectSetInteger(currChart,exprefix+"_hour_3",OBJPROP_COLOR,clrYellow);
   ObjectSetInteger(currChart,exprefix+"_hour_3",OBJPROP_BACK,true);
   
   }

「把近12个月极值钉在图上」

很多做波段的外汇、贵金属交易者会盯住年内的高/低点,因为它们往往是挂单和止损的密集区。直接在 MT5 图表上画出过去 12 根月线的极值,比手动翻日线省事得多,也避免肉眼读错。 下面这个函数从当前图表取月线数据,统计近 12 个月的最高 high 与最低 low,再用两条紫色水平线标出来。CopyRates 的第三个参数填 0、第四个填 12,表示取最新的 12 根月 K;若返回值不等于 12 就直接跳过,不画图。 [CODE] /* 在图表上显示去年的最高和最低价格。 currChart - 图表 id. */ void showMaxPrice(long currChart){ MqlRates rates[]; // 声明 rates 数组存放 K 线数据 ArraySetAsSeries(rates, true); // 设为时间序列,下标0为最新月 if(CopyRates(ChartSymbol(currChart), PERIOD_MN1, 0, 12, rates)==12){ // 取12根月线成功才继续 double maxPrice=0; // 初始化最高价变量 double minPrice=0; // 初始化最低价变量 for(int j=0; j<12; j++){ // 遍历近12个月

if( maxPrice==0maxPrice<rates[j].high ){ // 首次或遇到更高高点

maxPrice=rates[j].high; // 更新最高价 }

if( minPrice==0minPrice>rates[j].low ){ // 首次或遇到更低低点

minPrice=rates[j].low; // 更新最低价 } } ObjectCreate(currChart, exprefix+"_maxprice_line", OBJ_HLINE, 0, 0, maxPrice); // 建最高价水平线 ObjectSetInteger(currChart,exprefix+"_maxprice_line",OBJPROP_COLOR,clrMagenta); // 紫色 ObjectSetInteger(currChart,exprefix+"_maxprice_line",OBJPROP_SELECTABLE,false); // 不可选中 ObjectSetInteger(currChart,exprefix+"_maxprice_line",OBJPROP_BACK,true); // 置后显示 ObjectCreate(currChart, exprefix+"_minprice_line", OBJ_HLINE, 0, 0, minPrice); // 建最低价水平线 ObjectSetInteger(currChart,exprefix+"_minprice_line",OBJPROP_COLOR,clrMagenta); // 紫色 ObjectSetInteger(currChart,exprefix+"_minprice_line",OBJPROP_SELECTABLE,false); // 不可选中 ObjectSetInteger(currChart,exprefix+"_minprice_line",OBJPROP_BACK,true); // 置后显示 } } [/CODE] 紫色线只是视觉参考,价格触及后可能反弹也可能直接破位,外汇和贵金属杠杆高、波动快,真要依托它做单得自己加确认信号。把 exprefix 换成你的前缀串,在 OnChartEvent 或 OnInit 里调一次 showMaxPrice(ChartID()) 就能看到效果。

MQL5 / C++
class=class="str">"cmt">/*
在图表上显示去年的最高和最低价格。
currChart - 图表 id.
*/
class="type">void showMaxPrice(class="type">long currChart){
   class="type">MqlRates rates[];
   ArraySetAsSeries(rates, true);
   if(CopyRates(ChartSymbol(currChart), PERIOD_MN1, class="num">0, class="num">12, rates)==class="num">12){
      class="type">class="kw">double maxPrice=class="num">0;
      class="type">class="kw">double minPrice=class="num">0;


      for(class="type">int j=class="num">0; j<class="num">12; j++){
         if( maxPrice==class="num">0 || maxPrice<rates[j].high ){
            maxPrice=rates[j].high;
         }
         if( minPrice==class="num">0 || minPrice>rates[j].low ){
            minPrice=rates[j].low;
         }
      }

      ObjectCreate(currChart, exprefix+"_maxprice_line", OBJ_HLINE, class="num">0, class="num">0, maxPrice);
      ObjectSetInteger(currChart,exprefix+"_maxprice_line",OBJPROP_COLOR,clrMagenta); 
      ObjectSetInteger(currChart,exprefix+"_maxprice_line",OBJPROP_SELECTABLE,false); 
      ObjectSetInteger(currChart,exprefix+"_maxprice_line",OBJPROP_BACK,true); 
      ObjectCreate(currChart, exprefix+"_minprice_line", OBJ_HLINE, class="num">0, class="num">0, minPrice);
      ObjectSetInteger(currChart,exprefix+"_minprice_line",OBJPROP_COLOR,clrMagenta); 
      ObjectSetInteger(currChart,exprefix+"_minprice_line",OBJPROP_SELECTABLE,false); 
      ObjectSetInteger(currChart,exprefix+"_minprice_line",OBJPROP_BACK,true); 


   }
}

◍ 开图即读点差,但别当实时行情

做小止损策略时,品种点差往往直接决定一笔单子值不值得进。图表一打开就把当前点差亮出来,比事后翻交易品种属性省事得多。 下面这个函数只在图表加载时抓一次点差,写进注释区。它不会跟着报价跳,几分钟后数字就可能偏离真实盘口,仅用于估算该品种点差的大致区间。外汇和贵金属点差受流动性影响波动剧烈,高风险品种更要把这点记牢。 函数返回的是拼接字符串:先算 Ask 减 Bid 的差值,再按品种精度转成文本,附上盈利币种和点数。比如 EURUSD 在常规时段点差约 0.00010(即 1 p),打开图就能直接看到。

MQL5 / C++
class=class="str">"cmt">/*
返回具有指定交易品种的当前点差的字符串。
symname - 交易品种名称
*/
class="type">class="kw">string getmespread_symbol(class="type">class="kw">string symname){
   class="type">class="kw">double curSpread=SymbolInfoDouble(symname, SYMBOL_ASK)-SymbolInfoDouble(symname, SYMBOL_BID);
   class="kw">return "Spread: "+(class="type">class="kw">string) DoubleToString(curSpread, (class="type">int) SymbolInfoInteger(symname, SYMBOL_DIGITS))+" "+SymbolInfoString(symname, SYMBOL_CURRENCY_PROFIT)+" ("+DoubleToString(curSpread/SymbolInfoDouble(symname, SYMBOL_POINT), class="num">0)+" p)";
}

用命令代替手动点选套模板

模板在 MT5 里本是用来一键带出指标和 EA 配置的,但默认操作得进图表右键菜单选「模板/名称」,遇到要同时盯几十上百个品种就变成纯体力活。 若某个指标(比如均线)是你每图必看的决策依据,靠手点显然不现实。MQL5 和 MQL4 通用的 ChartApplyTemplate 能直接按文件名把 .tpl 套到指定图表,省掉所有菜单点击。 下面这行针对当前图表数组里最后一个 ID 套用模板,模板路径由 allApplyTemplate 变量拼接 .tpl 得到。你可以把它塞进循环,对 ChartOpen 返回的所有 ID 批量执行,开盘即带指标。 外汇与贵金属波动剧烈、杠杆高风险大,自动套模板只解决效率,不预示方向。

MQL5 / C++
        ChartApplyTemplate(curChartID[ArraySize(curChartID)-class="num">1], allApplyTemplate+".tpl");
把重复画线交给小布盯盘
这些昨日高低、整数位和开盘竖线的诊断,小布盯盘的 AIGC 已内置,打开对应品种页即可看到,不用自己写 MQL5 挨个挂。把重复劳动交给小布,你专注决策。

常见问题

不少日内流派倾向只做趋势延续的品种,今天方向和昨天不一致的标的容易走出反复扫损的行情,隐藏掉能减少干扰、缩小盯盘范围。
自带分隔会标出每个交易日开始,长期看图表容易杂乱;文中函数只画当前交易日开始的一根竖线,更聚焦单日背景,适合低周期快速判方向。
外汇贵金属高风险,整数位如 0.00 或 0.50 常作自然支撑阻力,价格靠近可能反弹或停滞,结合其他信号可提高进场参考概率。
可以,小布盯盘对应品种页已内置昨日高低、开盘线与整数位等层,无需自行部署 MQL5 程序,省去编译调试时间。
手动给几十个品种挨个加载模板极低效,用名称匹配批量套用,能保持多图视角一致,便于横向比较形态。