外汇EA编写教程:使用MQL5绘制阻力和支撑水平

目录

  1. 介绍
  2. 本文的目的
  3. 早期表示的支撑和阻力绘制方法概述
  4. 求极值原理
  5. ext_1,使用最低索引查找极值的函数(第一列)
  6. 通用函数ext_2查找所有后续极值
  7. 处理结果
  8. 显示支撑和阻力水平的常规程序
  9. 结论

介绍

首先,我将简要介绍支持线和阻力线,它们是如何建立的,以及它们是如何用于交易的。

所有趋势图、线和模型都由支撑线和阻力线组成,后面是经典的趋势分析。阻力线基于最高价格,交易员(“牛市势头”)停止高水平买入货币,并开始清算头寸。金融工具价格的反应是,在熊市中出现类似情况之前,金融工具价格回落,支持线基于最低价格。

因此,可以假设,当货币超卖时,它形成最大点和最小点——当货币超卖时。这就是为什么我使用元交易员的标准指数相对强度指数(RSI)来绘制支撑线和阻力线。1978年由约翰·怀尔德开发出版。此指标可用于确定货币超卖和超卖的区域。

我使用的是一个周期为8的RSI索引;这个值不是我的观察值-这个RSI参数是由Eric L.Nyman在他的书《小交易者百科全书-小交易者百科全书》中推荐的,可以用于除每日行和更高级别之外的所有图表周期。我对RSI(8)指标的运行结果非常满意。

对于寻找最高和最低价格时是否应考虑蜡烛芯(最大/最小)有两种不同的意见。我个人认为,在寻找极限点时,我们应该考虑它们,比较最高和最低的价格。如果您不想考虑它们,您可以简单地微调以下指示器代码。

支持线和阻力线的使用可能发生在这些线之外,价格可能在这些线形成的渠道之间波动。

当突破支撑和阻力级别时进行交易

图1。买入信号

我认为第二种方法效率低下,特别是在制定交易策略时,价格从某一条线回落起到了根本性的作用。图1说明了这种情况。当价格从阻力线回落时,它不会触及支撑线,翻滚并突破阻力线。这导致强烈的购买信号。通过分析这些线与时间轴的夹角,确定了金融工具的总体趋势方向,当金融工具的价格穿过这些线时,我们可以判断当前趋势是上升还是反转的结论。通常,在穿过支撑线之前,例如,价格只到达阻力线的中间(这个因素增强了交易信号)。

设计了一个名为Autochart的平台来识别趋势和模型。作为一个实验,我在一个演示账户中交易了两个月,使用价格自我阻力或支持水平回退作为信号-在这些情况下,许多交易在亏损时平仓,而不是使用水平突破作为信号。

支撑和阻力水平也用于确定趋势加速度或减速度。牛市趋势线角增大意味着加速,其出现将导致趋势继续。相反,在熊市情况下角度的增加表明趋势放缓。在牛市中,支持线(根据最低价格绘制)用作趋势线,而在熊市中,阻力线(根据最高价格绘制)用作趋势线。

牛势放缓

图2。牛减速

熊势放缓

图3。熊市减速

经济放缓预示着不久的将来会出现逆转。

本文的目的

分析支撑线和阻力线形成的图表是最古老的技术分析方法之一。根据我在外汇交易市场的经验,我可以说,这些方法不仅古老,而且仍然有效。我相信很多交易者会使用它。对于具有理论知识的交易者来说,使用MetaTrader 5终端手工构建支持线和阻力线非常容易。但是,如果建立一个程序来自动绘制这些线,情况就不是这样了。

在本文中,我打算提出我自己的实现方法,即绘制与MQL5和MQL4兼容的支撑线和电阻线。我希望你觉得这个信息非常有用。

早期表示的支撑和阻力绘制方法概述

很多时候,货币对的报价范围都在阻力线和支撑线之内——这背后的事实就是GlebSlobodov的文章如何绘制这些线。因此,我们有两个层次来定义价格波动的范围。突破其中一个。也许给我们一个买卖信号。然而,所提出的理论有几个缺点:

  • 分析列数需要手动选择,此参数设置价格范围,从中可以获得阻力和支持级别。
  • 绘图级别的过程不是完全自动化的,因此消除了创建自动化交易系统的可能性。
  • 使用这种方法,我们得到的水平不允许我们分析趋势的方向和强度。

