pekonoriブログ関連

Expert Advisor Programming for MetaTrader5【日本語訳 第二章】変数とデータ型

  1. HOME >
  2. pekonoriブログ関連 >

Expert Advisor Programming for MetaTrader5【日本語訳 第二章】変数とデータ型

変数とデータ型 P11

変数 P11

変数は、すべてのプログラミング言語におけるストレージの基本単位です。変数は、価格、指標値、取引パラメータなど、プログラムが機能するために必要な情報を保持します。

変数を使用する前に、変数を宣言する必要があります。データ型と一意の識別子を指定して、変数を宣言します。オプションで、変数を値で初期化できます。通常、変数はプログラムまたは関数の開始時、または最初に使用するときに宣言します。変数を複数回宣言するか、まったく宣言しないと、コンパイルエラーが発生します。

変数宣言の例を次に示します。

                  int myNumber = 1;

この例では、データ型はint(整数)、識別子はmyNumberで、値1で初期化します。変数が宣言されたら、新しい値を割り当てることでその値を変更できます。

                  myNumber = 3;

変数myNumberの値は3になりました。ある変数の値を別の変数に代入することもできます。

                  int myNumber;

                  int yourNumber = 2;

                  myNumber = yourNumber;

変数myNumberの値は2になりました。

変数を値で初期化しない場合、デフォルトの空の値が割り当てられます。数値型の場合、初期値は0になり、文字列型の場合、nullまたは空の文字列(NULLまたは””)になります。

データ型 P12

変数を宣言するとき、データ型によって、変数が保持できるデータの種類が決まります。MQ5のデータ型は、次の3つに編成できます。

  • 整数型は整数です。例 : 0、1、10563等
  • 実数型は小数点付きの少数です。例 : 1.35635等
  • 文字列はUnicode文字で構成されるテキストです。例 : “茶色の狐”

整数型 P12

MQ5には、様々な範囲の整数を保持する多くの整数型があります。符号付整数型を調べることから始めましょう。符号付の型は、正または負の数を保持できます。

  • char – char型は1バイトのメモリを使用します。値の範囲は -128~127です。
  • short - short型は2バイトのメモリを使用します。値の範囲は -32.768~32,767です。
  • int - int型は4バイトのメモリを使用します。値の範囲は -2.147.483.648~2.147.483.647です。
  • long – long型は8バイトのメモリを使用します。値の範囲は -9.223.372.036.854.775.808~9.223.372.036.854.775.807です。

では、どの整数型を使用する必要がありますか?MQ5関数で使用されるint型またはlong型を頻繁に目にするので、これらは最もよく利用する型です。必要に応じて、変数にcharまたはshort型を使用できます。

負の数を許可しない【符号なし整数型】もあります。符号なしの型は、対応する符号付の型と同じ量のメモリを使用しますが、最大値は符号付の型の2倍です。

  • uchar – uchar型は1バイトのメモリを使用します。値の範囲は0~255です。
  • ushort – ushort型2バイトのメモリを使用します。値の範囲は0~65.535です。
  • uint – uint型4バイトのメモリを使用します。値の範囲は0~4.294.967.295です。
  • ulong – ulong型8バイトのメモリを使用します。値の範囲は0~18.446.744.073.709.551.615です。

チケット番号やその他の取引パラメータはulong型を使用します。他のunsigned(署名なし)型はめったに使用されませんが、必要に応じてそれらを変数に使用できます。

実数型 P13

実数型は、価格などの小数部分のある数値を格納するために使用されます。MQ5には2つの実数型があります。2つのタイプの違いは、小数値を表すときの精度のレベルです。

  • float – float型は4バイトのメモリを使用します。有効数字7桁まで正確です。
  • double – double型は8バイトのメモリを使用します。有効数字15桁まで正確です。

MQ5ではdouble型を頻繁に使用します。float型は、実数の大きな配列を扱う際にメモリを節約するために使用できますが、MQ5関数では使用されません。

文字列型 P13

文字列型は、テキストの格納に使用されます。文字列は二重引用符(“)で囲む必要があります。文字列型の変数宣言の例を次に示します。

                  string myString = “これは文字列です”;

文字列内で一重引用符または二重引用符を使用する必要がある場合は、引用符の前にバックスラッシュ文字(\)を使用します。これは、文字のエスケープと呼ばれます。

                  string myQuote = “二重引用符を\”エスケープ\”しています”;

                  Print(myQuote);

                  //Output : 二重引用符を「エスケープ」しています。

文字列内でバックスラッシュを使用する必要がある場合は、次のように2つのバックスラッシュ文字を使用します。

                  string mySlash = “これはバックスラッシュです:\\”;

                  Print(mySlash);

                  //Output : これはバックスラッシュです:\

