English Русский Español Deutsch 日本語
preview
从新手到专家:支撑与阻力强度指标(SRSI)

从新手到专家:支撑与阻力强度指标(SRSI)

MetaTrader 5示例 |
1 468 6
Clemence Benjamin
Clemence Benjamin

内容


概述

市场始终对曾影响其走势的过往价格水平保持敬畏。典型交易者的日常操作,往往始于在MetaTrader 5中用广为人知的画线工具手动绘制这些关键价位。然而,这种手动操作可能导致遗漏重要价位或误判其重要性,这就凸显了自动化解决方案的必要性。

有人可能会问,为何需要自动化?尽管人类在复杂创意任务和适应新情境方面表现出色,但在一致性和处理大量数据方面却往往力不从心。Mark Angelo D. Julian、Danilo B. Villarino和Kristine T. Soberano在2024年7月7日的论文《人脑与计算机:谁更聪明?》中强调了这一点。他们的研究显示,尽管人类在理解语境方面更胜一筹,但计算机在处理速度、数据准确性和执行重复计算方面远超人类。这种对比促使我们不断开发交易和数据分析算法。


讨论概述

今天,我们将运用MQL5编程的问题解决技巧,来应对上述挑战。本次讨论面向所有技能水平的交易者,从新手到专家,因为我们探讨的是影响每个人的关键概念。如您所知,MetaTrader 5本质上是一个庞大的价格数据、分析工具和历史信息库。例如,蜡烛图系列是计算得出的柱状图,代表开盘价、最高价、最低价和收盘价,而移动平均线(MA)等流行指标则源自这些数值。想象一下手动审查5000根蜡烛图——这一过程不仅繁琐,而且容易出错。因此,自动化识别支撑和阻力水平显得尤为有益。

尽管市场上已有多种免费和付费工具,但今天我们将探索一种独特的方法。本次课程不仅关注最终产品,还旨在分享构建自定义解决方案所需的MQL5编程技能。以下是我们正在开发的SRSI优势概述:

  • 高效数据处理:分析大量历史K线图数据,精准定位关键价位。
  • 持续自动化:自动且持续运行,减少手动错误。
  • 价位区分:识别弱支撑和阻力水平以及强支撑和阻力水平。
  • 清晰可视化:提供这些关键价位清晰的可视化呈现。
  • 全面通知:通过终端和推送通知向用户发送通知。

在接下来的部分中,我们将首先使用MetaTrader 5图表和手动识别的支撑和阻力水平收集历史价格数据。这一初步分析将提供佐证,比较当前市场行为与过去表现。接下来,我们将深入开发过程,我将分享并解析自定义指标的代码——详细解释每一行,确保您完全理解如何实施MQL5并将理念转换为代码。

最后,我们将回顾测试过程并展示结果,让您既提升编程技能,又能获得一个可用的解决方案。请慢慢来,跟随步骤,享受编码之旅。


当今市场特性的佐证  

我的MetaTrader 5平台与经纪商相连,为我提供了广泛的交易对选择。根据账户类型,我可以交易波动率交易对、外汇交易对、股票交易对等。提供的图片显示了可供交易的众多附加的交易对。对于本次研究,我从这些交易对中选择了几个进行分析。

要查看您的经纪商提供的交易对并将其添加到市场观察列表中,只需按键盘上的CTRL + U或点击红色圆形图标(如下图所示)打开“交易品种”窗口。然后,双击所需的交易对,即可自动将其添加到列表中。

交易品种

MetaTrader 5 Symbols

合成交易对

我首先从波动率指数下的一个合成交易对——波动率75(1秒)指数——在周线图上开始分析。该交易对大约在2020年推出时,起初价格较高,但很快经历了长时间的暴跌,形成了数周的强劲下跌趋势。在那段时间做空该交易对的交易者可能获得了可观的利润。然而,我的主要关注点是市场结构,特别是过去三年的市场结构。

