『新メタトレ入門本』EAの基本プログラム
『新MT4対応 FXメタトレーダープログラミング入門』(新メタトレ入門本)連動企画です。
今回は、本書の第4章「エキスパートアドバイザー(EA)のプログラミング」「4-2 EAの基本プログラム」で紹介しているEAのサンプルプログラムについて説明します。
【目次】
第1章 メタトレーダーの紹介
第2章 スクリプトのプログラミング
第3章 カスタム指標のプログラミング
第4章 エキスパートアドバイザー(EA)のプログラミング
4-1 新規ファイルの作成
4-2 EAの基本プログラム
4-3 ストラテジーテスターによるEAの動作確認
4-4 EAのサンプルプログラム
4-5 EAのデバッグ
4-6 ストラテジーテスターによるEAの最適化
4-7 EAの自動売買のためのプログラミング
本書アップデート情報
このセクションでは、本書内容のアップデートはありません。
関連するMT5情報
本書のサンプルプログラムex1_ea.mq4は、モメンタムを売買シグナルとした基本的な途転売買のシステムです。
当然ながら拡張子を「mq5」にしてもMT5では動作しません。この記事では、コードの修正点を説明します。
修正するポイントは、すでに「2-6 トレード関数の使い方」「3-6 組み込みテクニカル指標関数の使い方」の記事で説明したところです。
テクニカル指標の取得
まず、1本前のバーにおけるモメンタムの値を「mon1」という変数に取得します。
モメンタムはMQL4と同じく組み込み関数iMomentum()を利用しますが、MQL5の場合、「組み込みテクニカル指標関数の使い方」の記事を参考にして、以下のように修正します。
int hMom; //モメンタムの指標ハンドル
double Buf[]; //モメンタム用配列
//初期化関数
int OnInit()
{
hMom = iMomentum(_Symbol, 0, MomPeriod, PRICE_CLOSE); //テクニカル指標の初期化
ArraySetAsSeries(Buf, true); //時系列配列に設定
return(INIT_SUCCEEDED);
}
//ティック時実行関数
void OnTick()
{
//1本前のモメンタム
CopyBuffer(hMom, 0, 0, 2, Buf);
double mom1 = Buf[1];
//省略
}
基本的にカスタム指標プログラムと同じ書き方をしています。そのため、外部変数、OnInit()関数、OnTick()関数を追加、修正しています。
注意するところは、モメンタムの指標値で必要なのは1本前のバーの値だけということです。
そのため、CopyBuffer(hMom, 0, 0, 2, Buf)のように、コピーする範囲を0から2個としています。つまり、最新のバーと、1本前のバーの計2本の指標値のみをコピーしています。
そして、Buf[1]にコピーされた指標値が1本前のモメンタムの値なので、それを「mon1」という変数に代入しています。
ちなみに、CopyBuffer()の3番目と4番目の引数を「0, 2」の代わりに「1,1」として、1本前の指標値のみコピーすることもできますが、その場合、1本前の指標値がBuf[0]にコピーされます。バーの位置と配列の添え字が一致しないので注意してください。
新規の売買注文
ex1_ea.mq4中では、OrderSend()が新規売買注文の関数です。この部分を「トレード関数の使い方(新規の売買注文)」の記事を参考にして、以下のように修正します。
MqlTradeRequest request = {};
MqlTradeResult result = {};
request.action = TRADE_ACTION_DEAL;
request.symbol = _Symbol;
request.volume = Lots;
request.price = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
request.type = ORDER_TYPE_BUY;
bool b = OrderSend(request, result);
if(result.retcode == TRADE_RETCODE_DONE) Ticket = result.order;
ただし、これは買い注文の場合で、売り注文の場合は、
request.price = SymbolInfoDouble(_Symbol, SYMBOL_BID);
request.type = ORDER_TYPE_SELL;
に代えてください。
また、カウントダウン注文の業者の場合、各注文に「request.type_filling」の指定を追加してください。
最後のif文は、「注文が成功した場合に、チケット番号を変数Ticketに代入する」という意味です。
ポジション情報の取得
ポジション情報の取得方法もMQL5用に変更する必要があります。
チケット番号からポジションを選択し、買いポジションであれば、「pos」を「1」に設定し、売りポジションであれば、「pos」に「-1」をセットします。
これも、「トレード関数の使い方(口座・ポジション情報)」の記事を参考にすると、以下のように記述することができます。
int pos = 0; //ポジションの状態
//未決済ポジションの有無
if(PositionSelectByTicket(Ticket))
{
if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) pos = 1; //買いポジション
if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL) pos = -1; //売りポジション
}
MQL4のOrderSelect()関数と違って、PositionSelectByTicket()はオープンポジションだけを選択するので、オープンポジションかどうかの判別は必要ありません。
ポジションの決済注文
売買シグナルとポジション情報により、ポジションを決済する注文を送信します。
MQL4では、OrderClose()を使いますが、MQL5では、OrderSend()を使います。「トレード関数の使い方(決済注文)」の記事を参考にすると、以下のように記述することができます。
MqlTradeRequest request = {};
MqlTradeResult result = {};
request.action = TRADE_ACTION_DEAL;
request.symbol = _Symbol;
request.volume = PositionGetDouble(POSITION_VOLUME); //ロット数
request.price = PositionGetDouble(POSITION_PRICE_CURRENT); //取引価格
request.type = ORDER_TYPE_BUY;
request.position = Ticket;
bool b = OrderSend(request, result);
if(result.retcode == TRADE_RETCODE_DONE) pos = 0; //決済成功すればポジションなしに
MQL5では、決済注文はポジションの逆取引を行う形なので、売り、買いを指定する必要があります。
上のコードは、売りポジションを決済するための買い注文となっています。買いポジションを決済する場合には、
request.type = ORDER_TYPE_SELL;
と売り注文にしてください。
また、新規注文と同様、カウントダウン注文の業者の場合、各注文に「request.type_filling」の指定を追加してください。
以上の修正を行った全体のプログラムを以下に示します。
最後に宣伝ですが、以下のkindle本の「共通ライブラリ」を利用すると、上のコードはこんな形で書けます。ご参考まで。