Erik Nayman 的绳索指标·进阶篇
🪢

Erik Nayman 的绳索指标·进阶篇

(2/3)· 接上篇概念铺垫,本篇直接落地代码实现、实盘用法与输入参数调优

新手友好 第 2/3 篇
不少交易者把绳索指标的两根力度线当普通均线交叉看,忽略了静态值与相邻周期动态增量的差别。这样容易在横盘拉锯段误判主导方,把多空均势当成趋势启动。

新K线出现时的数组与时间序列处理

在 MT5 自定义指标里,把 time、open、high、low、close 以及十几个 Buffer_ 开头的数组全部用 ArraySetAsSeries(...,true) 置为时间序列,是后续按索引 0 取最新值的前提。最低索引 0 对应历史中最后一个已知计算值,这个设定直接决定你循环里引用 close[0] 拿到的是不是当前未收盘柱。 当 prev_calculated==0(例如断网很久后重连,历史有缺口)或 prev_rates_total>rates_total(数据大小回缩,视为失败需重算),代码会把 _tm_prev 清零。只有 _tm_prev<time[0] 即新柱线出现时才进计算分支,避免每笔 tick 都重跑全量逻辑。 若 _tm_prev>0 表示已有旧计算数据,则调用 TakeShift_byTime(Symbol(),PERIOD_CURRENT,_tm_prev) 按最后计算时间做柱线移位;返回值 copy<=0 就直接 return 0,等下一 tick 再试。copy 有效时 bars_calc=copy+1,并从索引 0 开始把 Bull/Bear/mainline/MA/calc 等缓冲全清 0.0,颜色索引统一设 5(空色不绘制),保证未收盘首柱不显示残影。外汇与贵金属波动大、跳空频繁,这种断点重算机制直接影响指标在实盘里的重绘稳定性,建议开 MT5 用 EURUSD 15 分钟图断网测试一次。

