English Русский 中文 Español Deutsch Português 한국어 Français Italiano Türkçe
ZigZag インディケータ:新鮮なアプローチと新しいソリューション

ZigZag インディケータ:新鮮なアプローチと新しいソリューション

MetaTrader 5トレーディングシステム | 15 12月 2015, 07:28
4 164 0
Sergey Pavlov
Sergey Pavlov

はじめに

トレーダーならだれでも既定のまたは大きな振幅の価格変動の分析に使うZigZag インディケータをかならず知っています。ZigZag の線は破線でそのノードは価格チャートの最大および最小値にあります。

このインディケータには以下のように数多くのバリエーションがあります。12345678910111213141516。それでも多くのMQL5 プログラム開発者は自分自身の「理想の」 ZigZagを作成することに余念がありません。ZigZag インディケータの主な欠点は遅延、疑わしいノード(外部バー)の誤ったマーキング、満足のいかないパフォーマンスです。

私の意見では、もっとも洗練された ZigZag 実装は Yuri Kulikov (Yurich)によって提案されたものです。ほかにもひじょうにすぐれた MQL4 記事が何件かあります。 "Layman's Notes: ZigZag..." や "Show Must Go On, or Once Again about ZigZag"のようなものです。テーマは十分に研究され、ひじょうに多数の発行物が入手可能です。それについてはなにか引きつけられるものがまだあります。それには私も興味を引かれました。とくに高度な ZigZag インディケータを作成する可能性についてです。

本稿ではエンベロープ インディケータを用いて高度なZigZag を作成する方法についてお話します。連続したエンベロープに対する入力パラメータの特定の組合せを見つけることができ、そこでは ZigZag ノードはすべてエンベロープバンドの範囲 内にあると考えられます。

 

高度なZigZag を作成する方法

目標を設定します。2つのノードの座標を見つけること。2つのノードとは現在ノードと推定されるノードです(図1)。現在ノードはまだ完成されておらず座標が検索中または調整中のものです。その上それはつねに現在バー上(ゼロ)にあります。将来であれば推測されるノードが次のZigZag ノードの推定レベルを表示するはずです。

新しZigZag ノードの推測

図1 新しZigZag ノードの推測:現在ノードと次ノード

目標は設定されました。高度なインディケータを構築する基礎として移動平均エンベロープを使用する方法についての考えも得ました(図2)。ZigZag ノードからの偏差が最小であるエンベロープを検索します。ZigZag の頂点と谷 に対するエンベロープは個別に検索するというのはきわめて合理的であると思えます。

ZigZag インディケータと移動平均エンベロープ

図2 ZigZag インディケータと移動平均エンベロープ

推定の統計的有意性を高めるために、1つだけまたは10個のEnvelopesインディケータを使う代わりに異なるインプットデータを持つ100個以上のインディケータを使用する必要があります。それらはメインのインディケータラインの平均化期間と使用される価格(頂点に対する高値、谷に対する安値)が異なります。以下の表記と定型句を取り入れます。

  • ZZ -ZigZag インディケータ
  • ENV -Envelopes インディケータのメインライン(iMA インディケータと一致します)
  • Envelopes(i) -i 番目のバーにおけるエンベロープインディケータのメインライン値
  • ZZ(High) -ZigZag のピーク値
  • ZZ(Low) - ZigZag のtrough値
  • ENV(High) -ZigZag ピークに対応するEnvelopesインディケータのメインライン値
  • ENV(Low) ZigZag troughに対応するEnvelopesインディケータのメインライン値
  • n_high -ZigZag ピーク数
  • n_low -ZigZag troughs数

インディケータプールは2個あります。1つは頂点に対するもの、もう1つは谷 に対するものです(それぞれにインディケータは約100)。プールの各インディケータに対して Envelopes インディケータのメインラインからの ZigZag ノードの偏差を計算し、上記の式を用いて各プールインディケータに対する偏差の算術平均を求めます。下図はあるインディケータに対するメインラインENV から特定されるノードZZに関する偏差の略図を示しています。

ENVからの ZZ ノードの偏差略図

図3 ENVからの ZZ ノードの偏差図

偏差の算術平均はエンベロープバンドをプロットするためにEnvelopes インディケータのメインラインが移動されるべきレベルを決定するのに使用されます。Envelopes インディケータの上側の線を引くために ZigZag の頂点からの偏差の算術平均が必要で、上下側の線を引くために ZigZagの谷からの偏差の算術平均が必要なのです。

