ヒントとコツ P279
この章では、EAプロジェクトで役立つかもしれない追加のMQL5機能について説明します。エラーや取引イベントをユーザーに通知する方法について説明します。MetaTraderでチャートオブジェクトを操作し、CSVファイルを読み書きする方法を学びます。ターミナル変数を操作し、EAの実行を停止して取引ターミナルを閉じる方法を学びます。
ユーザー情報と交流する P279
取引アクション、エラーまたはその他のイベントをユーザーに通知する必要がある場合があります。このセクションでは、ダイアログボックス、電子メールとモバイル通知、サウンドアラート、チャートコメントについて説明します。
Alert()関数 P279
エラーやその他の不利な状況をユーザーに警告する必要がある場合は、組み込みの警告ダイアログが理想的です。アラートダイアログウィンドウには、アラートメッセージの実行中のログが表示され、それぞれの時間と記号が示されます。【ツール】メニューの【オプション】タブでサウンドイベントが有効になっている場合は、ダイアログが表示されたときにアラートサウンドが再生されます。
Alert()関数は、アラートダイアログを表示するために使用されます。Alert()関数は、任意の数の任意の型の引数を取ります。インクルードファイル全体でAlert()関数を使用してきました。たとえば、Trade.mqhのCTrade : :OpenPosition()関数でエラーが発生した時のAlert()関数呼び出しは次のとおりです。
Alert(“Open market order : Error ”, result.retcode,” – “, errDesc);
この関数には、文字列や整数変数など、すべてコンマで区切られた複数の引数があります。
図20.1 アラートダイアログ
MessageBOX()関数 P280
もう少し手の込んだものを好む場合、またはユーザー入力を受け入れる必要がある場合、MessageBox()関数を使用すると、ユーザー定義のテキスト、キャプション、アイコン、およびボタンを含む標準のWindowsダイアログボックスを表示できます。MassageBox()関数の定義は次のとおりです。
int MessageBox(
string text, //メッセージテキスト
string caption = NULL, //タイトルバーのキャプション
int flags= 0 //ボタンとアイコンの定数
);
textパラメータは、ダイアログウィンドウに表示するテキストです。キャプションパラメータは、ダイアログウィンドウのタイトルバーに表示されるテキストです。flagsパラメータは、表示するボタン、およびアイコンとデフォルトボタンを定義します。MessageBox()フラグは、標準定数… > 入力定数 > MessageBoxの下のMQL5リファレンスで表示できます。もっとも一般的に使用されるボタンフラグのいくつかを次に示します。
- MB_OK – OKボタン
- MB_OKCANCEL – OKボタンとキャンセルボタン
- MB YESNO – YESおよびNOボタン
- MB_RETRYCANCEL – リトライおよびキャンセルボタン
テキスト、キャプション、YES/NOを含む簡単なメッセージボックスを作成してみましょう。例えば、取引シグナルが受信されたときに注文を出すようにユーザーに促したい場合、次のようにします。
int place = MessageBox(“place the order?”, “Confirmation”, MB_YESNO);
これにより、下に示すメッセージボックスダイアログが作成されます。
図20.2-メッセージボックスダイアログ
アイコンを追加することで、メッセージボックスにコンテキストを追加できます。
ユーザーに質問を促すため、疑問符アイコンを使用します。
メッセージボックスアイコンのフラグは次のとおりです。
- MB_ICONERROR – 赤色のエラーアイコン
- MB_ICONQUESTION – 疑問符アイコン
- MB_ICONWARNING – 感嘆符/警告アイコン
- MB_ICONINFORMATION – 情報アイコン
メッセージボックスに疑問符アイコンを追加する方法を次に示します。フラグはパイプ文字(|)で区切る必要があります。
int place = MessageBox(“Place the order?”, “Confirmation”, MB_YESNO|MB_ICONQUESTION);
下の図20.3は、疑問符アイコンが付いたメッセージボックスダイアログを示しています。
図20.3-アイコン付きのメッセージボックスダイアログ
メッセージボックスが表示されたら、ユーザーがボタンをクリックすると、ボックスが閉じます。メッセージボックスが単純な情報またはエラーメッセージで【OK】ボタンが1つある場合は他に何もする必要はありません。ただし、複数のボタンがある場合は、ユーザーが押したボタンの値を取得し、適切なアクションを実行する必要があります。
以下の例では、place整数変数はMessageBox()関数の戻り値を保持します。【はい】ボタンの戻り値はIDYES、【いいえ】ボタンの戻り値はIDNOです。ユーザーが【はい】をクリックした場合は、注文に進む必要があります。
int place = MessageBox(“Place the order?”, ”Confirmation”, MB_YESNOMB_ICONQUESTION);
if(place == IDYES)
{
//オープンポジション
}
標準定数… > 入力/出力定数 > メッセージボックスの下のMQL5リファレンスで、メッセージボックス()ボタンの追加の戻り値定数を表示できます。
SendMail()関数 P281
取引が行われるたびにEAからメールが送信されるようにしたい場合は、注文の発注が確認された後、SendMail()関数をEAに追加するだけです。【ツール】メニュー > 【オプション】 > 【電子メール】タブで、MetaTraderの電子メール通知を有効にする必要があります。【電子メール】タブで、電子メールサーバー情報と電子メールアドレスを入力します。
SendMail()関数は2つのパラメータを取ります。1つ目はメッセージの件名で、2つ目はメッセージテキストです。たとえば、買いポジションが開かれた直後にメールを送信したい場合
//宣言を含める
#include <Mql5Book\Trade.mqh>
if(PositionSelect(_Symbol) == true)
{
string subject = “Buy position opened on ”+_Symbol;
string message = “Price: ”+PositionOpenPrice()+”, SL: ”+PositionStopLoss()+”,
TP: ”+PositionTakeProfit();
SendMail(subject, message);
}
PositionSelect()関数がtrueを返し、ポジションが正常に開かれたことを示す場合、電子メールの件名とメッセージ本文を準備し、それらの文字列変数をSendMail()関数に渡します。【ツール】メニュー > 【オプション】ダイアログの【電子メール】タブで定義した電子メールアドレスに電子メールが送信されます。
モバイル通知の送信 P282
MateTraderのモバイル版は、iPhoneおよびAndroidデバイスで利用できます。EAは、SendNotification()関数を使用して、スマートフォンのモバイルMetaTraderターミナルに取引通知を送信できます。【ツール】メニュー > 【オプション】 > 【通知】タブで、MetaTraderが通知を送信するように設定する必要があります。【通知】タブでは、MetaTraderのモバイルバージョンから取得できるMetaQuotesIDを入力します。
SendNotification()関数は、送信するテキストを示す文字列である1つのパラメータを取ります。SendNotification()関数は、SendMail()関数を使用する場所であればどこでも使用できます。次に例を示します。
//宣言を含める
#include <Mql5Book\Trade.mqh>
if(PositionSelect(_Symbol) == true)
{
string message = “Buy position opened on ”, +_Symbol+”. Price: ”+PositionOpenPrice()+”,
SL: ”+PositionStopLoss()+", TP: “+PositionTakeProfit();
SendNotification(message);
}
音を鳴らす P282
PlaySound()関数は、\SoundsディレクトリにあるWAVサウンドファイルを再生します。これは、取引が行われたとき、またはユーザーの注意が必要な時にいつでも可聴アラートを再生するために使用できます。MetaTraderにはいくつかのサウンドファイルが付属していますが、オンラインでさらに見つけることができます。
ユーザーがサウンドファイルを選択できるようにする場合は、入力文字列変数を使用してファイル名を入力します。
input string SoundFile = “alert.wav”;
// …
PlaySound(SoundFile);
Comment()関数 P283
Comment()関数は、チャートの左上隅にテキストを表示します。これは、注文の変数やクローズなどEAによって実行されたアクションをユーザーに通知するのに役立ちます。EA全体でComment()関数を使用して、有益なコメントをチャートに書き込んでいます。Trade.mqhのCTrade : : OpenPosition()関数の例を次に示します。
if(checkCode == CHECK_RETCODE_OK)
{
Comment(orderType,” position opened at “, result.price,” on “, pSymbol);
reture(true);
}
チャートコメントを使用する際の問題は、すべてのプログラムがこの機能にアクセスできることです。したがって、Comment()関数を使用してチャートにコメントを書き込むインディケータとEAがある場合、それらは互いに上書きします。チャートに常に存在する情報を表示する必要がある場合は、チャートオブジェクトの使用を検討してください。
チャートオブジェクト P283
チャートオブジェクトは、線、テクニカル分析ツール、図形、矢印、ラベル、およびその他のグラフィックオブジェクトで構成されます。【挿入】メニュー > 【オブジェクト】サブメニューを使用して、グラフにオブジェクトを挿入できます。MQL5には、チャートオブジェクトから情報を作成、操作、取得するための様々な関数があります。
オブジェクトの作成と変更 P283
ObjectCreate()関数は、新しいチャートオブジェクトを作成するために使用されます。ObjectCreate()の関数定義は次のとおりです。
bool ObjectCreate(
long chart_id, //チャート識別子
string name, //オブジェクト名
ENUM_OBJECT type, //オブジェクトタイプ
sub_window nwin, //ウィンドーインデックス
datetime time1, //最初のアンカーポイントの時間
double price1, //最初のアンカーポイントの価格
・・・
datetime timeN=0, //N番目のアンカーポイントの時間
double priceN=0, //N番目のアンカーポイント価格
)
chart_idパラメータは、オブジェクトを作成するチャートを指定します。常に現在のチャートで作業するため、chart_idは0になります。nameパラメータは、作成するオブジェクトの名前です。オブジェクトを使用する必要があるときはいつでも、この名前を参照する必要があります。typeパラメータは作成するオブジェクトのタイプです。ENUM_OBJECT列挙型の値を取ります。オブジェクトタイプは、MQL5リファレンスの【標準定数…】 > 【オブジェクト定数】 > 【オブジェクトタイプ】で確認できます。
nwinパラメータは、チャートのサブウィンドウのインデックスです。サブウィンドウは、別のウィンドウに表示されるRSIやストキャスティクスなどの指標によって開かれます。メインチャートウィンドウでオブジェクトを作成するため、nwinは0になります。time1およびprice1パラメータは、オブジェクトの最初のアンカーポイントの時間と価格です。ほとんどのオブジェクトには1つ以上のアンカーポイントの最初のセットは、使用されていない場合でも常に指定する必要があります。
オブジェクトが複数のアンカーポイントのセットを使用する場合は、それらも指定する必要があります。たとえば、ほとんどのトレンドラインオブジェクトは2つのアンカーポイントを使用します。そのため、ObjectCreate()関数では、アンカーポイントの2番目のセットが関数に渡されます。各タイプのオブジェクトのアンカーポイントの数は、MQL5リファレンスの【オブジェクト関数】 > 【ObjectCreate】で確認できます。
ObjectCreate()関数は、指定された場所にオブジェクトを作成します。ただし、オブジェクトのプロパティを設定する必要があります。
ObjectSet…()関数は、オブジェクトのプロパティを設定するために使用されます。ObjectSet…()関数には、ObjectSetInteger()、ObjectSetDouble()、ObjectSetString()の3つがあります。3つの関数はすべて同じパラメータを共有します。ObjectSetInteger()の関数定義を見てみましょう。
bool ObjectSetInteger(
long chart_id, //チャート識別子
string name, //オブジェクト名
int prop_id, //財産
long prop_value //価値
);
前に説明したように、chart_idは0になります。nameパラメータは、変更するオブジェクトの名前です。prop_idパラメータは、変更するプロパティを示すENUM_OBJECT_PROPERTY_INTEGER列挙の値を取ります。最後に、prop_valueパラメータは設定する値です。ENUM_OBJECT_PROPERTY_INTEGER定数は、標準定数… > オブジェクト定数 > オブジェクトプロパティの下のMQL5リファレンスで表示できます。
例として、トレンドラインオブジェクトを作成し、そのプロパティをいくつか設定してみましょう。トレンドラインのオブジェクトタイプはOBJ_TRENDです。トレンドラインには2つのアンカーポイントがあるため、時間と価格の値を2セット渡す必要があります。time1、time2、price1、およびprice2変数に適切な値が入力されていると仮定します。
datetime time1, time2;
double price1, price2
ObjectCreate(0, “Trend”, OBJ_TREND, 0, time1, price1, time2, price2);
これにより、現在のチャートに「Trend」という名前のトレンドラインオブジェクトが作成されます。次に、トレンドラインのいくつかのプロパティを変更しましょう。色、スタイル、右の線のプロパティを変更します。
ObjectSetInteger(0, “Trend”, OBJPROP_COLOR, clrGreen);
ObjectSetInteger(0, “Trend”, OBJPROP_STYLE, STYLE_DASH);
ObjectSetInteger(0, “Trend”, OBJPROP_RAY_RIGHT, true);
最初のObjectSetInteger()関数呼び出しは、OBJPROP_COLOR定数を使用して、色のプロパティを調節します。使用される値は、緑の色定数clrGreenです。関数の2番目の呼び出しは、OBJPROP_STYLE定数を使用して線のスタイルを調整します。値はENUM_LINE_STYLEタイプの定数である。STYLE_DASHです。最後に、OBJPROP_RAY_RIGHT定数を使用して、右の線プロパティをtureに設定します。右の線のプロパティは、トレンドラインを2番目のアンカーポイントを超えて右に延長します。
これで、右に伸びる緑色の破線のトレンドラインができました。上記のすべての例では、整数型を使用してプロパティを調整しています。各オブジェクトプロパティ定数に使用される型は、MQL5リファレンスの【標準定数…】 > 【オブジェクト定数】 > 【オブジェクトプロパティ】にリストされています。
図20.4 色、スタイル、光線右のプロパティが設定されたトレンドラインオブジェクト
オブジェクトを移動する必要がある場合、ObjectMove()関数を使用すると、オブジェクトのアンカーポイントの1つを調整できます。ObjectMove()の関数定義は次のとおりです。
bool ObjectMove(
long chart_id, // チャート識別子
string name, // オブジェクト名
int point_index, // アンカーポイント番号
datetime time, // 時間
double price // 価格
);
Nameパラメータは、変更するオブジェクトの名前です。point_indexパラメータは、変更するアンカーポイントです。アンカーポイントの番号は0から始めるため、最初のアンカーポイントは0、2番目のアンカーポイントは1、というようになります。時間と価格のパラメータは、指定されたアンカーポイントの時間と価格を変更します。
Lineオブジェクトから時間と価格を取得する P286
トレンドラインやチャンネルなどのラインオブジェクトを使用する場合、特定のバーでラインの価格値を取得する必要がある場合があります。バーのタイムスタンプがわかっていると仮定すると、価格を取得できます。ObjectGetValueByTime()関数は、指定された時間の価格を取得します。
double ObjectGetValueByTime(
long chart_id, // チャート識別子
string name, // オブジェクト名
datetime time, // 時間
int line_id // 行番号
);
いつものように、現在のチャートのchart_idは0です。nameパラメータは、チャート上の線オブジェクトの名前です。時間パラメータは、線と交差するバーのタイムスタンプです。line_idパラメータは、複数のラインを持つチャンネルオブジェクト用です。トレンドラインの場合、line_idは0になります。
上で作成した”Trend”ラインオブジェクトを使用して、現在のバーの価格を取得する方法を以下に示します。この本の前半で作成したCPrice : : Time()関数を使用します。
double trendPrice = ObjectGetValueByTime(0, “Trend”, Price.Time(), 0);
ObjectGetValueByTime()関数は、現在のバーのトレンドラインの値を返し、結果をtrendPrice変数に保存します。
では、価格があり、その価格に最も近いバーを知りたい場合はどうでしょうか?ObjectGetTimeByValue()関数は、ラインオブジェクトが特定の価格と交差するバーのタイムスタンプを返します。
datetime ObjectGetTimeByValue(
long chart_id, // チャート識別子
string name, // オブジェクト名
double value, // 価格
int line_id // 行番号
);
valueパラメータは、検索する価格です。この関数は、ラインが価格と交差する最も近いバーのタイムスタンプを返します。
datetime trendTime = ObjectGetTimeByValue(0, “Trend”, 1.265, 0);
ラベルと矢印のオブジェクト P287
この章の前半で、Comment()関数を使用して現在のチャートに情報を書き込むことについて説明しました。labelオブジェクトは、この目的にも使用できます。チャートコメントとは異なり、ラベルオブジェクトはチャートのどこにでも配置でき、好きな色やフォントを使用できます。
ラベルオブジェクトのオブジェクトタイプ定数はOBJ_LABELです。ラベルオブジェクトはアンカーポイントを使用しませんが、配置にはコーナー、x距離、y距離のプロパティを使用します。ラベルオブジェクトの作成と配置の例を次に示します。
ObjectCreate(0, “Label”, OBJ_LABEL, 0, 0, 0);
ObjectSetInteger(0, “Label”, OBJPROP_CORNER, 1);
ObjectSetInteger(0, “Label”, OBJPROP_XDISTANCE, 20);
ObjectSetInteger(0, “Label”, OBJPROP_YDISTANCE, 40);
「Label」という名前のラベルオブジェクトを作成し、OBJPROP_CORNERプロパティでObjectSetInteger()関数を使用して、位置を左隅に設定しました。ラベルは、左の境界から20ピクセル(OBJPROP_XDISTANCE)、下の境界から40ピクセル上(OBJPROP_YDISTANCE)にあります。
ObjectCreate()関数のtimeパラメータとpriceパラメータは、ラベル、オブジェクトの作成時に使用されないため、0に設定されていることに注意してください。コーナーには、左隅から反時計回りに0から3のラベルが付けられています。値1は左隅、3は右隅です。x距離とy距離は、指定されたコーナーからのピクセル単位で設定されます。
次に、ラベルオブジェクトの色、フォント、およびテキストを設定する必要があります。
double price = Bid();
ObjectSetInteger(0, “Label”, OBJPROP_COLOR, clrWhite);
ObjectSetString(0, “Label”, OBJPROP_FONT, “Arial”);
ObjectSetInteger(0, “Label”, OBJPROP_FONTSIZE, 10);
ObjectSetString(0, “Label”, OBJPROP_TEXT, “Bid: ”+(string)price);
図20.5 ラベルオブジェクト
10ポイントのArialフォントを使用して、ラベルオブジェクトの色を白に設定しました。ラベルのテキストには、現在の入札価格が含まれます。このコードが、実行されるたびに、ラベルオブジェクトは現在の入札価格で更新されます。
要約すると、ラベルオブジェクトは、有用な情報をチャートに出力するのに理想的です。オブジェクトはチャートウィンドウ自体に固定されており、チャートがスクロールされても移動しません。フォント、色、位置、およびテキストは完全に調整可能です。
最後に検討するオブジェクトタイプは、矢印オブジェクトです。注文時にチャート上に矢印を描きたいと思うかもしれません。MQL5は、OBJ_ARROW_BUYとOBJ_ARROW_SELLという、売買シグナルをマークするのに役立つ2つの矢印オブジェクトタイプを定義します。矢印オブジェクトは、1つのアンカーポイント(矢印を配置する価格と時間)を使用します。
string time = Price.time();
double price = Ask();
ObjectCreate(0, “BuyArrow” +time, OBJ_ARROW_BUY, 0, time, price);
図20.6 買い矢印オブジェクト
上記の例では、現在のバーの現在の売り気配価格で買い矢印オブジェクトを設定します。描画する各矢印が一意の名前を持つように、現在のバーの時間をオブジェクト名に追加します。このコードは、取引が行われた後に呼び出されます。
オブジェクトの削除 P288
オブジェクトを削除するにはObjectDelete()関数を呼び出して、chart_id(通常は0)とオブジェクト名を渡します。
ObjectDelete(0, “Label”);
チャートからすべてのオブジェクトを削除するには、ObjectDeleteAll()関数を使用します。特定のタイプのオブジェクトのみを削除するか、特定のサブウィンドウから削除するかを選択できます。現在のチャートからすべてのオブジェクトを削除するには、次の呼び出しを使用します。
ObjectsDeleteAll(0);
プログラムのOnDeinit()関数からこの関数を呼び出して、プログラムがチャートから削除されたときにすべてのオブジェクトが削除されるようにすることをお勧めします。
ファイル関数 P288
MQL5には、ファイルを読み書きするための一連の関数があります。たとえば、EA取引のログを作成したり、取引シグナルをファイルにインポート/エクスポートしたりできます。すべてのファイルは、MetaTrader5インストールの\MQL5\Experts\Filesフォルダーにある必要があります。
CSVファイルの読み書きの方法について説明します。CSV(コンマ区切り値)ファイルには、スプレッドシートによく似たデータが含まれています。MicrosoftExcelやGoogleSpreadsheetsなどのプログラムや、任意のテキストエディタでCSVファイルを作成および表示できます。この例では、CSVファイルの取引に関する情報が記録されます。ファイルの各行に、シンボル、始値、ストップロス、テイクプロフィット、トレードのオープン時間を書き込みます。次に、その情報をプログラムに読み込みます。
FilOpen()関数は、読み書き用にファイルを開きます。ファイルが存在しない場合は、作成されます。FileOpen()関数の定義は次のとおりです。
int FileOpen(
string file_name, //ファイル名
int open_flags, //フラグの組み合わせ
short delimiter = ‘\t’ //デルリミッター
uint codepage = CP_ACP //コードページ
);
file_nameパラメータは、\MQL5\Experts\Filesディレクトリのファイルの名前です。open_flagsパラメータには、ファイル操作を説明するフラグの組み合わせが含まれています。ファイルオープニングフラグは、表示定数… > 入力/出力定数 > ファイルオープニングフラグの下のMQL5リファレンスで表示できます。delimiterパラメータは、CSVファイルのフィールド区切り文字です。デフォルトはタブ文字ですが、カンマを使用します。codepageパラメータはデフォルトのままにします。
FileOpen()関数は、ファイルハンドルとして機能する整数を返します。ファイルに対して操作を実行するたびにファイルハンドルを参照する必要があります。ファイルを開くフラグについては、FILE_READ、FILE_WRITE、およびFILE_CSVの組み合わせを使用します。
CSVファイルへの書き込み P289
FileWrite()関数は、データ行をCSVファイルに書き込むために使用されます。次の例は、ファイルを開き、データ行を書き込み、ファイルを閉じる方法を示しています。
string symbol;
double openPrice, sl, tp;
datetime openTime;
//…
int fileHandle = FileOpen(“Trades.csv”, FILE_READ|FILE_WRITE|FILE_CSV, ”, ”);
FileSeek(fileHandle, 0, SEEK_END);
FileWrite(fileHandle, 0, symbol, openPrice, sl, tp, openTime);
FileClose(fileHandle, );
Symbol、openPrice、sl、tp、openTime変数には、ファイルに書き込む情報が含まれます。これらの変数には適切な値が入力されていると仮定します。FileOpen()関数は、「Trades.csv」という名前のファイルを作成します。フラグは、CSVファイルへの読み取りおよび書き込み権限を指定します。区切り文字はコンマになります。ファイルハンドルは、fileHandle変数に保存されます。
FILE_WRITEフラグを使用する場合は、ファイルから情報を読み取っていなくても、FILE_READフラグを追加する必要があります。これがないとFileSeek()関数が機能しないためです。FileSeek()関数は、ファイルポインターをファイル内の指定されたポイントに移動します。この例では、ポインターはファイルの末尾に移動されます。FileSeek()関数の最初のパラメータはファイルハンドル、2番目はバイト単位のシフト、3番目のパラメータは開始位置です。SEEK_END定数は、ファイルポインターをファイルの末尾に移動することを示します。既にデータが含まれているファイルを開くときに、ファイルポインタをファイルの末尾に移動しないと、データが上書きされます。したがって、データを書き込む前に常にFileSeek()を使用してファイルの末尾を特定します。
FileWrite()関数は、CSVファイルに1行のデータを書き込みます。最初のパラメータはファイルハンドルです。残りのパラメータは、ファイルに書き込まれるデータであり、表示される順序で指定されます。最大63個の追加パラメータを指定でき、それらは任意のタイプにすることができます。FileOpen()関数で指定された区切り文字は、CSVファイルの各データフィールドの間に配置され、改行文字(\r\n)が行末に書き込まれます。
最後に、FileClose()関数がファイルを閉じます。ファイルを使い終わったら、必ずファイルを閉じてください。そうしないと、別のプログラムで開くことができなくなる可能性があります。ファイルを長期間開いたままにして置く予定がある場合、または後続の読み取り/書き込み操作を行う場合は、FileFlush()関数を使用して、データをファイルに書き込むことなくファイルに書き込みます。
以下は、数行のデータが書き込まれたTrades.csvファイルの外観です。
EURUSD, 1.2345, 1.2325, 1.2375, 2012.11.15 04:17:41
EURUSD, 1.2357, 1.2337, 1.2397, 2012.11.15 04:20:04
EURUSD, 1.2412, 1.2398, 1.2432, 2012.11.15 04:21:35
左から右に、各行には、コンマで区切られたトレードシンボル、始値、ストップロス、テイクプロフィット、オープンタイムが含まれています。各行がファイルに書き込まれた後、新しい行が開始されます。
一度に複数行のデータをファイルに書き込む必要がある場合は、FileWrite()関数をループ内に配置し、必要な回数ループします。以下の例では、それぞれが同じ数の要素を持ち、適切なサイズでデータが入力された複数の配列があることを前提としています。(これには構造体配列を使用することもできます。)forループを使用して、データの各行をファイルに書き込みます。
string symbol[];
double openPrice[], sl[], tp[];
detetime openTime[];
//…
int fileHandle = FileOpen(“Trades.csv”, FILE_READ|FILE_WRITE|FILE_CSV, ”, ”);
FileSeek(fileHandle, 0, SEEK_END);
for(int i = 0; i < ArraySize(symbol); i++)
{
FileWrite(fileHandle, symbol[i], openPrice[i], sl[i], tp[i], openTime[i]);
}
FileClose(fileHandle);
Symbol[]配列でArraySize()関数を使用して、ループを実行する回数を決定します。iインクリメント変数は配列インデックスです。例えば、各配列に5つの要素がある場合、5行のデータをファイルに書き込みます。
CSVファイルからの読み取り P291
次に、CSVファイルからデータを読み取る方法を調べます。FileRead…()関数は、データの読み取りに使用されます。フィールドから適切な型に変換します。CSVファイルからデータを読み取るために使用される関数は4つあります。
- FileReadString() - CSVファイルから文字列を読み取ります。
- FileReadBool() - CSVファイルから文字列を読み取り、bool型に変換します。
- FileReadDatetime() - yyyy.mm.dd hh:mm:ss CSVファイルから文字列を読み取り、日時型に変換します。
- FileReadNumber() - CSVファイルから文字列を読み取り、double型に変換します。
FileReadNumber()関数を使用してCSVファイルから整数を読み取る場合、プログラムで整数型として使用する必要がある場合は、適切な型に変換する必要があります。
Trades.csvファイルのフィールドを調べると、各行に文字列、3つのdouble値、およびdatetime値があります。適切な関数を使用してファイルからデータの各フィールドを読み取り、正しい型に変換する必要があります。ファイルの内容全体を1行ずつ読み取り、結果を構造体配列に保存します。
struct Trades
{
string symbol;
double openPrice;
double sl;
double tp;
datetime openTime;
};
Trades trade[];
int i;
int fileHandle = FileOpen(“Trades.csv”, FILE_READ|FILE_CSV, “, ”);
while(FileIsEnding(fileHandle) == false)
{
ArrayResize(trade, ArraySize(trade) +1);
trade[1].symbol = FileReadString(fileHandle);
trade[1].openPrice = FileReadNumber(fileHandle);
trade[1].sl = FileReadNumber(fileHandle);
trade[1].tp = FileReadNumber(fileHandle);
trade[1].openTime = FileReadDatetime(fileHandle);
i++;
}
FileClose(fileHandle);
まず、CSVファイルから読み取ったデータを保持するためのtradesという名前の構造体を作成します。trade[]という名前の配列オブジェクトを作成し、インクリメント変数iを初期化します。FILE_READフラグとFILE_CSVフラグを使用してTrades.csvファイルを開きます。whileループは、一度に1フィールドずつ、ファイルからデータの各行を読み取ります。
FileIsEnding()関数は、ファイルの終わりに到達した場合はtrueの値を返し、それ以外の場合はfalseを返します。ファイルの終わりに達していない限り、次の行を読み続けます。ArrayResize()関数は、一度に1要素ずつ、trade[]配列のサイズを変更します。ArraySize()関数を呼び出して、trade[]配列の現在のサイズを取得し、それに1を追加してサイズを増やします。
FileRead…()関数は、ファイルからデータの各フィールドを読み取り、適切な型に変換します。結果は、trades[]配列の適切なメンバー変数に保存されます。現在の行が読み取られた後、i変数をインクリメントし、FileEnding()条件を再度チェックします。ループが終了したら、ファイルを閉じます。trade[]配列オブジェクトを使用して、CSVファイルから読み取ったデータにアクセスできるようになりました。
グローバル変数 P292
MetaTraderには変数をターミナルに保存する機能があり、ターミナルがシャットダウンされても保持されます。これらはグローバル変数と呼ばれます。端末に保存されたグローバル変数は、1か月後に削除されます。【ツール】メニュー > 【グローバル変数】をクリックするか、F3キーを押すと、ターミナルに保存されたグローバル変数を表示できます。
端末のグローバル変数と、プログラムのグローバルスコープで定義する変数を混同しないでください。プログラム内のグローバル変数はそのプログラムでのみ使用できますが、端末のグローバル変数はすべてのプログラムで使用できます。MetaTraderのグローバル変数を使用して、実行が中断された場合にプログラムの状態にする情報を保存できます。
図20.7-グローバル変数ウィンドウ
GlobalVariableSet()関数は、グローバル変数を端末に保存するために使用されます。変数の名前とそれに割り当てる値の2つのパラメータがあります。グローバル変数には必ず一意の名前を使用してください。たとえば、取引システムの名前の後に、変数の名前とそれが置かれているシンボルを使用できます。
string varName = “ForexRobot_TradeSize_”+_Symbol;
// 例: ForexRobot_TradeSize_EURUSD
GlobalVariableSet(varName, 1.5);
この例では、グローバル変数名はForexRobot_TradeSize_EURUSDです。現在のシンボルはEURUSDであるため、現在取引しているシンボルに基づいてグローバル変数を識別できます。値が設定または変更されるたびに、このグローバル変数を端末に保存します。
端末が予期せずシャットダウンした場合(コンピュータのクラッシュや電源障害)、GlobalVariableGet()を使用してグローバル変数の内容を読み取り、中断したところから続行できます。通常、これはOnInit()イベントハンドラで行います。
//OnInit()
string varName = “ForexRobot_TradeSize_”+_Symbol;
double tradeSize = GlobalVariableGet(varName)
プログラムが古いグローバル変数を使用しないようにするには、必要に応じてそれらを削除する必要があります。EAをチャートから手動で削除する場合、現在保存されているグローバル変数を削除する必要があります。GlobalVariableDel()関数を使用して、OnDinit()イベントハンドラでこれを行います。
void OnDeinit(const int reason)
{
String varName = “ForexRobot_TradeSize_”+_Symbol;
GlobalVariableDel(varName);
}
OnDinit()イベントハンドラは、多くの理由で呼び出されます。明らかに、プログラムがチャートから削除された場合、チャートが閉じられた場合、またはターミナルがシャットダウンされた場合に呼び出されます。ただし、入力パラメータが変更された場合、チャートの期間が変更された場合、またはテンプレートが適用された場合にも呼び出されます。これらの場合、グローバル変数を削除する前に初期化の理由を確認する必要があります。
OnDinit()関数のreasonパラメータには、初期化の理由が含まれています。MQL5リファレンスのStandard Constants… >Named Constants > Uninitalization Reason Codesの下にあるDeinitialization Codesを表示することができます。私たちが関心を持つのは、REASON_CHARTCHANGE、REASON_PARAMETERS、REASON_TEMPLATEのコードです。reasonパラメータにこれらのいずれかのコードが含まれている場合、グローバル変数を削除しません。
void OnDeinit(const int reason)
{
if(reason != REASON_CHARTCHANGE && reason !=REASON_PARAMETERS
&& reason != REASON_TEMPLATE)
{
string varName = “ForexRobot_TradeSize_”+_Symbol;
GlobalVariableDel(varName);
}
}
実行の停止 P294
EAの実行をプログラムで停止したい場合は、ExpertRemove()関数を使用します。現在のイベントの実行が完了すると、EAはその操作を停止し、チャートから削除されます。
ターミナルを閉じたい場合は、TerminalClose()関数がMetaTraderを閉じます。TerminalClose()関数は、1つのパラメータ(OnDiinit()関数に渡される初期化解除コード)を取ります。TerminalClose()関数を呼び出すときは、その後にreturn演算子を続ける必要があります。
TerminalClose(REASON_CLOSE);
Return;