自动构造支撑和阻力线

27 二月 2018, 09:13
Vladimir Mametov
0
16 473

概述

在本文中, 我们将研究构造支撑和阻力线。货币品种的技术分析是在金融市场内进行交易的重要组成部分。自动构造这些线将简化金融分析师和交易员的工作, 并加速技术分析。此外, 此处描述的指标可用于开发智能交易系统。

搜索所有波峰和波底

利用价格图表的局部波峰和波底绘制支撑和阻力线。为了判别这些极点值, 我们将应用众所周知的之字折线 (ZigZag) 指标。我们可以在其输入中设置支撑和阻力线的必要属性。

这些线的比例可以使用之字折线指标的参数进行更改, 且您可以在不同的时间帧应用相同的参数。这令我们能够获得构筑支撑和阻力位所需的极点值。

下面的图片显示极点值随时间帧的变化而改变。第一张图像显示包含 30 分钟周期的图表. 第二张图像显示的是四个小时。




选择合适的极点值来构造价位

我们仅构造位于当前价格附近的支撑/阻力线, 意即它们在技术分析期限内与我们的当前状况相关。此外, 为了令这些线的斜率与价格贴合, 我们在下降趋势 (对于阻力线) 期间选取的极点值高于或等于前一个极点值, 或在上升趋势中选取与前一个相同或较低的极点值。在第一幅图像中, 这些可能是 1-2-3-4-5-7, 而在第二幅中 — 1-2-3-6-7-8。

现在我们已定义了极点值的选择标准, 我们来研究如何在代码中实现它们。为了澄清要点, 我们在此仅显示其中一部分。

//+------------------------------------------------------------------+
struct trade_points               // 定义极点值的结构
  {
   double            price;       // 价格
   int               pos;         // 位置, 柱线的索引
   bool              hpoint;      // 为真, 则是波峰 
   bool              lpoint;      // 为真, 则是波底
  };

在 OnInit() 函数中创建之字折线指标的句柄:

int OnInit()
  {

   ZZ_handle=iCustom(_Symbol,_Period,"ZigZag",ExtDepth,ExtDeviation,ExtBackstep);

   return(INIT_SUCCEEDED);
  }

进而, 我们通过对所有之字折线指标极点值逐个进行排序, 将数据输入矩阵:

double max=close[1];
   double min=close[1];
   int z=0;

   for(shift=0;shift<rates_total && !IsStopped();shift++)
     {
      CopyBuffer(ZZ_handle,0,shift,1,ZigzagBuffer);

      if(ZigzagBuffer[0]>0)
        {

         if(ZigzagBuffer[0]>=max && ZigzagBuffer[0]==high[shift])
           {
            ArrayResize(mass,z+1);
            max=ZigzagBuffer[0];
            mass[z].price=ZigzagBuffer[0];
            mass[z].pos=shift;
            mass[z].hpoint=true;
            mass[z].lpoint=false;
            z++;
           }

         if(ZigzagBuffer[0]<=min && ZigzagBuffer[0]==low[shift])
           {
            ArrayResize(mass,z+1);
            min=ZigzagBuffer[0];
            mass[z].price=ZigzagBuffer[0];
            mass[z].pos=shift;
            mass[z].lpoint=true;
            mass[z].hpoint=false;
            z++;
           }

        }
     }

定义构造趋势线的标准

现在, 在形成具有极点值的数组后, 我们可以构造必要的支撑/阻力线。下面的图像解释了构造这些线的主要标准。

从第一点开始, 我们可以通过以下任何一点来构造趋势线。但并非所有这些趋势线都可以被视为支撑/阻力线。此外, 它们可能随着时间的推移失去其相关性, 从而变得无以致用。由于我们希望清理图表上不必要的图形对象, 我们执行排序来舍弃多余趋势线。

我们假设该趋势线的起点是 A, 第二个极点值是 B, 最后一根柱线附近的点是 C。