特徴的な点を見つけ、ZigZag ノードを推測するために利用するのがエンベロープの上下ラインなのです。ふたたび1組の Envelopes インディケータで構成されるプールに着目します。既定のエンベロープのメインラインから得られるZigZag ノードの偏差の算術平均は各インディケータに対して計算されます。チャート内プールの結果のライン(上下ライン)をプロットしたら、以下が表示されます。

平面上のEnvelopesライン

図4 平面上のEnvelopesライン

各ラインは個別の平面上にあるとすると、それらがすべて一緒に表面を作成するかたわら、上図だけが価格チャート平面上の各インディケータ予測を示すのです。これらラインの3D 画像はおおよそ以下のようなものです。

3Dでの Envelopes ライン

図5 3Dでの Envelopes ライン

ここで簡単に幾何学の学習を行います。Envelopes インディケータのラインのプールが 3D 表面であるとイメージします。価格チャートに対して平面を取り、現在(ゼロ)バーでその表面を切り取ります。

結果として曲線を表す表面の断面を取得します(上図は曲線が直線となる特殊ケースを表しています)。予測のためにはのちに計算に利用される曲線上の各点の座標を取得するので十分です。

次の断面特性が必要となります。最大および最小点、交点の重心(すべてのポイント値の算術的平均)。適切なデータは履歴に格納されているので取得した特徴点は現在(ゼロ)バーで予測されます。3個の特性ポイントは現および次 ZigZag ノードに対する基本としての役目を果たします。

Envelope バンドの検索が頂点と谷に対して個別に行われるため、結果断面を2個取得することとなります。1個はピーク、もう1個はボトムに対するものです。

予測値を得るにはもっとも近い特徴点を使用します。たとえば ZigZag 頂点を検索するときは切り取った平面を持つ Envelopes インディケータの上側ライン の表面の交点から得られる端面の特徴点を取ります。逆に を検索するときは切り取った平面を持つ Envelopes インディケータの 下側ラインの表面の交点から得られる断面の特徴点を取ります。

 

新インディケータの検証

これで方法は決定しました。それではインディケータを作成しましょう。まず ZigZag インディケータの最終ノードを見つけそれをチャートに描きます。このために取り組むタスクのために書くAdvancedZigZag クラスを使用します。

//+------------------------------------------------------------------+
//|                                               AdvancedZigZag.mqh |
//|                                           Copyright 2013, DC2008 |
//|                           https://www.mql5.com/ru/users/DC2008 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2013, DC2008"
#property link      "https://www.mql5.com/ru/users/DC2008"
#property version   "1.00"
//+------------------------------------------------------------------+
//|                                                 GetExtremums.mqh |
//+------------------------------------------------------------------+
#include <GetExtremums.mqh>   // author of the code Yurich
#property copyright "Copyright 2012, Yurich"
#property link      "https://www.mql5.com/ru/users/Yurich"
//+------------------------------------------------------------------+
//| ZigZag node structure                                            |
//+------------------------------------------------------------------+
struct MqlZigZag
  {
   double            price;   // Node coordinate
   datetime          t;       // Time
  };
//+------------------------------------------------------------------+
//| The AdvancedZigZag class                                         |
//+------------------------------------------------------------------+
class AdvancedZigZag
  {
private:
   MqlRates          rt[];
   dextremum         zz[];
   int               history;
   double            amplitude;
public:
   dextremum         zHL[];
   MqlZigZag         zzH[],zzL[];
   int               Count(const double range);
   int               Read(const int nodes);
                     AdvancedZigZag(const int bars);
                    ~AdvancedZigZag();
  };
//+------------------------------------------------------------------+
//| Class constructor                                                |
//+------------------------------------------------------------------+
AdvancedZigZag::AdvancedZigZag(const int bars)
  {
   history=bars;
   amplitude=0;
  }
//+------------------------------------------------------------------+
//| The Read method of the class                                     |
//+------------------------------------------------------------------+
int AdvancedZigZag::Read(const int nodes)
  {
   CopyRates(NULL,0,TimeCurrent(),history,rt);
   int cnt=GetExtremums(amplitude,rt,zHL,nodes);
   return(cnt);
  }