持续的下跌趋势很可能使交易者形成了跟风做空的思维定式,预期价格会进一步下跌。然而,如下图所示,市场动态已经发生了变化。现在,更长时间周期的图表呈现出震荡盘整的结构,在更短时间周期的图表上也能观察到类似特征。这种市场状况使得摇摆不定的交易者难以找到方向。

在这种情况下,基于支撑和阻力的价格走势分析对于识别关键交易机会变得至关重要。下图展示了这种市场行为,进一步强调了采用结构化方法进行技术分析的重要性。

波动率75(1秒)指数

波动率75(1秒)指数

股票交易对

我分析了美国科技股的周线图,很明显市场一直呈上升趋势,期间伴有周期性回调。这些回调往往会导致价格进入盘整阶段,在恢复趋势前价格走势放缓。在上升市场中,回调通常会形成强劲的支撑区域,进而强化多头契机。

在这个较长周期的时间框架下,很难识别出影响较短周期价格走势的精确形态。然而,随着深入分析,我们将看到支撑和阻力概念在不同时间框架下依然适用,这使我们能够更详细地观察各种市场形态。

     美国科技100指数周线图

美国科技100指数周线图

外汇交易对

欧元兑美元(EUR/USD)周线图显示,市场先经历了一小段脉冲式行情,随后进入长时间的波动阶段。这种走势在较长周期时间框架上表现明显,同时也延伸至较短周期时间框架。这里的关键要点是,价格长时间处于区间波动状态,凸显出市场在大部分时间里处于盘整而非趋势行情。下图即为这一在明确区间内长期市场走势的佐证。

欧元兑美元周线图

欧元兑美元周线图

总之,从上述分析中可以明显看出,尽管市场价格会经历涨跌趋势,但它们在很大程度上依赖先前的价格水平进行测试和验证。在盘整阶段,基于所选时间框架的这些水平线,成为令价格趋于产生反应的关键区域。

然而,并非每个水平位都强大到足以引发显著的价格变动。此外,即便是已确立的支撑位或阻力位,也不能保证价格一定会做出反应,但如果这些水平位足够强劲,那么它们对市场行为产生影响的可能性就会更高。

在下一部分中,我们将简要回顾支撑位和阻力位的基础知识,然后深入探讨算法开发。


实现MQL5开发SRSI 

支撑位与阻力位的定义

支撑位通常被定义为一个需求区域,多个价格水平在此汇聚,表明买入方倾向于介入并推动价格上涨。这一区域代表了市场的“底部”,买盘兴趣的积累往往会阻止价格进一步下跌。

  • 实际上,支撑位通常不是一个单一的价格点,而是一片区域,在此区域内,先前的低点或多个接触点已建立起买方的信心。

相反,阻力位是一个供给区域,多个价格水平在此汇聚,表明卖方可能会介入并推动价格下跌。这一区域充当市场的“顶部”,卖出压力超过买入压力,通常阻止价格进一步上涨。与支撑位类似,阻力位通常也被视为一个范围,而非一个精确的水平位,因为存在多个高点或接触点,这些点强化了卖盘兴趣。

基于这样的理解,运用支撑位和阻力位就变得简单多了。在以下视频中,我将带领大家了解日常操作,展示我通常如何绘制这些线。


算法设计与实现

我们需要让程序能够模拟我手动识别和标记支撑位和阻力位区域的方式。看完视频后,我在这里总结了关键步骤:

  1. 识别极端转折点:这些是重要的高点(用于阻力位)或低点(用于支撑位),价格在此反转方向。
  2. 寻找其他测试点:寻找价格等于或接近极端转折点(相差5个点以内)的其他价格水平,以确认其重要性。
  3. 形成反弹区域:创建矩形区域,包含极端转折点及其测试点,区域围绕这些接触点延伸。
  4. 自定义区域尺寸:

  • 高度:区域矩形的垂直尺寸(以点为单位)应可调整。
  • 宽度:区域(向右的K线数)的水平尺寸应当可调整。

