用于 MQL5 向导的 NRTR 指标和交易模块(基础篇)
📘

用于 MQL5 向导的 NRTR 指标和交易模块(基础篇)

第 1/3 篇

把 NRTR 塞进 MQL5 向导跑起来

NRTR(区间反转跟踪)指标在 MT5 里可以不做一行手写交易逻辑,直接借向导生成 EA。2018 年 1 月 8 日发布的这套模块,累计被查看 8142 次、收藏 9 次,说明手动派也在找半自动入口。 在 MQL5 向导里选「交易模块 + NRTR 信号」,平台会把指标反转点转成开仓条件,省掉自己接 iCustom 的麻烦。外汇与贵金属杠杆高,信号翻转只代表概率倾斜,不代表走势锁死。 想验证就开 MT5:调出向导→插入 NRTR 模块→默认周期 H1,看回测里反转触发的胜率分布,再决定要不要把通道系数从 2.0 往下调。

「把任意趋势指标接进通道系统」

动态价格通道在趋势段能给出清晰的进出场带,但在横盘里会刷出大量假突破信号,这是实盘里最烧钱的部分。 解决办法不是死磕某一个“最佳指标”,而是把趋势判定做成可插拔模块。我们做一个 MQL5 向导专用的交易信号模块,只输出“趋势存在 / 不存在”的 Yes/No 判定。 之后换 MACD、均线斜率或 ADX 都只需依样生成一个同类模块,在向导里勾选组合即可,不用改通道核心代码。外汇和贵金属杠杆高,横盘假信号可能连续止损,接模块前先想清楚自己要在哪种行情里跑。

◍ NRTR 的动态通道怎么跟着趋势跑

NRTR(Nick Rypock Trailing Reverse)由 Konstantin Kopyrkin 提出,本质是动态价格通道突破类趋势指标。它的核心不是固定周期均线,而是通道宽度随趋势起点动态拉长,前一计算周期的价格在趋势反转后被整体清零,不再参与后续运算。 在上升段,指标线悬于一段时间内检测到的局部高点下方固定距离;下降段则压在局部低点上方同距位置。如图中 H1、H2 被用作基准,而 H3 因低于前高直接弃用——通道只认延续趋势的极值。 当价格刺穿通道边界,信号才触发:下破支撑线出买入、上破阻力线出卖出。L3 点破通道后不仅给卖信号,还把 L3 设为新低点,周期从零重计,之后最低值顺着 L3-L4-L5 更新,通道周期一直延展到趋势变向或触到允许上限。 通道宽度按极值百分比或真实波动来算都行,两种都已实现。外汇与贵金属波动剧烈,NRTR 在震荡市可能频繁假突破,实盘前务必在 MT5 用历史数据验证参数敏感性。

NRTR 指标在 MT5 里的落地细节

做这个指标第一件事是定行为:基于收盘价算支撑阻力,但不完整烛条被突破时不给信号。代价是可能漏掉大阳线直接破通道那段行情,只有下一根开盘才进场;好处是挡掉一大批假突破,外汇和贵金属这种高波动品种上尤其值得。 原始思路里动态周期用 ArrayMaximum/Minimum(close,i,dynamic_period) 取极值,支撑阻力都能双向移动;若改成 MathMax() 配前值,支撑只涨不跌、阻力只跌不涨,两种方法都不完美,本文按作者初版来。 MQL5 的 close 默认 ArraySetAsSeries=false,和 MQL4 时间序列相反,这里必须显式 ArraySetAsSeries(close,true) 才能让 close[0] 指向当前最右柱。 缓冲区开四个:两个画支撑阻力虚线,两个画买卖箭头。箭头用 Wingdings 236/238,在 OnInit 里绑定。OnCalculate 里先用静态变量存 trend_prev、value_prev,只有柱线走完才更新,中途破线只改本地非静态量,回通道则保留原趋势。 实测挂两个实例:周期 12、宽度 0.1% 和周期 120、宽度 0.2%。小周期下支撑线随价格跌出动态窗口而深度下移;大周期支撑线基本不降,震荡里平滑得多。 别把正态当圣经:周期参数直接决定支撑线会不会乱跳,先开 MT5 用 12 和 120 对照看图再决定跟哪套。

MQL5 / C++
class="macro">#class="kw">property indicator_chart_window
class="macro">#class="kw">property indicator_buffers class="num">4
class="macro">#class="kw">property indicator_plots   class="num">4
class=class="str">"cmt">//指标线条样式
class="macro">#class="kw">property indicator_type1   DRAW_LINE
class="macro">#class="kw">property indicator_color1 Green
class="macro">#class="kw">property indicator_style1 STYLE_DASH
class="macro">#class="kw">property indicator_type2   DRAW_LINE
class="macro">#class="kw">property indicator_color2 Red
class="macro">#class="kw">property indicator_style2 STYLE_DASH
class="macro">#class="kw">property indicator_type3   DRAW_ARROW
class="macro">#class="kw">property indicator_color3 Green
class="macro">#class="kw">property indicator_type4   DRAW_ARROW
class="macro">#class="kw">property indicator_color4 Red
input class="type">int     period =class="num">12;       class=class="str">"cmt">//动态周期
input class="type">class="kw">double percent =class="num">0.2;     class=class="str">"cmt">//缩进百分比 
class="type">class="kw">double Buff_Up[],Buff_Dn[];
class="type">class="kw">double Sign_Up[],Sign_Dn[];
   SetIndexBuffer(class="num">2,Sign_Up,INDICATOR_DATA);
   PlotIndexSetDouble(class="num">2,PLOT_EMPTY_VALUE,class="num">0.0);
   PlotIndexSetInteger(class="num">2,PLOT_ARROW,class="num">236);
   PlotIndexSetInteger(class="num">2,PLOT_LINE_WIDTH,class="num">1);
   ArraySetAsSeries(Sign_Up,true);
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| 自定义指标迭代函数                                                |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">int OnCalculate(const class="type">int rates_total,
                const class="type">int prev_calculated,
                const class="type">class="kw">datetime &time[],
                const class="type">class="kw">double &open[],
                const class="type">class="kw">double &high[],
                const class="type">class="kw">double &low[],
                const class="type">class="kw">double &close[],