igor gerasko交易策略中使用的支持和阻力水平指标也定义了水平水平。

In this article, I will introduce you to the principle of drawing support and resistance lines, which can determine the direction of the trend, and form trend models and diagrams. 线条绘制基于最小和最大极值点。

求极值原理

在给定的时间内,确定最高和最低价格没有困难。选择正确的分析图表长度(时间间隔)非常重要,因为分析图表不断变化,因此无法手动设置。为了在货币表上找到这个区域,我将使用相对强度指数(RSI)指数,该指数包含在MetaTrader 5终端的一组标准指标中。

超买和超卖水平由RSI指标决定。此时此刻,我们的成对货币偏离了图表上的方向(趋势),导致价格回落。我们将在这些特殊的地方形成极端,在那里我们将寻找最低和最高的价格。

超售水平,我将使用相当于35的RSI指数值;超售水平-65(在同一位置两侧的中间RSI=50中有两个水平)。RSI指数的周期等于8。

值得注意的是,在一个强劲的趋势期间,例如,趋势增加,RSI反复越过上边界,但不触底。这将导致需要进行水平调整,但与趋势的方向不一致。

搜索极值点

图4。搜索极端柱区

在上图中,我指定了极端列的搜索区域:第一、第二、第三和第四,分别对应于数字1、2、3和4。在穿越下边界(rsi=35)之前,rsi索引从当前列开始,在超卖区域(rsi>=65)中三次,因此搜索第一个极值的时间间隔为三次。此外,搜索区域的顺序由三个连续列确定。

在区域1和3中,我将查找最高价格列,而在区域2和4中,我将查找最低价格。因此,我们将得到四个极端点——基于这种绘制光线的组合,我们将得到一个涨价通道。

图示.5. 上升通道

图5。上行通道

如果你曾经注意到,你可能已经注意到,只有几个支柱可以搜索到最低的价格,只有四个(每个区域两个)。由于上升趋势占主导地位,RSI指标很少触及最低水平,RSI=65水平之外的时间几乎与35<RSI<65频道内的时间相同。因此,我在本文中发布的用于查找点2和4的索引代码将使用移动到中间(接近50)的RSI级别。根据第一个极值(最小或最大)的类型,将设置RSI的高或低水平。

选择所有货币对、所有图表周期的RSI水平以及与其中一个周期的连续偏差进行测试。我认为这是我极端价值决定系统的一个缺陷。

ext_1,使用最低索引查找极值的函数(第一列)

我称之为ext_1的求极值柱面的函数有以下输入参数:

int Ext_1(double low,      //低位 RSI 级别, 超卖级别
          double high,     //高位 RSI 级别, 超买级别
          int bars,        //分析的柱线数量, 避免拷贝不必要的数据
                           //可能的设置 bars = 300
          int h_rsi,       // RSI 指标的句柄
          string symbol,   //图表品种
          float distans,   //距指标级别之一的偏离距离
                           //允许定义搜索第一个极值柱线边界
          ENUM_TIMEFRAMES period_trade) //图表周期


前两个函数的输入参数是RSI索引的输入参数。它们在性能计算中不起任何作用,只便于进行可视化评估(索引行的值与给定值相关)。我使用这些级别来确定我要搜索的最小和最大价格范围。参数“低”和“高”获得全局级指标代码中设置的外部变量值:

input double Low_RSI = 35.0; // 查找极值的低位 RSI 级别
input double High_RSI= 65.0; // 查找极值的高位 RSI 级别

输入参数“bars”设置将复制到包含最低和最高列元素数的数组中,如rsi索引值:

double m_rsi[],m_high[],m_low[];                              //数组初始化
int h_high = CopyHigh(symbol, period_trade, 0, bars, m_high); //以蜡烛的最高价填充数组
int h_low = CopyLow(symbol, period_trade, 0, bars, m_low);    //以蜡烛的最低价填充数组
if(CopyBuffer(h_rsi, 0, 0, bars, m_rsi)<bars)                 //以 RSI 数据填充数组
{
   Print("拷贝指标缓存区失败!");
}