一般来说,我们将配置程序以扫描可自定义数量的K线,识别符合我们标准的条件,并绘制适当的形状、线条和标签。我们还将提供输入选项,以控制程序的各种功能。对于警报,我们将实现推送通知和终端警报,在可自定义的4小时间隔内定期发送。与其他指标不同,支撑位和阻力位不需要持续监控,因此这种方法可确保及时通知,而不会产生过多警报。下面,我将逐步解释细节,并附上代码段。

当您打开MetaEditor并选择创建一个新的自定义指标时,它会提供一个基础模板供您使用。这个模板就像一块空白画布,帮助开发者入门,我们也将在这个模板基础上构建SRSI。以下是具体代码示例:

//+------------------------------------------------------------------+
//|                                                        _SRSI.mq5 |
//|                                   Copyright 2025, Metaquotes Ltd |
//|                                            https://www.mql5.com/ |
//+------------------------------------------------------------------+
#property copyright "Copyright 2025, Metaquotes Ltd"
#property link      "https://www.mql5.com/"
#property version   "1.00"
#property indicator_chart_window
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
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[])
  {
//---
   
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+

我们将以此作为基础指南,确保能够完全实现所有关键功能。在接下来的步骤中,我们将完善该模板,集成新功能,并详细解释其功能特性。请跟随操作直至最后,以便全面理解。

步骤1:自定义指标属性

首先,我们自定义指标属性,使其个性化并满足MetaTrader 5的要求。我们更新版权和链接详情,以反映自身的信息。我们添加了一项设置,用于进行更严格的错误检查,以便在开发过程中发现错误。将该指标设置为在主图表窗口显示。由于MetaTrader 5要求至少有一个缓冲区,我们定义了一个单一的隐藏“虚拟”缓冲区,因为指标将使用自定义对象(线条和矩形),而非绘制缓冲区数据。

#property copyright "Clemence Benjamin"
#property link      "https://www.mql5.com/en/users/billionaire2024/seller"
#property version   "1.00"
#property strict          // Enforces stricter error checking
#property indicator_chart_window
#property indicator_buffers 1  // MT5 requires at least one buffer
#property indicator_plots 1    // Ties to the buffer (even if unused for plotting)

步骤2:添加用户输入参数

接下来,我们添加用户可配置的输入参数,使指标具备可调整性。我们提供以下选项:设置指标分析过往多少根K线、设定检测水平位测试的价格范围(例如,默认设为7个点)、设定水平位被视为强劲所需的最小测试次数,以及显示或隐藏强劲水平位周围矩形区域的切换开关。这些输入参数使用户能够在不修改代码的情况下调整指标的行为。

input int InpLookBack = 1000;        // Number of bars to analyze
input double InpTestProximity = 0.0007; // Price range for tests (e.g., 7 pips)
input int InpMinTests = 3;           // Minimum tests for strong levels
input bool InpShowRectangles = true; // Show zones as rectangles

步骤3:创建虚拟缓冲区

MetaTrader 5要求每个指标至少有一个缓冲区,即使该缓冲区不显示。我们创建一个全局数组来充当这个虚拟缓冲区。在初始化期间,我们将其绑定到一个缓冲区槽位,并从图表中隐藏它。这样既满足了MetaTrader 5的要求,又让我们能够专注于绘制自定义的支撑位和阻力位。

double DummyBuffer[];

使用方法:

int OnInit()
{
   SetIndexBuffer(0, DummyBuffer, INDICATOR_DATA);   // Bind buffer to index 0
   PlotIndexSetInteger(0, PLOT_DRAW_TYPE, DRAW_NONE); // Hide it from the chart
   return(INIT_SUCCEEDED);
}

步骤4:定义数据结构

为了使数据井然有序,我们使用枚举和结构体。我们定义一个枚举类型,用于对水平位进行分类(例如,强劲支撑位、弱势阻力位),以提高清晰度。一个用于存储价格水平位的结构体,记录每个水平位的价格、测试次数、类型以及识别时间。另一个结构体则定义强劲水平位周围的区域,记录这些区域的顶部和底部价格以及时间范围。我们还设置了全局数组,用于存储强劲水平位、弱势水平位和区域,此外,还设置了一个变量,用于跟踪最后一次发出警报的时间。

enum ENUM_LEVEL_TYPE {
   LEVEL_STRONG_SUPPORT,      // Strong support level
   LEVEL_STRONG_RESISTANCE,   // Strong resistance level
   LEVEL_WEAK_SUPPORT,        // Weak support level
   LEVEL_WEAK_RESISTANCE      // Weak resistance level
};

struct PriceLevel {
   double price;           // Price value of the level
   int test_count;         // Number of times price tested it
   ENUM_LEVEL_TYPE type;   // Strong or weak, support or resistance
   datetime time;          // Time the level was identified
};

struct Zone {
   double top;             // Top price of the zone
   double bottom;          // Bottom price of the zone
   datetime start_time;    // When the zone starts
   datetime end_time;      // When the zone ends (current time)
};

PriceLevel StrongLevels[];    // Array for strong levels
PriceLevel WeakLevels[];      // Array for weak levels
Zone Zones[];                 // Array for strong level zones
datetime LastAlertTime = 0;   // Tracks the last alert time

步骤5:识别转折点

支撑位和阻力位通常在波段高点和波段低点处形成。我们创建一个函数,通过检查某根K线的高点是否高于其前后各5根K线的高点,来识别波峰。类似地,我们创建一个用于识别波段低点的函数,通过检查某根K线的低点是否低于其前后各5根K线的低点,来确认波谷。每侧使用5根K线的窗口范围,可确保这些点具有显著意义。

bool IsSwingHigh(int index, const double &high[])
{
   int window = 5;  // Check 5 bars on each side
   for (int i = 1; i <= window; i++) {
      if (index - i < 0 || index + i >= ArraySize(high)) return false; // Out of bounds
      if (high[index] <= high[index - i] || high[index] <= high[index + i]) return false; // Not a peak
   }
   return true;
}

bool IsSwingLow(int index, const double &low[])
{
   int window = 5;  // Check 5 bars on each side
   for (int i = 1; i <= window; i++) {
      if (index - i < 0 || index + i >= ArraySize(low)) return false; // Out of bounds
      if (low[index] >= low[index - i] || low[index] >= low[index + i]) return false; // Not a trough
   }
   return true;
}

步骤6:统计价格测试次数

一个水平位的强度取决于价格对其测试的频繁程度。我们添加一个函数,通过检查转折点之后的K线来统计这些测试次数。该函数会检查每根K线的高点或低点是否落在该水平位既定价格范围内,每出现一次符合条件的情况,就将计数器加1。最终的总测试次数会根据用户设定的最小阈值,来判断该水平位是强劲还是弱势。

int CountLevelTests(double price, int start_index, const double &high[], const double &low[])
{
   int tests = 0;
   for (int i = start_index + 1; i < ArraySize(high); i++) {
      if (MathAbs(high[i] - price) <= InpTestProximity || MathAbs(low[i] - price) <= InpTestProximity) {
         tests++;
      }
   }
   return tests;
}

步骤7:处理水平位

我们使用一个专用函数将每个转折点处理为一个水平位。该函数会根据转折点是波峰还是波谷,以及是否达到测试阈值,记录该水平位的价格、测试次数、时间以及类型(强劲/弱势、支撑/阻力)。对于强劲水平位,该函数还会在其周围定义一个包含价格区间的区域。随后,该水平位会被存储到相应的数组(强劲或弱势)中,以备后续使用。

void ProcessLevel(int index, double price, bool is_high, const double &high[], const double &low[], const datetime &time[])
{
   PriceLevel level;
   level.price = price;
   level.test_count = CountLevelTests(price, index, high, low);
   level.time = time[index];
   
   if (is_high) {
      level.type = (level.test_count >= InpMinTests) ? LEVEL_STRONG_RESISTANCE : LEVEL_WEAK_RESISTANCE;
   } else {
      level.type = (level.test_count >= InpMinTests) ? LEVEL_STRONG_SUPPORT : LEVEL_WEAK_SUPPORT;
   }
   
   if (level.test_count >= InpMinTests) {
      ArrayResize(StrongLevels, ArraySize(StrongLevels) + 1);
      StrongLevels[ArraySize(StrongLevels) - 1] = level;
      Zone zone;
      zone.start_time = time[index];
      zone.end_time = TimeCurrent();
      zone.top = price + InpTestProximity;
      zone.bottom = price - InpTestProximity;
      ArrayResize(Zones, ArraySize(Zones) + 1);
      Zones[ArraySize(Zones) - 1] = zone;
   } else {
      ArrayResize(WeakLevels, ArraySize(WeakLevels) + 1);
      WeakLevels[ArraySize(WeakLevels) - 1] = level;
   }
}

步骤8:在图表上绘制

为了在图表上展示水平位,我们使用两个绘制函数。其中一个函数用于绘制强劲水平位:若启用了区域显示功能,则用灰色矩形绘制该区域,并用实线绘制水平位本身——支撑位为蓝色,阻力位为红色——同时添加标签(表示强劲支撑的“SS”或表示强劲阻力的“SR”)。另一个函数用于绘制弱势水平位:用虚线绘制水平位——支撑位为浅蓝色,阻力位为粉色——并添加标签(表示弱势支撑的“WS”或表示弱势阻力“WR”)。每个绘制对象都会根据其时间生成一个唯一的名称,以确保在图表上对应正确。

void RenderZone(const Zone &zone, const PriceLevel &level)
{
   string name = "Zone_" + TimeToString(zone.start_time);
   if (InpShowRectangles) {
      ObjectCreate(0, name, OBJ_RECTANGLE, 0, zone.start_time, zone.top, zone.end_time, zone.bottom);
      ObjectSetInteger(0, name, OBJPROP_COLOR, clrLightGray);
      ObjectSetInteger(0, name, OBJPROP_FILL, true);
   }
   
   string line_name = "Line_" + TimeToString(level.time);
   ObjectCreate(0, line_name, OBJ_HLINE, 0, 0, level.price);
   ObjectSetInteger(0, line_name, OBJPROP_COLOR, (level.type == LEVEL_STRONG_SUPPORT) ? clrBlue : clrRed);
   ObjectSetString(0, line_name, OBJPROP_TEXT, (level.type == LEVEL_STRONG_SUPPORT) ? "SS" : "SR");
}

void RenderWeakLine(const PriceLevel &level)
{
   string name = "WeakLine_" + TimeToString(level.time);
   ObjectCreate(0, name, OBJ_HLINE, 0, 0, level.price);
   ObjectSetInteger(0, name, OBJPROP_STYLE, STYLE_DASH);
   ObjectSetInteger(0, name, OBJPROP_COLOR, (level.type == LEVEL_WEAK_SUPPORT) ? clrLightBlue : clrPink);
   ObjectSetString(0, name, OBJPROP_TEXT, (level.type == LEVEL_WEAK_SUPPORT) ? "WS" : "WR");
}

步骤9:发送警报

我们添加了一个功能,用于发送关于强劲水平位的警报,同时避免骚扰用户。该功能会检查自上次警报发出以来是否已过去一小时,以及是否存在强劲水平位。如果条件满足,它会生成一条包含最新强劲水平位类型、价格和当前价格的消息,并将其显示出来。随后,警报时间会更新,以防止频繁发送通知。

void SendPeriodicAlert(double current_price)
{
   if (TimeCurrent() - LastAlertTime < 3600) return; // Wait 1 hour between alerts
   if (ArraySize(StrongLevels) == 0) return;         // No strong levels, no alert
   
   PriceLevel latest = StrongLevels[ArraySize(StrongLevels) - 1];
   string message = "SRZones Alert: Strong " + 
                    ((latest.type == LEVEL_STRONG_SUPPORT) ? "Support" : "Resistance") + 
                    " at " + DoubleToString(latest.price, 5) + 
                    ", Current Price: " + DoubleToString(current_price, 5);
   Alert(message);
   LastAlertTime = TimeCurrent();
}

步骤10:清除旧图形

为了保持图表整洁,我们添加了一个用于移除旧图形对象的函数。该函数会通过特定的名称前缀,删除所有先前绘制的区域、强劲水平位线条和弱势水平位线条。此操作会在每次完整重新计算前执行,以确保仅显示当前水平位的最新图形。

void ClearDisplayObjects()
{
   ObjectsDeleteAll(0, "Zone_");       // Delete all zones
   ObjectsDeleteAll(0, "Line_");       // Delete strong lines
   ObjectsDeleteAll(0, "WeakLine_");   // Delete weak lines
}

步骤11:在OnCalculate函数中运行核心逻辑

最后,我们将所有功能整合到主计算函数(OnCalculate)中。在启动时或新K线形成时,该函数会清除旧图形对象并重置数组。其根据用户定义的回溯周期确定起始点,确保有足够的数据用于识别转折点。随后,该函数会遍历所有K线,识别波段高点和低点,将其处理为水平位并存储。接下来,它会绘制所有强劲和弱势水平位,并检查是否需要触发警报。最后,该函数将处理过的K线数量返回给MetaTrader 5。

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 (prev_calculated == 0 || rates_total > prev_calculated) { // Full recalc on start or new bar
      ClearDisplayObjects();
      ArrayResize(StrongLevels, 0);
      ArrayResize(WeakLevels, 0);
      ArrayResize(Zones, 0);
      
      int start = MathMax(5, rates_total - InpLookBack); // Start within lookback period
      for (int i = start; i < rates_total - 5; i++) {    // Leave room for swing checks
         if (IsSwingHigh(i, high)) ProcessLevel(i, high[i], true, high, low, time);
         if (IsSwingLow(i, low)) ProcessLevel(i, low[i], false, high, low, time);
      }
      
      for (int i = 0; i < ArraySize(StrongLevels); i++) {
         RenderZone(Zones[i], StrongLevels[i]);
      }
      for (int i = 0; i < ArraySize(WeakLevels); i++) {
         RenderWeakLine(WeakLevels[i]);
      }
      
      SendPeriodicAlert(close[rates_total - 1]);
   }
   return(rates_total); // Tell MT5 how many bars were processed
}

