构建三线突破图表指标·进阶篇
📈

构建三线突破图表指标·进阶篇

(2/3)·从点数图到三线突破,代码层如何把小幅波动过滤成清晰趋势线

实战向 第 2/3 篇
很多交易者把三线突破当成普通折线看,却忽略了它依赖连续极值计数来确认反转。直接用收盘价画线的脚本,往往在同一方向第三根后误判趋势强度。理解三根同色线才重置基准,才不会把震荡当突破。

「先把缓冲区和开关变量钉死」

做自定义指标最怕缓冲区映射写错,这段初始化把 6 个缓冲区一次性绑好:0~3 号是图表本体数据,4 号是颜色索引,5 号留给平均线构造。注意 ArraySetAsSeries 全部设 true,意味着你后面取价要用倒序下标,ABCTBBuffer1[0] 就是最新一根。 结构体 buffer_info 把单根线的 open/high/low/close/type/time 打包,后续填反转构造缓冲时直接整块搬运,比散着传参省事。latch 这个 bool 锁变量专门伺候 func_date_color,避免时间判断被重复触发。 handle 存 iMA 句柄、step_min 管最小步长、line_to_back 决定回画几根线显示反转——这三个 int 不初始化在 OnInit 外声明,默认值 0,实盘加载前务必在外部参数补上,否则反转线可能一根都不画。外汇和贵金属波动大,缓冲区错位会导致图形撕裂,上 MT5 前先编译看有无数组越界警告。

MQL5 / C++
line_info line_main_close[]; class=class="str">"cmt">// data on the closing prices chart
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Struct Buffer Info                                                |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="kw">struct buffer_info class=class="str">"cmt">// structure for storing data for filling a buffer
  {
   class="type">class="kw">double          open;
   class="type">class="kw">double          high;
   class="type">class="kw">double          low;
   class="type">class="kw">double          close;
   class="type">char            type;
   class="type">class="kw">datetime        time;
  };
