MQL4图形对象与信号指标实战
📊

MQL4图形对象与信号指标实战

从对象生命周期到多周期信号表构建

MQL5 编程 难度 · 入门 2026-07-06 9 分钟阅读
#MQL4#图形对象#自定义指标#信号面板

图形对象在交易中的价值

在 MetaTrader 4 终端中,图形对象是我们日常交易最频繁接触的元素之一。手动操作时,交易者会绘制水平支撑阻力线、枢轴点、斐波那契回调位以及各类文字和箭头标记。MQL4 提供的图形对象接口,让这些原本依赖手工的操作可以被脚本或指标自动化完成。例如,你不再需要每天手动计算枢轴点位并逐一画线,一段简单的脚本就能在图表加载时自动计算并绘制所有关键价位。更进一步的,利用图形对象可以开发出信息密度极高的信号指标,把多个指标在不同周期上的状态集中展示,极大降低盯盘负担。

图形对象不仅服务于指标,在脚本(Script)和智能交易系统(EA)中同样通用。理解它们的生命周期和坐标体系,是写出专业级辅助工具的前提。本文作为“面向初学者的 MQL4 语言”系列的第五篇,重点放在对象操作与综合案例,假定你已经了解基本的 MQL4 语法与内置指标函数。

✦ 学习建议
不要试图死记所有对象类型和属性常量。MetaEditor 内置帮助(F1)与参数提示(Ctrl+Shift+空格)足以让你在现场查询任何不熟悉的函数原型与枚举值。

图形对象的通用生命周期

在 MQL4 中处理任意图形对象,都遵循同一套逻辑:创建(Create)→ 修改(Modify)→ 删除(Delete)。这一生命周期清晰且可预测。创建阶段使用 ObjectCreate 确定对象类型与初始坐标;修改阶段通过 ObjectSet / ObjectSetText 调整颜色、线宽、位置等属性;删除阶段则通过 ObjectDelete 或 ObjectsDeleteAll 清理。掌握这个循环,你就能套用到终端支持的全部对象种类上,无论是趋势线、矩形还是文本标签。

创建对象:ObjectCreate 函数详解

所有图形对象的绘制都始于 ObjectCreate。其原型为:bool ObjectCreate(string name, int type, int window, datetime time1, double price1, datetime time2=0, double price2=0, datetime time3=0, double price3=0)。函数成功返回 true,失败返回 false,此时应调用 GetLastError 获取错误码并在日志中输出,便于排查。参数 name 是对象唯一标识,同名对象不可重复创建;type 来自标准常数中的对象类型枚举(如 OBJ_HLINE 水平线、OBJ_LABEL 标签);window 为窗口编号,主图填 0;time1/price1 是第一个点的时间(X轴)与价格(Y轴)坐标,复杂对象如矩形、三角形需追加 time2/price2 甚至 time3/price3。

bool ObjectCreate(string name, int type, int window, datetime time1, 
                  double price1, datetime time2=0,double price2=0, 
                  datetime time3=0, double price3=0)

不同对象所需点数不同:水平线只需一个价格点;线段需两个;三角形需三个。若参数不足或类型不匹配,创建会失败。以下示例标记昨日最高最低价水平线,注意我们省略了错误检查以突出主干,实盘代码务必加上 GetLastError 处理。

int  start()
{
   double price=iHigh(Symbol(),PERIOD_D1,0);
   ObjectCreate("highLine",OBJ_HLINE,0,0,price);
   price=iLow(Symbol(),PERIOD_D1,0);
   ObjectCreate("lowLine",OBJ_HLINE,0,0,price);
   return(0);
}
⚠ 常见坑
给对象取固定名称(如 "line")时,若图表已存在同名对象,二次创建会返回 false。建议在名称中拼接时间戳或计数器保证唯一性,或在 init 中先 ObjectsDeleteAll 清理。

修改与删除对象属性

对象创建后,使用 ObjectSet(name, index, value) 修改其属性。index 来自对象属性常数(如 OBJPROP_COLOR、OBJPROP_WIDTH、OBJPROP_STYLE)。以下代码将上例两条线改为浅绿粗线与深红点线,提升可视性。