在将所有模块整合完毕并解决各类问题后,我们成功编译了最终版,相关文件附于本讨论末尾。下一部分中,我们将分享测试体验,并在结论部分给出最终总结。


测试结果 

第一步是将指标加载至图表并采用默认设置进行测试,以欧元兑美元作为参考标的。对于其他货币对,可能需先调整参数(尤其是点值设置),以确保指标正确显示。例如,在测试波动率75指数(1秒级)时,起初未显示任何区域,直至将点值参数调整为70后才正常显示。

初始状态下(如下图所示),矩形区域的宽度较小,需通过自定义设置扩大尺寸,调整后的效果参见下一张图。所有参数设置均能即时生效,图表显示效果变化明显。此外,所有标签均清晰可见,且可以根据需要选择隐藏。

添加SRSI至图表

在图表中添加SRSI。

自定义SRSI

自定义SRSI设置

首次启动时,该指标会发送一条警报,显示当前的主导支撑位或阻力位以及当前价格。这有助于用户预判潜在的供需区域。以下是显示警报详情的expert日志。

2025.03.10 07:44:42.548 _SRSI (EURUSD,M15)      Alert: Key Level: SR at 1.08715 | Current Price: 1.09021
2025.03.10 07:54:04.239 _SRSI (EURUSD,M15)      Alert: Key Level: SR at 1.08715 | Current Price: 1.09033
2025.03.10 07:55:04.965 _SRSI (EURUSD,M5)       Alert: Key Level: SR at 1.09013 | Current Price: 1.09044
2025.03.10 09:25:13.506 _SRSI (EURUSD,M5)       Alert: Key Level: SR at 1.09013 | Current Price: 1.09210
2025.03.10 11:26:46.761 _SRSI (EURUSD,M5)       Alert: Key Level: SR at 1.09013 | Current Price: 1.09192

