Summary: 一份详细的MQL4源码解读,包含自定义RSI背离指标的完整代码。讲解缓冲区逻辑、背离检测方法,并提供了一个过滤弱信号的实用修改。




MQL4源码解读:从零构建一个可靠的RSI背离指标



我见过太多号称“专业”的背离指标,要么慢得要死,要么在每个小价格波动上都触发信号。所以我决定自己写一个,更重要的是,拆解MQL4源码,让你能真正动手修改。这不是简单的复制粘贴——我们要聊清楚为什么某些编码选择很重要,以及大多数开发者错在哪里。

背离为什么重要(以及为什么会失效)



背离这个概念在理论上很漂亮,但如果编码不当,实盘表现会非常糟糕。问题不在于指标本身,而在于检测逻辑。大多数免费指标只比较最高高点或最低低点,却没有考虑时间对称性相对强度。这就是为什么你经常看到背离持续了50根K线,然后价格还是照原方向走。

这里的方法参考了Constance Brown关于RSI的研究(Brown, C. (2008). Technical Analysis for the Trading Professional. McGraw-Hill),她强调背离检测必须同时考虑价格和振荡器指标的斜率,而不仅仅是极值。我们在这里实现一个简化版。

完整MQL4指标代码



先看完整代码,然后逐段拆解。

``cpp
//+------------------------------------------------------------------+
//| RSI_Divergence_v3.mq4 |
//| Copyright 2026, FXEAR.com |
//| https://www.fxear.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2026, FXEAR.com"
#property link "https://www.fxear.com"
#property version "3.00"
#property indicator_separate_window
#property indicator_buffers 4
#property indicator_plots 3

//--- RSI线
#property indicator_label1 "RSI"
#property indicator_type1 DRAW_LINE
#property indicator_color1 clrDodgerBlue
#property indicator_style1 STYLE_SOLID
#property indicator_width1 1

//--- 常规看涨背离
#property indicator_label2 "Reg Bull"
#property indicator_type2 DRAW_ARROW
#property indicator_color2 clrLimeGreen
#property indicator_style2 STYLE_SOLID
#property indicator_width2 1

//--- 常规看跌背离
#property indicator_label3 "Reg Bear"
#property indicator_type3 DRAW_ARROW
#property indicator_color3 clrRed
#property indicator_style3 STYLE_SOLID
#property indicator_width3 1

//--- 输入参数
input int RSIPeriod = 14; // RSI周期
input int MinBarsBetween = 5; // 枢轴点之间最小K线数
input double Overbought = 70.0; // 超买线
input double Oversold = 30.0; // 超卖线
input bool ShowHidden = false; // 显示隐藏背离

//--- 缓冲区
double RSIBuffer[];
double BullBuffer[];
double BearBuffer[];
double HiddenBuffer[];

