解读经典和隐藏背离的新途径。 第二部分·综合运用
(3/3)·经典与隐藏背离的非标准解读走到落地环节,多数交易者卡在信号过滤与仓位触发
背离后的三种入场与止盈路径
识别到背离后,经典做法是挂突破单:看涨背离在形态末根烛条高点上方挂 buy stop,看跌背离在末根低点下方挂 sell stop。图例 49 显示这是吃满波动的一种优选,但前提是形态标准且大周期可佐证。 想拿更大空间,可等“轨道线(26)”指标上边界附近入场,偏差按品种波动调;或依据背离前三点的高/低点画等距通道,贴边界进。图例 50、51 给出两种参考。止损放做多价下方最低价、做空价上方最高价,仅适合理想形态与中长周期。 止盈难预先定死,价位随行情漂移,算期望很麻烦。更稳的变体是画趋势线,突破趋势线才入场——它几乎等同于经典价位,却多一层反转确认。图例 53。目标位落在支撑阻力,双重/三重背离通常取首次信号结束处,偶尔用分形卡在背离之间或起点。图例 54、55。 止损是否必带?外汇与贵金属属高风险市场,新手务必带止损。仅经验丰富的交易者,在指标与技术面高度自信、能手动干预失控单时,才考虑不设或远放止损。
◍ 把 ADX 拆成零轴振荡器
ADX 的毛病老交易员都清楚:双重平滑让它滞后,主线方向常和行情拧着走。Wilder 当年设计它是为了展示趋势强度而非方向,DI- 线甚至和价格波谷上下颠倒,直接拿来当方向指标容易亏。 但把 MathAbs 从主值还原里删掉,ADX 就能变成一条绕零轴摆的振荡器(ADX_Osc)。改完之后方向显示变清楚,适合在全局找背离,剩下的一点滞后可用 DI+/DI- 的初期逆转信号补。 判别 DI- 与价格差值的逻辑基于一个事实:内孕柱线出现时,所谓“多空同时发力”只是转移。我们的定义不靠图形,而是“本根柱多头力度小于前一根、空头力度大于前一根”,主线形状忽略。 ADX_Osc 线若上涨趋势中递减而价格仍涨(背离),倾向逆转;趋势延展时 ADX 线值同向递增,则是盘整停止。我们用这套规则在 EURUSD、GBPUSD、USDJPY 的 H1/H4 上跑了 2016.1.1–2019.1.6 的 EA 测试,结果不亮眼但正向,外汇贵金属高风险,信号仅作短线参考。 别把正态当圣经 ADX 滞后不是缺陷而是特征。零轴化后它暴露的是强度拐点,DI 单向线标记的绿/紫点只是短线趋势识别,挂单直接吃这些点容易被假信号扫,等收盘价突破再动。
dTmp=class="num">100.0*MathAbs((ExtPDIBuffer[i]-ExtNDIBuffer[i])/dTmp); class="macro">#class="kw">property indicator_separate_window class="macro">#class="kw">property indicator_buffers class="num">8 class="macro">#class="kw">property indicator_plots class="num">3 class="macro">#class="kw">property indicator_type1 DRAW_LINE class="macro">#class="kw">property indicator_color1 LightSeaGreen class="macro">#class="kw">property indicator_style1 STYLE_SOLID class="macro">#class="kw">property indicator_width1 class="num">1 class="macro">#class="kw">property indicator_type2 DRAW_LINE class="macro">#class="kw">property indicator_color2 Green class="macro">#class="kw">property indicator_style2 STYLE_DOT class="macro">#class="kw">property indicator_width2 class="num">1
「给 ADX 指标加极值虚线通道」
在 MT5 自定义指标里,除了标准的 ADX、+DI、-DI 三条线,还可以用 indicator_type3 挂一条红色点线,用来标出极值参考带。上面这段声明把第三号绘图层设成 DRAW_LINE、Red、STYLE_DOT、线宽 1,标签直接写成 "-DI" 之外的独立层,避免和默认 DI 混淆。 参数区里 extremum=100 是极值阈值,注释写明了小于 1 就关掉除法缩放;Gep=4 表示以 4 个 point 作为缺口偏移;Bars_Calculated=300 限制只算最近 300 根,回测时加载更快。allLine=false 则只画主线,不铺满辅助线。 代码里 ExtUpBuffer 和 ExtDnBuffer 是两个额外的双精度数组,专门存上下极值缓冲。OnDeinit 里用 ObjectsDeleteAll(0,short_name) 清掉旧对象再 ChartRedraw,切换周期不会留垃圾图形。 循环从 start 或 rates_total-Bars_Calculated 取较大值起步,对 i 到 rates_total-1 遍历,每根把 ExtUpBuffer[i-1] 和 ExtDnBuffer[i-1] 先置为 EMPTY_VALUE,相当于动态擦除上一轮极值标记。外汇和贵金属波动大,这类极值带仅作概率参考,实盘前请在 MT5 用 14 周期 ADX 验证渲染表现。
class="macro">#class="kw">property indicator_type3 DRAW_LINE class="macro">#class="kw">property indicator_color3 Red class="macro">#class="kw">property indicator_style3 STYLE_DOT class="macro">#class="kw">property indicator_width3 class="num">1 class="macro">#class="kw">property indicator_label1 "ADX" class="macro">#class="kw">property indicator_label2 "+DI" class="macro">#class="kw">property indicator_label3 "-DI" class=class="str">"cmt">//--- input parameters input class="type">int InpPeriodADX=class="num">14; class=class="str">"cmt">// Period input class="type">int extremum=class="num">100; class=class="str">"cmt">// Extremum(<class="num">1 Div= OFF) input class="type">int Gep=class="num">4; class=class="str">"cmt">// Point to Gep input class="type">int Bars_Calculated=class="num">300; class=class="str">"cmt">//--- global variables input class="type">bool allLine=class="kw">false;class=class="str">"cmt">// All Line class="type">int ExtADXPeriod; class="type">class="kw">double PDI,NDI,pDI,nDI; class="type">class="kw">string short_name=""; class="type">int wid=-class="num">1; class=class="str">"cmt">//---- buffers class="type">class="kw">double ExtADXBuffer[]; class="type">class="kw">double ExtPDIBuffer[]; class="type">class="kw">double ExtNDIBuffer[]; class="type">class="kw">double ExtPDBuffer[]; class="type">class="kw">double ExtNDBuffer[]; class="type">class="kw">double ExtTmpBuffer[]; class="type">class="kw">double ExtUpBuffer[]; class="type">class="kw">double ExtDnBuffer[]; input class="type">int extremum=class="num">100; class=class="str">"cmt">// Extremum(<class="num">1 Div= OFF) input class="type">bool allLine=class="kw">false;class=class="str">"cmt">// All Line input class="type">int Gep=class="num">4; class=class="str">"cmt">// Point to Gep class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnDeinit(class="kw">const class="type">int reason) { ObjectsDeleteAll(class="num">0,short_name); ChartRedraw(class="num">0); } class=class="str">"cmt">//+------------------------------------------------------------------+ if(prev_calculated>class="num">1) start=prev_calculated-class="num">1; else { OnDeinit(class="num">9); start=class="num">1; ExtPDIBuffer[class="num">0]=class="num">0.0; ExtNDIBuffer[class="num">0]=class="num">0.0; ExtADXBuffer[class="num">0]=class="num">0.0; } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Fast divergence calculation | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">int bar=start; if(prev_calculated<class="num">2) bar=start+class="num">2; if(Bars_Calculated>class="num">0)bar=fmax(rates_total-Bars_Calculated,start); class=class="str">"cmt">//--- for(class="type">int i=bar;i<rates_total-class="num">1 && !IsStopped();i++) { ExtUpBuffer[i-class="num">1]=EMPTY_VALUE; ExtDnBuffer[i-class="num">1]=EMPTY_VALUE;
ADX 翻转时如何改画极值线
上面这段逻辑处理的是 DMI 双线同向后的极值标记重绘:当 +DI 与 -DI 同时上行或同时下行,说明趋势惯性还在,但 ADX 的拐头方向决定了高点线还是低点线被保留。 具体看,若 +DI 大于 -DI 且 ADX 走高,就在上一根 K 线高点写进 ExtUpBuffer;若 ADX 反而走低,则清空上行缓冲、把低点写进 ExtDnBuffer,并把下跌色改成金色(clrGold)。反过来 -DI 占优时逻辑镜像,ADX 走弱留低点线,ADX 走强则切到蓝色高点线。 两段都用了 MathAbs(...) < Gep*_Point 做黏合判断:若新旧极值差小于 Gep 个点数,就沿用前一根的缓冲值,避免在窄幅波动里画出一串碎线。Gep 一般设 1~3,EURUSD 的 _Point 是 0.00001,意味着差值小于 0.00003 就自动合并。 别把极值线当突破信号 这段代码只负责「画」不负责「喊」,极值线延续或变色只是 ADX 结构的可视化。真要用于外汇或贵金属下单,仍要结合价位结构和止损,这类品种杠杆高、滑点大,信号失效概率不低。
class=class="str">"cmt">//--- class="type">class="kw">color clrUp=clrLime; class="type">class="kw">color clrDn=clrDarkViolet; class=class="str">"cmt">//--- if((ExtPDIBuffer[i-class="num">1]<ExtPDIBuffer[i-class="num">2] && ExtNDIBuffer[i-class="num">1]<ExtNDIBuffer[i-class="num">2]) || (ExtPDIBuffer[i-class="num">1]>ExtPDIBuffer[i-class="num">2] && ExtNDIBuffer[i-class="num">1]>ExtNDIBuffer[i-class="num">2])) { if(ExtPDIBuffer[i-class="num">1]>ExtNDIBuffer[i-class="num">1]) { if(ExtADXBuffer[i-class="num">1]>ExtADXBuffer[i-class="num">2]) ExtUpBuffer[i-class="num">1]=high[i-class="num">1]; else { ExtUpBuffer[i-class="num">1]=EMPTY_VALUE; ExtDnBuffer[i-class="num">1]=low[i-class="num">1]; clrDn=clrGold; } class=class="str">"cmt">//--- if(MathAbs(ExtUpBuffer[i-class="num">1]-ExtUpBuffer[i-class="num">2])<Gep*_Point) ExtUpBuffer[i-class="num">1]=ExtUpBuffer[i-class="num">2]; if(MathAbs(ExtDnBuffer[i-class="num">1]-ExtDnBuffer[i-class="num">2])<Gep*_Point) ExtDnBuffer[i-class="num">1]=ExtDnBuffer[i-class="num">2]; class=class="str">"cmt">//--- } if(ExtPDIBuffer[i-class="num">1]<ExtNDIBuffer[i-class="num">1]) { if(ExtADXBuffer[i-class="num">1]<ExtADXBuffer[i-class="num">2]) ExtDnBuffer[i-class="num">1]=low[i-class="num">1]; else { ExtDnBuffer[i-class="num">1]=EMPTY_VALUE; ExtUpBuffer[i-class="num">1]=high[i-class="num">1]; clrUp=clrBlue; } class=class="str">"cmt">//--- if(MathAbs(ExtDnBuffer[i-class="num">1]-ExtDnBuffer[i-class="num">2])<Gep*_Point) ExtDnBuffer[i-class="num">1]=ExtDnBuffer[i-class="num">2]; if(MathAbs(ExtUpBuffer[i-class="num">1]-ExtUpBuffer[i-class="num">2])<Gep*_Point) ExtUpBuffer[i-class="num">1]=ExtUpBuffer[i-class="num">2]; class=class="str">"cmt">//--- }
◍ 箭头修补与背离扫描的衔接逻辑
指标在画箭头环节先做空值回填:若前一根的 ExtUpBuffer 或 ExtDnBuffer 等于 EMPTY_VALUE,就直接继承再前一根的值,避免图形断层。 随后按缓冲状态决定是否调用 ArrowCreate——上行缓冲有效时在当前及可能的上一根低位锚点画箭头,无效则退回到 i-2 的值补画,下行缓冲镜像处理、锚点改为顶部。 背离扫描从 bar=start 起步,若超出 rates_total-2 则截断;已有计算历史时取 rates_total-Bars_Calculated 与 start 的较大值,保证只扫新增 K 线。 循环内对每根调用 UP/DN 并传入 ExtADXBuffer、high/low、time,由这两个函数负责在 ADX 类缓冲上识别峰谷背离;外汇与贵金属品种波动剧烈,此类信号仅作概率参考,实盘须严控仓位。
}
class=class="str">"cmt">//---
if(ExtUpBuffer[i-class="num">1]==EMPTY_VALUE)
ExtUpBuffer[i-class="num">1]=ExtUpBuffer[i-class="num">2];
if(ExtDnBuffer[i-class="num">1]==EMPTY_VALUE)
ExtDnBuffer[i-class="num">1]=ExtDnBuffer[i-class="num">2];
class=class="str">"cmt">//---
if(ExtUpBuffer[i-class="num">1]!=EMPTY_VALUE)
{
ArrowCreate(short_name+(class="type">class="kw">string)time[i]+(class="type">class="kw">string)Lime,time[i],ExtUpBuffer[i-class="num">1],ANCHOR_BOTTOM,clrUp);
if(ExtUpBuffer[i-class="num">1]!=ExtUpBuffer[i-class="num">2])
ArrowCreate(short_name+(class="type">class="kw">string)time[i-class="num">1]+(class="type">class="kw">string)Lime,time[i-class="num">1],ExtUpBuffer[i-class="num">1],ANCHOR_BOTTOM,clrUp);
}
else
ArrowCreate(short_name+(class="type">class="kw">string)time[i]+(class="type">class="kw">string)Lime,time[i],ExtUpBuffer[i-class="num">2],ANCHOR_BOTTOM,clrUp);
class=class="str">"cmt">//---
if(ExtDnBuffer[i-class="num">1]!=EMPTY_VALUE)
{
ArrowCreate(short_name+(class="type">class="kw">string)time[i]+(class="type">class="kw">string)Red,time[i],ExtDnBuffer[i-class="num">1],ANCHOR_TOP,clrDn);
if(ExtDnBuffer[i-class="num">1]!=ExtDnBuffer[i-class="num">2])
ArrowCreate(short_name+(class="type">class="kw">string)time[i-class="num">1]+(class="type">class="kw">string)Red,time[i-class="num">1],ExtDnBuffer[i-class="num">1],ANCHOR_TOP,clrDn);
}
else
ArrowCreate(short_name+(class="type">class="kw">string)time[i]+(class="type">class="kw">string)Red,time[i],ExtDnBuffer[i-class="num">2],ANCHOR_TOP,clrDn);
}
class=class="str">"cmt">//+-------------------- Finding a discrepancy ----------------------+
bar=start;
if(bar>rates_total-class="num">2)bar=rates_total-class="num">2;
if(Bars_Calculated>class="num">0)bar=fmax(rates_total-Bars_Calculated,bar);
for(class="type">int i=bar;i<rates_total-class="num">2 && !IsStopped() && extremum>class="num">0;i++)
{
UP(i,ExtADXBuffer,high,time);
DN(i,ExtADXBuffer,low,time);
}
class=class="str">"cmt">//+----------- Detecting UP divergences ------------------------------+
class="type">void UP(class="type">int l,class="kw">const class="type">class="kw">double &buf[],class="kw">const class="type">class="kw">double &high[],class="kw">const class="type">class="kw">datetime &time[])
{
if(Extremum(buf[l+class="num">1],buf[l],buf[l-class="num">1])<class="num">0)
{
class="type">int i=l;
for(class="type">int j=class="num">0;j<extremum;j++)
{
class="type">int counted=LastPeak(i,buf);
if(counted!=-class="num">1)
{
if(buf[l]<buf[counted] && high[l]>high[counted])
{「下行背离的谷底扫描逻辑」
下行背离检测从指标谷底极值出发:当 buf[l] 高于前一个谷底 buf[counted],但价格低点 low[l] 却低于 low[counted],便满足「价创新低、指标未创新低」的雏形。 代码先算斜率 k = fabs(buf[l]-buf[counted])/(l-counted),即两个谷底之间每根 K 线的平均指标落差。随后用 z 从 1 递增,反向遍历 i 从 l-1 到 counted 之后,只要出现 buf[i] > buf[l]-k*z 就判定结构被破坏(yes=false)并跳出。 若全程未被破坏,则调用 DrawPriceTrendLine 与 DrawIndicatorTrendLine,以红色点线(STYLE_DOT)连接两处谷底的价格与指标,标记出潜在下行背离。外汇与贵金属市场波动剧烈,此类信号仅代表概率倾向,实盘前请在 MT5 用历史数据验证触发频率。 让小布替你跑这套:把 extremum 参数设为 3,观察 EURUSD 日线近 200 根 K 线里点线标记的遗漏率,再决定是否接入警报。
class="type">void DN(class="type">int l,class="kw">const class="type">class="kw">double &buf[],class="kw">const class="type">class="kw">double &low[],class="kw">const class="type">class="kw">datetime &time[]) { if(Extremum(buf[l+class="num">1],buf[l],buf[l-class="num">1])>class="num">0) { class="type">int i=l; class=class="str">"cmt">//--- for(class="type">int j=class="num">0;j<extremum;j++) { class="type">int counted=LastTrough(i,buf); if(counted!=-class="num">1) { if(buf[l]>buf[counted] && low[l]<low[counted]) { class="type">class="kw">double k=fabs(buf[l]-buf[counted])/(l-counted); class="type">int z=class="num">1; class="type">bool yes=true; for(i=l-class="num">1;i>counted;z++,i--) if(buf[i]>buf[l]-k*z){yes=class="kw">false;class="kw">break;} if(yes) { DrawPriceTrendLine(time[l],time[counted],low[l],low[counted],Red,STYLE_DOT); DrawIndicatorTrendLine(time[l],time[counted],buf[l],buf[counted],Red,STYLE_DOT); class="kw">break; } } } } i=counted; } }
背离判定里的阶梯容差与极值捕捉
这段逻辑在做一件事:当指标缓冲 buf 在 l 与 counted 之间走高、但价格低点反而下移时,用线性斜率 k 去校验中间每根 K 线是否都‘乖乖’落在阶梯容差带内。k 取两点的指标绝对值差除以柱数,z 从 1 递增,任一 buf[i] 低于 buf[l]-k*z 就判否并 break,全部通过才画绿色实线趋势线。 反向分支里 buf[l]<buf[counted] 且 low[l]>low[counted],校验条件换成 buf[i]<buf[l]+k*z,线型改为 STYLE_DOT 虚点。两种画法都同时输出价格趋势线与指标趋势线,方便肉眼比对背离结构。 Extremum() 用 (a-b)*(b-c)<=0 判定拐点:右端 c 大于中值 b 返回 1(向下极值),c 小于 b 返回 -1(向上极值),否则 0。LastPeak() 从 l-2 回扫到 i>4,对连续三点调用 Extremum,是在定位第二个 UP 极值——外汇与贵金属波动跳空多,这种容差带在 M15 以上周期误报可能更少,但高频品种仍建议手动复核。 开 MT5 把这段塞进自定义指标 OnCalculate 末尾,把 DrawPriceTrendLine / DrawIndicatorTrendLine 换成你自己的绘图封装,跑 EURUSD 日线看绿色实线出现频率,大概率比裸眼找背离快。
class="type">class="kw">double k=fabs(buf[l]-buf[counted])/(l-counted); class="type">int z=class="num">1; class="type">bool yes=true; for(i=l-class="num">1;i>counted;z++,i--) if(buf[i]<buf[l]-k*z){yes=class="kw">false;class="kw">break;} if(yes) { DrawPriceTrendLine(time[l],time[counted],low[l],low[counted],Green,STYLE_SOLID); DrawIndicatorTrendLine(time[l],time[counted],buf[l],buf[counted],Green,STYLE_SOLID); class="kw">break; } if(buf[l]<buf[counted] && low[l]>low[counted]) { class="type">class="kw">double k=fabs(buf[l]-buf[counted])/(l-counted); class="type">int z=class="num">1; class="type">bool yes=true; for(i=l-class="num">1;i>counted;z++,i--) if(buf[i]<buf[l]+k*z){yes=class="kw">false;class="kw">break;} if(yes) { DrawPriceTrendLine(time[l],time[counted],low[l],low[counted],Green,STYLE_DOT); DrawIndicatorTrendLine(time[l],time[counted],buf[l],buf[counted],Green,STYLE_DOT); class="kw">break; } } class="type">int Extremum(class="type">class="kw">double a,class="type">class="kw">double b,class="type">class="kw">double c) { if((a-b)*(b-c)<=class="num">0) { if(c>b) class="kw">return(class="num">1); class=class="str">"cmt">//DN extremum if(c<b) class="kw">return(-class="num">1);class=class="str">"cmt">//UP extremum } class="kw">return(class="num">0); } class="type">int LastPeak(class="type">int l,class="kw">const class="type">class="kw">double &buf[]) { for(class="type">int i=l-class="num">2; i>class="num">4; i--) { class="type">int ext=Extremum(buf[i+class="num">1],buf[i],buf[i-class="num">1]);
◍ 极值回溯与箭头落点的代码实现
在 ZigZag 类指标里,定位次高点和次低点靠的是反向极值回溯。LastPeak 从下标 l-2 向前扫到 4,遇到 Extremum 返回负值(局部峰)就吐出该下标;LastTrough 同理捕捉正值(局部谷),找不到则返回 -1。这种写法把「最近一个有效转折」的搜索窗口硬性锁在长度 4 以上,避免毛刺误判。 ArrowCreate 封装了 MT5 图形对象的创建细节:先用 ResetLastError 清错误码,再 ObjectCreate 画 OBJ_ARROW,箭头代码写死 167(即 Wingdings 里的某一下指符号)。随后一连串 ObjectSetInteger 把锚点、颜色、线宽 1、不选中、隐藏都设好——HIDDEN 置 true 后对象不会出现在终端对象列表,减少界面噪音。 DrawPriceTrendLine 负责连线,name_0 用短名拼颜色字符串做唯一标识;当 allLine 为 true 时,name_1 追加时间戳 DoubleToString(T_0,0) 以区分多条历史线。外汇与贵金属波动剧烈,这类辅助线仅作结构参考,实际突破概率需结合成交量与更高周期验证。
if(ext < class="num">0)class="kw">return (i); } class="kw">return (-class="num">1); } class=class="str">"cmt">//+----- Search for the second DN extremum --------------------------+ class="type">int LastTrough(class="type">int l,class="kw">const class="type">class="kw">double &buf[]) { for(class="type">int i=l-class="num">2; i>class="num">4; i--) { class="type">int ext=Extremum(buf[i+class="num">1],buf[i],buf[i-class="num">1]); if(ext > class="num">0)class="kw">return (i); } class="kw">return (-class="num">1); } class=class="str">"cmt">//+-------------------- Creates an arrow -----------------------------+ class="type">bool ArrowCreate(class="type">class="kw">string name, class="type">class="kw">datetime time, class="type">class="kw">double price, ENUM_ARROW_ANCHOR anchor, class="type">class="kw">color clr) { class=class="str">"cmt">//--- reset the error value ResetLastError(); class=class="str">"cmt">//--- create an arrow if(!ObjectCreate(class="num">0,name,OBJ_ARROW,class="num">0,time,price)) { Print(__FUNCTION__, ": failed to create an arrow! Error code = ",GetLastError()); class="kw">return(class="kw">false); } ObjectSetInteger(class="num">0,name,OBJPROP_ARROWCODE,class="num">167); class=class="str">"cmt">//--- set the binding type ObjectSetInteger(class="num">0,name,OBJPROP_ANCHOR,anchor); ObjectSetInteger(class="num">0,name,OBJPROP_COLOR,clr); ObjectSetInteger(class="num">0,name,OBJPROP_STYLE,STYLE_SOLID); ObjectSetInteger(class="num">0,name,OBJPROP_WIDTH,class="num">1); ObjectSetInteger(class="num">0,name,OBJPROP_BACK,class="kw">false); ObjectSetInteger(class="num">0,name,OBJPROP_SELECTABLE,class="kw">false); ObjectSetInteger(class="num">0,name,OBJPROP_SELECTED,class="kw">false); ObjectSetInteger(class="num">0,name,OBJPROP_HIDDEN,true); class=class="str">"cmt">//--- successful implementation class="kw">return(true); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//+------ Creating objects on the price chart -----------------------+ class="type">void DrawPriceTrendLine(class="type">class="kw">datetime T_0,class="type">class="kw">datetime T_1,class="type">class="kw">double P_0,class="type">class="kw">double P_1,class="type">class="kw">color color_0,class="type">int style) { class="type">class="kw">string name_0=short_name+"Line_Sn"+ColorToString(color_0); class="type">class="kw">string name_1=""; if(allLine) name_1=short_name+DoubleToString(T_0,class="num">0); else
「在主图与指标窗画趋势线的两套逻辑」
这段脚本把趋势线绘制拆成了主图与指标子窗两套入口。主图里用 DoubleToString(T_1,0) 拼对象名,先 ObjectDelete 清旧线再 drawLineS 重画;当 style 为 STYLE_DOT 时点线反向补一条 clrAqua 的射线,宽度设 3。 指标窗函数 DrawIndicatorTrendLine 用 wid 指定窗口号,对象名带 ColorToString(color_0) 防止同色覆盖;allLine 开关决定用 T_0+wid 还是 T_1+wid 命名。STYLE_SOLID 时额外画一条 clrMagenta、宽度 2 的反向线做视觉锚点。 真正干活的 drawLineS 只用 OBJ_TREND 一个类型:ObjectCreate 给时间/价格两点,OBJPROP_RAY_RIGHT 控制向右延伸,OBJPROP_SELECTABLE 设 false 让线不可点选,back 参数决定压在 K 线底下还是浮在上面。复制进 MT5 把 wid 改成你指标所在窗口号,就能直接看到双线叠加效果;外汇贵金属杠杆高,画线仅辅助判势,实际进出场仍需结合风控。
name_1=short_name+DoubleToString(T_1,class="num">0); class=class="str">"cmt">//--- ObjectDelete(class="num">0,name_1); drawLineS(name_1,T_0,T_1,P_0,P_1,color_0,style,class="num">0,true,class="kw">false,class="num">0); class=class="str">"cmt">//+-----------+ if(style==STYLE_DOT) { ObjectDelete(class="num">0,name_0); drawLineS(name_0,T_1,T_0,P_1,P_0,clrAqua,class="num">0,class="num">3,true,true,class="num">0); } } class=class="str">"cmt">//+------ Creating objects in the indicator window ------------------+ class="type">void DrawIndicatorTrendLine(class="type">class="kw">datetime T_0,class="type">class="kw">datetime T_1,class="type">class="kw">double P_0,class="type">class="kw">double P_1,class="type">class="kw">color color_0,class="type">int style) { class="type">int window=wid; class="type">class="kw">string name_0=short_name+"Line_Pn"+ColorToString(color_0); class="type">class="kw">string name_1=""; if(allLine) name_1=short_name+DoubleToString(T_0+wid,class="num">0); else name_1=short_name+DoubleToString(T_1+wid,class="num">0); class=class="str">"cmt">//--- ObjectDelete(class="num">0,name_1); drawLineS(name_1,T_0,T_1,P_0,P_1,color_0,style,class="num">0,class="kw">false,class="kw">false,window); class=class="str">"cmt">//--- if(style==STYLE_SOLID) { ObjectDelete(class="num">0,name_0); drawLineS(name_0,T_1,T_0,P_1,P_0,clrMagenta,style,class="num">2,true,true,window); } } class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void drawLineS(class="type">class="kw">string name,class="type">class="kw">datetime T_0,class="type">class="kw">datetime T_1,class="type">class="kw">double P_0,class="type">class="kw">double P_1,class="type">class="kw">color clr, class="type">int style,class="type">int width,class="type">bool back,class="type">bool ray,class="type">int window) { ObjectCreate(class="num">0,name,OBJ_TREND,window,T_0,P_0,T_1,P_1,class="num">0,class="num">0); ObjectSetInteger(class="num">0,name,OBJPROP_RAY_RIGHT,ray); ObjectSetInteger(class="num">0,name,OBJPROP_COLOR,clr); ObjectSetInteger(class="num">0,name,OBJPROP_STYLE,style); ObjectSetInteger(class="num">0,name,OBJPROP_WIDTH,width); ObjectSetInteger(class="num">0,name,OBJPROP_SELECTABLE,class="kw">false); ObjectSetInteger(class="num">0,name,OBJPROP_BACK,back); }
把工具请下神坛
这套背离研究只放出冰山一角:随文附的 ADX_Osc.mq5 指标与 TestADX.mql5 智能系统,是验证思路的实物,不是圣杯。作者本人写 EA 只为摸清 MQL5 语言边界、检验想法,而非承诺某种稳定盈利路径。 外汇与贵金属市场高杠杆、高波动,任何指标或机器人都只是你策略里的零件。与其追问怎么改已发表代码,不如自己开 MT5 把 ADX_Osc 加载到图表,用 TestADX 跑一段历史,看背离信号在你常做品种上的触发频率。 后续可能还有非标准解法的续篇,但主动权始终在你的终端里——工具请下神坛,参数自己调。