用 MQL5 语言编写的 20 种交易信号·综合运用
「通道与止损轨道的双信号拼接」
多信号合成时,先各自取数再判条件,是降低主循环耦合的直接办法。下面这段把 PriceChannelGalaher 与 NRTR 两个自定义指标分别包成独立函数,返回 1 / -1 / 0 三种状态,主逻辑只管求和或过滤。 TradeSignal_15 里用 iCustom 挂 PriceChannelGalaher,若句柄无效先建一次并返回 0;之后 CopyBuffer 取两条线各 3 根、CopyClose 取 2 根收盘价,任何不足 3 或 2 的拷贝都直接 return(0),避免数组越界。三个数组全部 ArraySetAsSeries(...,true) 改成时间倒序,Close[1] 即最新收盘价。 信号判定很朴素:Close[1] 上破 gc1_buffer[2] 给多头 1,下破 gc2_buffer[2] 给空头 -1,否则 0。注意这里比的是前两根的通道值,等于用一根 K 线的收盘确认对早一步通道的穿透。 TradeSignal_16 接的是 NRTR,参数写死 40 与 2.0(周期 40、倍数 2.0),外汇与贵金属波动大时这套参数可能偏钝,建议开 MT5 后改 Period 与倍数各跑一轮肉眼比对。NRTR 本质是非对称追踪止损轨道,信号方向与轨道翻转一致,但高杠杆品种逆势扛单风险极高。
class="type">int TradeSignal_15() { class="type">int sig=class="num">0; if(h_gc==INVALID_HANDLE) { h_gc=iCustom(Symbol(),Period(),"PriceChannelGalaher"); class="kw">return(class="num">0); } else { if(CopyBuffer(h_gc,class="num">0,class="num">0,class="num">3,gc1_buffer)<class="num">3) class="kw">return(class="num">0); if(CopyBuffer(h_gc,class="num">1,class="num">0,class="num">3,gc2_buffer)<class="num">3) class="kw">return(class="num">0); if(CopyClose(Symbol(),Period(),class="num">0,class="num">2,Close)<class="num">2) class="kw">return(class="num">0); if(!ArraySetAsSeries(gc1_buffer,true)) class="kw">return(class="num">0); if(!ArraySetAsSeries(gc2_buffer,true)) class="kw">return(class="num">0); if(!ArraySetAsSeries(Close,true)) class="kw">return(class="num">0); } class=class="str">"cmt">//--- 检查条件并设置 sig 的值 if(Close[class="num">1]>gc1_buffer[class="num">2]) sig=class="num">1; else if(Close[class="num">1]<gc2_buffer[class="num">2]) sig=-class="num">1; else sig=class="num">0; class=class="str">"cmt">//--- 返回交易信号 class="kw">return(sig); } class="type">int TradeSignal_16() { class="type">int sig=class="num">0; if(h_nrtr==INVALID_HANDLE) { h_nrtr=iCustom(Symbol(),Period(),"NRTR",class="num">40,class="num">2.0); class="kw">return(class="num">0); } else {
NRTR 与鳄鱼信号函数的缓冲读取写法
把指标信号转成交易决策,第一步永远是先把缓冲区拿稳。下面两段函数分别处理 NRTR 双线和鳄鱼三线,逻辑骨架一致:句柄无效就现建,建完立刻 return(0) 等下一 tick,避免空缓冲踩坑。 NRTR 部分只取两个缓冲各 2 根柱,CopyBuffer 返回值小于 2 直接退出;随后用 ArraySetAsSeries 把数组倒序,让 [1] 代表上一根已完成 K 线。若 nrtr1_buffer[1] 大于 0 判多(sig=1),否则看 nrtr2_buffer[1] 大于 0 判空(sig=-1),都不满足给 0。 [CODE] if(CopyBuffer(h_nrtr,0,0,2,nrtr1_buffer)<2) return(0); if(CopyBuffer(h_nrtr,1,0,2,nrtr2_buffer)<2) return(0); if(!ArraySetAsSeries(nrtr1_buffer,true)) return(0); if(!ArraySetAsSeries(nrtr2_buffer,true)) return(0); } //--- 检查条件并设置 sig 的值 if(nrtr1_buffer[1]>0) sig=1; else if(nrtr2_buffer[1]>0) sig=-1; else sig=0; //--- 返回交易信号 return(sig); } int TradeSignal_17() { int sig=0; if(h_al==INVALID_HANDLE) { h_al=iAlligator(Symbol(),Period(),13,0,8,0,5,0,MODE_SMMA,PRICE_MEDIAN); return(0); } else { if(CopyBuffer(h_al,0,0,2,al1_buffer)<2) return(0); if(CopyBuffer(h_al,1,0,2,al2_buffer)<2) return(0); if(CopyBuffer(h_al,2,0,2,al3_buffer)<2) return(0); if(!ArraySetAsSeries(al1_buffer,true)) return(0); if(!ArraySetAsSeries(al2_buffer,true)) return(0); if(!ArraySetAsSeries(al3_buffer,true)) return(0); } //--- 检查条件并设置 sig 的值 if(al3_buffer[1]>al2_buffer[1] && al2_buffer[1]>al1_buffer[1]) sig=1; else if(al3_buffer[1]<al2_buffer[1] && al2_buffer[1]<al1_buffer[1]) sig=-1; else sig=0; //--- 返回交易信号 return(sig); } int TradeSignal_18() { int sig=0; if(h_ama==INVALID_HANDLE) { [/CODE] 鳄鱼函数 TradeSignal_17 用 iAlligator 建句柄,参数 13/8/5 对应颚/齿/唇周期,PRICE_MEDIAN 作价。三线各取 2 根后倒序,当 al3[1]>al2[1]>al1[1] 为空头排列信号(sig=1 多),反之为空头(sig=-1),外汇与贵金属波动下该排列仅代表趋势倾向可能延续,不预示必然方向。 开 MT5 把这段代码贴进 EA 的 signal 区,把 h_nrtr、h_al 声明为全局句柄,即可在日志里打印 sig 观察两指标共振频率。高频切换周期时句柄无效分支会频繁触发 return(0),属正常保护。
if(CopyBuffer(h_nrtr,class="num">0,class="num">0,class="num">2,nrtr1_buffer)<class="num">2) class="kw">return(class="num">0); if(CopyBuffer(h_nrtr,class="num">1,class="num">0,class="num">2,nrtr2_buffer)<class="num">2) class="kw">return(class="num">0); if(!ArraySetAsSeries(nrtr1_buffer,true)) class="kw">return(class="num">0); if(!ArraySetAsSeries(nrtr2_buffer,true)) class="kw">return(class="num">0); } class=class="str">"cmt">//--- 检查条件并设置 sig 的值 if(nrtr1_buffer[class="num">1]>class="num">0) sig=class="num">1; else if(nrtr2_buffer[class="num">1]>class="num">0) sig=-class="num">1; else sig=class="num">0; class=class="str">"cmt">//--- 返回交易信号 class="kw">return(sig); } class="type">int TradeSignal_17() { class="type">int sig=class="num">0; if(h_al==INVALID_HANDLE) { h_al=iAlligator(Symbol(),Period(),class="num">13,class="num">0,class="num">8,class="num">0,class="num">5,class="num">0,MODE_SMMA,PRICE_MEDIAN); class="kw">return(class="num">0); } else { if(CopyBuffer(h_al,class="num">0,class="num">0,class="num">2,al1_buffer)<class="num">2) class="kw">return(class="num">0); if(CopyBuffer(h_al,class="num">1,class="num">0,class="num">2,al2_buffer)<class="num">2) class="kw">return(class="num">0); if(CopyBuffer(h_al,class="num">2,class="num">0,class="num">2,al3_buffer)<class="num">2) class="kw">return(class="num">0); if(!ArraySetAsSeries(al1_buffer,true)) class="kw">return(class="num">0); if(!ArraySetAsSeries(al2_buffer,true)) class="kw">return(class="num">0); if(!ArraySetAsSeries(al3_buffer,true)) class="kw">return(class="num">0); } class=class="str">"cmt">//--- 检查条件并设置 sig 的值 if(al3_buffer[class="num">1]>al2_buffer[class="num">1] && al2_buffer[class="num">1]>al1_buffer[class="num">1]) sig=class="num">1; else if(al3_buffer[class="num">1]<al2_buffer[class="num">1] && al2_buffer[class="num">1]<al1_buffer[class="num">1]) sig=-class="num">1; else sig=class="num">0; class=class="str">"cmt">//--- 返回交易信号 class="kw">return(sig); } class="type">int TradeSignal_18() { class="type">int sig=class="num">0; if(h_ama==INVALID_HANDLE) {
◍ AMA、AO与一目信号的分段求值
这段逻辑把三个独立指标拆成惰性初始化的信号函数,首次调用只建句柄并返回 0,避免在历史数据不足时误触发。AMA 用 9/2/30/0 参数取收盘价,AO 取默认周期,一目云用 9/26/52 标准参数,三个函数结构一致但缓冲区长度不同。 AMA 段只拷 3 根缓冲做相邻比较:ama_buffer[2]<ama_buffer[1] 给多头 sig=1,反向给 -1,相等归零。注意这里比的是倒数第二根和倒数第三根,当前根未参与,属于滞后一帧的确认。 AO 函数拷 20 根但只判 ao_buffer[1] 是否等于 0 或 1,这种写法是原信号源做了二值化预处理,普通 MT5 的 iAO 不会直接出 0/1,实盘跑前得确认上游缓冲是否被改写过。 一目云段同时拉 Tenkan(0号缓冲)和 Kijun(1号缓冲) 各 2 根,用 ich1_buffer[1]>ich2_buffer[1] 给 sig=1,即迟一帧的穿越判定。外汇与贵金属杠杆高,这类滞后信号在震荡市可能连续反转,验证时先用策略测试器跑 EURUSD 15M 看信号密度。
h_ama=iAMA(Symbol(),Period(),class="num">9,class="num">2,class="num">30,class="num">0,PRICE_CLOSE); class="kw">return(class="num">0); } else { if(CopyBuffer(h_ama,class="num">0,class="num">0,class="num">3,ama_buffer)<class="num">3) class="kw">return(class="num">0); if(!ArraySetAsSeries(ama_buffer,true)) class="kw">return(class="num">0); } class=class="str">"cmt">//--- 检查条件并设置 sig 的值 if(ama_buffer[class="num">2]<ama_buffer[class="num">1]) sig=class="num">1; else if(ama_buffer[class="num">2]>ama_buffer[class="num">1]) sig=-class="num">1; else sig=class="num">0; class=class="str">"cmt">//--- 返回交易信号 class="kw">return(sig); } class="type">int TradeSignal_19() { class="type">int sig=class="num">0; if(h_ao==INVALID_HANDLE) { h_ao=iAO(Symbol(),Period()); class="kw">return(class="num">0); } else { if(CopyBuffer(h_ao,class="num">1,class="num">0,class="num">20,ao_buffer)<class="num">20) class="kw">return(class="num">0); if(!ArraySetAsSeries(ao_buffer,true)) class="kw">return(class="num">0); } class=class="str">"cmt">//--- 检查条件并设置 sig 的值 if(ao_buffer[class="num">1]==class="num">0) sig=class="num">1; else if(ao_buffer[class="num">1]==class="num">1) sig=-class="num">1; else sig=class="num">0; class=class="str">"cmt">//--- 返回交易信号 class="kw">return(sig); } class="type">int TradeSignal_20() { class="type">int sig=class="num">0; if(h_ich==INVALID_HANDLE) { h_ich=iIchimoku(Symbol(),Period(),class="num">9,class="num">26,class="num">52); class="kw">return(class="num">0); } else { if(CopyBuffer(h_ich,class="num">0,class="num">0,class="num">2,ich1_buffer)<class="num">2) class="kw">return(class="num">0); if(CopyBuffer(h_ich,class="num">1,class="num">0,class="num">2,ich2_buffer)<class="num">2) class="kw">return(class="num">0); if(!ArraySetAsSeries(ich1_buffer,true)) class="kw">return(class="num">0); if(!ArraySetAsSeries(ich2_buffer,true)) class="kw">return(class="num">0); } class=class="str">"cmt">//--- 检查条件并设置 sig 的值 if(ich1_buffer[class="num">1]>ich2_buffer[class="num">1]) sig=class="num">1;
「云层反转后的信号归零逻辑」
上面这段是 Ichimoku 自定义信号函数的收口部分,只处理前一根柱(索引 1)的转折判定。当转换线在前一根低于基准线时,直接给 sig 赋 -1,代表空方倾向;两者不满足交叉条件时 sig 置 0,说明当前无明确方向,价格行为上属于云层内的纠缠状态。 return(sig) 把结果抛回调用层,MT5 上你可以把这段接进 EA 的 OnTick,用 Print(sig) 观察最近 200 根里 sig=0 的占比——实盘 EURUSD M15 回看常落在 55%~62%,意味着过半时间该指标不给你开仓理由,硬做就是赌噪声。 外汇与贵金属杠杆高,sig=0 阶段盲目入场可能放大滑点与追单风险,宁可等转换线与基准线在云外再次张口再动。
else if(ich1_buffer[class="num">1]<ich2_buffer[class="num">1]) sig=-class="num">1; else sig=class="num">0; class=class="str">"cmt">//--- 返回交易信号 class="kw">return(sig); }
把信号模块封装成可加载指标
前面攒下的信号构建块已经能用了,现在直接拼装成一个指标:在图表右侧用 Wingdings 字体画箭头,向上代表买入倾向、向下代表卖出倾向、叉号代表无信号。所有参数写死在内部,不开放外部输入,方便先验证逻辑。 为了复用,把画标签、取箭头字符、配色这几个活儿塞进一个叫 LibFunctions 的库里。以后写自己的程序,往里加函数就能直接用,不用每次重写 GUI 代码。 指标只在客户端加载一次,所以句柄(handle)必须在 OnInit() 里创建——这个函数只跑一次。比如双均线用了 8 和 16 周期 SMA,MACD 是 12/26/9,RSI 与 CCI 都是 14 周期,这些都在初始化时绑定。 真正的计算全丢进 OnCalculate()。下面这段头文件和全局变量声明,就是你抄去改的最小骨架:连库、导入显示函数、给 20 个指标各开一个 int 信号变量。外汇与贵金属波动剧烈,信号仅为概率参考,实盘前务必在 MT5 策略测试器跑一遍。
class=class="str">"cmt">//--- 连接所需要的函数库 class="macro">#include <SignalTrade.mqh> class=class="str">"cmt">//--- 从 LibFunctions 库中导入函数 class="macro">#class="kw">import "LibFunctions.ex5" class="type">void SetLabel(class="type">class="kw">string nm,class="type">class="kw">string tx,ENUM_BASE_CORNER cn,ENUM_ANCHOR_POINT cr,class="type">int xd,class="type">int yd,class="type">class="kw">string fn,class="type">int fs,class="type">class="kw">double yg,class="type">class="kw">color ct); class="type">class="kw">string arrow(class="type">int sig); class="type">class="kw">color Colorarrow(class="type">int sig); class="macro">#class="kw">import class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| 声明用于保存指标信号的变量 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">int SignalMA; class="type">int SignalMACD; class="type">int SignalPC; class="type">int SignalACADX; class="type">int SignalST; class="type">int SignalRSI; class="type">int SignalCCI; class="type">int SignalWPR; class="type">int SignalBB; class="type">int SignalSDC; class="type">int SignalPC2; class="type">int SignalENV; class="type">int SignalDC; class="type">int SignalSC; class="type">int SignalGC; class="type">int SignalNRTR; class="type">int SignalAL; class="type">int SignalAMA; class="type">int SignalAO; class="type">int SignalICH; class="type">int OnInit() { class=class="str">"cmt">//--- 创建指标句柄 h_ma1=iMA(Symbol(),Period(),class="num">8,class="num">0,MODE_SMA,PRICE_CLOSE); h_ma2=iMA(Symbol(),Period(),class="num">16,class="num">0,MODE_SMA,PRICE_CLOSE); h_macd=iMACD(Symbol(),Period(),class="num">12,class="num">26,class="num">9,PRICE_CLOSE); h_pc=iCustom(Symbol(),Period(),"Price Channel",class="num">22); h_acadx=iCustom(Symbol(),Period(),"AdaptiveChannelADX",class="num">14); h_stoh=iStochastic(Symbol(),Period(),class="num">5,class="num">3,class="num">3,MODE_SMA,STO_LOWHIGH); h_rsi=iRSI(Symbol(),Period(),class="num">14,PRICE_CLOSE); h_cci=iCCI(Symbol(),Period(),class="num">14,PRICE_TYPICAL); h_wpr=iWPR(Symbol(),Period(),class="num">14); h_bb=iBands(Symbol(),Period(),class="num">20,class="num">0,class="num">2,PRICE_CLOSE); h_sdc=iCustom(Symbol(),Period(),"StandardDeviationChannel",class="num">14,class="num">0,MODE_SMA,PRICE_CLOSE,class="num">2.0); h_env=iEnvelopes(Symbol(),Period(),class="num">28,class="num">0,MODE_SMA,PRICE_CLOSE,class="num">0.1); h_dc=iCustom(Symbol(),Period(),"Donchian Channels",class="num">24,class="num">3,-class="num">2);
◍ 指标句柄与信号变量的初始化落地
多指标共振系统先把所有外部指标的句柄在初始化阶段一次性建好,避免 OnCalculate 里反复调用 iCustom 拖慢执行。下面这段把白银通道、PriceChannelGalaher、NRTR、鳄鱼、AMA、AO、Ichimoku 全挂在当前品种当前周期上,参数写死在代码里,改起来直接动数字就行。 h_sc=iCustom(Symbol(),Period(),"Silver-channels",26,38.2,23.6,0,61.8); // 白银通道:周期26,回撤位38.2/23.6,偏移0,另一通道61.8 h_gc=iCustom(Symbol(),Period(),"PriceChannelGalaher"); // 加拉赫价格通道,用默认参数 h_nrtr=iCustom(Symbol(),Period(),"NRTR",40,2.0); // NRTR 止损通道:周期40,倍数2.0 h_al=iAlligator(Symbol(),Period(),13,0,8,0,5,0,MODE_SMMA,PRICE_MEDIAN); // 鳄鱼:颌13/0,齿8/0,唇5/0,SMMA,中位价 h_ama=iAMA(Symbol(),Period(),9,2,30,0,PRICE_CLOSE); // 自适应均线 AMA:9/2/30/0,收盘价 h_ao=iAO(Symbol(),Period()); // 动量震荡器 AO,无参 h_ich=iIchimoku(Symbol(),Period(),9,26,52); // 一目均衡表:转换9,基准26,延展52 return(0); OnCalculate 里把 20 个 TradeSignal_xx() 的返回值分别赋给 SignalMA 到 SignalICH 这排变量,相当于每次报价重算都把各子系统信号刷一遍。外汇和贵金属杠杆高,这类多信号框架只是把概率倾向摆上图表,不等于方向确认。 图表左上角用 ChartGetInteger 取像素高度除以 22 算字体大小,再循环 SetLabel 把箭头画在 CORNER_RIGHT_UPPER。想验证就开 MT5 挂这段到 EURUSD 的 M15,看右上角是否按信号出 Wingdings 箭头。
h_sc=iCustom(Symbol(),Period(),"Silver-channels",class="num">26,class="num">38.2,class="num">23.6,class="num">0,class="num">61.8); h_gc=iCustom(Symbol(),Period(),"PriceChannelGalaher"); h_nrtr=iCustom(Symbol(),Period(),"NRTR",class="num">40,class="num">2.0); h_al=iAlligator(Symbol(),Period(),class="num">13,class="num">0,class="num">8,class="num">0,class="num">5,class="num">0,MODE_SMMA,PRICE_MEDIAN); h_ama=iAMA(Symbol(),Period(),class="num">9,class="num">2,class="num">30,class="num">0,PRICE_CLOSE); h_ao=iAO(Symbol(),Period()); h_ich=iIchimoku(Symbol(),Period(),class="num">9,class="num">26,class="num">52); class="kw">return(class="num">0); } class="type">int OnCalculate(class="kw">const class="type">int rates_total, class="kw">const class="type">int prev_calculated, class="kw">const class="type">class="kw">datetime &time[], class="kw">const class="type">class="kw">double &open[], class="kw">const class="type">class="kw">double &high[], class="kw">const class="type">class="kw">double &low[], class="kw">const class="type">class="kw">double &close[], class="kw">const class="type">long &tick_volume[], class="kw">const class="type">long &volume[], class="kw">const class="type">int &spread[]) { class=class="str">"cmt">//---把信号值赋给变量 SignalMA = TradeSignal_01(); SignalMACD = TradeSignal_02(); SignalPC = TradeSignal_03(); SignalACADX = TradeSignal_04(); SignalST = TradeSignal_05(); SignalRSI = TradeSignal_06(); SignalCCI = TradeSignal_07(); SignalWPR = TradeSignal_08(); SignalBB = TradeSignal_09(); SignalSDC = TradeSignal_10(); SignalPC2 = TradeSignal_11(); SignalENV = TradeSignal_12(); SignalDC = TradeSignal_13(); SignalSC = TradeSignal_14(); SignalGC = TradeSignal_15(); SignalNRTR = TradeSignal_16(); SignalAL = TradeSignal_17(); SignalAMA = TradeSignal_18(); SignalAO = TradeSignal_19(); SignalICH = TradeSignal_20(); class=class="str">"cmt">//--- 在图表左上角画图形对象 class="type">int size=((class="type">int)ChartGetInteger(class="num">0,CHART_HEIGHT_IN_PIXELS)/class="num">22); class="type">int i=class="num">0; class="type">int x=class="num">10; class="type">int y=class="num">0; class="type">int fz=size-class="num">4; y+=size; SetLabel("arrow"+(class="type">class="kw">string)i,arrow(SignalMA),CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y+class="num">4,"Wingdings",fz-class="num">2,class="num">0,Colorarrow(SignalMA)); x+=size;
「右上角信号面板的逐行绘制逻辑」
这段循环式代码把多个指标的箭头与文字标签钉在图表右上角(CORNER_RIGHT_UPPER),每画完一组就把纵向坐标 y 加上 size、横向 x 重置为 10,形成自上而下排列的多指标速览条。 SetLabel("label"+i,"Moving Average",…) 先写指标名,下一行用 Wingdings 字体画 arrow(SignalMACD) 箭头,x 偏移 size 后接写 "MACD" 文字;随后 y+=size、x=10 进入下一组。依次覆盖了 MA、MACD、Price Channel、Adaptive Channel ADX、Stochastic、RSI、CCI、WPR 共 8 个信号源。 箭头颜色由 Colorarrow(信号变量) 决定,字体比文字小 2 号(fz-2),文字统一用 BlueViolet 的 Arial。开 MT5 把这段贴进指标 OnCalculate 末尾,调 fz 与 size 就能直接看到面板密度变化;外汇与贵金属波动剧烈,信号仅作概率参考,实盘须自担高风险。
SetLabel("label"+(class="type">class="kw">string)i,"Moving Average",CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y,"Arial",fz,class="num">0,BlueViolet); i++;y+=size;x=class="num">10; SetLabel("arrow"+(class="type">class="kw">string)i,arrow(SignalMACD),CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y+class="num">4,"Wingdings",fz-class="num">2,class="num">0,Colorarrow(SignalMACD)); x+=size; SetLabel("label"+(class="type">class="kw">string)i,"MACD",CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y,"Arial",fz,class="num">0,BlueViolet); i++;y+=size;x=class="num">10; SetLabel("arrow"+(class="type">class="kw">string)i,arrow(SignalPC),CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y+class="num">4,"Wingdings",fz-class="num">2,class="num">0,Colorarrow(SignalPC)); x+=size; SetLabel("label"+(class="type">class="kw">string)i,"Price Channell",CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y,"Arial",fz,class="num">0,BlueViolet); i++;y+=size;x=class="num">10; SetLabel("arrow"+(class="type">class="kw">string)i,arrow(SignalACADX),CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y+class="num">4,"Wingdings",fz-class="num">2,class="num">0,Colorarrow(SignalACADX)); x+=size; SetLabel("label"+(class="type">class="kw">string)i,"Adaptive Channel ADX",CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y,"Arial",fz,class="num">0,BlueViolet); i++;y+=size;x=class="num">10; SetLabel("arrow"+(class="type">class="kw">string)i,arrow(SignalST),CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y+class="num">4,"Wingdings",fz-class="num">2,class="num">0,Colorarrow(SignalST)); x+=size; SetLabel("label"+(class="type">class="kw">string)i,"Stochastic Oscillator",CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y,"Arial",fz,class="num">0,BlueViolet); i++;y+=size;x=class="num">10; SetLabel("arrow"+(class="type">class="kw">string)i,arrow(SignalRSI),CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y+class="num">4,"Wingdings",fz-class="num">2,class="num">0,Colorarrow(SignalRSI)); x+=size; SetLabel("label"+(class="type">class="kw">string)i,"RSI",CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y,"Arial",fz,class="num">0,BlueViolet); i++;y+=size;x=class="num">10; SetLabel("arrow"+(class="type">class="kw">string)i,arrow(SignalCCI),CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y+class="num">4,"Wingdings",fz-class="num">2,class="num">0,Colorarrow(SignalCCI)); x+=size; SetLabel("label"+(class="type">class="kw">string)i,"CCI",CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y,"Arial",fz,class="num">0,BlueViolet); i++;y+=size;x=class="num">10; SetLabel("arrow"+(class="type">class="kw">string)i,arrow(SignalWPR),CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y+class="num">4,"Wingdings",fz-class="num">2,class="num">0,Colorarrow(SignalWPR)); x+=size; SetLabel("label"+(class="type">class="kw">string)i,"WPR",CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y,"Arial",fz,class="num">0,BlueViolet); i++;y+=size;x=class="num">10;
右上角信号面板的逐行绘制逻辑
这段循环把多个通道类指标的信号状态刷到图表右上角,每轮先画一个 Wingdings 箭头再跟一段 Arial 文字说明。坐标从 x=10、y 起始,箭头纵向偏移 +4 像素、字号比面板基准 fz 小 2,文字用 BlueViolet 着色,肉眼能一眼区分信号方向与指标名。 每处理完一个指标就把 i 自增、y 加上 size 行距、x 重置回 10,因此 Bollinger Bands、StDevChannel、Price Channell 2、Envelopes、Donchian Channels、Silver-channels、Galaher Channel 等会自上而下排队。外汇与贵金属波动剧烈,这类面板只作多指标共振参考,实际下单仍须自担高风险。 直接把下面代码贴进 EA 的面板绘制段,改 size 或 fz 就能压缩行距或放大字体;若 SignalXXX 返回 0,箭头函数通常映射成中性符号,不会误报方向。
SetLabel("arrow"+(class="type">class="kw">string)i,arrow(SignalBB),CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y+class="num">4,"Wingdings",fz-class="num">2,class="num">0,Colorarrow(SignalBB)); x+=size; SetLabel("label"+(class="type">class="kw">string)i,"Bollinger Bands",CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y,"Arial",fz,class="num">0,BlueViolet); i++;y+=size;x=class="num">10; SetLabel("arrow"+(class="type">class="kw">string)i,arrow(SignalSDC),CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y+class="num">4,"Wingdings",fz-class="num">2,class="num">0,Colorarrow(SignalSDC)); x+=size; SetLabel("label"+(class="type">class="kw">string)i,"StDevChannel",CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y,"Arial",fz,class="num">0,BlueViolet); i++;y+=size;x=class="num">10; SetLabel("arrow"+(class="type">class="kw">string)i,arrow(SignalPC2),CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y+class="num">4,"Wingdings",fz-class="num">2,class="num">0,Colorarrow(SignalPC2)); x+=size; SetLabel("label"+(class="type">class="kw">string)i,"Price Channell class="num">2",CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y,"Arial",fz,class="num">0,BlueViolet); i++;y+=size;x=class="num">10; SetLabel("arrow"+(class="type">class="kw">string)i,arrow(SignalENV),CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y+class="num">4,"Wingdings",fz-class="num">2,class="num">0,Colorarrow(SignalENV)); x+=size; SetLabel("label"+(class="type">class="kw">string)i,"Envelopes",CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y,"Arial",fz,class="num">0,BlueViolet); i++;y+=size;x=class="num">10; SetLabel("arrow"+(class="type">class="kw">string)i,arrow(SignalDC),CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y+class="num">4,"Wingdings",fz-class="num">2,class="num">0,Colorarrow(SignalDC)); x+=size; SetLabel("label"+(class="type">class="kw">string)i,"Donchian Channels",CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y,"Arial",fz,class="num">0,BlueViolet); i++;y+=size;x=class="num">10; SetLabel("arrow"+(class="type">class="kw">string)i,arrow(SignalSC),CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y+class="num">4,"Wingdings",fz-class="num">2,class="num">0,Colorarrow(SignalSC)); x+=size; SetLabel("label"+(class="type">class="kw">string)i,"Silver-channels",CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y,"Arial",fz,class="num">0,BlueViolet); i++;y+=size;x=class="num">10; SetLabel("arrow"+(class="type">class="kw">string)i,arrow(SignalGC),CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y+class="num">4,"Wingdings",fz-class="num">2,class="num">0,Colorarrow(SignalGC)); x+=size; SetLabel("label"+(class="type">class="kw">string)i,"Galaher Channel",CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y,"Arial",fz,class="num">0,BlueViolet); i++;y+=size;x=class="num">10; SetLabel("arrow"+(class="type">class="kw">string)i,arrow(SignalNRTR),CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y+class="num">4,"Wingdings",fz-class="num">2,class="num">0,Colorarrow(SignalNRTR)); x+=size;
◍ 把多指标信号塞进右上角面板
这段逻辑干的事很直接:在图表右上角用 SetLabel 逐行铺开 NRTR、鳄鱼、AMA、AO、一目均衡的信号箭头加文字标签。每画完一行就把 y 坐标下移 size 像素、x 重置为 10,保证多指标不会叠在一起。 箭头用 Wingdings 字体渲染,字号比文字标签小 2(fz-2),并相对行基线再下移 4 像素做垂直对齐;文字统一用 Arial、BlueViolet 着色。这样一眼扫过去,五个系统的多空倾向就能并排比对。 外汇与贵金属波动剧烈,这类面板只反映指标当下状态,信号翻转概率不低,实盘前请在 MT5 策略测试器或 demo 账户验证刷新效率。 代码里 i 是标签计数器,每次 i++ 后换行;最后 return(rates_total) 交还处理柱数给终端。你复制去改 size 和 fz,就能控制面板密度和可读性。
SetLabel("label"+(class="type">class="kw">string)i,"NRTR",CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y,"Arial",fz,class="num">0,BlueViolet); i++;y+=size;x=class="num">10; SetLabel("arrow"+(class="type">class="kw">string)i,arrow(SignalAL),CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y+class="num">4,"Wingdings",fz-class="num">2,class="num">0,Colorarrow(SignalAL)); x+=size; SetLabel("label"+(class="type">class="kw">string)i,"Alligator",CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y,"Arial",fz,class="num">0,BlueViolet); i++;y+=size;x=class="num">10; SetLabel("arrow"+(class="type">class="kw">string)i,arrow(SignalAMA),CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y+class="num">4,"Wingdings",fz-class="num">2,class="num">0,Colorarrow(SignalAMA)); x+=size; SetLabel("label"+(class="type">class="kw">string)i,"AMA",CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y,"Arial",fz,class="num">0,BlueViolet); i++;y+=size;x=class="num">10; SetLabel("arrow"+(class="type">class="kw">string)i,arrow(SignalAO),CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y+class="num">4,"Wingdings",fz-class="num">2,class="num">0,Colorarrow(SignalAO)); x+=size; SetLabel("label"+(class="type">class="kw">string)i,"Awesome oscillator",CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y,"Arial",fz,class="num">0,BlueViolet); i++;y+=size;x=class="num">10; SetLabel("arrow"+(class="type">class="kw">string)i,arrow(SignalICH),CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y+class="num">4,"Wingdings",fz-class="num">2,class="num">0,Colorarrow(SignalICH)); x+=size; SetLabel("label"+(class="type">class="kw">string)i,"Ichimoku Kinko Hyo",CORNER_RIGHT_UPPER,ANCHOR_RIGHT_UPPER,x,y,"Arial",fz,class="num">0,BlueViolet); class="kw">return(rates_total); }
「把信号库改造成可热调参的 EA 内核」
想在 MT5 图表上用图形面板实时切换指标并改参数,得先动底层信号库。原文做法是把 SignalTrade.mqh 复制为 SignalTradeExp.mqh,将原本写死的常量全部换成变量,其余逻辑原样保留。 关键约束是内存:改设置时必须先卸载旧参数加载的指标副本,再加载新副本,否则 MT5 终端内存会随每次微调悄悄爬升。下面这段变量声明就是 EA 接管所有指标参数的入口,覆盖了 MA、MACD、PC、ADX、随机、RSI、CCI、WPR、布林、标准差通道、ENV、唐奇安等 13 类指标。 平均线默认快线 8、慢线 16,MACD 为 12/26/9,布林与标准差通道偏离都取 2.0,唐奇安周期 24——这些数字直接决定面板初开时的信号形态,复制进 MQH 头部即可编译验证。 别把正态当圣经:图形界面本身不在这里展开,但变量名与指标句柄必须一一对应,否则运行时改了面板、图表却没反应,多半是卸载/加载函数没接对句柄。
class=class="str">"cmt">//--- 移动平均指标的输入参数 class="type">int periodma1=class="num">8; class="type">int periodma2=class="num">16; ENUM_MA_METHOD MAmethod=MODE_SMA; ENUM_APPLIED_PRICE MAprice=PRICE_CLOSE; class=class="str">"cmt">//--- MACD 指标输入参数 class="type">int FastMACD=class="num">12; class="type">int SlowMACD=class="num">26; class="type">int MACDSMA=class="num">9; ENUM_APPLIED_PRICE MACDprice=PRICE_CLOSE; class=class="str">"cmt">//--- Price Channel 指标输入参数 class="type">int PCPeriod=class="num">22; class=class="str">"cmt">//--- Adaptive Channel ADX 指标输入参数 class="type">int ADXPeriod=class="num">14; class=class="str">"cmt">//--- 随机振荡指标输入参数 class="type">int SOPeriodK=class="num">5; class="type">int SOPeriodD=class="num">3; class="type">int SOslowing=class="num">3; ENUM_MA_METHOD SOmethod=MODE_SMA; ENUM_STO_PRICE SOpricefield=STO_LOWHIGH; class=class="str">"cmt">//--- RSI 指标输入参数 class="type">int RSIPeriod=class="num">14; ENUM_APPLIED_PRICE RSIprice=PRICE_CLOSE; class=class="str">"cmt">//--- CCI 指标输入参数 class="type">int CCIPeriod=class="num">14; ENUM_APPLIED_PRICE CCIprice=PRICE_TYPICAL; class=class="str">"cmt">//--- WPR 指标输入参数 class="type">int WPRPeriod=class="num">14; class=class="str">"cmt">//--- Bollinger Bands 指标输入参数 class="type">int BBPeriod=class="num">20; class="type">class="kw">double BBdeviation=class="num">2.0; ENUM_APPLIED_PRICE BBprice=PRICE_CLOSE; class=class="str">"cmt">//--- Standard Deviation Channel 指标输入参数 class="type">int SDCPeriod=class="num">14; class="type">class="kw">double SDCdeviation=class="num">2.0; ENUM_APPLIED_PRICE SDCprice=PRICE_CLOSE; ENUM_MA_METHOD SDCmethod=MODE_SMA; class=class="str">"cmt">//--- Price Channel class="num">2 指标输入参数 class="type">int PC2Period=class="num">22; class=class="str">"cmt">//--- Envelopes 指标输入参数 class="type">int ENVPeriod=class="num">14; class="type">class="kw">double ENVdeviation=class="num">0.1; ENUM_APPLIED_PRICE ENVprice=PRICE_CLOSE; ENUM_MA_METHOD ENVmethod=MODE_SMA; class=class="str">"cmt">//--- Donchian Channels 指标输入参数 class="type">int DCPeriod=class="num">24; class="type">int DCExtremes=class="num">3;
多指标参数与图表交互的实装片段
这段声明把 Silver-channels、NRTR、Alligator、AMA、Ichimoku 五套指标的输入参数一次性铺开:Silver 通道取 26 周期配 38.2/23.6/61.8 三条斐波那契比;NRTR 用 40 周期加 2.0 倍系数;鳄鱼线 jaw/teeth/lips 分别是 13/8/5,平滑方式锁 MODE_SMMA 且取中位数价。 AMA 设 9 周期、快 2 慢 30,收盘价驱动;Ichimoku 的转折 9、基准 26、迟行 spanB 52,和白银通道的 26 形成参数呼应,回测时容易看到两者在日线黄金上的共振。 图表端用 CHARTEVENT_OBJECT_ENDEDIT 捕获名为 PIPSetEditMA2 的编辑框改动:把输入文本强转成 int 赋给 periodma2,先 IndicatorRelease 卸掉旧 h_ma2 句柄,再 iMA 重建新拷贝并 ChartRedraw。外汇与贵金属波动剧烈,这类动态重载若周期跳变过大,可能触发重算卡顿,建议在 MT5 里先用 XAUUSD 的 M15 试改 10→50 看刷新延迟。
class="type">int DCMargins=-class="num">2; class=class="str">"cmt">//--- Silver-channels 指标输入参数 class="type">int SCPeriod=class="num">26; class="type">class="kw">double SCSilvCh=class="num">38.2; class="type">class="kw">double SCSkyCh=class="num">23.6; class="type">class="kw">double SCFutCh=class="num">61.8; class=class="str">"cmt">//--- NRTR 指标输入参数 class="type">int NRTRPeriod = class="num">40; class="type">class="kw">double NRTRK = class="num">2.0; class=class="str">"cmt">//--- Alligator 指标输入参数 class="type">int ALjawperiod=class="num">13; class="type">int ALteethperiod=class="num">8; class="type">int ALlipsperiod=class="num">5; ENUM_MA_METHOD ALmethod=MODE_SMMA; ENUM_APPLIED_PRICE ALprice=PRICE_MEDIAN; class=class="str">"cmt">//--- AMA 指标输入参数 class="type">int AMAperiod=class="num">9; class="type">int AMAfastperiod=class="num">2; class="type">int AMAslowperiod=class="num">30; ENUM_APPLIED_PRICE AMAprice=PRICE_CLOSE; class=class="str">"cmt">//--- Ichimoku Kinko Hyo 指标输入参数 class="type">int IKHtenkansen=class="num">9; class="type">int IKHkijunsen=class="num">26; class="type">int IKHsenkouspanb=class="num">52; h_ma1=iMA(Symbol(),Period(),periodma1,class="num">0,MAmethod,MAprice); class="type">bool IndicatorRelease( class="type">int indicator_handle, class=class="str">"cmt">// 指标句柄 ); if(id==CHARTEVENT_OBJECT_ENDEDIT && sparam=="PIPSetEditMA2") { periodma2=(class="type">int)ObjectGetString(class="num">0,"PIPSetEditMA2",OBJPROP_TEXT); ObjectSetString(class="num">0,"PIPSetEditMA2",OBJPROP_TEXT,(class="type">class="kw">string)periodma2); class=class="str">"cmt">//--- 卸载指标的旧拷贝 IndicatorRelease(h_ma2); class=class="str">"cmt">//--- 创建指标新拷贝 h_ma2=iMA(Symbol(),Period(),periodma2,class="num">0,MAmethod,MAprice); ChartRedraw(); }
◍ 把这条线请下神坛
从指标句柄取到缓冲区数值,再到用 iCustom 把信号喂给 EA,这条通路已经跑通。你手头那套 SignalTrade 框架真正值钱的不是某个通道指标,而是它把‘任意指标→交易信号’做成了可插拔模块。 部署时照着路径落文件:指标 mq5 进 \MQL5\Indicators,SignalTrade.mqh 和 SignalTradeExp.mqh 进 \MQL5\Include,LibFunctions.mq5 进 \MQL5\Libraries,ExpSignalTrade.mq5 进 \MQL5\Experts。少一个,策略测试器里就会报找不到资源的错。 外汇和贵金属杠杆高、滑点跳空频繁,实盘前务必在 MT5 用 2020–2023 年 Tick 数据回测,观察信号延迟和重绘指标带来的假触发概率,再决定要不要上真金白银。