MQL5 / C++
 class="kw">const class="type">int &spread[])
  {
  ArraySetAsSeries(time,true);
class=class="str">"cmt">//--- 设置数组索引作为时间序列, 最低索引 class="num">0 是历史中最后已知计算值
  ArraySetAsSeries(open,true);
  ArraySetAsSeries(high,true);
  ArraySetAsSeries(low,true);
  ArraySetAsSeries(close,true);
  ArraySetAsSeries(Buffer_main_bull,true);
  ArraySetAsSeries(Buffer_color_bull,true);
  ArraySetAsSeries(Buffer_main_bear,true);
  ArraySetAsSeries(Buffer_color_bear,true);
  ArraySetAsSeries(Buffer_mainline,true);
  ArraySetAsSeries(Buffer_mainline_color,true);
  ArraySetAsSeries(Buffer_MAfast,true);
  ArraySetAsSeries(Buffer_MAslow,true);
  ArraySetAsSeries(Buffer_calc,true);
  ArraySetAsSeries(Buffer_calc_bull,true);
  ArraySetAsSeries(Buffer_calc_bear,true);
  ArraySetAsSeries(Buffer_calcLINE,true);
class=class="str">"cmt">//--- 
  class="type">int copy=class="num">0;
  bars_calc=class="num">0;
class=class="str">"cmt">//--- 计算指标数据
class=class="str">"cmt">//--- 当 prev_calculated = class="num">0 所有已计算柱线的所有数据需要再次计算 , =class="num">0 历史数据中有缺口则等于零, 例如, 当断网很长一段时间
  if(prev_calculated==class="num">0) _tm_prev=class="num">0;
class=class="str">"cmt">//---如果以前的大小大于当前大小, 它表示失败且所有数据必须重计算
  if(prev_rates_total>rates_total) _tm_prev=class="num">0;
  if(_tm_prev<time[class="num">0]) class=class="str">"cmt">// 当新柱线出现时计算
    {
     if(_tm_prev>class="num">0) class=class="str">"cmt">// 如果指标已经有以前计算的数据
       {
       copy=TakeShift_byTime(Symbol(),PERIOD_CURRENT,_tm_prev); class=class="str">"cmt">// 当前品种柱线沿最后计算的柱线时间移位
       if(copy<=class="num">0) class=class="str">"cmt">// 如果移位未发现, 则计算偏离并在下一次瞬时报价重复
         {
          class="kw">return class="num">0;
         }
       bars_calc=copy+class="num">1; class=class="str">"cmt">// 设置自当前指标未收盘柱线开始计算
       class=class="str">"cmt">//--- 首根未收盘柱线清零, 即, 其数据未计算
       Buffer_main_bull[class="num">0]=class="num">0.0;
       Buffer_color_bull[class="num">0]=class="num">5; class=class="str">"cmt">// 设置颜色索引, 号码 class="num">5 对应空色, 所以不会绘制颜色
       Buffer_main_bear[class="num">0]=class="num">0.0;
       Buffer_color_bear[class="num">0]=class="num">5; class=class="str">"cmt">// 设置颜色索引, 号码 class="num">5 对应空色, 所以不会绘制颜色
       Buffer_mainline[class="num">0]=class="num">0.0;
       Buffer_mainline_color[class="num">0]=class="num">5; class=class="str">"cmt">// 设置颜色索引, 号码 class="num">5 对应空色, 所以不会绘制颜色
       Buffer_MAfast[class="num">0]=class="num">0.0;
       Buffer_MAslow[class="num">0]=class="num">0.0;
       Buffer_calc[class="num">0]=class="num">0.0;
       Buffer_calc_bull[class="num">0]=class="num">0.0;
       Buffer_calc_bear[class="num">0]=class="num">0.0;
       Buffer_calcLINE[class="num">0]=class="num">0.0;
       }
     else class=class="str">"cmt">// 如果指标首次设置且数值尚未计算

◍ 缓冲区清零与价格差值计算的开端

指标初始化时先把全部绘图缓冲清零,是避免 MT5 重绘错位的硬规矩。下面这段把 9 个 buffer 逐根柱线置 0,包括多空主缓冲、均线缓冲与计算缓冲,循环里还嵌了 IsStopped() 检查,终端手动停止时立刻断循环。 计算起点用 bars_calc = Bars(Symbol(),PERIOD_CURRENT)-1,即从倒数第二根柱开始,留出 i+1 作对比基准。若 bars_calc 算出来小于 0 直接 return 0 放弃本轮;若超过 max_bars 且 max_bars 不为 0 则截断,实盘把 max_bars 设 5000 可明显降 CPU 占用。 随后按 _price 枚举切换计算相邻柱线价差:收盘、开盘、最高、最低、中位数、典型价、加权价都能选。以 PRICE_TYPICAL 为例,Buffer_calc[i]=((high[i]+low[i]+close[i])/3)-((high[i+1]+low[i+1]+close[i+1])/3),这一步是后续多空动能拆分的原始输入。外汇与贵金属波动大,此类差值对点差敏感,建议先在策略测试器用 2023 年 XAUUSD 的 M5 数据跑一遍验证缓冲逻辑。

MQL5 / C++
bars_calc=Bars(Symbol(),PERIOD_CURRENT)-class="num">1; class=class="str">"cmt">// 柱线移位到总柱线数 -class="num">1 开始计算
class=class="str">"cmt">//--- 所有柱线的所有数据清零以避免绘图错误 
for(class="type">int i=class="num">0;i<Bars(Symbol(),PERIOD_CURRENT) && !IsStopped(); i++)
  {
   Buffer_main_bull[i]=class="num">0.0;
   Buffer_main_bear[i]=class="num">0.0;
   Buffer_mainline[i]=class="num">0.0;
   Buffer_MAfast[i]=class="num">0.0;
   Buffer_MAslow[i]=class="num">0.0;
   Buffer_calc[i]=class="num">0.0;
   Buffer_calc_bull[i]=class="num">0.0;
   Buffer_calc_bear[i]=class="num">0.0;
   Buffer_calcLINE[i]=class="num">0.0;
  }
class=class="str">"cmt">//--- 如果用于指标计算的柱线数量低于零, 则计算将被放弃
if(bars_calc<class="num">0) class="kw">return class="num">0;
class=class="str">"cmt">//--- 限制计算 max_bars 值的柱线数量
if(bars_calc>max_bars && max_bars!=class="num">0) bars_calc=max_bars;
for(class="type">int i=class="num">1; i<bars_calc && !IsStopped(); i++)
  {
   class=class="str">"cmt">//--- 根据 _price 设置, 计算两根柱线报价间的差值
   class="kw">switch(_price)
     {
      case PRICE_CLOSE:
       Buffer_calc[i]=close[i]-close[i+class="num">1];
       class="kw">break;
      case PRICE_OPEN:
       Buffer_calc[i]=open[i]-open[i+class="num">1];
       class="kw">break;
      case PRICE_HIGH:
       Buffer_calc[i]=high[i]-high[i+class="num">1];
       class="kw">break;
      case PRICE_LOW:
       Buffer_calc[i]=low[i]-low[i+class="num">1];
       class="kw">break;
      case PRICE_MEDIAN:
       Buffer_calc[i]=((high[i]+low[i])/class="num">2)-((high[i+class="num">1]+low[i+class="num">1])/class="num">2);
       class="kw">break;
      case PRICE_TYPICAL:
       Buffer_calc[i]=((high[i]+low[i]+close[i])/class="num">3)-((high[i+class="num">1]+low[i+class="num">1]+close[i+class="num">1])/class="num">3);
       class="kw">break;
      case PRICE_WEIGHTED:

「逐根K线累计多空力道的循环实现」

指标在主循环里对每根未计算柱线先清空 12 个缓冲区变量,再按 _period 窗口回看历史。注意 Buffer_color_bull[i]=5Buffer_color_bear[i]=5 这种初始值,是留给后续按信号强度重绘颜色的占位,MT5 里颜色索引 5 通常对应空画刷,初态不显示。 内层 for(int i2=i; i2<i+_period; i2++) 把窗口内每根 Buffer_calc[i2] 的正负分类:大于 0 累进 sum_bulltotal_bull++,小于 0 累进 sum_beartotal_bear++。这一步就是把一个分析周期内多头阳线动量、空头阴线动量分别记账。 窗口走完用 Buffer_calc_bull[i]=sum_bull/total_bull 求多头单根均值力道,空头同理。若 total_bull 为 0 则该缓冲区保持 0.0,意味着该窗口内无阳线,直方图不会误画多头柱。外汇与贵金属波动跳空频繁,这种按数量归一的做法在跳空缺口段可能低估真实单向力道,实盘前建议在 EURUSD 的 M15 上用 _period=10 跑一遍验证。 下方代码片段是分类累加的核心段,直接拷进 MT5 自定义指标 OnCalculate 后半段即可观察缓冲变化。

MQL5 / C++
for(class="type">int i=class="num">1; i<=bars_calc && !IsStopped(); i++)
{
   sum_bull=class="num">0.0;
   total_bull=class="num">0;
   sum_bear=class="num">0.0;
   total_bear=class="num">0;
   Buffer_main_bull[i]=class="num">0.0;
   Buffer_color_bull[i]=class="num">5;
   Buffer_main_bear[i]=class="num">0.0;
   Buffer_color_bear[i]=class="num">5;
   Buffer_mainline[i]=class="num">0.0;
   Buffer_mainline_color[class="num">0]=class="num">5;
   Buffer_calc_bull[i]=class="num">0.0;
   Buffer_calc_bear[i]=class="num">0.0;
   Buffer_calcLINE[i]=class="num">0.0;
   if(i>=(rates_total-_period)) class="kw">continue;
   for(class="type">int i2=i; i2<i+_period; i2++)
   {
      if(Buffer_calc[i2]>class="num">0)
      {
         sum_bull+=Buffer_calc[i2];
         total_bull++;
      }
      if(Buffer_calc[i2]<class="num">0)
      {
         sum_bear+=Buffer_calc[i2];
         total_bear++;
      }
   }
   if(total_bull>class="num">0) Buffer_calc_bull[i]=sum_bull/total_bull;
   if(total_bear>class="num">0) Buffer_calc_bear[i]=sum_bear/total_bear;
}

多空直方图的三级确认着色

指标把每一根柱线拆成多头和空头两条直方图,分别用累计点数除以柱线数量得到均值:total_bull>0 时 Buffer_main_bull[i]=sum_bull/total_bull,total_bear>0 时 Buffer_main_bear[i]=sum_bear/total_bear。这里的「活力」是柱线数量,「力度」是累计点数绝对值,「技巧」是覆盖周期内的力度/活力均值。 颜色索引不是拍脑袋,而是三个维度两两比较的结果。当 total_bull>total_bear 且 MathAbs(sum_bull)>MathAbs(sum_bear) 且 MathAbs(Buffer_main_bull[i])>MathAbs(Buffer_main_bear[i]),三个多头维度全压过空头,给 0 号色(深绿,高级别确认)。 只要任意两个多头指标胜出、一个空头指标胜出,就降一档到 1 号色(海绿,平均确认);若只有一个多头维度占优,则落到 2 号色(浅绿,低级别确认)。其余情况统一涂灰,代表买单禁止。外汇与贵金属波动剧烈,这种分级只描述概率倾向,实盘仍需自担高风险。 在 MT5 里把下面这段直接塞进 OnCalculate 的循环体,就能看见三档绿色随柱线切换;改一下比较里的 MathAbs 阈值,可以逼出更挑剔或更宽松的确认信号。

MQL5 / C++
if(total_bull>class="num">0) Buffer_main_bull[i]=sum_bull/total_bull;
class=class="str">"cmt">//--- 绘制空头的直方图, 用柱线的点数值除以柱线数量
if(total_bear>class="num">0) Buffer_main_bear[i]=sum_bear/total_bear;
class=class="str">"cmt">//--- class="num">0 直方图颜色 clrDarkGreen - 颜色索引 "仅买入", 买单具有高级别确认
class=class="str">"cmt">//--- 确认级别 - 所有指标示意多头趋势
class=class="str">"cmt">//--- 多头活力 > 空头活力 且 多头力度 > 空头力度 且 多头技巧 > 空头技巧
class=class="str">"cmt">//--- 活力 - 柱线数量
class=class="str">"cmt">//--- 力度 - 累计柱线点数大小
class=class="str">"cmt">//--- 技巧 - 覆盖指示周期的所有柱线的力度/活力计算平均值
if(total_bull>total_bear && MathAbs(sum_bull)>MathAbs(sum_bear) && MathAbs(Buffer_main_bull[i])>MathAbs(Buffer_main_bear[i])) Buffer_color_bull[i]=class="num">0;
else
  {
   class=class="str">"cmt">//--- 直方图颜色 clrMediumSeaGreen - 颜色索引 "买单允许", 买单具有平均级别确认
   class=class="str">"cmt">//--- 确认级别 - 任意两个多头指标和一个空头指标的组合
   if((total_bull>total_bear && MathAbs(sum_bull)>MathAbs(sum_bear) && MathAbs(Buffer_main_bull[i])<MathAbs(Buffer_main_bear[i])) ||
       (total_bull>total_bear && MathAbs(sum_bull)<MathAbs(sum_bear) && MathAbs(Buffer_main_bull[i])>MathAbs(Buffer_main_bear[i])) ||
       (total_bull<total_bear && MathAbs(sum_bull)>MathAbs(sum_bear) && MathAbs(Buffer_main_bull[i])>MathAbs(Buffer_main_bear[i]))) Buffer_color_bull[i]=class="num">1;
   else
     {
      class=class="str">"cmt">//--- 直方图颜色 clrLightGreen - 颜色索引 "买单允许", 买单具有低级别确认
      class=class="str">"cmt">//--- 确认级别 - 任意一个多头指标和两个空头指标的组合 
      if((total_bull>total_bear && MathAbs(sum_bull)<MathAbs(sum_bear) && MathAbs(Buffer_main_bull[i])<MathAbs(Buffer_main_bear[i])) ||
          (total_bull<total_bear && MathAbs(sum_bull)>MathAbs(sum_bear) && MathAbs(Buffer_main_bull[i])<MathAbs(Buffer_main_bear[i])) ||
          (total_bull<total_bear && MathAbs(sum_bull)<MathAbs(sum_bear) && MathAbs(Buffer_main_bull[i])>MathAbs(Buffer_main_bear[i]))) Buffer_color_bull[i]=class="num">2;
      else
        {
         class=class="str">"cmt">//--- 直方图颜色 clrGray - 颜色索引 "买单禁止"
         class=class="str">"cmt">//--- 确认级别 - 当多头指标缺失
        }
     }
  }

◍ 空头侧颜色分级的确认逻辑

这段着色代码只干一件事:根据多头与空头指标的数量差、绝对值求和差、以及主缓冲绝对值差,给空头直方图 Buffer_color_bear 打 0~3 四级标签。0 级(clrDarkRed)要求最严——total_bull<total_bear 且空头求和绝对值更大、主缓冲绝对值也更大,相当于所有指标一致看空,属高级别确认。

  • 级(clrIndianRed)放宽到「任意两个空头条件搭配一个多头条件」:比如数量空方占优但主缓冲多方更大,或数量多方占优但求和空方更大等三种组合,属平均级别确认。
  • 级(clrLightPink)则是「一个多头条件加两个空头条件」的逆向搭配,属低级别确认;其余情况统一归为 3 级(clrGray),即空头指标缺失、卖单禁止状态。

开 MT5 把这段塞进你自己的多指标合成脚本,改 Buffer_color_bear 的赋值色号,就能直接看出当前 K 线处在哪档做空置信度。外汇与贵金属波动剧烈,颜色分级只是概率倾向,不代表方向必现。

MQL5 / C++
if(total_bull<total_bear && MathAbs(sum_bull)<MathAbs(sum_bear) && MathAbs(Buffer_main_bull[i])<MathAbs(Buffer_main_bear[i])) Buffer_color_bear[i]=class="num">0;
else
  {
  if((total_bull<total_bear && MathAbs(sum_bull)<MathAbs(sum_bear) && MathAbs(Buffer_main_bull[i])>MathAbs(Buffer_main_bear[i])) ||
     (total_bull<total_bear && MathAbs(sum_bull)>MathAbs(sum_bear) && MathAbs(Buffer_main_bull[i])<MathAbs(Buffer_main_bear[i])) ||
     (total_bull>total_bear && MathAbs(sum_bull)<MathAbs(sum_bear) && MathAbs(Buffer_main_bull[i])<MathAbs(Buffer_main_bear[i]))) Buffer_color_bear[i]=class="num">1;
  else
    {
    if((total_bull<total_bear && MathAbs(sum_bull)>MathAbs(sum_bear) && MathAbs(Buffer_main_bull[i])>MathAbs(Buffer_main_bear[i])) ||
       (total_bull>total_bear && MathAbs(sum_bull)<MathAbs(sum_bear) && MathAbs(Buffer_main_bull[i])>MathAbs(Buffer_main_bear[i])) ||
       (total_bull>total_bear && MathAbs(sum_bull)>MathAbs(sum_bear) && MathAbs(Buffer_main_bull[i])<MathAbs(Buffer_main_bear[i]))) Buffer_color_bear[i]=class="num">2;
    else
      {
      Buffer_color_bear[i]=class="num">3;
      }
    }
  }

「主线着色与均线计算的收口逻辑」

主线 Buffer_mainline 的取值等于多空合计力度乘偏离系数,和 Buffer_calcLINE 共用同一算法,只是多了一层颜色判定。颜色索引写死为 0/1/2 三档:2 是灰(无确认),0 深绿(仅买、高级别确认),1 深红(仅卖、高级别确认)。 绿色触发要求三条件同时成立:total_bull>total_bear、绝对值 sum_bull>sum_bear、且当前柱 abs(Buffer_calc_bull[i])>abs(Buffer_calc_bear[i]);红色则三项全部反向。任一不满足就落回灰色,意味着信号未跨过「多指标共振」门槛。 均线部分先调用 ArraySetAsSeries(...,false) 关掉时间序列索引,把数组尾当作当前柱,再按 rates_total-bars_calc 起点向后推。max_bars>0 时若 i 小于 rates_total-max_bars 直接跳到边界并 continue,相当于只算最近 max_bars 根,老数据不重绘。 没拿到均线数据的柱先清 0,再按 method_MA_fast 分支选算法;MODE_SMA 只是入口,后面还有其它模式待接。外汇与贵金属波动剧烈,这种多指标确认仅降低假信号概率,实盘仍需自担高风险。

MQL5 / C++
Buffer_calcLINE[i]=(Buffer_calc_bull[i]+Buffer_calc_bear[i])*line_deviation;
class=class="str">"cmt">//--- 通过信号确认级别绘制填充颜色的线条
class=class="str">"cmt">// class="num">0 - clrDarkGreen - 颜色索引 "仅买入", 买单具有高级别确认
class=class="str">"cmt">// class="num">1 - clrDarkRed - 颜色索引 "仅卖出", 卖单具有高级别确认
class=class="str">"cmt">// class="num">2 - clrGray - 颜色索引 "无限制确认"
if(draw_line)
  {
   class=class="str">"cmt">//--- 绘制主线值, 累计空头和多头的技巧
   Buffer_mainline[i]=(Buffer_calc_bull[i]+Buffer_calc_bear[i])*line_deviation;
   class=class="str">"cmt">//--- 设置不确定线条颜色 (class="num">2 - clrGray)
   Buffer_mainline_color[i]=class="num">2;
   class=class="str">"cmt">//--- 设置多头线条颜色 (class="num">0 - clrDarkGreen) 当所有三个多头指标匹配 (多头 > 空头)
   if(total_bull>total_bear && MathAbs(sum_bull)>MathAbs(sum_bear) && MathAbs(Buffer_calc_bull[i])>MathAbs(Buffer_calc_bear[i])) Buffer_mainline_color[i]=class="num">0;
   class=class="str">"cmt">//--- 设置多头线条颜色 (class="num">1 - clrDarkRed) 当所有三个空头指标匹配 (空头 > 多头)
   if(total_bull<total_bear && MathAbs(sum_bull)<MathAbs(sum_bear) && MathAbs(Buffer_calc_bull[i])<MathAbs(Buffer_calc_bear[i])) Buffer_mainline_color[i]=class="num">1;
   }
  }
class=class="str">"cmt">//--- 计算并绘制均线
if(draw_MA_fast || draw_MA_slow)
  {
   class=class="str">"cmt">//--- 禁用索引作为时间序列来转换库 MovingAverages.mqh(索引改到数组结尾的当前历史柱线)
   ArraySetAsSeries(Buffer_calcLINE,class="kw">false);
   ArraySetAsSeries(Buffer_MAfast,class="kw">false);
   ArraySetAsSeries(Buffer_MAslow,class="kw">false);
   class=class="str">"cmt">//--- 迭代所有未计算柱线。迭代 = 所有柱线 (rates_total) - 柱线从最后已知计算过的时间 _tm_prev(bars_calc) 移位
   for(class="type">int i=rates_total-bars_calc; i<rates_total && !IsStopped(); i++)
     {
      class=class="str">"cmt">//--- 在参数 max_bars 里设置计算限制, 计算仅用设置在 max_bars 的数量作为所有柱线 (rates_total) 减设置数量 (max_bars) 的总差值。
      if(max_bars>class="num">0?(i<(rates_total-max_bars)):class="kw">false)
        {
         class=class="str">"cmt">//--- 如果当前索引 i 低于许可数值, 我们继续允许索引
         i=rates_total-max_bars;
         class="kw">continue;
         }
      class=class="str">"cmt">//--- 在未收到均线数据的情况下清空数组
      Buffer_MAfast[i]=class="num">0.0;
      Buffer_MAslow[i]=class="num">0.0;
      class=class="str">"cmt">//--- 基于 method_MA_fast 参数选择快速均线计算方法
      if(draw_MA_fast)
        {
         class="kw">switch(method_MA_fast)
           {
            case MODE_SMA: class=class="str">"cmt">// 简单平均
把重复劳动交给小布
绳索指标的逐根力度比较与动态增量计算,小布盯盘的 AIGC 已内置,打开对应品种页即可看到多空力度实时拉锯状态,你只管读方向。

常见问题

覆盖周期内正面变化合计大于负面变化合计时,对应方向数值更高即占主导;再叠加相邻周期动态增量方向可看力度是在增强还是衰减。
可以,小布盯盘对应品种页已内置基于价格变化速度的多空力度诊断,不需要自己逐根算 SPC 和 SNC。
将 BuF>BeF 且动态增量多头增长作为做多倾向,反之为空头增长做空倾向;具体触发还需结合周期与过滤条件。
覆盖周期决定力度平滑度,阈值影响信号频率,外汇贵金属高风险下建议先固定周期再窄幅扫阈值观察胜率变化。