English Русский 中文 Español Deutsch Português
初心者向け MQL4 言語カスタムインディケータ(パート 2)

初心者向け MQL4 言語カスタムインディケータ(パート 2)

MetaTrader 4 | 15 3月 2016, 15:19
7 106 0
Antoniuk Oleg
Antoniuk Oleg

-はじめに

本稿は『初心者向け MQL4 言語』シリーズの第5弾です。今日はグラフィカルオブジェクトの使用について学習します。それはインディケータを使用する機能を実質的に広げる強力な作成ツールです。また、スクリプトや Expert Advisor でも利用可能です。それからオブジェクトの作成、そのパラメータ変更、エラーチェックについても学習します。もちろん、すべてのオブジェクトの詳細を説明することはできません。ひじょうに数が多いのです。ですが、ご自身で学習できるように必要な知識は得られることでしょう。本稿には複雑なシグナルインディケータの作成の段階的なガイド例を盛り込んでいます。それを基に、複数インディケータに対して全期間におけるトレードシグナルを表示するシグナルインディケータを作成することができます。そこでは多くのパラメータは調整可能で、それによりインディケータの表示変更が簡単になります。




グラフィカルオブジェクトについて

MetaTrader 4 ターミナルで作業をするとき、頻繁に扱うものです。グラフィカルオブジェクトはさまざまな目的で利用することができます。トレーダーはサポートおよびレジスタンスレベル、ピボットポイント、フィボナッチレベルなどを設定します。オブジェクト使用の簡単な例を見ていきます。

このチャートには4つのグラフィカルオブジェクトがアタッチされています。

  • 2 本の横線
  • テキストオブジェクト
  • オブジェクトシンボル(矢印)

今日はMQL4 を用いてそのようなオブジェクトをアタッチする方法を学習します。オブジェクトを使うことでマニュアル操作がいくつ自動化されるかちょっと想像してください。たとえば、これまでピボットポイントやサポートおよびレジスタンスレベルを計算して、マニュアルで描画したことがありますか?それほどの作業ではありませんが、この手順が MQL4 で自動化されれば、ターミナルがレベルに応じて自分で計算と描画を行うのです。みなさんがするのはスクリプト名をクリックするだけで、それですべてが行われるのです。また、グラフィカルオブジェクトを使用することで、ひじょうに有用なシグナルインディケータを書くことができます。



オブジェクト作業のコンセプト

MQL4 ですべてのグラフィカルオブジェクトで作業するアルゴリズムは以下です。

  • オブジェクトを作成する
  • そのパラメータ(移動、色変更、スタイル等)を変更する
  • オブジェクトを削除する

これは一定の『ライフサイクル』です。それでは段階ごとに詳しく説明します。



グラフィカルオブジェクトを作成する

グラフィカルオブジェクトを描画するには、ユニバーサル関数 ObjectCreate() が使用されます。以下がそのプロトタイプです。

bool ObjectCreate(string name, int type, int window, datetime time1, 
                  double price1, datetime time2=0,double price2=0, 
                  datetime time3=0, double price3=0)

この関数は、すべてが正しければを、オブジェクトが作成されない、またはエラーが発生した場合はを返します。エラーコードを得るには、関数 GetLastError() を使用します。

if(ObjectCreate(/* arguments */)==false)
{
   // an error occurred, its code should be recorded into a journal
   Print("Error of calling ObjectCreate():",GetLastError());
}

エラーコードは何のために必要なのでしょうか?エラーコードはエラー説明を入手し、できればそのエラーを排除するのに役立ちます。コード説明はすべて MQL4 参照 → 標準定数 → エラーコード にあります。

関数 ObjectCreate()の引数をすべて詳しく説明します。

  • 名前 -オブジェクト独自の名前。同一名のオブジェクトを 2 つ作成することはできません。のちに、オブジェクト表示やオブジェクト移動のパラメータを変更するたの別の関数で、この名前が使用されます。
  • タイプ -オブジェクトタイプ。作成されるオブジェクトタイプはすべて MQL4 参照 → 標準定数 → オブジェクトタイプにあります。注意:関数の最後の引数が使用されるかどうかはオブジェクトタイプによります。プロトタイプをもう一度見ます。最後の4つの引数に対する値はデフォルトで割り当てられています。異なるオブジェクトには、作成に異なるデータ量が求められます。簡単なことです。ある点を描く必要があるとします。そこで必要な情報は何でしょうか?明らかに点の位置です。これで十分ですね?そして長方形を描くには、左上と右下の 2 点が必要です。同じことが関数 ObjectCreate() に言えます。それはユニバーサルです。よって、横線を引くための1点の位置と、線分を描くための2点が必要です。長方形を描くには、3点必要です。オブジェクトを作成する際、そのオブジェクトを描くために必要な点の数を適切に調べることをお薦めするのはそのためです。
  • ウィンドウ -オブジェクトが描かれるウィンドウ番号。 オブジェクトをあるチャート、すなわちメインウィンドウ、に描く必要がある場合、ウィンドウ番号として0 を使います。
  • 時刻 1 -1番目の点の X 座標。ターミナルの X 軸は時刻を示します。そのためここに時刻値を指定します。たとえば、最後に利用可能なバーの時刻を求めるには、定義済み配列 Time[] をTime[0] のように使用します。
  • 価格1 -1番目のポイントの Y 座標。ターミナルの Y 軸は価格を示します。そのため価格値が使用され ます。たとえば、定義済み配列 Open[]、Close[] などを使用します。
  • その他の引数はより複雑なオブジェクトを描画するための点を決める類似の座標の2つのペアです。オブジェクトがシンプルであれば、これらパラメータは使用されません。