此外,设置中还提供了推送通知选项(默认开启终端内通知)。当触发警报时,警报窗口会自动在终端屏幕上弹出显示。

警报

终端警报窗口:SRSI指标运行中


结论 

我们成功开发出无错误指标,圆满达成了本次讨论的目标。从测试结果来看,该指标满足了设计预期,实现了所需功能。现在,我只需轻轻点击几下,就能轻松绘制支撑线和阻力线,而算法会自动筛选出可靠的水平位。正如您在视频中所见,手动绘制过程相当耗时,但是有了算法,每次价格变动(tick)都能即时计算出这些水平位。在此过程中,我们积累了宝贵的MQL5指标开发经验。虽然指标性能需经时间检验,但高级开发者可通过多种方式对其进行优化和扩展。

我们采用结构体编写代码,使程序更加专业、条理清晰。然而,始终存在改进空间,相信您对完善这一工具也有独到的见解和建议。欢迎您对其进行修改和实践,并随时在下方评论区分享您的观点。

希望本次讨论能为您带来启发。希望下次再会时,各位开发者编码愉快、交易顺利!


附件(SRSI源文件) 

文件 描述
_SRSI.mq5 一款支撑阻力强度指标,可动态绘制可调节的矩形区域,并清晰标注强劲支撑(SS)与强劲阻力(SR)水平位。此外,该指标还通过虚线绘制弱势支撑(WS)与弱势阻力(WR)水平位,以便更直观地呈现市场结构。

