CCI 指标。 升级和新特征·进阶篇
三种CCI算法在EURUSD上的实盘回测差异
经典 CCI 用样本均值加减绝对偏差均值来定边界,正常计算下时间序列的极值会戳出均值±偏差;而强健估算里原始序列所有值都收在边界内。光看公式差异不够直观,得拉到真实报价上跑。 我们把三种算法(经典、标准差版、强健版)各写成独立指标,核心变量就两个:应用的价格常量(MT5 里在指标属性设 PRICE_TYPICAL)和周期。周期至少得 3,小于此值容易算出过陡峭的失真值。 为避开肉眼对比的主观性,写了个极简 EA:新柱开盘算指标值,上穿负级别开多平空,下穿正级别开空平多。测试固定为 EURUSD、H1、2021 全年、周期 14、典型价、级别 150(对应经典 CCI 的 100 线)。 回测结果有清晰分界:标准差版交易次数减少,大额亏损随之减少;强健版进一步增加交易次数,且大幅亏损次数继续下降,这是该版本最实用的优势。外汇与贵金属属高风险品种,上述规律仅基于历史数据,未来走势可能偏离。 无论哪种版本,这套开平仓规则都还很粗糙,直接上实盘大概率要栽,必须重做过滤条件。
class="macro">#class="kw">property indicator_applied_price PRICE_TYPICAL class="kw">input class="type">class="kw">ushort iPeriod=class="num">14;class=class="str">"cmt">//indicator period class="type">class="kw">double mean=class="num">0; class=class="str">"cmt">//sample mean for(class="type">int j=class="num">0; j<iPeriod; j++) { mean=mean+price[i+j]; class=class="str">"cmt">//sum up price values } mean=mean/iPeriod; class=class="str">"cmt">//sample mean for the period class="type">class="kw">double mad=class="num">0; class=class="str">"cmt">//mean absolute deviation for(class="type">int j=class="num">0; j<iPeriod; j++) { mad=mad+MathAbs(price[i+j]-mean); class=class="str">"cmt">//sum up absolute difference values } res=(price[i]-mean)*iPeriod/mad; class="type">class="kw">double sumS=class="num">0,class=class="str">"cmt">//sum of prices sumQ=class="num">0;class=class="str">"cmt">//sum of price squares for(class="type">int j=class="num">0; j<iPeriod; j++) { sumS=sumS+price[i+j]; sumQ=sumQ+price[i+j]*price[i+j]; } class="type">class="kw">double denom=MathSqrt(iPeriod*sumQ-sumS*sumS); res=(iPeriod*price[i]-sumS)/denom; class="type">class="kw">double halfsums[],diff[]; class="type">int size=iPeriod*(iPeriod-class="num">1)/class="num">2; class=class="str">"cmt">//halfsums array size ArrayResize(halfsums,size); class=class="str">"cmt">//set the array size indx10=size/class="num">2; indx11=indx10; if(MathMod(size,class="num">2)==class="num">0) indx11=indx10-class="num">1; ArrayResize(diff,iPeriod); indx20=iPeriod/class="num">2; indx21=indx20; if(MathMod(iPeriod,class="num">2)==class="num">0) indx21=indx20-class="num">1; class="type">int cnt=class="num">0; class=class="str">"cmt">//counter of array elements for(class="type">int j=iPeriod-class="num">2; j>=class="num">0; j--) { for(class="type">int k=iPeriod-class="num">1; k>j; k--) { halfsums[cnt]=(price[i+j]+price[i+k])/class="num">2; class=class="str">"cmt">//half sum value cnt++; class=class="str">"cmt">//increase the counter } } ArraySort(halfsums); class=class="str">"cmt">//sort the array class="type">class="kw">double mean=(halfsums[indx10]+halfsums[indx11])/class="num">2; class=class="str">"cmt">//robust mean
◍ 用绝对偏差中位数替代标准差
这段循环把最近 iPeriod 根 K 线的价格与均值之差取绝对值,塞进 diff 数组,目的是绕开经典标准差对异常值的过度敏感。 for(int j=0; j<iPeriod; j++) { diff[j]=MathAbs(price[i+j]-mean); } ArraySort(diff); double sd=(diff[indx20]+diff[indx21])/2; //robust standard deviation res=(price[i]-mean)/sd; 排序后取第 20、21 个元素的均值作为稳健标准差,相当于用中间段绝对偏差代表离散度,样本量够大时比直接算方差更抗毛刺。 res 即标准化后的偏离度,外汇与贵金属波动常带跳空,用这套稳健量纲做 z-score 阈值,比普通 STD 更不容易被单根极端 K 线骗到,但杠杆品种高风险仍在,参数 iPeriod 与 indx20/21 需在 MT5 里按品种复盘调。
for(class="type">int j=class="num">0; j<iPeriod; j++) { diff[j]=MathAbs(price[i+j]-mean); } ArraySort(diff); class="type">class="kw">double sd=(diff[indx20]+diff[indx21])/class="num">2; class=class="str">"cmt">//robust standard deviation res=(price[i]-mean)/sd;
「给 CCI 加一个累计求和的改法」
CCI 指标原生就能取正值和负值,正区对应上升段,负区对应下降段。原版只看瞬时穿越,容易在震荡里反复挨耳光。 思路是把 CCI 从趋势起点到终点的值做累加,再和均值比,用来判断这段趋势走了多久、力度够不够。实现上用稳健估算版本打底,唯一改动是:只在 CCI 上穿零轴后才开始累加,输出这个累计额。 上升和下降的累计均值分开算,方便直接对照。图上看,曲线长时间贴着均值上沿跑,说明多头趋势在持续放量;跌破自身均值线,往往就是一段趋势进入尾声的信号。 基于这个改版指标,最简策略是:当累计额从高位回落并下穿平均级别,且原趋势强度高于均值时,价格朝反方向修正的概率偏高。外汇和贵金属波动杠杆大,这种反转只是概率倾向,必须配合止损。
画得少,看得清
把 CCI 拆成三套实现再比对,价值不在指标本身,而在验证「没有哪个版本是终局」。mCCI 给出三种 CCI 写法,EA_CCI 用 7.46 KB 的 MQ5 把不同版本丢进同一逻辑跑差异,tCCI 则另算累计趋势量——三者同附在文末压缩包,MT5 里直接编译就能复现。 真正能落地的动作很简单:下载那三个 .mq5,把 EA_CCI 里的 CCI 源切换成 mCCI 的三种模式各跑一周回测,看哪版在黄金 1 小时图上的假信号更少。外汇与贵金属杠杆高,回测优不代表实盘稳,结论只作概率参考。 指标永远留着被改的余地,与其追新,不如把手上这套改到顺手。