「动态周期下的趋势状态机落地」

这段自定义指标的核心不是画一条线,而是用静态变量把上一根柱的趋势、数值和周期‘记住’,避免每 tick 重算整段历史。trend_prev 初值设为 1(升势),value_prev 以 close[start]*(1-0.01*percent) 做基准偏移,意味着回调百分比由外部 percent 参数控制,黄金与外汇品种建议先在 0.1~0.5 之间试。 首次计算时 start 直接跳到 rates_total-1,处理全部历史;非首次则只从 rates_total-prev_calculated 开始,仅补新柱。这一分支决定了 CPU 占用——在 EURUSD M5 上,若 period=200,首次加载可能扫 200 根以上,后续每根仅跑增量循环。 主循环里 Buff_Up / Buff_Dn / Sign_Up / Sign_Dn 每根先清零,再判断 curr_period 与 dyn_period 是否突破 period 上限。趋势大于 0 时取 ArrayMaximum(close,i,dyn_period) 定位窗口内最高收价赋给 maxmin,下行分支对称处理最低价,从而让支撑阻力随波动伸缩而非固定长度。 把下面片段直接塞进 OnCalculate 就能跑通骨架;实盘前务必在策略测试器用 2023 年 XAUUSD 数据验证 dyn_period 是否如预期在 1~period 间跳动,外汇与贵金属杠杆高,参数错配可能放大回撤。

MQL5 / C++
const class="type">long &tick_volume[],
const class="type">long &volume[],
const class="type">int &spread[])
{
 class="type">int start =class="num">0; class=class="str">"cmt">//计算的起始点
 class="type">int trend =class="num">0; class=class="str">"cmt">//趋势值, class="num">0 向上 -class="num">1 向下
 class="kw">static class="type">int trend_prev =class="num">0;
 class="type">class="kw">double value =class="num">0; class=class="str">"cmt">//指标值
 class="kw">static class="type">class="kw">double value_prev =class="num">0;
 class="type">int dyn_period =class="num">1; class=class="str">"cmt">//动态周期值
 class="kw">static class="type">int curr_period =class="num">1;
 class="type">class="kw">double maxmin =class="num">0; class=class="str">"cmt">//用于计算的技术变量
 ArraySetAsSeries(close,true);
 if(rates_total<period) class="kw">return(class="num">0);
 if(prev_calculated==class="num">0) class=class="str">"cmt">// 检查指标计算的首次开始
 {
  start=rates_total-class="num">1; class=class="str">"cmt">// 所有柱线的起始计算索引
  trend_prev =class="num">1;
  value=close[start]*(class="num">1-class="num">0.01*percent);
 }
 else
  {
   start=rates_total-prev_calculated; class=class="str">"cmt">// 新柱线的起始计算索引
  }
trend =trend_prev;
value =value_prev;
dyn_period =curr_period;
trend =trend_prev;
value =value_prev;
dyn_period =curr_period; class=class="str">"cmt">//---------------------------------------------------+
class=class="str">"cmt">// 主要的计算循环 //---------------------------------------------------+
for(class="type">int i=start;i>=class="num">0;i--)
{
  Buff_Up[i] =class="num">0.0;
  Buff_Dn[i] =class="num">0.0;
  Sign_Up[i] =class="num">0.0;
  Sign_Dn[i] =class="num">0.0;
  if(curr_period>period) curr_period=period;
  if(dyn_period>period) dyn_period=period;
  class=class="str">"cmt">// 如果趋势为升势
  if(trend>class="num">0)
  {
   maxmin =close[ArrayMaximum(close,i,dyn_period)];

常见问题

先确认指标能输出趋势方向和缓冲区,再按向导要求的接口写好信号模块,把指标句柄传进去即可在通道系统里调用。
它用上一根K线的极值加减动态步长重算通道边界,趋势反转才翻转基准,所以通道会贴着趋势跑而不是固定宽度。
小布可以读取品种页里的通道状态和历史翻转点,帮你标注近期假突破概率,省去手动翻周期核对。
只要状态机用根索引和周期参数隔离计算,切到 M15 或 H1 会各自维护状态,不会串周期误判。
多是缓冲区未初始化或步长参数为零导致除零,检查 iCustom 调用和输入参数默认值就能避开。