数组m rsi[]、m_high[]和m_low[]具有反向索引顺序:

ArraySetAsSeries(m_rsi,true); 
ArraySetAsSeries(m_high,true); 
ArraySetAsSeries(m_low,true);

如我之前所说,RSI指标的范围在0到100之间,大多数情况下该值应该是50。在形成最小点时,RSI值应比中心(50)低得多,且大于形成最大点的时期。因此,在索引的第一个交叉点(最低或最高),其他值将接近中间。偏差的大小由输入参数“distans”确定,其值由外部变量给出:

input float Distans=13.0;    // RSI 级别的偏离

函数“ext_1”的输入参数“h_rsi”获得在初始化irsi()函数期间获得的rsi句柄值:

h_RSI=iRSI(Trade_Symbol,Period_Trade,Period_RSI,PRICE_CLOSE);  //返回 RSI 指标的句柄

变量交易符号和期间交易将在全局级别初始化,并包含有关货币对和相应图表周期的信息。可变周期包含在索引外部参数中指定的RSI索引的周期值:

input uchar Period_RSI =8;   // RSI 周期

一旦我们创建并填充了一个包含最高和最低价格的数组,也有对应于列行的RSI索引值,因此您可以真正搜索第一个极值过程。为了确定第一个极限值(支撑线或阻力线)的位置,并在正确的时间停止分析列,需要两个布尔类型变量:

bool ext_max = true;    //布尔型变量用于停止
bool ext_min = true;    //在正确的时间分析柱线

另外,numeric ext_max=true授权搜索最大极值、numeric ext_min=true和授权搜索最小极值。在一个级别(最小或最大)的第一个RSI指示器的交叉点处,其中一个布尔变量的值变为假,并且在RSI级别的交叉点处禁止进行列分析,这意味着已经分析了所需的列数,并找到了第一个极值。nbsp;

在对西安第一支柱的分析中,如果RSI指数的值超过其水平,似乎已经找到了由极值形成的价格区间,这是不完整的,这里没有可分析的点。应排除此类列分析。在下图中,我在没有分析的情况下突出显示了价格范围(注意相对较高水平的RSI指标的位置):

在不完整的价格范围禁止分析

图6。不完全价格范围内禁止分析

为此,需要创建另一个布尔变量:

bool flag=false;

为了确定分析列之间的最大和最小价格,需要创建以下额外的双精度类型变量:

double min = 100000.0;  //用于识别最大和最小价格的变量
double max = 0.0;       //...

搜索第一个极值的完整周期如下:

for(int i=0;i<bars;i++) //柱线循环
{
   double rsi = m_rsi[i];                                   //获取 RSI 指标值
   double price_max = NormalizeDouble(m_high[i], digits);   //最高价 prices
   double price_min = NormalizeDouble(m_low[i], digits);    //选择柱线的最低价
   if(flag==false) //避免在不完整趋势里搜索极值的条件
   {
      if(rsi<=low||rsi>=high) //如果第一根柱线在超卖或超卖区域,
         continue;            //则移至下一根柱线
      else flag = true;       //如果不是, 分析处理  
   }
   if(rsi<low) //如果发现 RSI 于级别交叉
   {
      if(ext_min==true) //如果 RSI 未与高位级别交叉
      {
        if(ext_max==true) //如果搜索最大极值被禁
        {
           ext_max=false;     //则禁止搜索最大极值
           if(distans>=0) high=high-distans; //改变高位级别, 之后
        }                                    //将执行第二根柱线的搜索
        if(price_min<min) //搜索和记忆第一根柱线索引
        {                 //比较最低蜡烛价格
           min=price_min;
           index_bar=i;
        }
      }
      else break; /*由于搜索最小极值已被禁止, 退出循环,
                    这意味着最大值已经找到*/
   }
   if(rsi>high) //进一步, 算法相同, 仅搜索最大极值
   {
      if(ext_max==true)
      {
        if(ext_min==true)
        {
           ext_min=false;
           if(distans>=0) low=low+distans;
        }
        if(price_max>max)
        {
           max=price_max;
           index_bar=i;
        }
      }
      else break; /*由于搜索最大极值已被禁止, 退出循环,
                    这意味着最小值已经找到*/
   }
}