返回内容目录

本文由MetaQuotes Ltd译自英文
原文地址: https://www.mql5.com/en/articles/17450

附加的文件 |
_SRSI.mq5 (29.97 KB)
最近评论 | 前往讨论 (6)
Clemence Benjamin
Clemence Benjamin | 20 3月 2025 在 18:13
Darz #:
我非常喜欢您的文章,并在外汇货币对上试用过,似乎效果不错......那么 US30 等指数呢?我试着将文本接近度设置为 0.035,结果看起来很滑稽。
你好,@Darz,我的好朋友。感谢您的回复!
我注意到,对于 US Tech 和其他合成货币对,由于它们的点值较高,因此需要更高的接近值。我不得不将其设置为10,然后 US Tech 上才开始出现阻力区--见下图。
我建议您尝试使用该值,直到找到适合您特定货币对的最佳设置。

谢谢!


Anil Varma
Anil Varma | 21 3月 2025 在 08:53
Clemence Benjamin #:
你好,@Darz,我的好朋友。感谢您的回复!
我注意到,由于 US Tech 和其他合成货币对的点值较高,因此需要更高的接近值。我不得不将其设置为10,然后 US Tech 上才开始出现阻力区--见下图。
我建议您尝试使用该值,直到找到适合您特定货币对的最佳设置。