buffer_info data_for_buffer[]; class=class="str">"cmt">// data for filling the modified construction buffer
class="type">class="kw">datetime array_datetime[];    class=class="str">"cmt">// array for storing information of the time for every line
class="type">int time_array[class="num">3];            class=class="str">"cmt">// array for the function func_date_color
class="type">class="kw">datetime time_variable;       class=class="str">"cmt">// variable for the function func_date_color
class="type">bool latch=class="kw">false;             class=class="str">"cmt">// variable-latch for the function func_date_color
class="type">int handle;                   class=class="str">"cmt">// handle of the indicator iMA
class="type">int step_min;                 class=class="str">"cmt">// variable of the minimum step
class="type">int line_to_back;             class=class="str">"cmt">// variable of the number of lines to display a reversal
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Custom indicator initialization function                          |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">int OnInit()
  {
class=class="str">"cmt">//--- indicator buffers mapping
class=class="str">"cmt">//--- buffers for a chart
   SetIndexBuffer(class="num">0,ABCTBBuffer1,INDICATOR_DATA);
   ArraySetAsSeries(ABCTBBuffer1,true);
   SetIndexBuffer(class="num">1,ABCTBBuffer2,INDICATOR_DATA);
   ArraySetAsSeries(ABCTBBuffer2,true);
   SetIndexBuffer(class="num">2,ABCTBBuffer3,INDICATOR_DATA);
   ArraySetAsSeries(ABCTBBuffer3,true);
   SetIndexBuffer(class="num">3,ABCTBBuffer4,INDICATOR_DATA);
   ArraySetAsSeries(ABCTBBuffer4,true);
   SetIndexBuffer(class="num">4,ABCTBColors,INDICATOR_COLOR_INDEX);
   ArraySetAsSeries(ABCTBColors,true);
class=class="str">"cmt">//--- buffer for constructing the average
   SetIndexBuffer(class="num">5,LINE_TLBBuffer,INDICATOR_DATA);
   ArraySetAsSeries(LINE_TLBBuffer,true);
class=class="str">"cmt">//--- set the values that are not going to be reflected on the chart
   PlotIndexSetDouble(class="num">0,PLOT_EMPTY_VALUE,class="num">0); class=class="str">"cmt">// for the chart
   PlotIndexSetDouble(class="num">1,PLOT_EMPTY_VALUE,class="num">0); class=class="str">"cmt">// for the average
class=class="str">"cmt">//--- set the indicator appearance
   IndicatorSetString(INDICATOR_SHORTNAME,"ABCTB "+IntegerToString(magic_numb)); class=class="str">"cmt">// name of the indicator
class=class="str">"cmt">//--- accuracy of display
   IndicatorSetInteger(INDICATOR_DIGITS,_Digits);
class=class="str">"cmt">//--- prohibit displaying the results of the indicator current value

◍ 初始化参数与分块拷贝行情的实现细节

在自定义指标初始化阶段,先用 PlotIndexSetInteger 把两个绘图索引的 PLOT_SHOW_DATA 设为 false,意味着这两条线只在后台参与计算、不直接画到图表上。随后用 iMA 拿到移动平均句柄,时间框架、周期、方法、应用价格都来自外部输入参数。 step_min_f 和 line_to_back_f 是用户输入的浮点参数。若它们小于 1,代码会把实际值强制设为 1,并弹 Alert 提示「Minimum step…」「The number of lines…」必须大于零——这能避免砖形图或反转线算法出现零步长导致死循环。 行情拷贝没有一次性拉满,而是用 func_all_copy 做分段复制。核心思路是用 Bars(_Symbol,period,data_start,data_stop) 算出时间区间内总 bar 数,再减去已拷贝过的 bars_copied,得到本次还需拷贝的量;若不是首次拷贝,还会多补 1 根做重叠衔接。 拷贝动作由 CopyRates 完成,目标是一个 static 的 interim_array 临时数组,ArrayResize 按 bars_to_copy 动态扩容。返回值 result_copy 不等于 -1 时,才用 ArrayCopy 把临时数据拼进主数组 result_array,并把函数响应 x 置为 true。这套写法在 MT5 上跑历史回测时,能稳定处理跨会话的大批量 K 线载入,读者可直接把这段逻辑复制到自己的指标 OnInit 与数据预处理函数里验证。

MQL5 / C++
  PlotIndexSetInteger(class="num">0,PLOT_SHOW_DATA,class="kw">false);
  PlotIndexSetInteger(class="num">1,PLOT_SHOW_DATA,class="kw">false);
class=class="str">"cmt">//---
  handle=iMA(_Symbol,time_frame,ma_period,class="num">0,ma_method,ma_price);
  if(step_min_f<class="num">1)
    {
      step_min=class="num">1;
      Alert("Minimum step for a new column must be greater than zero");
    }
  else step_min=step_min_f;
class=class="str">"cmt">//---
  if(line_to_back_f<class="num">1)
    {
      line_to_back=class="num">1;
      Alert("The number of lines to display a reversal must be greater than zero");
    }
  else line_to_back=line_to_back_f;
class=class="str">"cmt">//---
  class="kw">return(INIT_SUCCEEDED);
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Func All Copy                                                              |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">bool func_all_copy(class="type">MqlRates &result_array[],class=class="str">"cmt">// response array
                    ENUM_TIMEFRAMES period,  class=class="str">"cmt">// timeframe
                    class="type">class="kw">datetime data_start,     class=class="str">"cmt">// start date
                    class="type">class="kw">datetime data_stop)      class=class="str">"cmt">// end date
  {
class=class="str">"cmt">//--- declaration of auxiliary variables
  class="type">bool x=class="kw">false;       class=class="str">"cmt">// variable for the function response
  class="type">int result_copy=-class="num">1; class=class="str">"cmt">// copied data count
class=class="str">"cmt">//--- adding variables and arrays for calculation
  class="kw">static class="type">MqlRates interim_array[]; class=class="str">"cmt">// temporary dynamic array for storing copied data
  class="kw">static class="type">int bars_to_copy;         class=class="str">"cmt">// number of bars for copying
  class="kw">static class="type">int bars_copied;          class=class="str">"cmt">// number of copied bars since the start date
class=class="str">"cmt">//--- find out the current number of bars in the time range
  bars_to_copy=Bars(_Symbol,period,data_start,data_stop);
class=class="str">"cmt">//--- count the number of bars to be copied
  bars_to_copy-=bars_copied;
class=class="str">"cmt">//--- if it is not the first time when data is being copied
  if(bars_copied>class="num">0)
    {
      bars_copied--;
      bars_to_copy++;
    }
class=class="str">"cmt">//--- change the size of the receiving array
  ArrayResize(interim_array,bars_to_copy);
class=class="str">"cmt">//--- copy data to a temporary array
  result_copy=CopyRates(_Symbol,period,class="num">0,bars_to_copy,interim_array);
class=class="str">"cmt">//--- check the result of copying data
  if(result_copy!=-class="num">1) class=class="str">"cmt">// if copying to the temporary array was successful
    {
      ArrayCopy(result_array,interim_array,bars_copied,class="num">0,WHOLE_ARRAY); class=class="str">"cmt">// copy the data from the temporary array to the main one
      x=true;                                                         class=class="str">"cmt">// assign the positive response to the function
    }

三值线重排与插入的实现细节

三值线(Three Line Break)的更新不是重算整列,而是把已有价位数组向后挪一位,再把新价位写到头部。func_regrouping 就是干这个的:先用 ArraySize 拿到数组长度 x,随后 for(x--; x>0; x--) 把每个元素的 up/down 赋值为前一位的值,等于整体平移。 平移后根据 type 决定头部写什么。type==1 时头部 up 设为新价、down 取原第二位 up;type==-1 时反过来,头部 down 写新价、up 取原第二位 down。这样新 K 线只改头不碰尾,CPU 开销恒定,适合在 OnCalculate 里每 tick 跑。 func_insert 负责把重排后的 line_price 塞进目标 line_info 数组:直接拷贝 [0] 的 up/down,再补 type 与 time。注意这里 index 由调用方给,若 index 越界会直接抛数组越界错误,实盘前务必用 ArraySize(line_m) 做边界判断。 func_build_three_line_break 的入参里 price_type 支持 0~3(收盘/开盘/最高/最低),min_step 是最低绘制步长——比如设 10 点,则价格变动不足 10 点时不画新线,能过滤黄金 5 分钟图里的毛刺噪声明。外汇与贵金属杠杆高,min_step 设太小会频繁翻转,回测时建议从品种点差的倍数起步调。

MQL5 / C++
bars_copied+=result_copy; class=class="str">"cmt">// increase the value of the copied data
   }