可能会有多个标准, 且它们的组合在不同情况下会不断变化。我们只研究最基本的。将来, 所有人都可以根据自己的判断来改进这一指标。以下是主要标准:

  1. АB/BС 距离比率
  2. 价格穿越 AB 段的次数
  3. 价格穿越 BC 段的次数
  4. 从 С 到当前价格的距离
  5. 趋势线的最小和最大长度
  6. 趋势线的斜率
  7. 价格位于阻力线之上或之下

我们来更详尽地研究上述标准, 以更好地理解输入配置。

  1. 为了保持可接受的比例, 您可以使用菲波纳奇比率并将最小允许比率设置为 0.25 或 0.382。根据这一标准, 长度比率应对应于条件 АB/АС>=02.25 (0.382) 且 BС/АС>=02.25 (0.382)。出于便利起见, 可以在输入中设置该参数的值。
  2. 所有存在的趋势线也应按照价格穿过 AB 线的次数进行彻底排序。如何进行这种验证也有很多选项。我们可以只参考收盘价突破这条线的柱线, 或者我们可以参考最高/最低价突破的柱线。第二个标准要验证的是穿过这条线段的柱线数。这些参数也作为输入。
  3. 我们可以通过突破次数, 其性质和相对于 BC 段的当前价格位置来评估这条线的重要性。当开发 EA 时, 上述所有标准均可用于形成趋势线以及交易策略。在此指标中, 我们只会显示尚未穿越此段的趋势线。
  4. 根据趋势线当前的相关性, 可以过滤从当前价格到首条趋势线的距离。例如, 我们可能只绘制其距离不超过 50-100 点的趋势线。
  5. 在我们的案例中, 趋势线的最小长度由之字折线指标的输入决定, 但是如果需要也可以监控该参数。指标将检查 AB 和 BC 段的最小长度。
  6. 由于支撑线更为重要, 因为它们用于开仓, 因此该指标所构造的上升趋势斜率为零或正数, 下跌趋势线斜率为零或负数。
  7. 我们可以用两种方式使用这些趋势线。第一个是只参考不折返的趋势线并顺势交易。第二个是只在反向突破趋势线时开单。两种类型的趋势线都很重要, 因此两者都要反映在指标中。

以下是形成下跌趋势阻力线的一部分代码。

// 判断这些趋势线是否符合我们的标准并填写下跌趋势矩阵。

   for(j=z-1; j>=0; j--)
     {
      if(mass[j].hpoint)
         for(i=j-1; i>=0; i--)
           {
            if(mass[i].hpoint)
               if(i<j)
                 {

                  a=mass[j].pos;
                  b=mass[i].pos;

                  double ratio=double((a-b)*100/a);       // 定义 AB 段与 AC 总长度的比率

                  if(ratio>fibo && ratio<(100-fibo))      // 定义是否符合标准 1, АB/BС 段的比例
                     if(b>Min_dist &&(a-b)>Min_dist)      // 定义是否满足标准 5, АB 和 BС 段的最小长度
                       {

                        ax=mass[j].price;
                        bx=mass[i].price;

                        coef=(ax-bx)/(a-b);

                        price=close[1];

                        deviation=(ax+coef*bx)-price;

                        cross_bc=0;
                        cross_ab=0;


                        if(MathAbs(deviation)<tolerance*_Point)   // 定义是否满足条件4 (点 С 到前一根柱线收盘价的距离)
                          {

                           // 从 a 点到 b 点的交叉次数 
                           for(int n=a; n>b; n--)
                              if((close[n]-(ax+coef*(b-n)))>0)
                                 cross_ab++;
                           // 从 b 点到端点的交叉次数  
                           for(int n=b-1; n>=0; n--)
                              if(close[n]>(bx+coef*(b-n)) && close[n+1]<(bx+coef*(b-n+1)))
                                 cross_bc++;

                           if(cross_bc<=Intersection_bc && cross_bc<=Intersection_ab)// 定义是否满足条件 2 和 3
                             {
                              // 填写下降趋势矩阵
                              ArrayResize(DownTrend,y+1);
                              DownTrend[y].a=a;
                              DownTrend[y].b=b;
                              DownTrend[y].ax=ax;
                              DownTrend[y].bx=bx;
                              DownTrend[y].dst=MathAbs(deviation);
                              DownTrend[y].coef=coef;

                              y++;

                             }
                          }
                       }
                 }
           }
     }