通用函数ext_2查找所有后续极值

此函数将接收与ext_1函数相同的输入参数,以及其他三个重要参数:

  1. 参数包含对结构的引用,该结构表示将保存哪个列索引。它需要确定开始搜索极值的列。
  2. 找到了极值列的序列号(范围从2到4)。它需要从结构中选择所需的列引线,并确定将定位预期极限值的线(支撑或阻力)。
  3. Boolean类型参数确定下一行(支撑或阻力)的第一个极端圆柱体的位置。如果没有这些信息,就无法根据序列号确定要定位的行列。
int Ext_2(double low,    //低位 RSI 级别, 超卖级别
          double high,   //高位 RSI 级别, 超买级别
          int bars,      //分析的柱线数量, 避免拷贝不必要的数据到数组
          int h_rsi,     //RSI 指标的句柄
          string symbol, //表品种
          st_Bars &bars_ext,//包含已发现柱线号码的结构
          char n_bar,    //所需查找的柱线序数号码 (2,3 或 4)
          float distans, //距指标级别之一的偏离距离
          bool first_ext,//第一根柱线类型
          ENUM_TIMEFRAMES period_trade)//图表周期

在全球层面上,我们创建了一个包含所有四个极端圆柱引线的结构类型:

struct st_Bars //结构初始化
  {
   int               Bar_1;
   int               Bar_2;
   int               Bar_3;
   int               Bar_4;
  };

st_Bars Bars_Ext; //声明结构类型变量

为了确定索引行的预期极值在哪里,首先,必须创建第二个布尔类型变量:

bool high_level= false; //确定期望柱线类型的变量
bool low_level = false; //...

如果期望的极端列数等于2或4,并且第一条极端列线落在支撑线上,则预期的列线必须落在阻力线上。因此,有必要对RSI值高于或等于上层(高参数)的列行进行分析。如果期望极值列的序数等于3,并且第一个极值列位于支撑线上,则期望列也将位于该线上。如果第一个极端气缸位于电阻线上,则也将相应地选择所需气缸的位置。

if(n_bar!=3)
{
   if(first_ext==true)//如果第一点是最大值
   {
      low_level=true;//则这应是最小值
      if(distans>=0) low=low+distans; //若有必要, 取代 RSI 的低位级别
   }
   else //如果最小值
   {
      high_level = true;
      if(distans>=0) high=high-distans; //若有必要, 取代 RSI 的高位级别
   }
}
else
{
   if(first_ext==false)//如果第一点是最小值
   {
      low_level=true;//则这应是最小值
      if(distans>=0) high=high-distans; //若有必要, 取代 RSI 的高位级别
   }
   else //如果最大值
   {
      high_level = true;
      if(distans>=0) low=low+distans; //若有必要, 取代 RSI 的低位级别
   }
}

另一个布尔变量用于确定期望极值的发现时间和列分析的停止时间。

bool _start = false;    

当我们在历史数据中找到分析所需的列范围时,这个变量的值变为真。列分析终端,如果_start=true,当low_level=true时,rsi索引线穿过较高的级别,而当high_level=true时,rsi索引线穿过较低的级别。

if(_start==true && ((low_level==true && rsi>=high) || (high_level==true && rsi<=low)))
  break; //如果发现第二个极值, 且 RSI 穿越反向级别

最大气缸搜索周期如下:

for(int i=bar_1;i<bars;i++) //分析剩余柱线
{
   rsi=m_rsi[i];
   price_max = NormalizeDouble(m_high[i], digits);
   price_min = NormalizeDouble(m_low[i], digits);
   if(_start==true && ((low_level==true && rsi>=high) || (high_level==true && rsi<=low)))
   {
      break; //如果发现第二个极值, 且 RSI 穿越反向级别
   }
   if(low_level==true) //如果搜索最小极值
   {
      if(rsi<=low)
      {
         if(_start==false) _start=true;
         if(price_min<min)
         {
            min=price_min;
            index_bar=i;
         }
      }
   }
   else //如果搜索最大极值
   {
      if(rsi>=high)
      {
         if(_start==false) _start=true;
         if(price_max>=max)
         {
            max=price_max;
            index_bar=i;
         }
      }
   }
}