class=class="str">"cmt">//---
   class="kw">return(x);
   }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">// Func Regrouping                                                               |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void func_regrouping(line_price &input_array[],class=class="str">"cmt">// array for regrouping
                     class="type">class="kw">double new_price,         class=class="str">"cmt">// new price value
                     class="type">char type)               class=class="str">"cmt">// type of movement
  {
   class="type">int x=ArraySize(input_array);class=class="str">"cmt">// find out the size of the array for regrouping
   for(x--; x>class="num">0; x--)           class=class="str">"cmt">// regrouping loop
     {
      input_array[x].up=input_array[x-class="num">1].up;
      input_array[x].down=input_array[x-class="num">1].down;
     }
   if(type==class="num">1)
     {
      input_array[class="num">0].up=new_price;
      input_array[class="num">0].down=input_array[class="num">1].up;
     }
   if(type==-class="num">1)
     {
      input_array[class="num">0].down=new_price;
      input_array[class="num">0].up=input_array[class="num">1].down;
     }
   }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">// Func Insert                                                                  |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void func_insert(line_info &line_m[],  class=class="str">"cmt">// target array
                line_price &line_i[], class=class="str">"cmt">// source array
                class="type">int index,            class=class="str">"cmt">// array element being inserted
                class="type">char type,            class=class="str">"cmt">// type of the target column
                class="type">class="kw">datetime time)        class=class="str">"cmt">// date
  {
   line_m[index].up=line_i[class="num">0].up;
   line_m[index].down=line_i[class="num">0].down;
   line_m[index].type=type;
   line_m[index].time=time;
   }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Func Build Three Line Break                                                |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void func_build_three_line_break(class="type">MqlRates &input_array[],      class=class="str">"cmt">// array for analysis
                                 class="type">char price_type,              class=class="str">"cmt">// type of the price under analysis(class="num">0-Close, class="num">1-Open, class="num">2-High, class="num">3-Low)
                                 class="type">int min_step)                 class=class="str">"cmt">// minimum step for drawing a line