オブジェクト作成例 -線を引く

よりよく理解するために線をいくつか引きます。前日の高値と安値に印をつけます。まず、新規にスクリプトを作成し、関数start() に変更を加えます。

int  start()
{
   double price=iHigh(Symbol(),PERIOD_D1,0);
   // this useful function returns the maximal price for:
   // * specified security, in our case it is Symbol() - 
   //   active security
   // * specified period, in our case it is PERIOD_D1 (daily)
   // * specified bar, in our case it is 0, the last bar
 
   ObjectCreate("highLine",OBJ_HLINE,0,0,price);
   // let us view all parameters: 
   // "highLine" - the unique object name
   // OBJ_HLINE - object type of the horizontal line
   // 0 - the object is drawn in the main window (chart window)
   // 0 - X coordinate (time), it shouldn't be indicated, because
   //     we are drawing a horizontal line
   // price - Y coordinate (price). It is the maximal price
   
   price=iLow(Symbol(),PERIOD_D1,0);
   // the function is identical with iHigh in arguments, but it returns
   // the minimal price
   
   ObjectCreate("lowLine",OBJ_HLINE,0,0,price);
 
   return(0);
}

もちろんエラーチェックを逃しました。よって、2つのオブジェクトに同じ名前をつけたら、それはご自身の間違いです。スクリプトをスタートすると、以下のようになります。

線は引かれていますがなにか腑に落ちないところがあります。それは赤い色です。あまりにも強いので淡い色にします。一般的に線の外観は設定可能です。



オブジェクトのプロパティを変更する -線の外観設定

作成済みのグラフィカルオブジェクトのパラメータを設定できる特殊関数があります。それが関数 ObjectSet() です。以下がそのプロトタイプです。

bool ObjectSet( string name, int index, double value);

前出の関数同様、すべてが正しければを、なにか問題がある場合はを返します。たとえば、存在しないオブジェクト名を指定してしまった場合など。この関数の引数を見ます。

  • 名前 -作成されたオブジェクト名。変更を始める前に、その名前のオブジェクトが存在することを確認します。
  • インデックス -変更されるオブジェクトプロパティのインデックス。インデックスはすべて MQL4 参照 → 標準定数 → オブジェクトプロパティにあります。この関数もユニバーサルです。それは以下の原則に従って処理をします。:どのプロパティを変更するか、このプロパティにどの値を割り当てるか指定します。
  • -これは選択されたプロパティが変更される値です。たとえば、色を変更する場合、ここで新しい色を指定します。

それでは線を変更します。すなわち、色、幅、スタイルの変更です。同じスクリプトの関数 start() を変更します。

int  start()
{
   double price=iHigh(Symbol(),PERIOD_D1,0);
 
   ObjectCreate("highLine",OBJ_HLINE,0,0,price);
   price=iLow(Symbol(),PERIOD_D1,0);
   ObjectCreate("lowLine",OBJ_HLINE,0,0,price);
   
   ObjectSet("highLine",OBJPROP_COLOR,LimeGreen);
   // changing the color of the upper line
   ObjectSet("highLine",OBJPROP_WIDTH,3);
   // now the line will be 3 pixel wide
   
   ObjectSet("lowLine",OBJPROP_COLOR,Crimson);
   // changing the color of the lower line
   ObjectSet("lowLine",OBJPROP_STYLE,STYLE_DOT);
   // now the lower line will be dashed   
 
   return(0);
}

そうするとチャートに以下が表示されます。



オブジェクトを削除する

よく、古い不要なオブジェクトを削除する必要があります。これを行う関数は複数あります。

bool ObjectDelete(string name);

この関数は指定された名前のオブジェクトを削除します。存在しない名前を指定すると、「偽」が返されます。

int ObjectsDeleteAll(int window=EMPTY,int type=EMPTY);

これは高度な関数で、削除済みオブジェクト数を返します。この関数にはデフォルト値もあります。パラメータを指定しなければ、ターミナルはアクティブなチャートのオブジェクトをすべて削除します。

ObjectsDeleteAll();
// deleting all objects

サブウィンドウ(たとえば、インディケータのウィンドウ)にオブジェクトを作成する場合、1番目の引数にこのウィンドウの番号を指定することでそのオブジェクトをすべて削除することができます。サブウィンドウについてはのちほどお話しします。ここでは1番目の引数に 0 を指定します。

特定タイプのオブジェクトをすべて削除する場合は、2番目の引数にこのタイプを指定します。

ObjectsDeleteAll(0, OBJ_ARROW);
// deleting all arrows



これをすべて正しく使うには?

これをすべて正しく使うのには多くの知識が必要だとお思いかもしれません。たとえば、プロパティやオブジェクトタイプをすべて知る必要があるとか。しかしそうではありません。すべて「ユーザーガイド」にあるのです。

まずツールボックス (CTRL+T)を開きます。下にタブがいくつかあります。そこからヘルプを選択します。グラフィカルオブジェクトを描画する必要があるのに、どうすれば描画できるかわからないとします。ここで関数 ObjectCreate() を使うのです。それを書いて、引数は空のままにします。ここでカーソルを関数名にもってきて、F1 を押します。そうすると、「ヘルプ」ウィンドウがこの関数についての情報を表示します。何も検索する必要がないということです。そうして関数説明を確認します。それに続き、その関数の引数がすべて説明されています。引数タイプの説明に注目します。

そこにはリンクがあります。そのリンクをクリックすると、既存オブジェクトのリストが表示されます。楕円を描画したいとします。