\nエスケープ文字を使用して、文字列に改行文字を追加することもできます。

                  staring myNewline = “この文字列には\n改行文字があります”;

                  Print(myNewline);

                  //Output : この文字列には

                  //                  改行文字があります。

連結演算子(+)を使用して文字列を結合できます。これは複数の文字列を1つに結合します。

string :

                  string insert = “連結”;

                  string myConcat = “これは” + insert + “文字列の例です。”;

                  Print(myConcat);

                  //Output : これは連結文字列の例です。

StringConcatenate()関数を利用して文字列を連結することもできます。連結演算子を使用するよりもメモリ効率が高くなります。StringConcatenate()関数の最初のパラメータは、連結された文字列をコピーする文字列変数で、残りのパラメータは連結する文字列です。

string newString;

string insert = “連結された”;

StringConcatenate(newString,”これは”, insert, “文字列の例です。”);

Print(newString);

//Output: これは連結された文字列の別の例です。

newString変数には連結された文字列が含まれます。連結する文字列はStringConcatenate()関数内でカンマで区切られていることに注意してください。

最後に、文字列が非常に長い場合は、文字列を複数の行に分割できます。連結演算子を使用する必要はありません。各行は二重引用符で囲む必要があり、式の最後にはセミコロンが必要です。

                  string myMultiline = “これは複数上の文字列です。”

          “これらの行は結合されます。”;

                  Print(myMultiline);

                  //Output: これは複数行の文字列です。これらの行は結合されます。

bool型 P14

ブール(bool)型は真/偽の値を格納するために使用されます。技術的には、ブール型は0または1(false or true)の値をとるため整数型です。ブール型変数宣言の例を次に示します。

                  bool myBool = true;

                  Print(myBool);

                  //Output: true

ブール変数がtureの値で明示的に初期化されていない場合、デフォルト値は0またはfalseになります。ブール変数の0以外の値はすべてtrueと評価されます。

                  book myBool;

                  Print(myBool);

                  //Output: false

                  myBool = 5;

                  if(myBool == true) Print(“myBool は true”);

                  //Output: myBool はtrue

上記の例ではブール変数myBoolを値なしで初期化しています。したがって、myBoolは0またはfalseです。myBoolに値5を割り当てると、myBoolはブール演算でtrueと評価されます。ブール演算については第3章で詳しく説明します。

カラー型 P15

カラー型は色に関する情報を格納するために使用されます。色は定義済みの色定数RBG値または16進数値で表すことができます。

色定数をもっともよく使用します。これらはインジケータラインまたはチャートオブジェクトの色を選択するときに使用する色と同じです。色定数の完全なセットはMQ5リファレンスの[標準定数] > [オブジェクト定数] > [Webカラー]で確認できます。

色定数を使用した色変数宣言の例を次に示します。

                  color lineColor = clrRed

色変数lineColorは赤の色定数clrRedを使用して初期化されます。赤のRGB値を使用した例を次に示します。

                  color lineColor = C‘255,0,0’;

赤のRBG値は255,0、0です。RGB定数は大文字のCで始まり、RGB値は一重引用符で囲みます。最後に赤の16進法を使用した例を次に示します。

                  color lineColor = 0xFF0000;

16進値の前には「0x」が付き、その後に6文字の16進値FF0000が続きます。

RGB値と16進数値はカスタムカラー(色定数で定義されていないもの)に使用されます。RGBまたは16進数値の色に慣れている場合は独自の色を定義できます。それ以外の場合は、色定数が簡単で便利であることがわかります。

日時型 P16

Datetime型は時刻と日付を格納するために使用されます。Datetime変数の時刻と日付は1970年1月1日からの経過秒数であるUnix時間で格納されます。

Datetime変数を特定の日時に初期化する必要がある場合はdatetime定数を使用します。Datetime定数は大文字のDで始まり日時と時刻は一重引用符で囲みます。日時と時刻はyyy.mm.dd hh:mm:ssの形式で表されます。次に例を示します。

                  datetime myDate = D’2012.01.01 00:00:00’;

上記の例では変数myDateを2012年1月1日の午前0時に初期化します。Datetime定数の一部が使用されていない場合は省略できます。次の例は次のことを示しています。

                  datetime myDate = D’2012.01.01 00:00’; //時と分

                  datetime myDate = D’2012.01.01 00’; //時間のみ

                  datetime myDate = D’2012.01.01’; //日付のみ

これらの例は全て変数myDateを同じ時刻(2012年1月1日 午前0時)に初期化します。

datetime定数のhh:mm:ssの部分は使用されないため省略できます。

では、日付を省略した場合はどうなるでしょう。コンパイラは今日の日付(コンパイルの日付)に置き換えます。今日が2012年1月1日であるとすると日付けなしでdatetime定数を使用すると次のようになります。

                  datetime myDate = D’’;        //2012.01.01 00:00

                  datetime myDate = D’02:00’;   //2012.01.01 02:00