变量栏_1包含上一个极值列的索引,该列使用switch运算符计算:

switch(n_bar) //查找前一根柱线索引
{
   case 2: bar_1 = bars_ext.Bar_1; break;
   case 3: bar_1 = bars_ext.Bar_2; break;
   case 4: bar_1 = bars_ext.Bar_3; break;
}

为了找出第一个极值列所处的索引线(支持或阻力),就可以得到其索引和索引列的RSI索引值。

bool One_ext (st_Bars & bars_ext, // 结构类型变量用于获取第一根柱线的索引
             string symbol,     //图表品种
             int h_rsi,         //指标的句柄
             double low,        //设置 RSI 的超卖级别 (可以使用的高位级别)
             ENUM_TIMEFRAMES period_trade) //图表周期
  {
   double m_rsi[];               //指标数据数组初始化
   ArraySetAsSeries(m_rsi,true); //索引
   CopyBuffer(h_rsi,0,0,bars_ext.Bar_1+1,m_rsi); //用 RSI 数据填充数组
   double rsi=m_rsi[bars_ext.Bar_1]; //定义第一个极值柱线的 RSI 数值
   if(rsi<=low)                      //如果数值低于低位级别,
      return(false);                 //则第一个极值是最小值
   else                              //如果不是,
   return(true);                     //则是最大值
  }

处理结果

现在我们知道了所有四列第一索引及其对应的价格(最低或最高)。为了用每列匹配的指标值填充阵列,需要得到两个与电阻和支撑线相对应的方程。众所周知,用于此目的的线性方程是y=kx+b。在我们的例子中,“x”是列的前导,“y”是价格(支撑线-蜡烛的最低价格,阻力线-蜡烛的最高价格)。

为了求出“k”和“b”系数,在线方程中将两个已知的极值柱面值以及在平方系统中得到的组合表达式替换为相应的值。因此,我们在系统上得到以下表达式:

K=(price_2-price_1)/(_bar2-_bar1);  //查找系数 K
B=price_1-K*_bar1;                  //查找系数 B

在这里

double K,B;

“k”和“b”是全局变量,对应于线性方程中“k”和“b”系数的值。

int _bar1,_bar2;

这些列引线位于同一行。

double price_1,price_2;

这是每列的最低价格。如果需要定义“k”和“b”支撑线,或每列的最高价格,则需要确定“k”和“b”阻力线。

以下函数设置支撑线的“k”和“b”全局变量,如果参数“_line”为假,对于阻力线,如果参数“_line”为真:

void Level(bool _line,              //参数定义需要查找阻力和支撑线的哪根系数
           bool _first_ext,         //第一个极值的类型 (您已经熟悉了)
           st_Bars &bars_ext,       //包含柱线索引的结构
           string _symbol,          //品种
           ENUM_TIMEFRAMES _period) //图表周期
  {
   int bars=Bars_H;           //分析柱线的数量
   double m_high[],m_low[];         //数组初始化
   ArraySetAsSeries(m_high,true);   //数组从第一个元素开始索引
   ArraySetAsSeries(m_low,true);    //...
   int h_high = CopyHigh(_symbol, _period, 0, bars, m_high); //以蜡烛的最高价填充数组
   int h_low = CopyLow(_symbol, _period, 0, bars, m_low);    //以蜡烛的最低价填充数组
   double price_1,price_2;
   int _bar1,_bar2;
   int digits=(int)SymbolInfoInteger(_symbol,SYMBOL_DIGITS);//当前品种的小数点位数
   if(_line==true)                                          //如果所需是阻力线
     {
      if(_first_ext==true) //如果第一个极值是最大值
        {
         price_1 = NormalizeDouble(m_high[bars_ext.Bar_1], digits);
         price_2 = NormalizeDouble(m_high[bars_ext.Bar_3], digits);
         _bar1 = bars_ext.Bar_1;
         _bar2 = bars_ext.Bar_3;
        }
      else                                                  //如果是最小值
        {
         price_1 = NormalizeDouble(m_high[bars_ext.Bar_2], digits);
         price_2 = NormalizeDouble(m_high[bars_ext.Bar_4], digits);
         _bar1 = bars_ext.Bar_2;
         _bar2 = bars_ext.Bar_4;
        }
     }
   else                                                     //如果所需是支撑线
     {
      if(_first_ext==true) //如果第一个极值是最大值
        {
         price_1 = NormalizeDouble(m_low[bars_ext.Bar_2], digits);
         price_2 = NormalizeDouble(m_low[bars_ext.Bar_4], digits);
         _bar1 = bars_ext.Bar_2;
         _bar2 = bars_ext.Bar_4;
        }
      else                                                  //如果是最小值
        {
         price_1 = NormalizeDouble(m_low[bars_ext.Bar_1], digits);
         price_2 = NormalizeDouble(m_low[bars_ext.Bar_3], digits);
         _bar1 = bars_ext.Bar_1;
         _bar2 = bars_ext.Bar_3;
        }
     }
   K=(price_2-price_1)/(_bar2-_bar1);  //查找系数 K
   B=price_1-K*_bar1;                  //查找系数 B
  }