説明を読み、2つ座標が必要なことがわかります。では始めます。

int  start()
{
   ObjectCreate("ellipse",OBJ_ELLIPSE,0,Time[100],Low[100],Time[0],High[0]);
   // indicate 2 points for creating an ellipse:
   // * 1st - lower left point
   // * 2nd - upper right point 
 
   return(0);
}

また、プロパティOBJPROP_SCALE は辺の相関を決めるということも書かれています。なので、1 を設定すると、円を取得します。

int  start()
{
   ObjectsDeleteAll();
   // clear the chart before drawing
   
   ObjectCreate("ellipse",OBJ_ELLIPSE,0,Time[100],Low[100],Time[0],High[0]);
   
   ObjectSet("ellipse",OBJPROP_SCALE,1.0);
   // change the correlation of sides
   ObjectSet("ellipse",OBJPROP_COLOR,Gold);
   // change the color
 
   return(0);
}



みなさんが円を取得しなかったことはわかっています。なぜなら、チャートプロパティに1:1 のスケールを設定する必要があるからです(チャートの余白のどこかで右クリックし、プロパティを選択します)。

おわかりですね。すべて簡単です。実際、キーワードのどれかにカーソルを置き、F1を押すと、「ヘルプ」から対応する情報を見ることができるのです。そのため、内蔵の「ヘルプ」を利用すると、迅速で効率的なコーディングのためにタイプ名やプロパティをすべて覚える必要はないのです。MetaEditor には、コードを書くのに役立つ重要なプロパティがもう一つ備わっています。それには、組み込み関数に引数を書くとき、CTRL + SHIFT + space を押します。関数のプロトタイプのプロンプティングが表示されます。



サブウィンドウにグラフィカルオブジェクトを作成する

カスタムインディケータウィンドウなど、サブウィンドウにグラフィカルオブジェクトを作成する必要がある場合、その番号を知っていなければなりません。例として、別のウィンドウに横線を描くシンプルなインディケータを書きます。カスタムインディケータを作成し、コードに以下を追加します。

//+------------------------------------------------------------------+
//|                                   creatingObjectsInSubWindow.mq4 |
//|                                                     Antonuk Oleg |
//|                                            antonukoleg@gmail.com |
//+------------------------------------------------------------------+
#property copyright "Antonuk Oleg"
#property link      "antonukoleg@gmail.com"
 