谢谢!


你好,朋友

我一直在关注您的文章,它们信息量很大。感谢您分享和传播知识。

我尝试了下面的 21 期 ATR 倍率:

gTestProximity = (MathMax((75/_Digits),0.10*getATR(rates_total - 1))); // (n*getATR(index) replaced for ...InpTextProximity;

gMinDistance = (MathMax((150/_Digits),0.20*getATR(rates_total - 1))); // (n*getATR(index) 替换为...InpMinWeakDistance);

这帮助我获得了欧元兑美元(EURUSD)和美元兑澳元(XAUUSD)货币对的 SRZones,其数值从 1.08000 到 3000.00 之间差别很大。

对您文章的读者来说,进一步微调可能会有所帮助。这样,指标设置就能适用于大多数符号。

Clemence Benjamin
Clemence Benjamin | 25 3月 2025 在 22:09
Anil Varma #:

你好,朋友

我一直在关注您的文章,它们信息量很大。感谢您分享和传播知识。

我尝试了 21 期 ATR 多头,如下所示:

gTestProximity = (MathMax((75/_Digits),0.10*getATR(rates_total - 1))); // (n*getATR(index) replaced for ...InpTextProximity;

gMinDistance = (MathMax((150/_Digits),0.20*getATR(rates_total - 1))); // (n*getATR(index) 替换为...InpMinWeakDistance;