int  start()
{
   double price=iHigh(Symbol(),PERIOD_D1,0);
   ObjectCreate("highLine",OBJ_HLINE,0,0,price);
   price=iLow(Symbol(),PERIOD_D1,0);
   ObjectCreate("lowLine",OBJ_HLINE,0,0,price);
   ObjectSet("highLine",OBJPROP_COLOR,LimeGreen);
   ObjectSet("highLine",OBJPROP_WIDTH,3);
   ObjectSet("lowLine",OBJPROP_COLOR,Crimson);
   ObjectSet("lowLine",OBJPROP_STYLE,STYLE_DOT);
   return(0);
}

删除方面,ObjectDelete(name) 按名删除,失败时返回 false;ObjectsDeleteAll(window=EMPTY, type=EMPTY) 则批量删除,省略参数即清空当前图表全部对象,指定类型如 OBJ_ARROW 可只删箭头。指标卸载时应在 deinit 中调用 ObjectsDeleteAll 防止残留。

bool ObjectDelete(string name);
int ObjectsDeleteAll(int window=EMPTY,int type=EMPTY);
ObjectsDeleteAll();
ObjectsDeleteAll(0, OBJ_ARROW);

利用帮助系统自学新对象

MQL4 对象类型繁多,无需背诵。在 MetaEditor 中写函数名留空参数,光标置于函数内按 F1,帮助窗口即显示说明与参数细节;点开 type 参数链接可览全部对象类型。例如绘制椭圆 OBJ_ELLIPSE 需两个对角点,设置 OBJPROP_SCALE=1 可获正圆(还需图表属性中设 1:1 比例)。按 Ctrl+Shift+空格 可在编码时呼出参数提示。这种查询驱动的学习方式,能让你独立掌握任何未接触过的图形元素。

int  start()
{
   ObjectCreate("ellipse",OBJ_ELLIPSE,0,Time[100],Low[100],Time[0],High[0]);
   return(0);
}

子窗口中绘制对象的陷阱

当指标声明 indicator_separate_window 时,它拥有独立子窗口。若在 init 中直接用 WindowFind 获取窗号并画线,常因终端初始化顺序而导致找不到窗口(返回 -1),线不显示,直到切换周期才出现。规避方案是引入 initFinished 标志,将创建逻辑推迟到 start 首次执行时,此时子窗口已存在。以下为修正版核心结构。

bool initFinished=false;
int init(){ return(0); }
int deinit(){ ObjectsDeleteAll(); return(0); }
int start()
{
   if(initFinished==false)
   {
      IndicatorShortName("NiceLine");
      int windowIndex=WindowFind("NiceLine");
      if(windowIndex<0){ Print("Can't find window"); return(0); }
      ObjectCreate("line",OBJ_HLINE,windowIndex,0,5.0);
      ObjectSet("line",OBJPROP_COLOR,GreenYellow);
      ObjectSet("line",OBJPROP_WIDTH,3);
      WindowRedraw();
      initFinished=true;
   }
   return(0);
}
⚠ 关键记忆点
子窗口编号只能在 start 中获取,不可在 init 中依赖。任何依赖子窗口存在的对象创建,都应延后至 start 首轮。

OBJ_LABEL:像素坐标的固定标签

多数对象绑定时间/价格坐标,随图表滚动而移动,不适合做固定信号面板。OBJ_LABEL 例外:它以像素定位(OBJPROP_XDISTANCE/YDISTANCE),左上角为 (0,0),X 右增左减,Y 下增上减,且不因图表平移错位。用它可搭建稳定信号表。创建时不传坐标,后用 ObjectSet 设距离,ObjectSetText 设文字、字体、颜色。Wingdings 字体提供方块、圆点等符号,通过 CharToStr(代码) 调用。

int init()
{
   ObjectCreate("signal",OBJ_LABEL,0,0,0,0,0);
   ObjectSet("signal",OBJPROP_XDISTANCE,50);
   ObjectSet("signal",OBJPROP_YDISTANCE,50);
   ObjectSetText("signal","lambada",14,"Tahoma",Gold);
   return(0);
}

构建多周期信号表格模型

我们目标:用 9 列(M1~MN1)x 3 行(MA、WPR、SAR)的色块,直观显示多指标多周期信号。先用双重循环批量生成标签,名称动态拼接 "signal"+x+y,位置按 x*20、y*20 排布,初始用 Wingdings 方块 110 码金色。加上 offsetX/offsetY 缩进避免被图表文字遮挡。