#property indicator_separate_window
// indicator will be written in a separate window
#property indicator_minimum 1
// minimal indicator value is 1
#property indicator_maximum 10
// maximal is 10
 
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init()
{
   IndicatorShortName("NiceLine");
   // this simple function sets a short indicator name,
   // you see it in the upper left corner of any indicator.
   // What for do we need it?関数 WindowFind がサブウィンドウを検索します。
   // with a specified short name and returns its number.
 
   int windowIndex=WindowFind("NiceLine");
   // finding the window number of our indicator
   
   if(windowIndex<0)
   {
      // if the number is -1, there is an error
      Print("Can\'t find window");
      return(0);
   }
 
   ObjectCreate("line",OBJ_HLINE,windowIndex,0,5.0);
   // drawing a line in the indicator subwindow
               
   ObjectSet("line",OBJPROP_COLOR,GreenYellow);
   ObjectSet("line",OBJPROP_WIDTH,3);
 
   WindowRedraw();
   // redraw the window to see the line
 
   return(0);
}
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
int deinit()
{
   ObjectsDeleteAll();
   // delete all objects
   
   return(0);
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int start()
{
   return(0);
}

インディケータを開始します。線がありません!



チャート期間を変更する必要があります。



今度は線があります。何が起こったのでしょうか?最初に開始したとき、実は、サブウィンドウ番号が関数 init() 内に見つからなかったのです。おそらく、初期化中にターミナルでまだサブウィンドウが作成されていなかったことが理由です。それを避ける方法があります。すべては関数 start() 内で行います。ウィンドウがすでに作成されている場合、以下のようになります。

//+------------------------------------------------------------------+
//|                                   creatingObjectsInSubWindow.mq4 |
//|                                                     Antonuk Oleg |
//|                                            antonukoleg@gmail.com |
//+------------------------------------------------------------------+
#property copyright "Antonuk Oleg"
#property link      "antonukoleg@gmail.com"
 
#property indicator_separate_window
#property indicator_minimum 1
#property indicator_maximum 10
 
bool initFinished=false;
// adding a variable that will remember the initialization state.
// false - there was no initialization
// true - there was initialization
 
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init()
{
   return(0);
}
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
int deinit()
{
   ObjectsDeleteAll();
   // deleting all objects
   
   return(0);
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int start()
{
   if(initFinished==false)
   {
      IndicatorShortName("NiceLine");
 
      int windowIndex=WindowFind("NiceLine");
   
      if(windowIndex<0)
      {
         // if the subwindow number is -1, there is an error
         Print("Can\'t find window");
         return(0);
      }
 
      ObjectCreate("line",OBJ_HLINE,windowIndex,0,5.0);
      // drawing a line in the indicator subwindow
               
      ObjectSet("line",OBJPROP_COLOR,GreenYellow);
      ObjectSet("line",OBJPROP_WIDTH,3);
 
      WindowRedraw();
      // redraw the window to see the line   
      
      initFinished=true;
      // drawing is finished
   }
   
   return(0);
}

これで最初からすべて描画されるようになります。ここで覚えておくべきことは、サブウィンドウ番号は関数 init() 内ではなく start() 内で検出されるということです。



すこし練習をしてください

「ヘルプ」を利用して、いくつか新しいグラフィカルオブジェクトタイプを学習するようにします。その後、グラフィカルオブジェクトを描画するスクリプトを書き、パラメータを設定します。このプロパティを調べて練習をしたら、初めて本稿を読み進めてください。




シグナルインディケータを書く -シグナルインディケータとは何でしょうか?

次の状況を想像します。トレーダーが市場参入を判断するために複数のインディケータを使用します。それは、移動平均、パラボリック SAR、ウィリアムズの%Rです。これらは組み込みインディケータで、以下のようなものです。



トレーダーは以下の方法で絶えず市況を推定します。:3つのインディケータすべてからシグナルが入って着たら市場参入する。

  • 高速移動平均が低速を超えたら、これは買いの合図です。逆であれば、売りです。
  • 価格がパラボリック SARより低ければ、これは売りの合図です。逆であれば、買いです。
  • WPR が-20 より大きければ、それは買いの合図です。WPR が -80 より低ければ、それは売りの合図です。

トレーダーはすべての条件を絶えず確認しなければなりません。また複数期間に関して状況を追跡する必要もあります。それはたいへんな仕事です。そうすると、すべての確認をしてくれるシグナルインディケータはトレーダーの助けとなることでしょう。

今日はこの問題の解決方法を学びます。簡単に設定できるシグナルインディケータを書きます。また、このインディケータを基に、お好きなインディケータに簡単にご自身で変更を加えることができます。




基礎

このインディケータを作成しているとき、描画についての問題に出会います。グラフィカルオブジェクトはどれも価格軸と時刻軸を用いて描画されます。このために、描画されるものは常に移動します。オブジェクトを一か所に留めるためには、座標を絶えず変更する必要があるでしょう。ですが、前はどうだったかを確認したくてチャートを移動すれば、シグナルテーブルも移動してしまいます。ただし、ルールには必ず例外あり、です。グラフィカルオブジェクトの中に OBJ_LABEL と呼ばれるものがあります。それは価格や時刻ではなく、ウィンドウの座標をピクセルで配置するのに使用されるテキストマークです。簡単です。



共通テキスト記号 "X" が表示されます。そのパラメータで、座標がピクセルで指定されているのがわかります。ピクセルは画面上の小さな点です。左上隅の座標が x=0, y=0 (0,0) であることに注意します。x を増やす場合、オブジェクトはに移動し、減らす場合、に移動します。同じことが y 座標にも言えます。また上方下方にも移動可能です。この原則を理解し、覚えておくことは重要です。練習のために、マークを作成し、プロパティでその座標がどのように変化するか確認することができます。また、チャートを移動して古いクオートを閲覧することも可能です。そのときマークは移動しません。このようなマークを使用して、前述の欠点のないシグナルインディケータを作成することができます。



テキストマークのオプション

われわれのシグナルインディケータはテキストマークしか使用しません。そこでそれらのオプションについて詳しく説明します。まず、新規でインディケータを作成します(データバッファやパラメータは指標しません)。そして関数 init() を変更します。

int init()
{
   // now we will crate a text mark.
   // for this use the function ObjectCreate.
   // do not indicate coordinates
   ObjectCreate("signal",OBJ_LABEL,0,0,0,0,0);
 
   // change the x-coordinate
   ObjectSet("signal",OBJPROP_XDISTANCE,50);
 
   // change the y-coordinate
   ObjectSet("signal",OBJPROP_YDISTANCE,50);
 
   // to indicate the mark text, use the following function
   ObjectSetText("signal","lambada",14,"Tahoma",Gold);
   // "signal" - object name
   // "lambada" - text
   // 14 - font size
   // Gold - color
 
   return(0);
}

おわかりですね。すべて簡単です。ObjectCreate() 関数は必要なオブジェクトをすべて作成するための初期化にのみ使用されます。ObjectSetText() によって関数 start() 内での価格変化のたびにオブジェクトの表示を変えます。また関数 deinit(): を変更することも必要です。

int deinit()
{
   // when deleting the indicator delete all objects
   ObjectsDeleteAll();
 
   return(0);
}

ここでインディケータを開始して結果を見ます。

マークの次のようなオプションを利用します。

  • 友好な特殊シンボルを作るためフォントを Wingdings に変更します(正方形と円からスマイルに)。

  • マークの色とテキストを変更します。
  • マークの位置とサイズを変更します。



フォント Wingdings を使用する

ここから Windings フォントを使用してマークを作成します。init() 関数を変更します。

int init()
{
 
   ObjectCreate("signal",OBJ_LABEL,0,0,0,0,0);
   ObjectSet("signal",OBJPROP_XDISTANCE,50);
   ObjectSet("signal",OBJPROP_YDISTANCE,50);
 
   // use symbols from the Wingdings font
   ObjectSetText("signal",CharToStr(164),60,"Wingdings",Gold);
   // CharToStr() - this function returns a line with a single
   // symbol, the code of which is specified in the single argument.
   // Simply select a symbol from the table above and write
   // its number into this function
   // 60 - use large font
   // "Wingdings" - use font Wingdings
 
   return(0);
}

以下が結果です。



シグナルテーブルのモデルを描画する

シグナルのテーブルモデルを描画します。実際これは数多くの正方形です。

int init()
{
   // use 2 cycles. The first cycle, with the counter "x" draws one by one
   // each column from left to wright. The second cycle draws symbols of each
   // column from top downward. 反復ごとにサイクルはマークを作成します。
   // These 2 cycles create 9 columns (9 periods) 3 marks each (3 signal types).
   for(intx=0;x<9;x++)
      for(int y=0;y<3;y++)
      {
         ObjectCreate("signal"+x+y,OBJ_LABEL,0,0,0,0,0);
         // create the next mark, Note that the mark name
         // is created "on the fly" and depends on "x" and "y" counters
 
         ObjectSet("signal"+x+y,OBJPROP_XDISTANCE,x*20);
         // change the X coordinate.
         // x*20 - each mark is created at the interval of 20 pixels
         // horizontally and directly depends on the "x" counter
 
         ObjectSet("signal"+x+y,OBJPROP_YDISTANCE,y*20);
         // change the Y coordinate.
         // y*20 - each mark is created at the interval of 20 pixels
         // vertically and directly depends on the "y" counter
 
         ObjectSetText("signal"+x+y,CharToStr(110),20,"Wingdings",Gold);
         // use the 110th symbol code (square)
      }
   
   return(0);
}


パターンができました。ターミナルテキストが見えるようにその左上にインデントを追加します。

int init()
{
   for(int x=0;x<9;x++)
      for(int y=0;y<3;y++)
      {
         ObjectCreate("signal"+x+y,OBJ_LABEL,0,0,0,0,0);
         ObjectSet("signal"+x+y,OBJPROP_XDISTANCE,x*20+12);
         // adding a horizontal indent 12 pixels
         ObjectSet("signal"+x+y,OBJPROP_YDISTANCE,y*20+20);
         // adding a vertical indent 20 pixels
         ObjectSetText("signal"+x+y,CharToStr(110),20,"Wingdings",Gold);
      }
 
   return(0);
}



パターンをアクティブにします。

少なくとも正方形の一つを操作します。左上の正方形が1分足のタイムフレーム(M1)で移動平均のシグナルを表示するとします。買いシグナルがあれば、正方形の色がグリーンに変わります。売りのシグナルがあれば、赤になります。関数 start() を変更する必要があります。

int start()
{
   // if quick moving average (period - 13) is larger than the slow one,
   // this is a signal to buy. Check the last bar
   if(iMA(Symbol(),1,13,0,0,0,0)>iMA(Symbol(),1,24,0,0,0,0))
      ObjectSetText("signal00",CharToStr(110),20,"Wingdings",YellowGreen);
   // change the color of the mark named "signal00" (the upper left)
   // into green
 
   else
   // else, if the quick MA is smaller than the slow one, this is a signal to sell.
      ObjectSetText("signal00",CharToStr(110),20,"Wingdings",Tomato);
      // change the color into red
 
   return(0);
}



上側の行をアクティブにします。

アクティブ化を続けます。左の正方形は最小タイムフレーム:M1、を示しています。正方形がそれぞれ前回のタイムフレームより大きいタイムフレームを示すようにします。2番目の正方形はM5 でのシグナルを、3番目の正方形は M15 でのシグナルを示す、という具合に MN1 までいきます。もちろんこれはすべてサイクル内で行われます。変わったのは名前と期間です。正方形がないので、カウンターを一つ使用します。ただし、期間について問題があります。というのも、期間は規則性なく変化するからです。以下をごらんください。


ここではサイクルは使えないと思われるかもしれません。しかしそうではありません。必要なのは、以下で始まるインディケータコード内で特殊配列を宣言することです。

//////////////////////////////////////////////////////////////////////
//
//                                                  signalTable.mq4 
//                                                     Antonuk Oleg 
//                                            antonukoleg@gmail.com 
//
//////////////////////////////////////////////////////////////////////
#property copyright "Antonuk Oleg"
#property link      "antonukoleg@gmail.com"
 
#property indicator_chart_window
 
intperiod[]={1,5,15,30,60,240,1440,10080,43200};

期間はすべてこの配列に書き込まれ、サイクルで簡単に使用することが可能です。

int start()
{
   // use a cycle to activate all squares of the first line
   for(int x=0;x<9;x++)
   {
      if(iMA(Symbol(),period[x],13,0,0,0,0)>iMA(Symbol(),period[x],24,0,0,0,0))
         ObjectSetText("signal"+x+"0",CharToStr(110),20,"Wingdings",YellowGreen);
         // "signal"+x+"0" - create a mark name dynamically depending on
         // the counter "x"
      else
         ObjectSetText("signal"+x+"0",CharToStr(110),20,"Wingdings",Tomato);
   }
 
   return(0);
}

"x" カウンターと期間に対応するテーブルとして配列period[] を使用します。この小さな配列でなければ、コードはいくつ必要になるか想像してください。シグナルの正方形の最初の行は準備できました。







表記を追加する

すべてOKですが、正方形のタイムフレームが何なのか理解するのは困難であるため、説明用の署名を作成します。また、列ごとに表記を格納する対応の配列も使用します。

#property indicator_chart_window
 
int period[]={1,5,15,30,60,240,1440,10080,43200};  
 
stringperiodString[]={"M1","M5","M15","M30","H1","H4","D1","W1","MN1"};

表記は以下のサイクルの助けを借りて init() 内に作成されます。

int init()
{
   for(int x=0;x<9;x++)
      for(int y=0;y<3;y++)
      {
         ObjectCreate("signal"+x+y,OBJ_LABEL,0,0,0,0,0);
         ObjectSet("signal"+x+y,OBJPROP_XDISTANCE,x*20+12);
         ObjectSet("signal"+x+y,OBJPROP_YDISTANCE,y*20+20);
         ObjectSetText("signal"+x+y,CharToStr(110),20,"Wingdings",Gold);
      }
 
   // create writings for periods from left to right
   for(x=0;x<9;x++)
   {
      // everything is as usual
      ObjectCreate("textPeriod"+x,OBJ_LABEL,0,0,0,0,0);
      ObjectSet("textPeriod"+x,OBJPROP_XDISTANCE,x*20+12);
      ObjectSet("textPeriod"+x,OBJPROP_YDISTANCE,10);
      ObjectSetText("textPeriod"+x,periodString[x],8,"Tahoma",Gold);
      // we use the array periodString[], to indicate writings
   }
   
   return(0);
}






パラメータを追加する。

インディケータの外観をユーザーが設定できるよう、パラメータをいくつか追加して、インディケータをもっと柔軟なものにします。

#property copyright "Antonuk Oleg"
#property link      "antonukoleg@gmail.com"
 
#property indicator_chart_window
 
extern int scaleX=20, // horizontal interval at which the squares are created
           scaleY=20, // vertical interval
           offsetX=35, // horizontal indent of all squares
           offsetY=20, // vertical indent
           fontSize=20; // font size
           
int period[]={1,5,15,30,60,240,1440,10080,43200};
string periodString[]={"M1","M5","M15","M30","H1","H4","D1","W1","MN1"};

また、関数 init() および start() のコードも変更します。

int init()
{
   for(int x=0;x<9;x++)
      for(int y=0;y<3;y++)
      {
         ObjectCreate("signal"+x+y,OBJ_LABEL,0,0,0,0,0);
         ObjectSet("signal"+x+y,OBJPROP_XDISTANCE,x*scaleX+offsetX);
         ObjectSet("signal"+x+y,OBJPROP_YDISTANCE,y*scaleY+offsetY);
         ObjectSetText("signal"+x+y,CharToStr(110),fontSize,"Wingdings",Gold);
      }
 
   for(x=0;x<9;x++)
   {
      ObjectCreate("textPeriod"+x,OBJ_LABEL,0,0,0,0,0);
      ObjectSet("textPeriod"+x,OBJPROP_XDISTANCE,x*scaleX+offsetX);
      ObjectSet("textPeriod"+x,OBJPROP_YDISTANCE,offsetY-10);
      ObjectSetText("textPeriod"+x,periodString[x],8,"Tahoma",Gold);
   }
   
   return(0);
}
 
int start()
{
   for(int x=0;x<9;x++)
   {
      if(iMA(Symbol(),period[x],13,0,0,0,0)>iMA(Symbol(),period[x],24,0,0,0,0))
         ObjectSetText("signal"+x+"0",CharToStr(110),fontSize,"Wingdings",YellowGreen);
      else
         ObjectSetText("signal"+x+"0",CharToStr(110),fontSize,"Wingdings",Tomato);
   }
 
   return(0);
}



その他の行をアクティブにする

2行目はウィリアムズの%Rを、3行目はパラボリック SARを示します。関数 start() を変更します。

int start()
{
   for(int x=0;x<9;x++)
   {
      if(iMA(Symbol(),period[x],13,0,0,0,0)>iMA(Symbol(),period[x],24,0,0,0,0))
         ObjectSetText("signal"+x+"0",CharToStr(110),fontSize,"Wingdings",YellowGreen);
      else
         ObjectSetText("signal"+x+"0",CharToStr(110),fontSize,"Wingdings",Tomato);
   }
 
   // activate the second row
   for(x=0;x<9;x++)
   {
      // if the absolute value of WPR is lower than 20, this is a signal to buy
      if(MathAbs(iWPR(Symbol(),period[x],13,0))<20.0)
         ObjectSetText("signal"+x+"1",CharToStr(110),fontSize,"Wingdings",YellowGreen);
      // if the absolute value of WPR is larger than 80, this is a signal to sell
      else if(MathAbs(iWPR(Symbol(),period[x],13,0))>80.0)
         ObjectSetText("signal"+x+"1",CharToStr(110),fontSize,"Wingdings",Tomato);
      // else, if there are no signals, a square is painted gray
      else
         ObjectSetText("signal"+x+"1",CharToStr(110),fontSize,"Wingdings",DarkGray);
   }
 
   // activate the third row
   for(x=0;x<9;x++)
   {
      // if the current price is larger than the value of SAR, this is a signal to buy
      if(iSAR(Symbol(),period[x],0.02,0.2,0)<Close[0])
         ObjectSetText("signal"+x+"2",CharToStr(110),fontSize,"Wingdings",YellowGreen);
      // otherwise, it is a signal to sell
      else
         ObjectSetText("signal"+x+"2",CharToStr(110),fontSize,"Wingdings",Tomato);
   }
 
   return(0);
}





シグナル名を追加する

各行に名前を入れます。前の配列を使用して、左側に表記を3つ作成します。

int period[]={1,5,15,30,60,240,1440,10080,43200};
string periodString[]={"M1","M5","M15","M30","H1","H4","D1","W1","MN1"},
       // create one more array with indicator names
string signalNameString[]={"MA","WPR","SAR"};

関数 init() を変更します。

int init()
{
   for(int x=0;x<9;x++)
      for(int y=0;y<3;y++)
      {
         ObjectCreate("signal"+x+y,OBJ_LABEL,0,0,0,0,0);
         ObjectSet("signal"+x+y,OBJPROP_XDISTANCE,x*scaleX+offsetX);
         ObjectSet("signal"+x+y,OBJPROP_YDISTANCE,y*scaleY+offsetY);
         ObjectSetText("signal"+x+y,CharToStr(110),fontSize,"Wingdings",Gold);
      }
 
   for(x=0;x<9;x++)
   {
      ObjectCreate("textPeriod"+x,OBJ_LABEL,0,0,0,0,0);
      ObjectSet("textPeriod"+x,OBJPROP_XDISTANCE,x*scaleX+offsetX);
      ObjectSet("textPeriod"+x,OBJPROP_YDISTANCE,offsetY-10);
      ObjectSetText("textPeriod"+x,periodString[x],8,"Tahoma",Gold);
   }
   
   // draw signal names from top downwards
   for(y=0;y<3;y++)
   {
      ObjectCreate("textSignal"+y,OBJ_LABEL,0,0,0,0,0);
      ObjectSet("textSignal"+y,OBJPROP_XDISTANCE,offsetX-25);
      ObjectSet("textSignal"+y,OBJPROP_YDISTANCE,y*scaleY+offsetY+8);
      ObjectSetText("textSignal"+y,signalNameString[y],8,"Tahoma",Gold);
   }
   
   return(0);
}






バインディングコーナー変更のオプションを追加する

シグナルインディケータのポジションを選択するオプションを追加します。それは左上角に来ます。マークのプロパティ、OBJPROP_CORNER を変更するなら角は変わります。このプロパティは以下の値をとります。

  • 0 -左上隅
  • 1-右上隅
  • 2 -左下隅
  • 3 -右下隅

新しいパラメータ、 corner: を追加します。

#property indicator_chart_window
 
extern int scaleX=20,
           scaleY=20, 
           offsetX=35, 
           offsetY=20, 
           fontSize=20,
           corner=0; // adding a parameter for choosing a corner

そして関数 init() を変更します。

int init()
{
   // a table of signals
   for(int x=0;x<9;x++)
      for(int y=0;y<3;y++)
      {
         ObjectCreate("signal"+x+y,OBJ_LABEL,0,0,0,0,0);
         ObjectSet("signal"+x+y,OBJPROP_CORNER,corner);
         // change the corner
         ObjectSet("signal"+x+y,OBJPROP_XDISTANCE,x*scaleX+offsetX);
         ObjectSet("signal"+x+y,OBJPROP_YDISTANCE,y*scaleY+offsetY);
         ObjectSetText("signal"+x+y,CharToStr(110),fontSize,"Wingdings",Gold);
      }
 
   // name of timeframes
   for(x=0;x<9;x++)
   {
      ObjectCreate("textPeriod"+x,OBJ_LABEL,0,0,0,0,0);
      ObjectSet("textPeriod"+x,OBJPROP_CORNER,corner);
      // changing the corner
      ObjectSet("textPeriod"+x,OBJPROP_XDISTANCE,x*scaleX+offsetX);
      ObjectSet("textPeriod"+x,OBJPROP_YDISTANCE,offsetY-10);
      ObjectSetText("textPeriod"+x,periodString[x],8,"Tahoma",Gold);
   }
 
   // names of indicators
   for(y=0;y<3;y++)
   {
      ObjectCreate("textSignal"+y,OBJ_LABEL,0,0,0,0,0);
 ObjectSet("textSignal"+y,OBJPROP_CORNER,corner);// change the corner
      ObjectSet("textSignal"+y,OBJPROP_XDISTANCE,offsetX-25);
      ObjectSet("textSignal"+y,OBJPROP_YDISTANCE,y*scaleY+offsetY+8);
      ObjectSetText("textSignal"+y,signalNameString[y],8,"Tahoma",Gold);
   }
   
   return(0);
}



新規パラメータの追加

インディケータ表示の設定が柔軟になるよう、もういくつかパラメータを追加することができます。全パラメータ:

  • 有効な色をすべて
  • 有効なシンボルコードをすべて

まず、コード冒頭でこれらパラメータを宣言する必要があります。

extern int scaleX=20,
           scaleY=20,
           offsetX=35,
           offsetY=20,
           fontSize=20,
           corner=0,
           symbolCodeBuy=110, // a symbol code for a buy signal
           symbolCodeSell=110, // sell signal
           symbolCodeNoSignal=110; // no signal
           
extern color signalBuyColor=YellowGreen, // color of the symbol of a buy signal
             signalSellColor=Tomato, // for a sell signal
             noSignalColor=DarkGray, // no signal
             textColor=Gold; // color of all writings

関数 init() を変更します。

int init()
{
   // table of signals
   for(int x=0;x<9;x++)
      for(int y=0;y<3;y++)
      {
         ObjectCreate("signal"+x+y,OBJ_LABEL,0,0,0,0,0);
         ObjectSet("signal"+x+y,OBJPROP_CORNER,corner);
         ObjectSet("signal"+x+y,OBJPROP_XDISTANCE,x*scaleX+offsetX);
         ObjectSet("signal"+x+y,OBJPROP_YDISTANCE,y*scaleY+offsetY);
         ObjectSetText("signal"+x+y,CharToStr(symbolCodeNoSignal),
                       fontSize,"Wingdings",noSignalColor);
      }
 
   // names of timeframes
   for(x=0;x<9;x++)
   {
      ObjectCreate("textPeriod"+x,OBJ_LABEL,0,0,0,0,0);
      ObjectSet("textPeriod"+x,OBJPROP_CORNER,corner);
      ObjectSet("textPeriod"+x,OBJPROP_XDISTANCE,x*scaleX+offsetX);
      ObjectSet("textPeriod"+x,OBJPROP_YDISTANCE,offsetY-10);
      ObjectSetText("textPeriod"+x,periodString[x],8,"Tahoma",textColor);
   }
 
   // names of indicators
   for(y=0;y<3;y++)
   {
      ObjectCreate("textSignal"+y,OBJ_LABEL,0,0,0,0,0);
      ObjectSet("textSignal"+y,OBJPROP_CORNER,corner);
      ObjectSet("textSignal"+y,OBJPROP_XDISTANCE,offsetX-25);
      ObjectSet("textSignal"+y,OBJPROP_YDISTANCE,y*scaleY+offsetY+8);
      ObjectSetText("textSignal"+y,signalNameString[y],8,"Tahoma",textColor);
   }
   
   return(0);
}

関数 start() を変更します。

int start()
{
   for(int x=0;x<9;x++)
   {
      if(iMA(Symbol(),period[x],13,0,0,0,0)>iMA(Symbol(),period[x],24,0,0,0,0))
         ObjectSetText("signal"+x+"0",CharToStr(symbolCodeBuy),fontSize,
         "Wingdings",signalBuyColor);
      else
         ObjectSetText("signal"+x+"0",CharToStr(symbolCodeSell),fontSize,
         "Wingdings",signalSellColor);
   }
 
   for(x=0;x<9;x++)
   {
      if(MathAbs(iWPR(Symbol(),period[x],13,0))<20.0)
         ObjectSetText("signal"+x+"1",CharToStr(symbolCodeBuy),fontSize,
         "Wingdings",signalBuyColor);
      else if(MathAbs(iWPR(Symbol(),period[x],13,0))>80.0)
         ObjectSetText("signal"+x+"1",CharToStr(symbolCodeSell),fontSize,
         "Wingdings",signalSellColor);
      else
         ObjectSetText("signal"+x+"1",CharToStr(symbolCodeNoSignal),fontSize,
         "Wingdings",noSignalColor);
   }
 
   for(x=0;x<9;x++)
   {
      if(iSAR(Symbol(),period[x],0.02,0.2,0)<Close[0])
         ObjectSetText("signal"+x+"2",CharToStr(symbolCodeBuy),fontSize,
         "Wingdings",signalBuyColor);
      else
         ObjectSetText("signal"+x+"2",CharToStr(symbolCodeSell),fontSize,
         "Wingdings",signalSellColor);
   }
 
   return(0);
}



外観を変更する

インディケータは準備が整いました。入力パラメータを変更することで、外観を完全に変更できます。

extern int scaleX=20,
           scaleY=20,
           offsetX=35,
           offsetY=20,
           fontSize=20,
           corner=2,
           symbolCodeBuy=67, 
           symbolCodeSell=68, 
           symbolCodeNoSignal=73; 
           
extern color signalBuyColor=Gold,
             signalSellColor=MediumPurple,
             noSignalColor=WhiteSmoke,
             textColor=Gold;




宿題

ご自身のシグナルインディケータを作成して、1行追加してみてください。新規パラメータをいくつか作成します。たとえば、表記(タイムフレームやシグナル名)のフォントサイズを検出するパラメータです。お好みに応じてインディケータの外観を設定します。



おわりに

今日はスクリプトやインディケータでグラフィカルオブジェクトを利用する方法を学習しました。オブジェクト作成、そのパラメータの変更、エラーチェックの方法も学びました。ご自身で新しいタイプのグラフィカルオブジェクトを学ぶために十分な知識を得ました。また、簡単で柔軟に設定可能な複雑なインディケータを段階的に作成しました。


以下は「初心者向け MQL4 言語』シリーズの先行記事です。

  1. 初心者向け MQL4 言語 -はじめに
  2. 初心者向け MQL4 言語 -シンプルなフレーズにおける難しい質問
  3. 初心者向け MQL4 言語 -テクニカルインディケータと組み込み関数
  4. 初心者向け MQL4 言語 -カスタムインディケータ(パート 1)

MetaQuotes Ltdにより英語から翻訳されました。
元の記事: https://www.mql5.com/en/articles/1503

添付されたファイル |
creatingLines.mq4 (1.71 KB)
settingLines.mq4 (1.29 KB)
signalTable.mq4 (4.34 KB)
金融時系列の予測 金融時系列の予測
金融時系列の予測はあらゆる投資活動に必要とされる要素です。将来利益を得るために今資金を投入する、という投資そのもののコンセプトは、将来予測のコンセプトに基づいています。そのため、金融時系列の予測は、組織化された為替やその他有価証券の取引システムといった投資業界全体に根差すものです。
初心者向け MQL4 言語カスタムインディケータ(パート 1) 初心者向け MQL4 言語カスタムインディケータ(パート 1)
本稿は『初心者向け MQL4 言語』シリーズの第4 弾です。今日はカスタムインディケータの書き方を学習します。インディケータを特徴で分類する知識を得、この特徴がインディケータにどのように影響するかを確認し、新しい関数や最適化について学び、最後に自分のインディケータを書きます。また、本稿末尾にはプログラミングスタイルのアドバイスもあります。『初心者の方にとって』本稿が最初に読む記事であれば、先行記事を読むのが良いかもしれません。また、この記事では基礎は説明していないので、前の資料を正しく理解できていることを確認してください。
MetaEditor:支点としてのテンプレート MetaEditor:支点としてのテンプレート
読者の多くにとって EA を書く準備はすべて一度だけすると、それを継続的に利用できるというのは初耳でしょう。
時間に基づくパターン分析への MetaTrader 4 利用 時間に基づくパターン分析への MetaTrader 4 利用
時間を基にしたパターン分析は、トレードに参入するより適した時刻または取引を完全に避けるべき時間を判断するために通貨市場で利用されます。ここでは、MetaTrader 4 を利用して、履歴市場データを分析し、自動取引システムに適用するのに便利な最適化結果を導きます。