趋势有多长?·进阶篇
(2/2)· 30%趋势对70%震荡是经验还是错觉?用四种改造指标跑数据揭穿
◍ 多周期 ADX 趋势占比的批量统计写法
在 MT5 里做多周期扫描,常见做法是先用循环给每个周期拿指标句柄。下面这段逻辑遍历 tf_size 个周期,分别建 ADX 句柄并做失败校验,拿不到句柄直接返回 false,避免后面空跑。 循环内先按可用 K 线数决定拷贝深度:bars 不足 NumCandles 时取 bars,否则取 NumCandles。CopyBuffer 拿到 adx 数组后,统计其中大于 TrendLevel 的柱子数 count,再用 (count/to_copy)*100 算出该周期的趋势占比 result[i],最后 IndicatorRelease 释放句柄。 统计完各周期占比后,把结果写进画布表格第 1 列:UI.m_canvas_table.SetValue(i,1,DoubleToString(result[i-1],2)),再 UpdateTable(true) 刷新。外汇与贵金属波动剧烈,ADX 阈值仅是概率参考,实际趋势延续倾向需结合多周期共振判断。 顺带看另一类占比统计:以趋势百分比为例,InpPeriodPoT=20、UpTrendLevel=0.8、DnTrendLevel=0.2,若 pot[j]>=0.8 或 <=0.2 就计一次数,同样归算成百分比。BB、RSI、ZZ 等模块也是同样套路——满足条件的柱子累加后除以 to_copy 乘 100。开 MT5 把 TrendLevel 从默认 25 改成 20,能明显看到占比数值上浮,可自行验证灵敏度。
for(class="type">int i=class="num">0;i<tf_size;i++) { count=class="num">0; Ind_Handle[i]=iADX(Symbol(),Ind_Timeframe[i],InpInd_ADXPeriod); if(Ind_Handle[i]==INVALID_HANDLE) { Print(" 取得指标句柄失败"); class="kw">return(class="kw">false); } class=class="str">"cmt">//--- 模块 class="num">2 bars=Bars(Symbol(),Ind_Timeframe[i]); to_copy=(bars<NumCandles)?bars:NumCandles; class=class="str">"cmt">//--- if(CopyBuffer(Ind_Handle[i],class="num">0,class="num">0,to_copy,adx)<=class="num">0) class="kw">return(class="kw">false); class=class="str">"cmt">//--- 模块 class="num">3 for(class="type">int j=class="num">0;j<to_copy;j++) { if(adx[j]>TrendLevel) count++; } result[i]=(count/to_copy)*class="num">100; IndicatorRelease(Ind_Handle[i]); } class=class="str">"cmt">//--- 模块 class="num">4 for(class="type">int i=class="num">1;i<=tf_size;i++) UI.m_canvas_table.SetValue(i,class="num">1,DoubleToString(result[i-class="num">1],class="num">2)); UI.m_canvas_table.UpdateTable(true); class="kw">return(true); } for(class="type">int j=class="num">0;j<to_copy;j++) { if(bb[j]) count++; } result[i]=(count/to_copy)*class="num">100; class=class="str">"cmt">//--- 趋势百分比的参数 class="kw">input class="type">int InpPeriodPoT=class="num">20; class="kw">input class="type">class="kw">double UpTrendLevel=class="num">0.8; class="kw">input class="type">class="kw">double DnTrendLevel=class="num">0.2; for(class="type">int j=class="num">0;j<to_copy;j++) { if(pot[j]>=UpTrendLevel || pot[j]<=DnTrendLevel) count++; } result[i]=(count/to_copy)*class="num">100; for(class="type">int j=class="num">0;j<to_copy;j++) { if(rsi[j]) count++; } result[i]=(count/to_copy)*class="num">100; for(class="type">int j=class="num">0;j<to_copy;j++) { if(zz[j]) count++; } result[i]=(count/to_copy)*class="num">100; class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| 计算所有数据平均值的函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">class="kw">string GetAverage(class="type">class="kw">double &arr[]) { class="type">class="kw">double sum=class="num">0.0; class="type">int size=ArraySize(arr);
「初始化里把多指标统计结果压成一行」
EA 在 OnInit 里先调 SetInfoPanel 搭好界面,再串行跑五个统计函数:GetADXCount、GetColorBBCount、GetPoTCount、GetRSICount、GetZZCount。五个都返回真,才认为历史柱扫描有效。 若全部通过,标签直接输出“已完成. N 个柱的结果. 平均有趋势时间段 - X%”,其中 N 来自 NumCandles,X 是 GetAverage(avr_result) 算出的两位小数文本。任一函数失败则标签写“错误”,不抛异常但面板失去参考意义。 GetAverage 内部就是最朴素的求和除size,再 DoubleToString(sum,2) 截断两位小数——外汇与贵金属品种上跑这套统计属于高频重算,实盘前务必在 MT5 策略测试器用小周期样本核对 NumCandles 与 avr_result 的对应关系,避免大样本下界面刷新拖慢主线程。
for(class="type">int i=class="num">0;i<size;i++) sum+=arr[i]; sum/=size; class="kw">return(DoubleToString(sum,class="num">2)); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| EA交易初始化函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">int OnInit() { SetInfoPanel(); if(GetADXCount() && GetColorBBCount() && GetPoTCount() && GetRSICount() && GetZZCount() ) UI.m_label1.LabelText("已完成. "+IntegerToString(NumCandles)+" 个柱的结果. 平均有趋势时间段 - "+GetAverage(avr_result)+"%"); else { UI.m_label1.LabelText("错误"); } class=class="str">"cmt">//--- class="kw">return(INIT_SUCCEEDED); }
用斯皮尔曼系数拆穿样本大小的陷阱
跨资产回测选了 EURUSD、USDCHF、USDJPY、GBPUSD 四个货币对,外加期货 GOLD-6.17 与股票 #MCD,统一取 2000 根 K 线做样本。四个货币对平均约 60% 时间处于趋势状态,且不同时段与方法差异不大;但 D1、W1 的期货因历史不足 2000 根,实际按最大可用历史计算,结果偏离整体。 真正值得做的是追问:趋势/平盘比例会不会随样本长度变?用 Spearman 等级相关系数测 X(测试柱数)与 Y(趋势时间占比)的依赖。公式 ρ=1-6Σd²/(n(n²-1)),值域 -1 到 1,正为同向、负为反向、零为无关。以 EURUSD 的 ADX 法为例,n=7,柱数取 100/200/300/500/1000/1500/2000,对应趋势占比 75.78% 到 81.44%,算得 ρ=0.96,属强正相关。 把五种方法在 EURUSD 上的系数列出来:ADX 0.96、ColorBBCount 0.89、趋势百分比 0.68 为正向;RSI 过滤器 -0.68 反向;ZigZagTrendDetector -0.07 几乎无关。跨品种汇总后分化明显——EURUSD、GBPUSD、#MCD 多数方法显正向,USDCHF 与 GOLD-6.17 多为负或零,USDJPY 基本不依赖样本大小。 拿周线长历史验证:EURUSD 1995–2007 是两波持续数年的强趋势,之后波动双向化、趋势强度走弱,和系数暗示一致;USDJPY 周线自 1995 起先强涨后频繁震荡,印证其无样本依赖;#MCD 过去单边涨无回调,越近现在趋势/平盘混杂,五种方法全显关联。外汇与贵金属属高风险品种,样本结论仅描述历史概率倾向,实盘须自测。 下面这段输入参数可直接拷进 MT5 EA 头部,把 NumCandles 从 2000 改成 100~2000 扫一遍,就能复算自己的 Spearman 依赖。
class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| EA交易的输入参数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="kw">input class="type">int NumCandles=class="num">2000; class=class="str">"cmt">//分析的柱数 class=class="str">"cmt">//---- ADX 参数 class="kw">input class="type">class="kw">string com1=""; class=class="str">"cmt">//---- ADX 参数 class="kw">input class="type">int InpInd_ADXPeriod=class="num">14; class=class="str">"cmt">//ADX 周期数 class="kw">input class="type">class="kw">double TrendLevel=class="num">20.0; class=class="str">"cmt">//--- ColorBBCandles 参数 class="kw">input class="type">class="kw">string com2=""; class=class="str">"cmt">//---- ColorBBCandles 参数 class="kw">input class="type">int BandsPeriod=class="num">20; class=class="str">"cmt">// BB 平均周期数 class="kw">input class="type">class="kw">double BandsDeviation=class="num">1.0; class=class="str">"cmt">// 偏差
◍ 把三层过滤器塞进输入参数
做多周期共振的警报指标,第一道关是把可调参数全部摊在 input 区,避免硬编码后改一次重新编译。下面这段声明同时挂了趋势百分比、RSI 过滤、ZigZag 拐点三组条件,每组用空字符串 input 当分隔标签,MT5 参数面板上会显示成分组空白行。 趋势百分比默认看 20 根 K 线,上线 0.7、下线 0.3,意思是收盘价比率高于七成判为多、低于三成判为空。RSI 过滤周期给 10,超买 60、超卖 40,比经典的 70/30 更敏感,适合剥头皮或 H1 以内周期。 ZigZag 探测器 Depth=5、Deviation=5、Backstep=3,是极轻量的拐点识别,用来确认前面两组过滤不发生在震荡假突破里。外汇与贵金属杠杆高,参数敏感也意味着信号频次高,实盘前务必在策略测试器里跑至少三个月 tick 数据验证误报率。 打开 MT5 新建指标,把下面代码整段贴进顶层声明区,编译后就能在参数页看到三组滑杆,先不动数值跑一遍 EURUSD 的 M15 看信号密度。
class="kw">input ENUM_MA_METHOD MA_Method_=MODE_SMA; class=class="str">"cmt">// 指标平均方法 class="kw">input Applied_price_ IPC=PRICE_CLOSE_; class=class="str">"cmt">// 价格常数 class=class="str">"cmt">//--- 趋势百分比的参数 class="kw">input class="type">class="kw">string com3=""; class=class="str">"cmt">//---- 趋势百分比参数 class="kw">input class="type">int InpPeriodPoT=class="num">20; class="kw">input class="type">class="kw">double UpTrendLevel=class="num">0.7; class="kw">input class="type">class="kw">double DnTrendLevel=class="num">0.3; class=class="str">"cmt">//--- RSIFilter 参数 class="kw">input class="type">class="kw">string com4=""; class=class="str">"cmt">//---- RSIFilter 参数 class="kw">input class="type">uint RSIPeriod=class="num">10; class=class="str">"cmt">// 指标周期数 class="kw">input ENUM_APPLIED_PRICE RSIPrice=PRICE_CLOSE; class=class="str">"cmt">// 价格 class="kw">input class="type">uint HighLevel=class="num">60; class=class="str">"cmt">// 超买水平 class="kw">input class="type">uint LowLevel=class="num">40; class=class="str">"cmt">// 超卖水平 class=class="str">"cmt">//--- ZigZagTrendDetector 参数 class="kw">input class="type">class="kw">string com5=""; class=class="str">"cmt">//---- ZigZagTrendDetector 参数 class="kw">input class="type">int ExtDepth=class="num">5; class="kw">input class="type">int ExtDeviation= class="num">5; class="kw">input class="type">int ExtBackstep = class="num">3;
「六成时间有趋势,但平盘正在吃掉区间」
把五个直盘和黄金、MCD 的综合数值拉成一张表后,趋势时间占比的平均数落在 59.55%–63.05% 之间:EURUSD 62.54%、USDCHF 62.27%、USDJPY 63.05%、GBPUSD 60.68%、GOLD-6.17 59.55%、#MCD 59.71%。 给定这套测试条件,市场处于趋势态的时间平均约 60%;但顺着时间轴从远到近看,趋势和平盘的比例在慢慢滑向平盘占优,逐渐逼近 30:70 这个当初假设的初始水平。 这背后说明一件事:外汇和贵金属的高风险环境里,波动在被放大,趋势和平盘的切换频率比以前更高。原本能拿几周的长期趋势,越来越多地塌缩成短期杂波,形态边界也变得更模糊,行情的阶段和转折肉眼更难拆。
一点提醒
这套工具包以 ZIP 形式提供,体积 1693.17 KB,解压后把 MQL5 目录整体丢进终端根目录即可,EA 与指标会自动归位到对应文件夹。里面含 TrendCount.mq5 这类测试用 EA,以及 ColorBBCandles、percentageoftrend 等基于布林带和 RSI 过滤的趋势识别指标。 有读者在下方讨论里提到,找不到文中说的修改版 ADX 代码,作者也未补发;这意味着你拿到的是已列明的 6 个文件,别指望压缩包里藏了额外滤波器。 外汇和贵金属杠杆高、滑点随机,这类趋势统计工具只能帮你看清状态比例,不预示下一根 K 线方向。真要上实盘,先开 MT5 用 TrendCount 跑一周历史,再决定信哪根线。