最初の例では変数myDateが今日の日付の午前0時に設定されます。2番目の例ではdatetime定数で時刻を指定します。これにより、myDateが指定された時刻の今日の日付に設定されます。

MQ5には現在の日付と時刻の定義済み定数がいくつかあります。_DATE__定数はコンパイル時に現在の時刻と日時を返します。これは、空のdatetimeを使用するのと同じです。_DATETIME__定数はコンパイル時に現在の時刻と日付を返します。各定数の前後に2つのアンダースコア文字()があることに注意してください。

_DATE__定数を使用した例を次に示します。現在の日付が2012年1月1日であると仮定します。

                  datetime myDate = _DATA__;  //2012.01.01 00:00

                  datetime myDate = D’’;       //2012.01.01 00:00

_DATETIME__定数を使用した例を次に示します。コンパイルの日時が2012年1月1日 03:15:05であると仮定します。

                  datetime myDate = __DATETIME__;          //2012.01.01 03:15:05

第18章ではdatetime値を処理および操作する方法をさらに検討します。

定数 P17

定数は値が変化しない識別子です。定数は変数を使用できる場所であればどこでも使用できます。変数のように定数に新しい値を割り当てることはできません。

プログラムで定数を定義するには2つの方法があります。グローバル定数は#defineプリプロセッサディレクティブを使用してプログラムで定義されます。#defineディレクティブはすべてプログラムの最初に配置します。定数定義の例を次に示します。

                  #define COMPANY_NAME “Easy Expert Forex”

#defineディレクティブはこれが定数宣言であることをコンパイラに伝えます。COMPANY_NAMEは識別子です。文字列“Easy Expert Forex”は定数値です。定数値は任意のデータ型にすることができます。

グローバル定数はプログラムのどこでも使用できます。上記の定数を使用する方法の例を次に示します。

                  Print(“Copyright©2012”,COMPANY_NAME);                

                  //Output: Copyright©2012 Easy Expert Forex

Print()関数の定数識別子COMPANY_NAMEは定数値“Easy Expert Forex”に置き換えられます。

定数を宣言する別の方法はconst指定子を使用することです。変数宣言の前にconst指定子を置くことで変数の値を変更できないことを示しています。

                  const int cVer = 1;

                  cVer = 2;           //コンパイルエラー

cVer変数はconst指定子を使用して定数として設定されます。この変数に新しい値を割り当てようとするとコンパイルエラーが発生します。

配列 P18

配列は複数の値を保持できる任意の型の変数です。配列を数値リストと考えてください。リスト内の各番号は異なる値に対応しています。このリストを数値的に反復し、数値インデックスによって各値にアクセスできます。

配列の宣言と代入の例を次に示します。

                  int myArray[3];

                     myArray[0] = 1;

                     myArray[1] = 2;

                     myArray[2] = 3;

これを静的配列と呼びます。静的配列のサイズは固定です。静的配列が宣言されている場合、配列のサイズは角括弧{[]}で指定されます。この例では、配列myArrayが3つの要素で初期化されています。次の行は配列の3つの要素のそれぞれに整数値を割り当てます。

配列を最初に宣言するときに、配列値を割り当てることもできます。下のコード行は前の例の4行のコードと同じタスクを実行します。

                  int myArray[3] = {1,2,3};

配列値は角括弧{[]}内でカンマで区切られます。これらは出現順に配列に割り当てられるため、最初の配列要素には値1が割り当てられ2番目の配列要素には値2が割り当てられます。値が割り当てられていない配列要素は、ディフォルトで空の値(この場合ゼロ)になります。

配列のインデックスはゼロから始まります。したがって、配列に3つの要素がある場合、要素には0,1,2の番号が付けられます。下の図2.1を参照してください。最大のインデックスは常に配列のサイズより1小さい値です。配列の要素にアクセスする場合、インデックスは角括弧で指定されます。上記の例では最初の要素myArray[0]に値1が割り当てられ3番目の要素 myArray[2]に値3が割り当てられます。

図2.1配列のインデックス付け

この配列には要素が3つしかないため2より大きいインデックスにアクセスしようとするとエラーが発生します。

例えば:

                  int myArray[3];

                     myArray[3] = 4;     //コンパイルエラーになる

配列のインデックスは0から始まるためインデックス3は配列の4番目の要素を参照します。この配列には3つの要素しかないため4番目の要素にアクセスしようとすると「配列が範囲外です」という重大なエラーが発生します。