// 使用获得的矩阵显示图表上的下跌趋势线

   for(j=0; j<ArraySize(DownTrend); j++)
     {

      a=DownTrend[j].a;
      b=DownTrend[j].b;
      ax=DownTrend[j].ax;
      bx=DownTrend[j].bx;
      coef=DownTrend[j].coef;

      if(a>0 && b>0 && MathAbs(a-b)>0)
        {
if(a>0 && b>0 && MathAbs(a-b)>0)
        {
         //--- 创建趋势线 
         TrendCreate(0,"DownTrend "+string(j),0,time[a],ax,time[b],bx,DColor,DStyle,DWidth,DBack,DSelection,DRayLeft,DRayRight,DHidden,DZOrder);
         ChartRedraw();
        }
     }

指标结构的示例:


在交易中使用支撑/阻力线

应用支撑/阻力位的主要交易原则是在上升趋势期间(并在下跌趋势期间卖出)或平坦时段在支撑线附近买入。一些图形模型 (形态) 也会用到。

这种交易策略令您能够从趋势变化中受益, 即使金融产品处于横盘状态, 或价格形成一种形态。趋势有助于确定交易方向。例如, 如果当前的趋势是向下, 但随后走向横盘, 那么最好在阻力线附近卖出, 而非在支撑位买入。出现下跌趋势意味着卖出交易比买入成功机会更大。如果趋势向上且后面呈三角形, 那么最好在这个三角形的支撑线附近买入。

在接近支撑/阻力位时顺势交易可能会带来利润, 但价格往往会突破这些价位。所以, 我们需要等待确认此金融产品在该特定价位的重要性。在依据趋势线买入或卖出之前, 您需要等待, 直至价格稳定在其附近。或者, 您可以等待价格从该价位反弹, 并在此后开始交易。

当自支撑线进行买入交易时, 在价格突破整理区域的高点之后, 等待价格在其附近稳定后再买入是合理的。这可确保该价位能够真实影响价格, 且价格开始自该价位向必要方向 (向上) 移动。这正是我们进行买入交易所需要的。自阻力线进行卖出交易时也会发生类似的情况: 您需要等待阻力区附近的盘整, 并在价格跌破该区域的低点时开仓。

在开始交易时, 一定要预测它的平仓条件。当从支撑线进行买入交易时, 建议在价格达到强阻力线之前将之平仓。当进行卖出交易时也会发生类似的情况。您也可以在次要支撑/阻力位平仓。当自支撑线买入时, 您需要在上升趋势通道的阻力位卖出。如果价格突破该价位, 您也可以尝试获得更大的利润。例如, 从三角形支撑位 (通常上涨趋势) 买入时, 您可以持仓等待, 直到价格突破三角形并继续向上移动。之后, 您可以在下一条阻力线上离场。

基于指标的 EA

以下是拥有以下功能的 EA:

  • 止损和止盈
  • 最大买入/卖出订单数量
  • 尾随停止
  • 盈亏平衡
  • 通过指标信号将反向交易平仓
  • 四种高时帧滤波器 (MACD, RSI, WPR, MA) 可供选择

EA 直接与指标生成的趋势线配合工作。因此, 它需要在同一个图表上启动指标才能实时工作。指标设定已在指标本身中配置。EA 也有指标设置, 但它们仅用于测试目的。为了测试 EA, 初始化 EA 时定义的指标句柄已经在代码中创建。

有三种 EA 操作模式:

  • from level — 在趋势线的潜在价格回滚方向上进行交易。如果柱线的高位或低位与该价位交叉, 而收盘价未突破当前趋势线, 且下一根柱线收盘时也未能破位, 则开单交易。EA 检查价格接触后是否突破该趋势线。
  • level breakdown — 在趋势线的潜在突破方向上交易。如果柱线的高位或低位突破该价位, 而收盘价并未突破当前趋势线, 且下一根蜡烛的收盘价突破该趋势线, 则开单交易。
  • all — 使用上述两种模式。

以下代码是信号形成时买入和卖出的函数:

//+------------------------------------------------------------------+
int signal()
  {
   int res=0;

   int macd=0;
   int rsi=0;
   int wpr=0;
   int ma=0;

   if(Use_macd==true)macd=macdS();
   if(Use_rsi==true)rsi=rsiS();
   if(Use_wpr==true)wpr=wprS();
   if(Use_ma==true)ma=maS();

   CopyOpen(NULL,0,1,3,O);
   CopyHigh(NULL,0,1,3,H);
   CopyLow(NULL,0,1,3,L);
   CopyClose(NULL,0,1,3,C);

   Signals=0;
   for(int i=0;i<ObjectsTotal(0,0,OBJ_TREND);i++)
     {
      string sName=ObjectName(0,i,0,OBJ_TREND);
      if(StringFind(sName,"UpTrend")==0 || StringFind(sName,"DownTrend")==0)
        {
         ax=ObjectGetDouble(0,sName,OBJPROP_PRICE,0);
         bx=ObjectGetDouble(0,sName,OBJPROP_PRICE,1);
         p1=(int)ObjectGetInteger(0,sName,OBJPROP_TIME,0);
         p2=(int)ObjectGetInteger(0,sName,OBJPROP_TIME,1);
         a=iBarShift(p1);
         b=iBarShift(p2);
         kkk=(bx-ax)/(a-b);
         lvl=bx+kkk*b;
         plvl=bx+kkk*(b-1);

         if(mode==0 || mode==2)
           {
            if(StringFind(sName,"UpTrend")==0 && L[1]<=plvl && C[1]>plvl && C[0]>lvl)Signals=1;
            if(StringFind(sName,"DownTrend")==0 && H[1]>=plvl && C[1]<plvl && C[0]<lvl)Signals=2;
           }

         if(mode==1 || mode==2)
           {
            if(StringFind(sName,"UpTrend")==0 && L[1]<=plvl && C[1]>plvl && C[0]<lvl)Signals=2;
            if(StringFind(sName,"DownTrend")==0 && H[1]>=plvl && C[1]<plvl && C[0]>lvl)Signals=1;
           }
        }
     }

   if(Signals==1
      &&(macd==1 || Use_macd==false)
      && (rsi==1 || Use_rsi==false)
      && (wpr==1 || Use_wpr==false)
      && (ma==1 || Use_ma==false))res=1;

   if(Signals==2
      &&(macd==2 || Use_macd==false)
      && (rsi==2 || Use_rsi==false)
      && (wpr==2 || Use_wpr==false)
      && (ma==2 || Use_ma==false))res=2;

   return(res);
  }
//+------------------------------------------------------------------+

测试表明, 与突破交易相比, 回滚交易的盈利能力较低。

使用以下输入参数测试三种模式的测试图如下所示:

input string s="-------------------------------------------"; // 主设置
input int Magic=12345;
input double LotSize=0.1;
input int Slippage=30; //滑点, 点数 
input int StopLoss=0; //止损, 点数 
input int TakeProfit=0; //止盈, 点数
input int TrailingStart=0; //为谁开始, 点数     
input int TrailingStop= 0; //尾随停止, 点数     
input int TrailingStep= 0; //尾随步长, 点数
input int SL_prof=0; //开始 BE, 点数
input int SL_lev=0; //BE 价位, 点数
input int Buy_max=1; //最大买单数量
input int Sell_max=1; //最大卖单数量
input bool Sig_close=true; //逆势交易平仓
input tip mode=0;
input string s0="-------------------------------------------"; // 指标设置
input int _ExtDepth=12;
input int _ExtDeviation=5;
input int _ExtBackstep=3;

input int _Min_dist=0;                                  // 最小距离
input int _fibo=30;                                     // 菲波纳奇比率
input int _tolerance=200;                               // 冗余
input int _Intersection_ab=1;                           // 从 a 点到 b 点允许的交汇点数量
input int _Intersection_bc=1;                           // 从 b 点到 c 点允许的交汇点数量

input string s1="-------------------------------------------";     // MACD 设置
input ENUM_TIMEFRAMES macd_tf=PERIOD_CURRENT;                      // 周期
input int fast_ema_period=12;                                      // 快速均线周期 
input int slow_ema_period=26;                                      // 慢速均线周期 
input int signal_period=9;                                         // 差值的均化周期 
input ENUM_APPLIED_PRICE applied_price=PRICE_CLOSE;                // 价格类型 

input string s2="-------------------------------------------";     // RSI 设置
input ENUM_TIMEFRAMES rsi_tf=PERIOD_CURRENT;                       // 周期
input int rsi_period=14;                                           // 周期 
input ENUM_APPLIED_PRICE rsi_applied_price=PRICE_CLOSE;            // 价格类型
input double rsi_max_s=100;                                        // 卖出的最大价格
input double rsi_min_s=70;                                         // 卖出的最小价格
input double rsi_max_b=30;                                         // 买入的最大价格
input double rsi_min_b=0;                                          // 买入的最小价格

input string s3="-------------------------------------------";     // WPR 设置
input ENUM_TIMEFRAMES wpr_tf=PERIOD_CURRENT;                       // 周期
input int calc_period=14;                                          // 周期  
input double wpr_max_s=0;                                          // 卖出的最大价格
input double wpr_min_s=-20;                                        // 卖出的最小价格
input double wpr_max_b=-80;                                        // 买入的最大价格
input double wpr_min_b=-100;                                       // 买入的最小价格

input string s4="-------------------------------------------";     // MA 设置
input ENUM_TIMEFRAMES ma_tf=PERIOD_CURRENT;                        // 周期
input int ma_period=10;                                            // MA 周期
input int ma_shift=0;                                              // 平移 
input ENUM_MA_METHOD ma_method=MODE_SMA;                           // 平滑类型
input ENUM_APPLIED_PRICE ma_applied_price=PRICE_CLOSE;             // 价格类型 

input bool Use_macd=true;                                          // 使用 MACD 作为滤波器
input bool Use_rsi=false;                                          // 使用 RSI 作为滤波器
input bool Use_wpr=false;                                          // 使用 WPR 作为滤波器
input bool Use_ma=false;                                           // 使用 MA 作为滤波器

input int sbar=1;                                                  // 信号柱线 0-当前, 1-已收盘

在测试过程中, 在其中一个方向上只会开一笔 0.1 手的交易。如果信号相反, 当前交易被平仓, 之后反向开单。应用 MACD 作为过滤器, 意味着在指标值小于零时进行买入交易, 而指标值在大于零时进行卖出交易。测试针对 2015-2017 年 EURUSD H1 进行。

自价位:


价位突破:


以下是几种货币对按照默认设置的测试结果。

在中我们可以看到, 只有 EURUSD 和 USDCHF 才显示出良好结果。首先, 事实上这是由于交易时不应参考所有的趋势线。我们还需要参考文章开头列出的其它因素。

另外, 我们应记住基本面分析的影响力, 因为支撑/阻力线在重要新闻发布后经常会被突破。

因此, 可以在 EA 中添加新闻过滤器, 并且测试仅在新闻发布时操作, 以及在新闻期间完全禁止交易两种情况。替代方案, EA 可以在 RENKO 图表上使用。 

优化

在我看来, 前七个参数已经具有最佳值, 因此我没有进一步优化它们。之字折线参数按默认值设置, 但有点不合适。优化时, 可以确定所有先前测试的货币的最适合的参数值如下:

  • _ExtDepth=24;
  • _ExtDeviation=55;
  • _ExtBackstep=9;

为了在优化过程中开单交易, 我们为金融产品定义了最适合的操作模式, 以及过滤器对结果的影响有多强。只有 MACD 指标被用作过滤器。但您可在不同的时间帧内尝试其它指标。

由反向信号平仓的函数被用于盈利或亏损交易的平仓。为了锁定利润并获得最大的结果, 使用了盈亏平衡和止盈功能。在测试这些功能期间确定了每种货币的最佳参数。

未使用止损。亏损交易仅由相反的信号平仓。

优化结果显示在表格中。该测试在 2017 年以 0.1 手执行。此外, 买入和卖出交易的开单数量增加到了 10, 所有其它参数都是默认设置的。

 品种 模式
  MACD 过滤器 止盈
开始 BE
盈利
 盈利因子: 恢复因子:
 最大回撤,%
 总交易: 盈利交易,% 
EURUSD
价位突破
false
0
25
117.20
1.88
1.65
0.69
79
73.42
USDCHF
价位突破 false 20
10
135.24
1.31
1.12
1.03
482
72.41
GBPCHF
自价位
true
20
10
91.56
1.39
0.51
1.58
246
91.06
AUDUSD
价位突破 false 20
10
139.20
1.39
1.66
0.79
485
71.96
AUDCAD
价位突破 true 25
5
117.51
1.94
1.06
0.57
246
84.96
EURJPY
价位突破 false 20
5
128.90
1.60
0.98
1.26
341
78.89
GBPUSD
自价位 false 100
0
102.1
1.20
1.32
0.58
274
52.92
USDJPY
自价位 false 30
0
147.75
1.56
0.79
1.73
348
79.89
EURGBP
自价位 true 20
5
124.45
1.39
1.14
1.03
341
78.01
EURCHF
自价位 true 20
5
141.08
2.07
1.88
0.68
367
63.22
USDCAD
价位突破 false
100
25
142.57
1.46
0.45
1.22
248
78.87
NZDUSD
自价位 false 0
25
270.50
1.37
1.04
2.37
616
62.11
GBPJPY
价位突破 true 150
20
163.62
2.56
1.10
1.41
103
68.25

结束语

在本文中, 我们研究了自动构造支撑和阻力线的基本原理。利用该原理开发了一款 EA, 并用其优化了 13 个金融产品的输入参数。若要获得特定金融产品的最大结果, 您需要单独选择其最佳参数。含有许多基本功能和四个高时帧过滤器的 EA 已经开发出来, 以便找到最佳参数, 实现自动检查支撑/阻力线并据此交易。指标和 EA 可以根据具体需求进行扩展和改进。

已发现, 相比突破交易, 某些货币在进行回滚交易时的盈利能力较差。这表明每个金融产品都以独特的方式运行, 需要采取单独的方法。


本文译自 MetaQuotes Software Corp. 撰写的俄文原文
原文地址: https://www.mql5.com/ru/articles/3215

附加的文件 |
TrendlinesEA.mq5 (46.6 KB)
Trendlines.mq5 (30.78 KB)
测试交易货币对篮子时出现的形态。第三部分 测试交易货币对篮子时出现的形态。第三部分

在本文中, 我们将完成测试交易货币对篮子时可能检测到的形态。在此, 我们会跟踪货币对中每支货币彼此相对的走势形态, 并展示其测试结果。

如何降低交易者的风险 如何降低交易者的风险

在金融市场上进行交易是与各种风险相关的,这些风险在交易系统的算法中都应当被考虑到。降低这样的风险是在交易中获利的最重要的任务。

基于快速数学计算的自定义策略测试器 基于快速数学计算的自定义策略测试器

本文将介绍创建自定义策略测试器和自定义优化通关分析器的方法。阅读之后, 您将了解数学计算模式, 和所谓分帧机制如何工作, 如何准备和加载用于计算的自定义数据, 以及如何使用有效的算法将它们压缩。对于那些打算在智能系统中存储自定义信息感兴趣的人来说, 这篇文章会很有趣。

交易员生存技巧: 由指标制作的快餐 交易员生存技巧: 由指标制作的快餐

如果您刚刚切换到 MQL5, 那么本文将会很有用处。首先, 以正常的 MQL4 风格访问指标数据和序列已经完成。其次, 以 MQL5 实现这些整体上更简单。所有函数都尽可能地清晰, 并且非常适合单步调试。