用于 MQL5 向导的 NRTR 指标和交易模块(基础篇)
把 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 对照看图再决定跟哪套。
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 间跳动,外汇与贵金属杠杆高,参数错配可能放大回撤。
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)];