这帮助我获得了欧元兑美元(EURUSD)和美元兑澳元(XAUUSD)货币对的 SRZones,其数值从 1.08000 到 3000.00 之间差别很大。

对您文章的读者来说,进一步微调可能会有所帮助。这样,指标设置就能适用于大多数符号。

你好,我的好朋友@Anil Varma

感谢您分享这种独特的方法!我一定会试一试。

Evgeny Fedorenko
Evgeny Fedorenko | 9 6月 2025 在 14:44
Anil Varma #:

你好,朋友

我一直在关注您的文章,它们信息量很大。感谢您分享和传播知识。

我尝试了 21 期 ATR 多头,如下所示:

gTestProximity = (MathMax((75/_Digits),0.10*getATR(rates_total - 1))); // (n*getATR(index) replaced for ...InpTextProximity;

gMinDistance = (MathMax((150/_Digits),0.20*getATR(rates_total - 1))); // (n*getATR(index) 替换为...InpMinWeakDistance;

这帮助我获得了欧元兑美元(EURUSD)和美元兑澳元(XAUUSD)货币对的 SRZones,其数值从 1.08000 到 3000.00 之间差别很大。

对您文章的读者来说,进一步微调可能会有所帮助。这样,指标设置就能适用于大多数符号。

您好
您能分享一下您的 ATR 指标版本吗?
Anil Varma
Anil Varma | 18 6月 2025 在 10:25
Evgeny Fedorenko #:
您好
能否分享一下您的 ATR 指标版本?

你好@Evgeny Fedorenko

首先很抱歉回复得太晚了,实际上我已经把注意力转移到了定量金融建模课程上。

其次,我并没有为自己创建任何指标,只是尝试了克利芒斯-本杰明(Clemence Benjamin)的指标代码,并根据我帖子中的建议进行了调整。

希望能帮到您。

交易中的神经网络:配备注意力机制(MASAAT)的智代融汇(终章) 交易中的神经网络:配备注意力机制(MASAAT)的智代融汇(终章)
在上一篇文章中,我们讲述了多智代自适应框架 MASAAT,其用一组智代的融汇在不同数据尺度下对多模态时间序列进行交叉分析。今天我们将继续实现该框架方法的 MQL5 版本,并将这项工作带至逻辑完结。
MQL5 简介(第 12 部分):构建自定义指标的初学者指南 MQL5 简介(第 12 部分):构建自定义指标的初学者指南
了解如何在 MQL5 中构建自定义指标。采用基于项目的方法。本初学者指南涵盖指标缓冲区、属性和趋势可视化,让您一步一步地学习。
市场模拟(第四部分):创建 C_Orders 类(一) 市场模拟(第四部分):创建 C_Orders 类(一)
在本文中,我们将开始创建 C_Orders 类,以便能够向交易服务器发送订单。我们将循序渐进地进行,目标是通过消息系统详细说明这一过程的具体实现方式。
优化中自定义准则的新方法(第一部分):激活函数示例 优化中自定义准则的新方法(第一部分):激活函数示例
本系列文章首篇将探讨自定义准则的数学原理,重点聚焦神经网络中使用的非线性函数、MQL5实现代码,以及目标导向与校正偏移量的应用。