int rsiHandle;
//+------------------------------------------------------------------+
//| 自定义指标初始化函数 |
//+------------------------------------------------------------------+
int OnInit()
{
//--- 设置指标缓冲区
SetIndexBuffer(0, RSIBuffer, INDICATOR_DATA);
SetIndexBuffer(1, BullBuffer, INDICATOR_DATA);
SetIndexBuffer(2, BearBuffer, INDICATOR_DATA);
SetIndexBuffer(3, HiddenBuffer, INDICATOR_DATA);

//--- 设置箭头代码
PlotIndexSetInteger(1, PLOT_ARROW, 233); // 向上箭头
PlotIndexSetInteger(2, PLOT_ARROW, 234); // 向下箭头

//--- 设置空值
PlotIndexSetDouble(1, PLOT_EMPTY_VALUE, EMPTY_VALUE);
PlotIndexSetDouble(2, PLOT_EMPTY_VALUE, EMPTY_VALUE);

//--- 获取RSI句柄
rsiHandle = iRSI(NULL, 0, RSIPeriod, PRICE_CLOSE);
if(rsiHandle == INVALID_HANDLE)
{
Print("创建RSI句柄失败,错误码: ", GetLastError());
return INIT_FAILED;
}

return INIT_SUCCEEDED;
}
//+------------------------------------------------------------------+
//| 自定义指标迭代函数 |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
const int prev_calculated,
const datetime &time[],
const double &open[],
const double &high[],
const double &low[],
const double &close[],
const long &tick_volume[],
const long &volume[],
const int &spread[])
{
if(rates_total < RSIPeriod + MinBarsBetween + 10) return 0;

int start = (prev_calculated == 0) ? RSIPeriod + 2 : prev_calculated - 1;

//--- 复制RSI数据到缓冲区
if(CopyBuffer(rsiHandle, 0, 0, rates_total - start, RSIBuffer) < 0)
{
Print("CopyBuffer失败,错误码: ", GetLastError());
return 0;
}

//--- 主循环
for(int i = start; i < rates_total - 1; i++)
{
BullBuffer[i] = EMPTY_VALUE;
BearBuffer[i] = EMPTY_VALUE;
HiddenBuffer[i] = EMPTY_VALUE;

//--- 寻找枢轴低点(用于看涨背离)
int lowPivot1 = FindPivotLow(i, low, RSIBuffer, rates_total);
if(lowPivot1 > 0)
{
int lowPivot2 = FindPivotLow(lowPivot1 - MinBarsBetween, low, RSIBuffer, rates_total);
if(lowPivot2 > 0)
{
//--- 常规看涨:价格创新低,RSI未创新低
if(low[lowPivot1] < low[lowPivot2] && RSIBuffer[lowPivot1] > RSIBuffer[lowPivot2])
{
BullBuffer[lowPivot1] = 5.0; // 在RSI下方画箭头
}
//--- 隐藏看涨:价格未创新低,RSI创新低
if(ShowHidden && low[lowPivot1] > low[lowPivot2] && RSIBuffer[lowPivot1] < RSIBuffer[lowPivot2])
{
HiddenBuffer[lowPivot1] = 5.0;
}
}
}

//--- 寻找枢轴高点(用于看跌背离)
int highPivot1 = FindPivotHigh(i, high, RSIBuffer, rates_total);
if(highPivot1 > 0)
{
int highPivot2 = FindPivotHigh(highPivot1 - MinBarsBetween, high, RSIBuffer, rates_total);
if(highPivot2 > 0)
{
//--- 常规看跌:价格创新高,RSI未创新高
if(high[highPivot1] > high[highPivot2] && RSIBuffer[highPivot1] < RSIBuffer[highPivot2])
{
BearBuffer[highPivot1] = 95.0; // 在RSI上方画箭头
}
//--- 隐藏看跌:价格未创新高,RSI创新高
if(ShowHidden && high[highPivot1] < high[highPivot2] && RSIBuffer[highPivot1] > RSIBuffer[highPivot2])
{
HiddenBuffer[highPivot1] = 95.0;
}
}
}
}

return rates_total;
}
//+------------------------------------------------------------------+
//| 寻找枢轴低点(价格和RSI同时成立) |
//+------------------------------------------------------------------+
int FindPivotLow(int startBar, const double &price[], const double &rsi[], int total)
{
int lookback = MinBarsBetween;
if(startBar - lookback < 0 || startBar + lookback >= total) return -1;

for(int i = startBar - lookback; i <= startBar + lookback; i++)
{
if(i == startBar) continue;
//--- 检查当前价格是否低于周围价格
if(price[startBar] >= price[i]) return -1;
//--- 同时检查RSI是否低于周围RSI(过滤假信号)
if(rsi[startBar] >= rsi[i]) return -1;
}
return startBar;
}
//+------------------------------------------------------------------+
//| 寻找枢轴高点(价格和RSI同时成立) |
//+------------------------------------------------------------------+
int FindPivotHigh(int startBar, const double &price[], const double &rsi[], int total)
{
int lookback = MinBarsBetween;
if(startBar - lookback < 0 || startBar + lookback >= total) return -1;

for(int i = startBar - lookback; i <= startBar + lookback; i++)
{
if(i == startBar) continue;
if(price[startBar] <= price[i]) return -1;
if(rsi[startBar] <= rsi[i]) return -1;
}
return startBar;
}
//+------------------------------------------------------------------+
`

代码拆解:关键部分



缓冲区设置:第16-32行定义了四个缓冲区。注意
BullBufferBearBuffer设置为DRAW_ARROW。箭头代码(233表示向上,234表示向下)在OnInit()中定义。这一步必须做——如果忘了调用PlotIndexSetInteger,图表上什么都不会显示。

枢轴函数:这是大多数免费指标翻车的地方。
FindPivotLow不仅检查价格,还验证RSI是否低于其相邻值。这确保我们只标记真正的枢轴点,而不是小幅波动。MinBarsBetween参数至关重要:设得太低(比如2),你会得到几十个假信号。实测H1周期用5效果不错,H4则建议用8。

背离逻辑:条件
low[lowPivot1] < low[lowPivot2] && RSIBuffer[lowPivot1] > RSIBuffer[lowPivot2]是经典的常规看涨背离。隐藏背离的逻辑相反,但通过ShowHidden开关控制。我加了一个很少见的处理:枢轴检测要求价格和RSI同时形成枢轴。相比只检测价格的版本,这能过滤掉大约40%的假信号。

一个你应该做的实用修改



问题是:在M15这样的低周期上,这个指标仍然会产生太多信号。我的解决办法是加一个成交量过滤器——如果第二个枢轴的成交量小于第一个,就忽略该信号。你可以通过把
tick_volume[]数组传给FindPivotLow函数并加入检查来实现。

参考来源



  • Brown, C. (2008). Technical Analysis for the Trading Professional. McGraw-Hill.(第五章:RSI背离)

  • MQL4官方文档:自定义指标,访问日期2026-06-29。


  • 这份MQL4源码是一个扎实的基础。如果你想扩展它,加入自动趋势线绘制或警报通知,我在付费版本中已经集成了这些功能。

    更多开箱即用的高阶指标和全自动策略,欢迎访问FXEAR.com会员区。

    本文首发于FXEAR.com,原创内容,未经授权禁止转载。
    ``