//+------------------------------------------------------------------+
//| The Count method of the class                                    |
//+------------------------------------------------------------------+
int AdvancedZigZag::Count(const double range)
  {
   amplitude=range;
   CopyRates(NULL,0,TimeCurrent(),history,rt);
   int cnt=GetExtremums(amplitude,rt,zz);
   ArrayResize(zzH,cnt);
   ArrayResize(zzL,cnt);
   int h=0;
   int l=0;
   for(int i=0; i<cnt; i++)
     {
      if(zz[i].type>0)
        {
         zzH[h]=(MqlZigZag)zz[i];
         h++;
        }
      else
        {
         zzL[l]=(MqlZigZag)zz[i];
         l++;
        }
     }
   ArrayResize(zzH,h);
   ArrayResize(zzL,l);
   return(cnt);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
AdvancedZigZag::~AdvancedZigZag()
  {
  }

メソッドは合計2つあります。

  • Count メソッドは与えられた期間中(バー番号) ZigZag ノードをすべて見つけ、それをさまざまな配列に頂点を谷から分けて保存します。このようにエンベロープの分析と計算は簡単になります。
  • Read メソッドは最終ノードを見つけそれを1個の配列に保存します。ZigZag インディケータを可視化するためにはこのメソッドが必要です。

GetExtremumsライブラリ(Yury Kulikovによる)もまたノード検索に必要となります。

Expert Advisorでインディケータも考慮に入れます。なぜインディケータではなく Expert Advisor なのでしょうか?もちろん好みの問題ですが、私はこの方が効率的だと思います。Expert Advisorのグラフィカルな特徴はもちろん弱いものですが、おなじシンボルインディケータが単独のストリームで処理するためパフォーマンスを高めます。各 EA はそれ自体の個別のストリームで処理を行います。それではコードを見ていきましょう。

//+------------------------------------------------------------------+
//|                                                   two_Comets.mq5 |
//|                                           Copyright 2013, DC2008 |
//|                           https://www.mql5.com/ru/users/DC2008 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2013, DC2008"
#property link      "https://www.mql5.com/ru/users/DC2008"
#property version   "1.00"
#include <AdvancedZigZag.mqh>
//--- Depth of history for the indicator calculation
input int      depth_stories=5000;  // Depth stories for calculating the indicator [bars]
//--- Minimum ZigZag amplitude value
input int      amplitude=100;        // The minimum value of the amplitude of the indicator [points]
//--- Declaring the class
AdvancedZigZag Azz(depth_stories);
//---
#define NUMBER_MA   227
#define START_MA    5
//--- macros
#define SIZE(i)                     (double)i*0.3<1?1:(int)(i*0.25)
#define ObjF1                       ObjectSetString(0,name,OBJPROP_FONT,"Wingdings")
#define ObjF2                       ObjectSetInteger(0,name,OBJPROP_ANCHOR,ANCHOR_CENTER)
#define ObjF3(T)                    ObjectSetInteger(0,name,OBJPROP_TIME,T)
#define ObjF4(P)                    ObjectSetDouble(0,name,OBJPROP_PRICE,P)
#define ObjF5(size)                 ObjectSetInteger(0,name,OBJPROP_FONTSIZE,size)
#define ObjF6(code)                 ObjectSetString(0,name,OBJPROP_TEXT,CharToString(code))
#define ObjF7(clr)                  ObjectSetInteger(0,name,OBJPROP_COLOR,clr)
#define ObjF8                       ObjectSetInteger(0,name,OBJPROP_COLOR,clrMagenta)
#define ObjF9                       ObjectSetInteger(0,name,OBJPROP_WIDTH,3)
#define ObjF10                      ObjectSetInteger(0,name,OBJPROP_BACK,true) 
#define ObjFont                     ObjF1;ObjF2;
#define ObjCoordinates(T,P)         ObjF3(T);ObjF4(P);
#define ObjProperty(size,code,clr)  ObjF5(size);ObjF6(code);ObjF7(clr);
#define ObjZZ                       ObjF8;ObjF9;ObjF10;
//---
double      MA[1],sumHi[NUMBER_MA],sumLo[NUMBER_MA];
int         handle_MA_H[NUMBER_MA],handle_MA_L[NUMBER_MA];
datetime    t[1];
int         H,L;
int         t_min,t_max;
int         err=-1;
double      sumH[2],maxH[2],minH[2];
double      sumL[2],maxL[2],minL[2];
string      name;
int         count;
int         shift;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   shift=PeriodSeconds()/30;
//--- calculation of ZigZag nodes using historical data
   Azz.Count(amplitude*Point());
   H=ArraySize(Azz.zzH);
   L=ArraySize(Azz.zzL);
   if(H<30 || L<30)
     {
      Print("Not enough data to calculate ZigZag nodes: "+
            "increase the depth of history; "+
            "or decrease the amplitude value.");
      return(-1);
     }
//---
   for(int i=0; i<NUMBER_MA; i++)
     {
      handle_MA_H[i]=iMA(NULL,0,i+START_MA,0,MODE_SMA,PRICE_HIGH);
      handle_MA_L[i]=iMA(NULL,0,i+START_MA,0,MODE_SMA,PRICE_LOW);
     }
//---
   return(0);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   ObjectsDeleteAll(0,-1,-1);
   for(int i=0; i<NUMBER_MA; i++)
     {
      IndicatorRelease(handle_MA_H[i]);
      IndicatorRelease(handle_MA_L[i]);
     }
//---
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+

void OnTick()
  {
//--- get the current bar's opening time value
   CopyTime(NULL,0,0,1,t);
//--- ZigZag: last 7 nodes
   count=Azz.Read(7);
   for(int i=1; i<count; i++)
     {
      name="ZZ"+(string)i;
      ObjectCreate(0,name,OBJ_TREND,0,0,0);
      ObjectSetInteger(0,name,OBJPROP_COLOR,clrRed);
      ObjectSetInteger(0,name,OBJPROP_WIDTH,10);
      ObjectSetInteger(0,name,OBJPROP_BACK,true);
      ObjectSetDouble(0,name,OBJPROP_PRICE,0,Azz.zHL[i-1].value);
      ObjectSetInteger(0,name,OBJPROP_TIME,0,Azz.zHL[i-1].time);
      ObjectSetDouble(0,name,OBJPROP_PRICE,1,Azz.zHL[i].value);
      ObjectSetInteger(0,name,OBJPROP_TIME,1,Azz.zHL[i].time);
     }
//--- check for integrity of preliminary calculations
   if(err<0)
     {
      //--- calculate the sums of deviations of the nodes from MA for ZigZag peaks
      ArrayInitialize(sumHi,0.0);
      for(int j=H-1; j>=0; j--)
        {
         for(int i=0; i<NUMBER_MA; i++)
           {
            err=CopyBuffer(handle_MA_H[i],0,Azz.zzH[j].t,1,MA);
            if(err<0) return;
            sumHi[i]+=Azz.zzH[j].price-MA[0];
           }
        }
      //--- calculate the sums of deviations of the nodes from MA for ZigZag troughs
      ArrayInitialize(sumLo,0.0);
      for(int j=L-1; j>=0; j--)
        {
         for(int i=0; i<NUMBER_MA; i++)
           {
            err=CopyBuffer(handle_MA_L[i],0,Azz.zzL[j].t,1,MA);
            if(err<0) return;
            sumLo[i]+=MA[0]-Azz.zzL[j].price;
           }
        }
     }
  }
//+------------------------------------------------------------------+

ここで明確にすることが数点あります。

  • iEnvelopes インディケータは iMA インディケータと置き換えられています。それは誤りでもなければ誤解でもありません。問題はiEnvelopes のメインラインが iMAと一致していることなのです。よって移動平均指数を利用する方が好都合です。
  • 移動平均のプールを2とおり使用しています。それぞれ 227 行で構成されており、そのため合計 454の iMA を作成しているのです。それは多いのでしょうか少ないのでしょうか?基本的にそれは大きな数字です。しかしまず必要であればインディケータ数を変更することができます。そして次に統計が必要です。10数個のノードに対してエンベロープを検索する趣旨は何なのでしょうか?最低100個は必要です。
  • インディケータ値 OnInit()の代わりにOnTick() ブロックでロードされます。データロードブロックが OnInit() にあれば、データの中にはロードされるのが遅いものがあり、結果としてインディケータは正確に完全に計算されなくなります。結局計算データが取得され err 変数値は静になりこのブロックは処理から除外されてしまいます。

結果のインディケータは最後の7個の ZigZag ノードをプロットし、既定の履歴についてその他ノードすべての座標を計算します(図6)。計算は一度だけ行われ、その計算データをのちに使用します。もちろんデータが定期的に更新されるように実装することもできますが、本稿では単一パスのままにしておきます。

ZigZag インディケータ(7ノード)

図6 ZigZag インディケータ(7ノード)

そして Envelopes インディケータの表面の断面をプロットします。このためには OnTick() メソッドに以下を追加します。

//--- PEAKS
   sumH[0]=0.0;
   maxH[0]=0.0;
   minH[0]=0.0;
   for(int i=0; i<NUMBER_MA; i++)
     {
      CopyBuffer(handle_MA_H[i],0,t[0],1,MA);
      double envelope=MA[0]+sumHi[i]/H;
      if(i==0 || envelope<minH[0])
        {
         minH[0]=envelope;
         t_min=SIZE(i);
        }
      if(envelope>maxH[0])
        {
         maxH[0]=envelope;
         t_max=SIZE(i);
        }
      sumH[0]+=envelope;
      name="H"+(string)i;
      ObjectCreate(0,name,OBJ_TEXT,0,0,0);
      ObjFont
      ObjCoordinates(t[0]-(NUMBER_MA-i*2)*shift,envelope)
      ObjProperty(SIZE(i),158,clrBlue)
     }
//--- TROUGHS
   sumL[0]=0.0;
   maxL[0]=0.0;
   minL[0]=0.0;
   for(int i=0; i<NUMBER_MA; i++)
     {
      CopyBuffer(handle_MA_L[i],0,t[0],1,MA);
      double envelope=MA[0]-sumLo[i]/L;
      if(i==0 || envelope<minL[0])
        {
         minL[0]=envelope;
         t_min=SIZE(i);
        }
      if(envelope>maxL[0])
        {
         maxL[0]=envelope;
         t_max=SIZE(i);
        }
      sumL[0]+=envelope;
      name="L"+(string)i;
      ObjectCreate(0,name,OBJ_TEXT,0,0,0);
      ObjFont
      ObjCoordinates(t[0]+(NUMBER_MA-i*2)*shift,envelope)
      ObjProperty(SIZE(i),158,clrGold)
     }
初心者プログラマーのための注意: 「頂点」と「谷」のブロック末尾にある演算子には文字列の最後に ';' がありません。これは誤りでもタイプミスでもありません。これらは macros(宣言されているデータセクションを確認してください)で、とても便利です。 みなさんのプログラムでお使いになることをお薦めします。

エンベロープラインで形成される表面の断面点を識別するには、ポイントはサイズを変えます。 Envelopesインディケータのメインラインの平均期間が大きいほど、ポイントは大きくなります(図7)。その上、断面は現(ゼロ)バーを異なる方向に横切る縦軸の周囲で回転します。頂点は右に90°、谷は左に90°です。

これでそれらは価格チャート平面に表示できます。最初それらは切り取った平面にありました(図5)。そして観測できませんでした。それらをわれわれに対して描画することができただけでその形についてなにも考えていませんでした。断面線はひじょうに特殊な形でることが判ります。これはグラフ分析に都合がよいようにされています。視覚的に断面は2つの彗星のようです。

Envelopes インディケータプールの断面

図7 Envelopes インディケータプールの断面

断面特性の計算に進みます。最大、最小、重心(算術的平均)です。結果の値は現在バー上の点として表示されます。適切な特性のサイズに対応するポイントサイズを伴います。またそれらをのちの分析のため履歴に保存します。そのため既存コードに以下を追加します。

//--- PEAKS

...

//--- midi
   string str=(string)t[0];
   name="Hmidi"+str;
   ObjectCreate(0,name,OBJ_TEXT,0,0,0);
   ObjFont
   ObjCoordinates(t[0],sumH[0]/NUMBER_MA)
   ObjProperty(10,119,clrBlue)
//--- max
   name="Hmax"+str;
   ObjectCreate(0,name,OBJ_TEXT,0,0,0);
   ObjFont
   ObjCoordinates(t[0],maxH[0])
   ObjProperty(t_max,158,clrBlue)
//--- min
   name="Hmin"+str;
   ObjectCreate(0,name,OBJ_TEXT,0,0,0);
   ObjFont
   ObjCoordinates(t[0],minH[0])
   ObjProperty(t_min,158,clrBlue)

...

//--- TROUGHS

...

//--- midi
   name="Lmidi"+str;
   ObjectCreate(0,name,OBJ_TEXT,0,0,0);
   ObjFont
   ObjCoordinates(t[0],sumL[0]/NUMBER_MA)
   ObjProperty(10,119,clrGold)
//--- max
   name="Lmax"+str;
   ObjectCreate(0,name,OBJ_TEXT,0,0,0);
   ObjFont
   ObjCoordinates(t[0],maxL[0])
   ObjProperty(t_max,158,clrGold)
//--- min
   name="Lmin"+str;
   ObjectCreate(0,name,OBJ_TEXT,0,0,0);
   ObjFont
   ObjCoordinates(t[0],minL[0])
   ObjProperty(t_min,158,clrGold)

それではグラフとして表現するとどのように見えるか確認します。

断面特性

図8 断面特性:それぞれ頂点と谷に対してプロットされた最大点、最小点、重心

高度な ZigZag ノードを見つけプロットすることで最期の仕上げを加える必要があります。下記を追加することでコードを強化します。

//--- ZigZag: advanced nodes
   if(Azz.zHL[0].type>0) // peak
     {
      ObjectDelete(0,"MIN");
      ObjectDelete(0,"MINfuture");
      name="MAX";
      ObjectCreate(0,name,OBJ_TREND,0,0,0);
      ObjZZ
      ObjectSetDouble(0,name,OBJPROP_PRICE,0,Azz.zHL[1].value);
      ObjectSetInteger(0,name,OBJPROP_TIME,0,Azz.zHL[1].time);
      ObjectSetInteger(0,name,OBJPROP_TIME,1,t[0]);
      double price=minH[0];
      ObjectSetDouble(0,name,OBJPROP_PRICE,1,price);
      if(Azz.zHL[0].value>minH[0])
        {
         price=sumH[0]/NUMBER_MA;
         ObjectSetDouble(0,name,OBJPROP_PRICE,1,price);
        }
      if(Azz.zHL[0].value>sumH[0]/NUMBER_MA)
        {
         price=maxH[0];
         ObjectSetDouble(0,name,OBJPROP_PRICE,1,price);
        }
      //--- into the future
      name="MAXfuture";
      ObjectCreate(0,name,OBJ_TREND,0,0,0);
      ObjZZ
      ObjectSetDouble(0,name,OBJPROP_PRICE,0,price);
      ObjectSetInteger(0,name,OBJPROP_TIME,0,t[0]);
      ObjectSetDouble(0,name,OBJPROP_PRICE,1,maxL[0]);
      ObjectSetInteger(0,name,OBJPROP_TIME,1,t[0]+NUMBER_MA*shift);
      if(price<maxL[0])
         ObjectSetDouble(0,name,OBJPROP_PRICE,1,sumL[0]/NUMBER_MA);
      if(price<sumL[0]/NUMBER_MA)
         ObjectSetDouble(0,name,OBJPROP_PRICE,1,minL[0]);
     }
   if(Azz.zHL[0].type<0) // trough
     {
      ObjectDelete(0,"MAX");
      ObjectDelete(0,"MAXfuture");
      name="MIN";
      ObjectCreate(0,name,OBJ_TREND,0,0,0);
      ObjZZ
      ObjectSetDouble(0,name,OBJPROP_PRICE,0,Azz.zHL[1].value);
      ObjectSetInteger(0,name,OBJPROP_TIME,0,Azz.zHL[1].time);
      ObjectSetInteger(0,name,OBJPROP_TIME,1,t[0]);
      double price=maxL[0];
      ObjectSetDouble(0,name,OBJPROP_PRICE,1,price);
      if(Azz.zHL[0].value<maxL[0])
        {
         price=sumL[0]/NUMBER_MA;
         ObjectSetDouble(0,name,OBJPROP_PRICE,1,price);
        }
      if(Azz.zHL[0].value<sumL[0]/NUMBER_MA)
        {
         price=minL[0];
         ObjectSetDouble(0,name,OBJPROP_PRICE,1,price);
        }
      //--- into the future
      name="MINfuture";
      ObjectCreate(0,name,OBJ_TREND,0,0,0);
      ObjZZ
      ObjectSetDouble(0,name,OBJPROP_PRICE,0,price);
      ObjectSetInteger(0,name,OBJPROP_TIME,0,t[0]);
      ObjectSetDouble(0,name,OBJPROP_PRICE,1,minH[0]);
      ObjectSetInteger(0,name,OBJPROP_TIME,1,t[0]+NUMBER_MA*shift);
      if(price>minH[0])
         ObjectSetDouble(0,name,OBJPROP_PRICE,1,sumH[0]/NUMBER_MA);
      if(price>sumH[0]/NUMBER_MA)
         ObjectSetDouble(0,name,OBJPROP_PRICE,1,maxH[0]);
     }

これで新規ノードのポジションを予測する新しい高度な ZigZag インディケータを入手しました(図9)。ノード自体は特徴断面点:最大点、最小点、重心にあります。このインディケータの実用的なタイトルは『2つの彗星』です。

将来のことになりますが、次ノードの完了時刻は判らないことに注意が必要です。基本的にノード1個の座標-価格が予測できるだけです。

予測された ZigZag ノード

図9 高度な ZigZag インディケータは現ノードと次ノードを予測します。i

 

結果分析と開発者への提言

インディケータの観測から以下を提示します。

  1. 予測されたノードからの ZigZag ノード座標の偏差は許容範囲内です。大量のノードは対応する断面の陰にあります。これは確かに定量的な評価です。より正確な結果は今後の記事に続きます。
  2. エンベロープラインの断面はマーケット動向と予想価格変動を示しています。最小平均期間(最小サイズ)を持つ点でできた彗星の尻尾に注意が必要です。それは価格方向で指示されています。彗星の尻尾はもっとも複雑な方法で曲がり、逆方向にまがる度合が大きいほど、トレンド変更の可能性が大きくなります。ただ異なる振幅を持つ異なるタイムフレームで変動を観察します。これはひじょうに興味深いものです。
  3. 価格変動に対するレジスタンスを強く表示する可能性のあるラインからの断面の特徴点です。よってそれらはサポートおよびレジスタンスラインとみなすことができます。
  4. 断面の重心がそれよりの先にくるとき(図9の頂点のように)、これは上昇トレンドが存在することを示しています。

結果入手したものはトレーディング戦略で試してみることのできるひじょうに興味深いインディケータです。

 

おわりに

  • 本稿で検討した ZigZag インディケータノードを予測する方法により新しいインディケータ『2つの彗星』を作成することができました。
  • 高度な ZigZag は、予測にすぎないとしても、新しいノードの可能性ある座標を表示します。
  • 本稿で考察したアルゴリズムは ZigZag インディケータに限らず、たとえばフラクタルインディケータやセマフォインディケータのような、類似の高度なインディケータをプロットするのに利用可能です。
  • 初心者の MQL5プログラマーの方はそれらがプログラムの中で繰り返されるコードの量を減らすためにどのようにマクロを策絵師するか確認するのがおもしろいと思われるかもしれません。

MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/646

添付されたファイル |
advancedzigzag.mqh (3.54 KB)
getextremums.mqh (5.24 KB)
two_comets.mq5 (10.16 KB)
トレードシグナルを購読選択する場合のチップステップバイステップガイド トレードシグナルを購読選択する場合のチップステップバイステップガイド
このガイドは、シグナルサービス・トレードシグナルのテスト・要求されたシグナルを調べるアプローチシステムのためのものであり、潜在性・リスク・トレード意図・様々な口座タイプや金融ツールで稼働するという基準を満たします。
エキスパートアドバイザーの注文と希望の結果の取得方法 エキスパートアドバイザーの注文と希望の結果の取得方法
どのように正しく必要条件の明記を記載するのでしょうか?エキスパートアドバイザーやインジケーターを注文する際にプログラマーに期待すべき点と、期待すべきではない点は何でしょうか?やりとりを記録するにはどうすべきで、何に対して特に注意すべきでしょうか?この記事は、これらの質問や、その他多くの人にとって明白ではない様々な質問に対する答えを提供します。
われわれはいかにして MetaTrader シグナルサービスとソーシャルトレーディングを発展させたのでしょうか われわれはいかにして MetaTrader シグナルサービスとソーシャルトレーディングを発展させたのでしょうか
われわれはシグナルサービスを強化し、メカニズムを改良し、新しい関数を追加し、欠陥を修正し続けています。2012年の MetaTrader シグナルサービスと現在の MetaTrader シグナルサービスはまったく異なる2つのサービスのようなものです。現在、特定バージョンの MetaTrader クライアントターミナルをサポートするサーバーのネットワークで構成される仮想ホスティングクラウドサービスを導入中です。
「チュヴァショーフのフォーク」という取引システム 「チュヴァショーフのフォーク」という取引システム
この記事では、スタニスラブ・チュヴァショーフで作成された取引システムの特徴とソースコードについて説明しています。この相場の状態を分析する方法がトーマス・デマークで作成された「一番近い時間帯のためのトレンドラインを作成するために基準点としてフラクタルを使う」方法に似ています。