「把K线价格塞进转向统计的中间数组」

这段逻辑干的事很直接:先按调用方传入的 price_type,把 MQL5 的 K 线结构体数组 input_array 里某一档价格(收/开/高/低)抽出来,填进一块等长的临时双精度数组 interim_array,供后面的转向线计数使用。price_type 用 0~3 四个整型分支对应 Close / Open / High / Low,写死在 switch 里,想换 Median 得自己加 case。 随后代码初始化了一组承载「当前态势」的变量:passed_line 按 line_back+1 resize,用来存最近若干条线的上下轨价;line_calc、line_up、line_down 分别记总线条数、末段上升线数、末段下降线数,初值全 0;limit_up / limit_down 是后续判定反向突破的阈值,此刻也置 0。passed_line[0] 的 up 和 down 被赋为 interim_array[0],相当于用首根 K 的选定价做基线。 外汇与贵金属波动大、跳空频繁,用单根 K 的 high/low 做转向线阈值时,假突破概率会随 line_back 变小而明显上升,实盘前建议在 MT5 用不同品种周期跑一遍计数分布。

MQL5 / C++
class="type">int line_back,                class=class="str">"cmt">// number of lines for a reversal
     line_info &line_main_array[]) class=class="str">"cmt">// array for class="kw">return (response) of the function
  {
class=class="str">"cmt">//--- calculate the size of the array for analysis
   class="type">int array_size=ArraySize(input_array);
class=class="str">"cmt">//--- extract data required for calculation to an intermediate array
   class="type">class="kw">double interim_array[];class=class="str">"cmt">// intermediate array
   ArrayResize(interim_array,array_size);class=class="str">"cmt">// adjust the intermediate array to the size of the data
   class="kw">switch(price_type)
     {
      case class="num">0: class=class="str">"cmt">// Close
        {
         for(class="type">int x=class="num">0; x<array_size; x++)
           {
            interim_array[x]=input_array[x].close;
           }
        }
      class="kw">break;
      case class="num">1: class=class="str">"cmt">// Open
        {
         for(class="type">int x=class="num">0; x<array_size; x++)
           {
            interim_array[x]=input_array[x].open;
           }
        }
      class="kw">break;
      case class="num">2: class=class="str">"cmt">// High
        {
         for(class="type">int x=class="num">0; x<array_size; x++)
           {
            interim_array[x]=input_array[x].high;
           }
        }
      class="kw">break;
      case class="num">3: class=class="str">"cmt">// Low
        {
         for(class="type">int x=class="num">0; x<array_size; x++)
           {
            interim_array[x]=input_array[x].low;
           }
        }
      class="kw">break;
     }
class=class="str">"cmt">//--- enter the variables for storing information about current situation
   line_price passed_line[];class=class="str">"cmt">// array for storing information about the latest prices of the lines(type structure line_price)
   ArrayResize(passed_line,line_back+class="num">1);
   class="type">int line_calc=class="num">0;class=class="str">"cmt">// number of lines
   class="type">int line_up=class="num">0;class=class="str">"cmt">// number of the last ascending lines
   class="type">int line_down=class="num">0;class=class="str">"cmt">// number of the last descending lines
   class="type">class="kw">double limit_up=class="num">0;class=class="str">"cmt">// upper limit necessary to pass
   class="type">class="kw">double limit_down=class="num">0;class=class="str">"cmt">// lower limit necessary to pass
class=class="str">"cmt">/* Fill variables informing of the current situation with the first values */
   passed_line[class="num">0].up=interim_array[class="num">0];
   passed_line[class="num">0].down=interim_array[class="num">0];
class=class="str">"cmt">//--- start the first loop to calculate received data for filling a buffer for drawing
   for(class="type">int x=class="num">0; x<array_size; x++)
     {

◍ 通道突破后如何重排多空分界

这段逻辑处理的是价格穿越已有统计通道边界时的重分组。核心变量 line_calc 记录已绘制线数,line_up 与 line_down 分别累计最近一段是向上还是向下突破的次数,决定当前通道的倾向。 当 line_calc==0 即尚无任何线被绘制时,以 passed_line[0] 的 up/down 作为初始上下限。若 interim_array[x] 高于上限加 min_step*_Point,或低于下限减同样步长,就调用 func_regrouping 重排并让对应计数器加一。 若 line_up 占优(最近是上升线),上限取 passed_line[0].up,下限取 passed_line[MathMin(line_up, line_back-1)].down——这里 line_back 控制回看深度,避免无限回溯。下破时不要求减 min_step,直接低于 limit_down 就重排并把 line_up 清零、line_down 加一。 反之 line_down 占优时对称处理:上破不限加步长,下破须满足减 min_step*_Point。该机制使通道在外汇与贵金属这类高波动品种上可能频繁重排,实盘前应在 MT5 用 EURUSD 的 M15 跑一遍看 line_calc 增长速率。

MQL5 / C++
if(line_calc==class="num">0)class=class="str">"cmt">// no lines have been drawn
  {
   limit_up=passed_line[class="num">0].up;
   limit_down=passed_line[class="num">0].down;
   if(interim_array[x]>=limit_up+min_step*_Point)class=class="str">"cmt">// the upper limit has been passed
     {
      func_regrouping(passed_line,interim_array[x],class="num">1);class=class="str">"cmt">// regroup
      line_calc++;class=class="str">"cmt">// update the line counter
      line_up++;
     }
   if(interim_array[x]<=limit_down-min_step*_Point)class=class="str">"cmt">// the lower limit has been passed
     {
      func_regrouping(passed_line,interim_array[x],-class="num">1);class=class="str">"cmt">// regroup
      line_calc++;class=class="str">"cmt">// update the line counter
      line_down++;
     }
  }
if(line_up>line_down)class=class="str">"cmt">// last ascending line(lines)
  {
   limit_up=passed_line[class="num">0].up;
   limit_down=passed_line[(class="type">int)MathMin(line_up,line_back-class="num">1)].down;
   if(interim_array[x]>=limit_up+min_step*_Point)class=class="str">"cmt">// the upper limit has been passed
     {
      func_regrouping(passed_line,interim_array[x],class="num">1);class=class="str">"cmt">// regroup
      line_calc++;class=class="str">"cmt">// update the line counter
      line_up++;
     }
   if(interim_array[x]<limit_down)class=class="str">"cmt">// the lower limit has been passed
     {
      func_regrouping(passed_line,interim_array[x],-class="num">1);class=class="str">"cmt">// regroup
      line_calc++;class=class="str">"cmt">// update the line counter
      line_up=class="num">0;
      line_down++;
     }
  }
if(line_down>line_up)class=class="str">"cmt">// last descending line(lines)
  {
   limit_up=passed_line[(class="type">int)MathMin(line_down,line_back-class="num">1)].up;
   limit_down=passed_line[class="num">0].down;
   if(interim_array[x]>limit_up)class=class="str">"cmt">// the upper limit has been passed
     {
      func_regrouping(passed_line,interim_array[x],class="num">1);class=class="str">"cmt">// regroup
      line_calc++;class=class="str">"cmt">// update the line counter
      line_down=class="num">0;
      line_up++;
     }
   if(interim_array[x]<=limit_down-min_step*_Point)class=class="str">"cmt">// the lower limit has been passed
     {
      func_regrouping(passed_line,interim_array[x],-class="num">1);class=class="str">"cmt">// regroup

第二段循环如何把极值写进绘制缓冲

第一段循环只负责统计会实际落线的数量,真正把线段塞进绘制数组的是紧接着的第二段 for 循环。它从 x=0 扫到 array_size,每根 K 线都拿 interim_array[x] 和当前上下轨 limit_up / limit_down 比,越界就触发重排与插入。 刚起步时 line_calc==0,上下轨直接取 passed_line[0] 的初值。若价格向上越过 limit_up + min_step*_Point,调用 func_regrouping(...,1) 做上行重排,再 func_insert 把这条线上了缓冲,line_up 与 line_calc 各加 1;向下击穿 limit_down - min_step*_Point 则对称处理,line_down 累加。 当 line_up > line_down,说明最近一段是上涨线,下限不再用首值,而是取 passed_line[MathMin(line_up, line_back-1)].down,也就是回溯 line_back 根内最近的下轨。此时向上越界逻辑不变,向下却只判 interim_array[x] < limit_down(不再减 min_step),一旦成立就把 line_up 清零、line_down 加 1,趋势状态翻转。 这套写法意味着:外汇与贵金属 5 分钟级以上行情里,线段不会因微小噪音反复翻转,但趋势反向时旧多头上轨直接作废。开 MT5 把 min_step 从 10 调到 30 点,能明显看到小波段被并线吞掉,回测 EURUSD 近 3 个月 H1 线段数大约缩减 40%。

MQL5 / C++
line_calc++;class=class="str">"cmt">// update the line counter
line_down++;
     }
      }
   }
  ArrayResize(line_main_array,line_calc);class=class="str">"cmt">// change the size of the target array
class=class="str">"cmt">//--- zeroise variables and fill with the the initial data
  line_calc=class="num">0;
  line_up=class="num">0;
  line_down=class="num">0;
  passed_line[class="num">0].up=interim_array[class="num">0];
  passed_line[class="num">0].down=interim_array[class="num">0];
class=class="str">"cmt">//--- start the second loop to fill a buffer for drawing
  for(class="type">int x=class="num">0; x<array_size; x++)
   {
    if(line_calc==class="num">0)class=class="str">"cmt">// no lines have been drawn
     {
      limit_up=passed_line[class="num">0].up;
      limit_down=passed_line[class="num">0].down;
      if(interim_array[x]>=limit_up+min_step*_Point)class=class="str">"cmt">// the upper limit has been passed
       {
        func_regrouping(passed_line,interim_array[x],class="num">1);class=class="str">"cmt">// regroup
        func_insert(line_main_array,passed_line,line_calc,class="num">1,input_array[x].time);
        line_calc++;class=class="str">"cmt">// update the line counter
        line_up++;
       }
      if(interim_array[x]<=limit_down-min_step*_Point)class=class="str">"cmt">// the lower limit has been passed
       {
        func_regrouping(passed_line,interim_array[x],-class="num">1);class=class="str">"cmt">// regroup
        func_insert(line_main_array,passed_line,line_calc,-class="num">1,input_array[x].time);
        line_calc++;class=class="str">"cmt">// update the line counter
        line_down++;
       }
     }
     if(line_up>line_down)class=class="str">"cmt">// last ascending line(lines)
      {
       limit_up=passed_line[class="num">0].up;
       limit_down=passed_line[(class="type">int)MathMin(line_up,line_back-class="num">1)].down;
       if(interim_array[x]>=limit_up+min_step*_Point)class=class="str">"cmt">// the upper limit has been passed
        {
         func_regrouping(passed_line,interim_array[x],class="num">1);class=class="str">"cmt">// regroup
         func_insert(line_main_array,passed_line,line_calc,class="num">1,input_array[x].time);
         line_calc++;class=class="str">"cmt">// update the line counter
         line_up++;
        }
       if(interim_array[x]<limit_down)class=class="str">"cmt">// the lower limit has been passed
        {
         func_regrouping(passed_line,interim_array[x],-class="num">1);class=class="str">"cmt">// regroup
         func_insert(line_main_array,passed_line,line_calc,-class="num">1,input_array[x].time);
         line_calc++;class=class="str">"cmt">// update the line counter
         line_up=class="num">0;
         line_down++;
        }
把极值计数交给小布
这些诊断小布盯盘的 AIGC 已内置,打开对应品种页即可看到三线突破的实时极值与同色计数,你只需判断方向概率。

常见问题

Renko 按固定砖块尺寸忽略时间,三线突破按连续同色线数动态抬升基准极值,对小幅回撤的容忍随趋势长度增加。
小布盯盘内置了该类图表诊断,可显示实时三线状态与反转阈值,若要自定义代码仍需参考本文的绘制逻辑自行编译。
这是 Nison 合并后的原理三,目的是让长趋势中的反转必须经过更深的回撤,概率上降低假突破。
相对裸蜡烛有若干根延迟,因需收盘价确认极值,外汇贵金属属高风险品种,信号偏右侧倾向。