创建具有图形控制选项的指标·综合运用
(3/3)·把传统、Elder、三色OSMA等五种MACD变型塞进一个带图形开关的指标里
在指标里塞两个图表开关按钮
这段逻辑演示了如何不依赖外部脚本,直接在自定义指标里画出两个右上角按钮,用来切换 MACD 主图线的显示状态。按钮坐标用 CORNER_RIGHT_UPPER 锚定,X 距离 75 像素、Y 距离分别 5 和 30,尺寸 70×20,字号 8,且设成不可选中,避免误拖。 核心判定在尾部:若名为 ShowMACD 的按钮 OBJPROP_STATE 不等于 1,就把 PlotIndex 0 和 1 的绘制类型设为 DRAW_NONE,主线与信号线直接从图表消失;否则走 else 分支恢复绘制。 外汇与贵金属波动剧烈、杠杆风险高,这类显示开关仅改变视觉呈现,不改变任何信号计算逻辑,实盘使用前建议在 MT5 策略测试器里先验证按钮状态读取是否如预期。
const class="type">long &volume[], const class="type">int &spread[]) { ArraySetAsSeries(HistogramBuffer,false); ArraySetAsSeries(HistogramColors,false); class="type">int MACDhadling=iMACD(NULL,class="num">0,Fast,Slow,Signal,PRICE_CLOSE); CopyBuffer(MACDhadling,class="num">0,class="num">0,rates_total,MACDlineBuffer); CopyBuffer(MACDhadling,class="num">1,class="num">0,rates_total,SignallineBuffer); for(class="type">int i=class="num">0;i<rates_total;i++) { HistogramBuffer[i]=MACDlineBuffer[i]-SignallineBuffer[i];HistogramColors[i]=class="num">1; } ObjectCreate(class="num">0,"ShowMACD",OBJ_BUTTON,ChartWindowFind(),class="num">100,class="num">100); ObjectSetInteger(class="num">0,"ShowMACD",OBJPROP_XDISTANCE,class="num">75); ObjectSetInteger(class="num">0,"ShowMACD",OBJPROP_YDISTANCE,class="num">5); ObjectSetInteger(class="num">0,"ShowMACD",OBJPROP_CORNER,CORNER_RIGHT_UPPER); ObjectSetString(class="num">0,"ShowMACD",OBJPROP_TEXT,"ShowMACD"); ObjectSetInteger(class="num">0,"ShowMACD",OBJPROP_FONTSIZE,class="num">8); ObjectSetInteger(class="num">0,"ShowMACD",OBJPROP_XSIZE,class="num">70); ObjectSetInteger(class="num">0,"ShowMACD",OBJPROP_YSIZE,class="num">20); ObjectSetInteger(class="num">0,"ShowMACD",OBJPROP_SELECTABLE,false); ObjectCreate(class="num">0,"ShowOsMA",OBJ_BUTTON,ChartWindowFind(),class="num">100,class="num">100); ObjectSetInteger(class="num">0,"ShowOsMA",OBJPROP_XDISTANCE,class="num">75); ObjectSetInteger(class="num">0,"ShowOsMA",OBJPROP_YDISTANCE,class="num">30); ObjectSetInteger(class="num">0,"ShowOsMA",OBJPROP_CORNER,CORNER_RIGHT_UPPER); ObjectSetString(class="num">0,"ShowOsMA",OBJPROP_TEXT,"Show OsMA"); ObjectSetInteger(class="num">0,"ShowOsMA",OBJPROP_FONTSIZE,class="num">8); ObjectSetInteger(class="num">0,"ShowOsMA",OBJPROP_XSIZE,class="num">70); ObjectSetInteger(class="num">0,"ShowOsMA",OBJPROP_YSIZE,class="num">20); ObjectSetInteger(class="num">0,"ShowOsMA",OBJPROP_SELECTABLE,false); if(ObjectGetInteger(class="num">0,"ShowMACD",OBJPROP_STATE)!=class="num">1) { PlotIndexSetInteger(class="num">0,PLOT_DRAW_TYPE,DRAW_NONE); PlotIndexSetInteger(class="num">1,PLOT_DRAW_TYPE,DRAW_NONE); } else {
「用按钮切换 MACD 绘制样式」
在指标初始化尾部,先用 PlotIndexSetInteger 把前两条线强制设为 DRAW_LINE,保证快线慢线永远以线性呈现,不会因外部设置丢失画法。 OsMA 柱体的显隐由名为 ShowOsMA 的图表对象状态控制:若其 OBJPROP_STATE 不等于 1,第 2 号绘图索引改为 DRAW_NONE 直接隐藏;否则切到 DRAW_COLOR_HISTOGRAM 画彩色柱。 随后在右下角(CORNER_RIGHT_LOWER)创建两个不可选按钮:2color 距右 75 像素、距底 50 像素,尺寸 70×20,字号 8;Impulse 距底 25 像素,其余几何参数一致。按钮文字初值分别为 MultiColor 与 Impulse。 如果 2color 按钮处于按下状态(OBJPROP_STATE 为真),就把它的标签改写成 2ColorMACD,否则维持 MultiColor——这给了交易者在 MT5 上不重编译就切换配色方案的直接入口。外汇与贵金属波动剧烈,这类视觉开关只辅助读图,不构成方向判断。
PlotIndexSetInteger(class="num">0,PLOT_DRAW_TYPE,DRAW_LINE); PlotIndexSetInteger(class="num">1,PLOT_DRAW_TYPE,DRAW_LINE); } if(ObjectGetInteger(class="num">0,"ShowOsMA",OBJPROP_STATE)!=class="num">1) { PlotIndexSetInteger(class="num">2,PLOT_DRAW_TYPE,DRAW_NONE); } else { PlotIndexSetInteger(class="num">2,PLOT_DRAW_TYPE,DRAW_COLOR_HISTOGRAM); } ObjectCreate(class="num">0,"2color",OBJ_BUTTON,ChartWindowFind(),class="num">100,class="num">100); ObjectSetInteger(class="num">0,"2color",OBJPROP_XDISTANCE,class="num">75); ObjectSetInteger(class="num">0,"2color",OBJPROP_YDISTANCE,class="num">50); ObjectSetInteger(class="num">0,"2color",OBJPROP_CORNER,CORNER_RIGHT_LOWER); ObjectSetInteger(class="num">0,"2color",OBJPROP_FONTSIZE,class="num">8); ObjectSetInteger(class="num">0,"2color",OBJPROP_XSIZE,class="num">70); ObjectSetInteger(class="num">0,"2color",OBJPROP_YSIZE,class="num">20); ObjectSetInteger(class="num">0,"2color",OBJPROP_SELECTABLE,false); ObjectSetString(class="num">0,"2color",OBJPROP_TEXT,"MultiColor"); ObjectCreate(class="num">0,"Impulse",OBJ_BUTTON,ChartWindowFind(),class="num">100,class="num">100); ObjectSetInteger(class="num">0,"Impulse",OBJPROP_XDISTANCE,class="num">75); ObjectSetInteger(class="num">0,"Impulse",OBJPROP_YDISTANCE,class="num">25); ObjectSetInteger(class="num">0,"Impulse",OBJPROP_CORNER,CORNER_RIGHT_LOWER); ObjectSetInteger(class="num">0,"Impulse",OBJPROP_FONTSIZE,class="num">8); ObjectSetInteger(class="num">0,"Impulse",OBJPROP_XSIZE,class="num">70); ObjectSetInteger(class="num">0,"Impulse",OBJPROP_YSIZE,class="num">20); ObjectSetInteger(class="num">0,"Impulse",OBJPROP_SELECTABLE,false); ObjectSetString(class="num">0,"Impulse",OBJPROP_TEXT,"Impulse"); if(ObjectGetInteger(class="num">0,"2color",OBJPROP_STATE)) ObjectSetString(class="num">0,"2color",OBJPROP_TEXT,"2ColorMACD"); else ObjectSetString(class="num">0,"2color",OBJPROP_TEXT,"MultiColor");
◍ 双色与三色脉冲的着色分支
这段逻辑决定了直方图上色到底看几层确认。先根据界面开关切换标签文字:若名为 Impulse 的物件处于激活态,文本写 Impulse,否则写 Elder's;同时用 iMA 取周期 EldersEMA、模式 MODE_EMA、价格 PRICE_CLOSE 的均线句柄,经 CopyBuffer 把数据塞进 EldersiEMA 数组,供后续比较。 若 2color 开关打开,只比直方图自身前后根:HistogramBuffer[i] 大于前一根则颜色索引 0,小于则 1,不判方向强度。这种画法在震荡市里可能更敏感,但也更容易被毛刺刷色。 2color 关闭时才进真正的脉冲确认。Impulse 开时,要求直方图与 MACDlineBuffer 同向上行才给色 0,同向下行给色 1,其余情况归为色 2(犹豫区);Impulse 关时把 MACD 线换成 EldersiEMA 均线做同样比对。外汇与贵金属波动大,色 2 占比高时往往意味趋势动能未共振,入场概率倾向偏弱。 最后 return(rates_total) 把已处理柱数交还系统,下一 tick 从缓存接续,避免重复算整段历史。
if(ObjectGetInteger(class="num">0,"Impulse",OBJPROP_STATE)) ObjectSetString(class="num">0,"Impulse",OBJPROP_TEXT,"Impulse"); else ObjectSetString(class="num">0,"Impulse",OBJPROP_TEXT,"Elder&class="macro">#x27;s"); CopyBuffer(iMA(NULL,class="num">0,EldersEMA,class="num">0,MODE_EMA,PRICE_CLOSE),class="num">0,class="num">0,rates_total,EldersiEMA); if(ObjectGetInteger(class="num">0,"2color",OBJPROP_STATE)) { for(class="type">int i=class="num">1;i<rates_total;i++) { if(HistogramBuffer[i] > HistogramBuffer[i-class="num">1]) HistogramColors[i]=class="num">0; if(HistogramBuffer[i] < HistogramBuffer[i-class="num">1]) HistogramColors[i]=class="num">1; } } else { if(ObjectGetInteger(class="num">0,"Impulse",OBJPROP_STATE)) { for(class="type">int i=class="num">1;i<rates_total;i++) { if((HistogramBuffer[i]>HistogramBuffer[i-class="num">1]) && (MACDlineBuffer[i]>MACDlineBuffer[i-class="num">1])) HistogramColors[i]=class="num">0; else { if((HistogramBuffer[i]<HistogramBuffer[i-class="num">1]) && (MACDlineBuffer[i]<MACDlineBuffer[i-class="num">1])) HistogramColors[i]=class="num">1; else HistogramColors[i]=class="num">2; } } } else { for(class="type">int i=class="num">1;i<rates_total;i++) { if((HistogramBuffer[i]>HistogramBuffer[i-class="num">1]) && (EldersiEMA[i]>EldersiEMA[i-class="num">1])) HistogramColors[i]=class="num">0; else { if((HistogramBuffer[i]<HistogramBuffer[i-class="num">1]) && (EldersiEMA[i]<EldersiEMA[i-class="num">1])) HistogramColors[i]=class="num">1; else HistogramColors[i]=class="num">2; } } } } class=class="str">"cmt">//--- 返回prev_calculated的值用于下一次调用 class="kw">return(rates_total); }
记住这一条就够了
图形控件这套思路在 MT5 里落地的关键,是把交互从鼠标点击转成全局变量状态驱动。原文评论区里 Mykola Demko 想在 MT4 跑同款指标被劝退,根因是 MQL4 缺 OBJ_BUTTON 这类对象,只能拿挂热键的脚本改全局变量凑合。 外汇与贵金属市场高波动、高杠杆,任何控件方案都只是辅助你看清盘口,不替你下注。真要验证,开 MT5 新建指标把下面这行对象类型丢进 OnChartEvent,按一次键看按钮是否实时响应,比读十篇文都实在。 [OBJ_BUTTON] 是 MT5 图表里可点击控件的底层类型,缺了它 MT4 那套按钮逻辑直接废掉。
OBJ_BUTTON