静的配列はサイズ変更できませんが配列のサイズを変更する必要がある場合は代わりに動的配列を宣言できます。動的配列は固定サイズなしで宣言される配列です。動的配列は使用する前にサイズを変更する必要があり、動的配列はいつでもサイズ変更できます。ArrayResize()関数は動的配列のサイズを設定するために使用されます。

動的配列の宣言、サイズ変更、割り当ての例を次に示します。

                  double myDynamic [];

                  ArrayResize(myDynamic, 3);

                  myDynamic [0] = 1.50;

動的配列は空の角括弧で宣言されます。角括弧で宣言することでこれが動的配列であることをコンパイラに伝えます。ArrayResize()関数は配列名(myDynamic)を最初のパラメータとして受け取り、新しいサイズ(3)を2番目のパラメータとして受け取ります。この場合myDynamicのサイズを3に設定しています。配列のサイズが決まったら、配列に値を割り当てることができます。

動的配列は指標値とか各データを格納するためにMQ5で使用されます。MQ5関数で使用する動的配列を頻繁に宣言します。関数自体が配列のサイズを適切に調整しデータを入力します。独自のコードで動的配列を使用する場合は最初にArrayResize()を使用してサイズを調整してください。

多次元配列 P19

ここまでは1次元配列を宣言してきました。2次元配列を見てみましょう。

                  double myDimension[3][3];

                  myDimension[0][1] = 1.35;

上記の例ではmyDimensionという名前の2次元配列を宣言しており、両方の次元に3つの要素があります。多次元配列を「配列内の配列」と考えてください。2次元配列をテーブルとして視覚化するとより簡単になります。下の図2.2を参照してください。

図2.2多次元配列のインデックス付け

最初の次元は表の横の行になり、2番目の次元は縦の列になります。したがってこの例ではテーブルmyDimension[0][0]は1行目、1列目になります。myDimension[1][2]は2行目、3列目などになります。2次元配列はテーブル形式で整理できるデータセットがある場合に非常に便利です。

多次元配列の最初の次元のみを動的にすることができます。他のすべての次元では静的サイズを宣言する必要があります。これはテーブルに必要な“行”の数がわからない場合に役立ちます。例を見てみましょう。

                  double myDimension[][3];

                  int rows = 5;

                  ArrayResize(myDimension,rows);

最初の次元は空白でこれが動的配列であることを示しています。2番目の次元は3要素に設定されます。整数変数rowsは配列の最初の次元のサイズを設定するために使用されます。この値をArrayResize()関数の2番目のパラメータに渡します。例えば、rows = 5の場合、配列の最初の次元は5要素に設定されます。

配列は4次元まで持つことができますが、2次元または3次元以上が必要になることはめったにありません。ほとんどの場合、複雑なデータ構造を実装するには構造体の方が簡単です。この章の後半で構造について説明します。

配列の反復処理 P20

配列の主な利点は完全なデータセットを簡単に反復処理できることです。配列内のすべての要素の値を出力する例を次に示します。

                  string myArray[3] = {“チーズ”,”パン”,”エール”};

for(int index = 0; index < 3; index++)

{

                  Print(myArray[index]);

}

//Output : チーズ

            パン

            エール

サイズが3のmyArrayという名前の文字列配列を宣言します。配列内の3つの要素すべてをそれぞれ“チーズ”“パン”“エール”の値で初期化します。これにforループが続きます。forループはindexという名前のカウンター変数を0に初期化します。ループの反復ごとにindexの値を1ずつ増やします。indexが3未満である限りループし続けます。index変数は配列のインデックスとして使用されます。ループの最初の反復ではindexは0になるためPrint()関数はmyArray[0]の値をログ(この場合は“チーズ”)に出力します。次の反復ではindexは1になるためmyArray[1]の値がログに出力されます。

この章で前述したように最大配列インデックスより大きい配列要素にアクセスしようとするとプログラムは失敗します。配列をループするときは配列のサイズを知ることが重要です。上記の例では固定サイズの配列を使用しているため、配列のサイズは事前にわかっています。動的配列を使用している場合、または配列のサイズがわからない場合はArraySize()関数を使用して配列のサイズを決定できます。

int myDynamic[];

ArrayResize(myDynamic,10);

Int size = ArraySize(myDynamic);

for(int i = 0; i < size; i ++)

{

                  myDynamic[i] = i;

                  Print(i);              //Output: 0, 1, 2. . . 9

}

この例では配列myDynamicに10個の要素があります。ArraySize()関数は配列内の要素数を返し、その値をサイズ変数に割り当てます。次にサイズ変数を使用してforループの終了条件を設定します。このループはiの値をmyDyamic配列の各要素に割り当てます。

Forループについては第4章で説明します。ただし、ループを使用して配列のすべての要素を反復処理できることを覚えておいてください。この目的のために配列を頻繁に使用することになります。 

列挙(enum) P21