线性方程:y=kx+b,其中金融工具价格为“y”轴,该列指向“x”轴。如果我们使用自1970年1月1日以来经过的秒数作为“x”轴,那么折线图上的其余区域将显示“混乱”的结果,这就是为什么我使用列前导。

自从“oncalculate”函数以来,函数“level”被调用了两次:第一次是在填充电阻线阵列之前,第二次是在填充支撑线阵列时:

for(int i=0;i<Bars_H;i++)
{
   resistanceBuffer[i]=NormalizeDouble(K*i+B,Dig);
}
Level(false,First_Ext,Bars_Ext,Trade_Symbol,Period_Trade); //得到阻力线的系数 K 和 B
for(int i=0;i<Bars_H;i++)
{
   supportBuffer[i]=NormalizeDouble(K*i+B,Dig);
}

显示支持和阻力水平的指标示例

下图显示了使用上述所有功能的操作结果绘制的支撑线和阻力线:

指标操作结果

图7。指示器运行结果

在新的极限缸线形成后,用这种方法构造了指数。可以更改支撑线和阻力线的阵列值,并且可以自动重新绘制标高。但是,如果我们计算并记住图表上一条线与时间轴之间的角度,并将其与同一条线的新角度进行比较,我们就可以判断趋势的加速度和加速度,如本文所述。

指标的完整代码文件附在本文之后。

结论

当然,手工构建这些行很容易,因为您不需要为每个种类和周期选择索引参数。然而,这个指标可以作为自动化交易系统的基础或策略的一部分。在从索引线接收到一组数据后,您可以分析倾斜度、趋势方向,并识别这些线形成的图形。所有这些最终都允许它分析买入或卖出信号的强度,在价格渠道内进行交易,或者突破支持线和阻力线。

本文由MetaQuotes Software Corp.翻译自俄语原文
,网址为https://www.mql5.com/ru/articles/1742。

附加文件下载zip s ou rind.mq5(34.78 kb)

 

 


MyFxtop迈投(www.myfxtop.com)-靠谱的外汇跟单社区,免费跟随高手做交易!

 

免责声明:本文系转载自网络,如有侵犯,请联系我们立即删除,另:本文仅代表作者个人观点,与迈投财经(www.myfxtop.cn)无关。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。

著作权归作者所有。
商业转载请联系作者获得授权,非商业转载请注明出处。

風險提示

MyFxtops邁投所列信息僅供參考,不構成投資建議,也不代表任何形式的推薦或者誘導行為。MyFxtops邁投非外匯經紀商,不接觸妳的任何資金。 MYFXTOPS不保證客戶盈利,不承擔任何責任。從事外彙和差價合約等金融產品的槓桿交易具有高風險,損失有可能超過本金,請量力而行,入市前需充分了解潛在的風險。過去的交易成績並不代表以後的交易成績。依據各地區法律法規,MyFxtops邁投不向中國大陸、美國、加拿大、朝鮮居民提供服務。

邁投公眾號

聯繫我們

客服QQ:981617007
Email: service@myfxtop.com

MyFxtops 邁投