int init()
{
   for(int x=0;x<9;x++)
      for(int y=0;y<3;y++)
      {
         ObjectCreate("signal"+x+y,OBJ_LABEL,0,0,0,0,0);
         ObjectSet("signal"+x+y,OBJPROP_XDISTANCE,x*20+12);
         ObjectSet("signal"+x+y,OBJPROP_YDISTANCE,y*20+20);
         ObjectSetText("signal"+x+y,CharToStr(110),20,"Wingdings",Gold);
      }
   return(0);
}

周期无规律,故声明数组 period[]={1,5,15,30,60,240,1440,10080,43200} 与 periodString[] 对应文字。在 start 中循环比对 iMA 快慢线,绿涨红跌。第二行用 iWPR 绝对值判买卖,第三行用 iSAR 与 Close 比较,无信号置灰。以下为激活三行的核心。

int start()
{
   for(int x=0;x<9;x++)
   {
      if(iMA(Symbol(),period[x],13,0,0,0,0)>iMA(Symbol(),period[x],24,0,0,0,0))
         ObjectSetText("signal"+x+"0",CharToStr(110),20,"Wingdings",YellowGreen);
      else
         ObjectSetText("signal"+x+"0",CharToStr(110),20,"Wingdings",Tomato);
   }
   for(x=0;x<9;x++)
   {
      if(MathAbs(iWPR(Symbol(),period[x],13,0))<20.0)
         ObjectSetText("signal"+x+"1",CharToStr(110),20,"Wingdings",YellowGreen);
      else if(MathAbs(iWPR(Symbol(),period[x],13,0))>80.0)
         ObjectSetText("signal"+x+"1",CharToStr(110),20,"Wingdings",Tomato);
      else
         ObjectSetText("signal"+x+"1",CharToStr(110),20,"Wingdings",DarkGray);
   }
   for(x=0;x<9;x++)
   {
      if(iSAR(Symbol(),period[x],0.02,0.2,0)<Close[0])
         ObjectSetText("signal"+x+"2",CharToStr(110),20,"Wingdings",YellowGreen);
      else
         ObjectSetText("signal"+x+"2",CharToStr(110),20,"Wingdings",Tomato);
   }
   return(0);
}

参数化与外观灵活配置

为让指标通用,用 extern 暴露 scaleX、scaleY、offsetX、offsetY、fontSize、corner(0~3角)、symbolCodeBuy/Sell/NoSignal 及各类 color。corner 改 OBJPROP_CORNER 可绑定任意角落;外部参数使用户免改代码即可换肤。最终 init 据参数布点,start 据参数上色,形成完整可复用信号面板。读者可作业添加新行(如 RSI)与新参数(文字大小),深化理解。

extern int scaleX=20, scaleY=20, offsetX=35, offsetY=20, fontSize=20, corner=0;
extern int symbolCodeBuy=110, symbolCodeSell=110, symbolCodeNoSignal=110;
extern color signalBuyColor=YellowGreen, signalSellColor=Tomato, noSignalColor=DarkGray, textColor=Gold;
✦ 扩展练习
尝试增加一行基于 iRSI 的信号,并添加 extern 控制标签字体大小,体会参数驱动开发的便利。

常见问题

检查返回值,若false则立即用GetLastError()获取代码,在MQL4参考->标准常数->错误代码中查说明;常见原因为同名对象已存在、window编号错或坐标参数不足。
因init时子窗口尚未创建,WindowFind返回-1。应将对象创建移至start首次执行,并用bool标志控制只建一次,如文中initFinished方案。
使用OBJ_LABEL类型,通过ObjectSet设OBJPROP_XDISTANCE/YDISTANCE像素坐标,配合ObjectSetText写文字;它基于像素定位,不受平移影响。
调用ObjectsDeleteAll(0, OBJ_ARROW); 第一参数0指主图,第二参数指定类型;无参ObjectsDeleteAll()会删全部对象。
MetaEditor中写ObjectCreate留空参数,光标放函数内按F1看帮助,点type链接览所有对象;编码时按Ctrl+Shift+空格呼出参数提示。