列挙型は整数値を表す定数のリストを定義する特殊な整数型です。列挙型で定義された値のみがその型の変数で使用できます。

例えば曜日を表す整数変数を作成する必要があるとします。1週間は7日しかないため、0未満または7より大きい値は必要ありません。また、説明的な定数を使用して曜日を指定したいと考えています。

ユーザーが曜日を選択できる列挙型の例を次に示します。

enum DayOfWeek

{

                  Sunday,

                  Monday,

                  Tuesday,

                  Wendnesday,

                  Thursday,

                  Friday,

                  Saturday,

};

これを列挙型として定義するには、型識別子enumを使用します。列挙型の名前はDayOfWeekです。週7つの曜日はコンマで区切られた格好内にリストされています。閉じ括弧はセミコロンで終わります

列挙型のメンバーには0から始まる連続番号が付けられます。つまり、日曜日=0、月曜日=1、土曜日=6などです。これらの整数値はたまたまMQL5が曜日のMqlDateTime構造で使用する値に対応しています。本書の後半でMqlDateTimeについて詳しく学びます。ENUM_DAY_OF_WEEK列挙もこれらの値を使用します。

列挙型を使用するには型識別子として列挙型の名前を使用して変数を定義する必要があります。この例ではDayという名前の変数を作成し、それに月曜日の値を割り当てます。

DayOfWeek Day;

Day = Monday;

Print(Day);       //Output: 1

最初の行では列挙型の名前であるDayOfWeekを型として使用します。これは注意すべき重要な概念です。列挙を作成すると、int、 double、 またはstringが型になるのと同じように列挙の名前が型になります。次に、列挙名を型識別子として使用してその型の変数を宣言します。この概念は、後で説明する構造体とクラスにも適用されます。

列挙型で定義された定数を使用して、Day変数に値を割り当てます。この場合、定数Mondayの値をDay変数に代入します。Day変数の値をログに出力すると、定数Mondayの整数値が1であるため結果は1になります。

列挙をゼロ以外の数値から開始したい場合はどうすればよいでしょうか?おそらく、列挙のメンバーに連続しない値を持たせたいと思いませんか?代入演算子(=)を使用して列挙内の各定数に値を割り当てることができます。次の例を示します。

enum yearIntervals

{

month = 1,

twoMonths,     //2

quarter,         //3

halfYear = 6,

year = 12,

}

この例はMQL5リファレンスから改作されました。列挙の名前はyearIntervalsです。最初のメンバー名はmonthで、値1が割り当てられます。次の2つのメンバーであるtwoMonthsとQuarterは1ずつ増分され、それぞれ2と3の値が割り当てられます。残りのメンバーには、それぞれの値が割り当てられます。

列挙が役立つ領域の1つはユーザーが選択できる一連の値を提供することです。例えば、EAでタイマー機能を作成していてユーザーに曜日を選択してもらいたい場合は前に定義したDayOfWeek列挙を入力パラメータの1つとして使用できます。ユーザーはEAの[プロパティ]ダイアログに定数のドロップダウンリストが表示されそこから選択できます。

MQL5には多くの定義済み標準列挙があります。MQL5のすべての標準列挙はENUM_で始まり、アンダースコア文字を含むすべての大文字です。MQL5リファレンスの標準定数、列挙及び構造で標準列挙を表示できます。

構造物 P23

構造体は様々なタイプの関連する変数のセットです。概念は列挙型に似ていますが、構造体のメンバーは任意の型にすることができます。MQL5にはいくつかの事前定義された構造があり、それらを頻繁に使用します。独自の構造を頻繁に作成する必要はないかもしれませんが、構造がどのように機能するかを知っておくことは重要です。

構造の例を見てみましょう。この構造体は、取引設定を保存するために使用できます。

sutruct tradeSettings

{

                  ulong slippage;

                  double price;

                  double stopLoss;

                  double takeProfit;

                  string comment;

};

型識別子structはこれを構造体として定義します。構造体の名前はtradeSettingsです。括弧内には6つのメンバー変数が定義されています。代入演算子(=)を使用してメンバー変数にデフォルト値を割り当てることができますが、通常はオブジェクトが初期化された後に値を割り当てます。

コードで構造体を使用する方法の例を次に示します。

                  tradeSettings trade;

                  trade.slippage = 50;

                  trade.stopLoss = StopLoss * _Point;

構造体名tradeSettingsをタイプとして使用して、tradeという名前のオブジェクトを定義します。このオブジェクトを使用すると構造体のメンバー変数にアクセスできます。オブジェクトについては第6章で詳しく説明します。構造体のメンバーにアクセスするには、オブジェクト名とメンバー名の間にドット演算子(.)を使用します。この場合、値50を構造メンバのスリッページに割り当て、計算されたストップロス値を構造メンバーstopLossに割り当てます。

