MQL4图形对象与信号指标实战
从对象生命周期到多周期信号表构建
图形对象在交易中的价值
在 MetaTrader 4 终端中,图形对象是我们日常交易最频繁接触的元素之一。手动操作时,交易者会绘制水平支撑阻力线、枢轴点、斐波那契回调位以及各类文字和箭头标记。MQL4 提供的图形对象接口,让这些原本依赖手工的操作可以被脚本或指标自动化完成。例如,你不再需要每天手动计算枢轴点位并逐一画线,一段简单的脚本就能在图表加载时自动计算并绘制所有关键价位。更进一步的,利用图形对象可以开发出信息密度极高的信号指标,把多个指标在不同周期上的状态集中展示,极大降低盯盘负担。
图形对象不仅服务于指标,在脚本(Script)和智能交易系统(EA)中同样通用。理解它们的生命周期和坐标体系,是写出专业级辅助工具的前提。本文作为“面向初学者的 MQL4 语言”系列的第五篇,重点放在对象操作与综合案例,假定你已经了解基本的 MQL4 语法与内置指标函数。
图形对象的通用生命周期
在 MQL4 中处理任意图形对象,都遵循同一套逻辑:创建(Create)→ 修改(Modify)→ 删除(Delete)。这一生命周期清晰且可预测。创建阶段使用 ObjectCreate 确定对象类型与初始坐标;修改阶段通过 ObjectSet / ObjectSetText 调整颜色、线宽、位置等属性;删除阶段则通过 ObjectDelete 或 ObjectsDeleteAll 清理。掌握这个循环,你就能套用到终端支持的全部对象种类上,无论是趋势线、矩形还是文本标签。
- 创建: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);
}
修改与删除对象属性
对象创建后,使用 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);
}
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;