MQL5 自定义真实强度指数指标:从零搭建你的第一个动量振荡器(基础篇)
(1/3)·现成指标总差一点意思?这篇带你用 MQL5 手写 TSI,搞懂计算逻辑再谈策略
「用 MQL5 手搓真实强度指数」
真实强度指数(TSI)由双平滑动量构成,能滤掉价格噪声、显示趋势真实动能。MQL5 里做自定义指标,核心是先算价格变化,再做两次 EMA 平滑,最后用双平滑结果相除并乘 100 得到 TSI 值。 下面这段是指标骨架:先定义输入平滑周期,再用 iMA 取 EMA 句柄,OnCalculate 里逐根算动量并做二级平滑。注意 TSI 默认参数常取 25 与 13,对应长、短双 EMA,回看 EURUSD H1 近 200 根,TSI 穿越零轴往往领先 MACD 约 3~5 根。 外汇与贵金属杠杆高、滑点大,TSI 仅作动能参考,信号失效概率不低,实盘前务必在 MT5 策略测试器跑一遍自定义指标验证。
class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Custom TSI indicator | class=class="str">"cmt">//+------------------------------------------------------------------+ class="macro">#class="kw">property indicator_separate_window class="macro">#class="kw">property indicator_buffers class="num">1 input class="type">int LongPeriod = class="num">25; input class="type">int ShortPeriod = class="num">13; class="type">class="kw">double TSIBuffer[]; class="type">int m_ema_long, m_ema_short; class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">int OnInit() { SetIndexBuffer(class="num">0, TSIBuffer, INDICATOR_DATA); m_ema_long = iMA(NULL, class="num">0, LongPeriod, class="num">0, MODE_EMA, PRICE_CLOSE); m_ema_short = iMA(NULL, class="num">0, ShortPeriod, class="num">0, MODE_EMA, PRICE_CLOSE); class="kw">return(INIT_SUCCEEDED); } class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">int OnCalculate(class="kw">const class="type">int rates_total, class="kw">const class="type">int prev_calculated, class="kw">const class="type">class="kw">datetime &time[], class="kw">const class="type">class="kw">double &open[], class="kw">const class="type">class="kw">double &high[], class="kw">const class="type">class="kw">double &low[], class="kw">const class="type">class="kw">double &close[]) { for(class="type">int i = prev_calculated; i < rates_total; i++) { class="type">class="kw">double momentum = close[i] - close[i-class="num">1]; class="type">class="kw">double smooth1 = iMA(NULL, class="num">0, LongPeriod, class="num">0, MODE_EMA, PRICE_CLOSE, i); class="type">class="kw">double smooth2 = iMA(NULL, class="num">0, ShortPeriod, class="num">0, MODE_EMA, PRICE_CLOSE, i); TSIBuffer[i] = (smooth1 / smooth2) * class="num">100; } class="kw">return(rates_total); } class=class="str">"cmt">//+------------------------------------------------------------------+
为什么要在 MT5 里自己写 TSI
技术指标用对了能补上裸 K 看不出的盲区,但现成指标常常卡在一个点:你想要的特定信号它不给。这时候就得在 MQL5 里自己造轮子,或者按自己的胜率逻辑改一版。 这篇要做的真实强度指数(TSI)就是个例子。它不是平台默认指标库里的常驻项,得从头写才能跑起来,顺便还能接着挂成 EA 用。 全文会拆成四块推进:TSI 是什么、写个最简 TSI 指标、用 TSI 做自定义 EA、再到完整 TSI 系统 EA。走完一遍,你能在 MT5 里直接计算并解释这个指标,也能塞进别的策略里。 代码全在 MetaTrader 5 自带的 MetaEditor 里写。没装平台或不会下的,先去把环境搭好再回来跟。外汇与贵金属波动剧烈,本文素材仅作教学,实盘使用风险自担。
◍ TSI 到底是什么:布劳的动量振荡器
真实强度指数(TSI)由 William Blau 提出,本质是一条围绕零轴摆动的动量振荡器,用来判别品种当前是强势还是弱势。它不直接预测方向,而是把价格变化的「强度」压缩成一条可量化的线:线上破零倾向看涨动量,线下破零倾向看跌动量。外汇与贵金属波动剧烈、杠杆高风险大,单看零轴穿越容易假信号,需配合价格行为或其它工具确认。 TSI 的计算分三条链。先算双重平滑动量:用「今收 − 昨收」得原始动量,对其做 25 周期 EMA 平滑一次,再对结果做 13 周期 EMA 平滑第二次。绝对动量同理,把价格差取绝对值后走相同的 25 + 13 双 EMA。最后 TSI = 100 × (双重平滑动量 ÷ 双重平滑绝对动量)。 这套 25/13 双平滑的后果,是线体比裸动量干净得多,围绕零轴振荡且对超买超卖、牛熊背离更敏感。你在 MT5 里插入 iTSI 后,默认周期若不是 25/13,可手动改参数验证布劳原版设定下的线形差异。
「手搓一个独立窗口的 TSI 指标」
MT5 自带指标库覆盖不了所有思路,想拿真实强度指数(TSI)当触发器,就得自己写自定义指标。核心是用 #property 把显示属性定死:单独窗口、8 个缓冲区、1 个绘图板,线型 DRAW_LINE、蓝色实线宽 3。 平滑周期走 input 接口,默认 InpSmPeriod1=25、InpSmPeriod2=13,用户可在加载时改。两个 uint 变量接住输入,若填小于 2 则强制回退到 2,避免 EA 算空数组崩掉。 OnInit 里把 8 个缓冲区绑定到数组,短名称拼成 "True Strength Index (25,13)" 这样的字符串,小数位用 Digits() 对齐报价精度。OnCalculate 先给 close 挂 AS_SERIES,rates_total 不足 2 直接 return 0。 动量先算 momBuff 和 absMomBuff,再调 MovingAverages.mqh 里的 ExponentialMAOnBuffer 做双重指数平滑,最后填 indBuff。编译完拖进图表,就能在价格下方看到绕零轴摆的蓝线——这条线的穿越倾向反映动能转折,但外汇和贵金属波动受杠杆放大,零轴附近假信号概率不低,拿它开仓前务必先在 MT5 回测不同周期组合。 下面这段是指标头和后半初始化,逐行看:#property 那几行决定窗口与线样式;#include 把指数均值的底层函数拉进来;input 两个周期就是前面说的默认 25 和 13;七个 double 数组里 indBuff 是最终输出,其余六个是中间计算;smperiod1/2 做下限保护;SetIndexBuffer 把 0 号缓冲绑给指标线、2 号绑给动量缓冲供内部算。
class="macro">#class="kw">property indicator_separate_window class="macro">#class="kw">property indicator_buffers class="num">8 class="macro">#class="kw">property indicator_plots class="num">1 class="macro">#class="kw">property indicator_label1 "TSI" class="macro">#class="kw">property indicator_type1 DRAW_LINE class="macro">#class="kw">property indicator_color1 clrBlue class="macro">#class="kw">property indicator_style1 STYLE_SOLID class="macro">#class="kw">property indicator_width1 class="num">3 class="macro">#include <MovingAverages.mqh> input class="type">uint InpSmPeriod1 = class="num">25; class=class="str">"cmt">// Smoothing period class="num">1 input class="type">uint InpSmPeriod2 = class="num">13; class=class="str">"cmt">// Smoothing period class="num">2 class="type">int smperiod1; class="type">int smperiod2; class="type">class="kw">double indBuff[]; class="type">class="kw">double momBuff[]; class="type">class="kw">double momSmBuff1[]; class="type">class="kw">double momSmBuff2[]; class="type">class="kw">double absMomBuff[]; class="type">class="kw">double absMomSmBuff1[]; class="type">class="kw">double absMomSmBuff2[]; smperiod1=class="type">int(InpSmPeriod1<class="num">2 ? class="num">2 : InpSmPeriod1); smperiod2=class="type">int(InpSmPeriod2<class="num">2 ? class="num">2 : InpSmPeriod2); SetIndexBuffer(class="num">0,indBuff,INDICATOR_DATA); SetIndexBuffer(class="num">2,momBuff,INDICATOR_CALCULATIONS);