MQL5の定義済み構造は取引サーバーから値を返すためによく使用されます。例えば、MqlTick構造体は銘柄の最新の時間、価格、および出来高を格納します。MqlTick構造体の定義は次の通りです。

struct MqlTick

{

datetime   time;       //価格が最後に更新された時刻

double     bid;        //現在のbid価格

double     ask;       //現在のask価格

double     last;      //最後の取引の価格(last)

ulong      volume;  //現在の最終価格の出来高

};

Mql構造体を使用するには、MqlTick型のオブジェクトを初期化します。次にSymbolInfoTick()関数を使用して取引サーバーからの現在のシンボルの時間、価格および出来高のデータをオブジェクトに入力します。

MqlTick price;

symbolInfoTick(_Symbol,price);

Print(price,bid);                   //現在のbid価格を返します。

タイプとして構造体名MqlTickを使用してpriceという名前のオブジェクトを定義します。オブジェクトをSymbolInfoTick()関数に渡します。この関数はサーバーからの現在の価格情報で満たされたオブジェクトを返します。この価格情報にアクセスするにはオブジェクト名とメンバー変数名の間にドット演算子(.)を使用します。式price.bidは現在のbid価格を返し、price.askは現在のask価格を返します。

本書の後半でMqlTick構造とその他の一般的に使用される構造について詳しく説明します。

タイプキャスティング  P24

ある型から別の型に値を返還するプロセスはタイプキャスティングと呼ばれます。変数の内容を別の型の別の変数にコピーすると内容は適切な型にキャストされます。注意しないと予期しない結果が生じる可能性があります。

ある変数から別の変数をコピーする場合、あるタイプから別の小さいタイプにコピーするとデータが失われる可能性があります。12ページの整数型の説明を思い出してください。int値をlong変数にコピーする場合、long型はより広い範囲の値を保持できるためデータが失われる可能性はありません。

小さい数値型を大きい数値型に自由にコピーできます。float値をdouble変数にコピーしてもデータが失われることはありません。ただし、double値をfloat変数にコピーするとdouble値が切り捨てられます。int値を short変数にコピーすると同じ結果になる可能性があります。これは浮動小数点型(doubleなど)を整数型にキャストする場合は特に当てはまります。小数点以下はすべて失われます。ただし、数値の小数部分が必要ない場合はこれで問題ありません。

大きな型の値を小さな型の変数にキャストする場合、コンパイラは『型変換によりデータが失われる可能性があります』というメッセージで警告します。大きな型の値が小さな型の範囲を超えないことが確実な場合はメッセージを無視しても問題ありません。それ以外の場合は新しい値を明示的に型キャストして警告を消すことができます。

例えば、整数値を必要とする関数にdouble値を渡す必要がある場合『型変換によりデータが失われる可能性があります』というエラーが発生します。変数の前に(int)を付けることで新しい値を整数としてキャストできます。

例えば:

                  double difference = (high - low) / _Point;

                  BuyStopLoss(_Symbol,(int)difference);

double変数差は2つの浮動小数点値を除算することによって計算されます。BuyStopLoss()関数では2番目のパラメータに整数値が必要です。difference変数を渡すとコンパイラの警告が発生します。差分変数名の前に(int)を付けることで差分の値を整数にキャストし、効果的に値を切り捨てコンパイラエラーを回避します。

入力変数 P25

MQL5プログラムの入力変数はユーザーが変更できる唯一の変数です。これらの変数はトレード設定、指標設定、ストップロスとテイクプロフィットの値などで構成されます。これらはプログラムの[プロパティ]ウィンドウの[入力]タブに表示されます。

入力変数の前にはinputキーワードがあります。入力変数は関数やその他のプログラムコードの前に、プログラムの先頭に配置されます。入力変数は列挙を含む任意の型にすることができます。配列と構造体は入力変数として使用できません。入力変数の識別子は明確で説明的である必要があります。

以下は、EAで表示される入力変数の例です。

                  input int MAPeriod = 10;

                  input ENUM_MA_METHOD MAMethod = MODE_SMA;

                  input double StopLoss = 20;

                  input string Comment = “ea”;

これらの入力変数は移動平均インジケータの期間と計算方法を設定し注文のストップロスを設定し、注文コメントを追加します。

入力変数にコメントを追加することで[入力]タブでわかりやすい表示名を設定できます。コメント文字列は[入力]タブの[変数]列に表示されます。上記で定義した入力変数と説明的なコメントを次に示します。

input int MAPeriod = 10;                       //移動平均期間

                  input ENUM_MA_METHOD MAMethod = MODE_SMA; //移動平均法

                  input double StopLoss = 20;                         //ストップロス(ポイント)

                  input string Comment = “ea”;                       //取引コメント

静的入力変数はsinputキーワードを使用して定義できます。静的入力変数の値は変更できますが、ストラテジーテスターで最適化することはできません。静的入力変数は入力パラメータの論理的なグループ化に役立ちます。文字列型のsinput変数を宣言しコメントを含めるだけです。

                  sinput string MASettings;       //移動平均の設定

下の図2.3は上記の入力変数が[プロパティ]ウィンドウの[入力]タブにどのように表示されるかを示しています。

図2.3‐変数名の代わりにコメントを表示する[入力]タブ

作製した列挙型を入力変数の型として使用するには、入力変数自体の前に定義する必要があります。この本の前半で定義したDayOfWeekを使用します。

enum DayOfWeek

{

sunday,

monday,

tuesday,

wednesday,

thursday,

friday,

saturday,

};

input DayOfWeek Day = monday;

これによりDayOfWeek列挙型をタイプとして使用し、Dayという名前の入力変数が作成されます。デフォルト値はMondayまたは1です。ユーザーがDay入力変数の値を変更しようとすると、列挙のすべての値を含むドロップダウンボックスが表示されます。

ローカル変数 P27

ローカル変数は関数内で宣言される変数です。関数が最初に実行されるときにローカル変数がメモリに割り当てられます。関数が終了すると、変数はメモリからクリアされます。

この例では、単純な関数を作成します。関数については第5章で詳しく説明します。関数内でローカル変数を宣言します。この関数のコードが実行されると、変数が宣言されて使用されます。関数が終了すると、変数はメモリからクリアされます。

void myFunction()

{

                  int varInt = 5;

                  Print(varInt);       //output: 5

}

この関数の名前はmyFunction()です。この関数はプログラムの別の場所から呼び出されて実行されます。変数varIntはこの関数の外からまたはプログラム内のどこからも参照できません。それらは関数の実行時に作成され関数の終了時に破棄されます。

変数のスコープを詳しく見てみましょう。ローカル変数のスコープは宣言されているブロックに限定されます。ブロックは関数または関数内の複合演算子として定義されます。ブロックは開き括弧と閉じ括弧で({})囲まれます。ブロック内で宣言された変数はそのブロックに対してのみローカルです。

関数の変更例を見てみましょう。

void myFunction()

{

                  bool varBool = true;

                  if(varBool) == true

                  {

                                   int varInt = 5

                                   Print(varInt);         //Output: 5

}

}

新しいローカル変数、varBoolという名前のブール変数を追加しました。if演算子ブロックも追加しました。if演算子、それに付随する角括弧及びそれらの中のコードは複合演算子です。括弧内で宣言された変数は、if演算子ブロックに対してローカルです。

if式は「varBoolにtrueの値が含まれている場合、カッコ内のコードを実行する」と読むことができます。この場合、式はtrueであるためカッコ内のコードが実行されます。varInt変数が宣言され値がログに出力されます。

Varint変数はif演算子ブロックに対してローカルです。つまり、varIntブロックの外では参照できません。ブロックが終了するとvarIntは範囲外になります。if演算子ブロックの外から参照しようとするとコンパイルエラーが発生します。

if(varBool == true)

{

                  int varInt = 5;

                  Print(varInt);          //Output: 5

}

varInt = 7;                     //これらの式はどちらも

Print(varInt);                  //エラーを生成します。

式varInt = 7はコンパイル時にエラーを生成します。if演算子ブロック内で宣言した変数varInt変数はスコープ外です。このコードを修正したい場合はif演算子ブロックの外側にあるvarInt変数を宣言するだけです。

if(varBool == true)

{

                  int varInt = 5;

                  Print(varInt);                //Output : 5

}

int varInt = 7;                           //これは別の変数です!

Print(varInt);                            //Output : 7

これで、このスコープにvarIntという名前の変数ができました。これはif演算子ブロック内で宣言されたvarInt変数とは異なる変数であることに注意して下さい。両方とも同じ名前を持っています。

別の例を次に示します。変数varIntが関数の先頭で宣言され、同じ名前と型の別の変数が、関数内にネストされたif演算子ブロック内で宣言されています。

void myFunction()

{

                  bool varbool = true;

                  int varInt = 7;

                  if(varBool == true)

                  {

                                   int varInt = 5;

                                   Print(varInt);                   //Output : 5

}

Print(varInt);                           //Output : 7

}

varIntという名前の整数変数が関数の先頭で宣言され、値7が割り当てられます。varIntという名前の2番目の整数変数がif演算子ブロック内で宣言され、値5で初期化されます。If演算子ブロック内のvarIntでは値5が出力されます。

if演算ブロックが終了し、再びvarIntの値を出力すると、今度は値7が出力されます。これは、関数の先頭で宣言された値と同じです!つまり、if演算子ブロック内で宣言されたvarInt変数は関数のスコープ内で宣言された変数をオーバーライドします。ちなみに、これをコンパイルしようとすると「'varInt’の宣言がローカル宣言を隠しています・・・」という警告メッセージが表示されます。上記の例は適切な方法とはみなされないため2番目のvarInt変数の名前を変更すると修正されます。

わかりやすくするために、if演算子ブロックの外側でvarInt変数を宣言し、if演算子ブロック内でそれを参照するとどうなるか見てみましょう。

void myFunction()

{

                  bool varBool = true;

                  int varInt = 5;

                  if(varBool == true)

                  {

                                   Print(varInt);           //Output : 5

}

}

varInt変数は関数スコープ内のif演算子ブロックの外で宣言されているため、これは期待どおりに機能します。より高いスコープで宣言された変数はネストされたブロックに同じ名前と型の変数がない限りネストされたブロック内のスコープ内にあります。

これは恣意的で紛らわしいように思えるかもしれませんが、最新のプログラミング言語のほとんどは変数スコープをこのように扱います。変数が宣言されているブロック内でのみローカルであることを要求することによりプログラミングエラー変数が同じ名前を共有している場合は防止されます。又、これはローカル変数がMQL4では関数内で宣言されたローカル変数は複合演算子又はブロック内で宣言されていても、その関数内のどこでも有効でした。

グローバル変数 P30

グローバル変数は関数の外で宣言される変数です。グローバル変数はプログラムの先頭で通常は入力変数の後に定義されます。グローバル変数のスコープはプログラム全体です。

前のセクションで示したようにブロック内で宣言されたローカル変数はより高いスコープで同じ名前と型の変数をオーバーライドします。これをグローバル変数に対して行うと「Declaration of variable hides global definition」というコンパイル警告が表示されます。この方法でグローバル変数をオーバーライドする実際的な理由はないので注意して下さい。

グローバル変数の値はプログラムのどこでも変更でき、それらの変更はプログラム内の全ての関数で利用できます。次に例を示します。

//グローバル変数

int GlobalVarInt = 5

void functionA()

{

                  GlobalVarInt = 7

}

void function()

{

                  Print(GlobalVarInt)             //Output : 7

}

グローバル変数GlobalVarIntはプログラムの先頭で宣言され、値5が割り当てられます。functionA()が最初に実行されると仮定します。これにより、GlobalVarIntの値が7に変更されます。FunctionB()が実行されると変更されたGlobalVarIntの値が出力されます。現在の値は7です。

プログラム全体で複数の関数からアクセスする必要がある変数がある場合は、プログラムの先頭でそれをグローバル変数として宣言します。関数呼び出し間で値を保持する必要があるローカル変数がある場合は代わりに静的変数を使用してください。

静的変数 P30

静的変数はプログラムが変数のスコープを出た場合でもメモリ内に残るローカル変数です。Static修飾子を先頭につけて静的変数を宣言します。関数内の静的変数の例を次に示します。

関数の呼び出しごとに静的変数は1ずつインクリメントされます。静的変数の値は関数呼び出し間で保持されます。

void staticFunction()

{

                  static int staticVar = 0;

                  staticVar++;               //staticVarを1ずつ増やします

                  Print(staticVar);           //Output : 1、2、3など

}

staticVarという名前の静的整数変数がstatic修飾子で宣言されています。関数の最初の呼び出しでstaticVarは0に初期化されます。変数は1ずつインクリメントされ、結果がログに出力されます。ログの最初のエントリーは1を読み取ります。この関数の次の呼び出しでは、staticVarの値は1になります。(ゼロに再初期化されないことに注意して下さい!)2がログに出力されます。

定義済み変数 P31

 MQL5には一般的に使用される値にアクセスするための定義済み変数がいくつかあります。事前定義された変数はアンダースコア文字(_)で始まります。これらの変数にはすべて同等の関数もありますが関数のパラメータとして頻繁に使用されるため、事前定義された変数の方が読みやすくなっています。

以下はMQL5で一般的に使用される定義済み変数のリストです。これらの変数はすべてプログラムが現在接続されているチャートのプロパティを参照します。

  • _Symbol ―現在のチャートの金融証券の記号。
  • _Period ―現在のチャートの分単位の期間。
  • _Point ―現在のsymbolのポイント値。5桁の外国為替通貨ペアの場合ポイント値は0.00001、3桁の通貨ペア(JPY)の場合ポイント値は0.001です。
  • _Digits ―現在のSymbolの小数点以下の桁数。5桁の外国為替通貨ペアの場合、桁数は5です。JPYペアは3桁です。

≪≪【日本語訳 第一章】MQL5の基本

【日本語訳 第三章】操作≫≫

-pekonoriブログ関連