MT4のEA自動売買のプログラムをMT5に移植してバックテストしてみた! MQL5プログラミング

システム開発
スポンサーリンク

MT4の自作EAをMT5で動かすべく、MQL5プログラミングをマスター

自作のMT4自動売買のEAをMT5で動くようにプログラムを移植してみました!

いきなりつまずいたのが、パラメータの設定です。

EAプログラムの重要な設定ですね。

MT4で使えたextern 〇〇が機能しません。

extern int パラメータ名= 値; //EAのパラメータ画面で変更させる
inputは使用できますが、なぜかコンパイルでエラーが発生します。

例:input double Lots = 0.1;

MT5のパラメーター設定画面で変更できなくても、MetaEditorで直接プログラムを書き換えればパラメーター値は変更できるので、そのままにして開発を進めます。

MT4で使えた関数Hour()やMinute()が廃止?代わりに使用する関数は?

MT4のEAで使えた、Hour()Minute()といった時間の関数がMT5では使用できなくなりました。

調べた結果、以下のプログラムで動作確認できたので、今回はこのプログラムを使用します。

datetime tm=TimeCurrent();
MqlDateTime stm;
TimeToStruct(tm,stm);

//— output date components
//(“Year: ” +(string)stm.year);
//(“Month: ” +(string)stm.mon);
//(“Day: ” +(string)stm.day);
//(“Hour: ” +(string)stm.hour);
//(“Minute: ” +(string)stm.min);
//(“Day of the week: “+(string)stm.day_of_week);

/* 以下 MQL4からMQL5に変更
Year()↓
stm.year

Month()↓
stm.mon

Day()↓
stm.day

Hour()↓
stm.hour

Minute()↓
stm.min

DayOfWeek()↓
stm.day_of_week
*/

//使用例 4月は夏時間
if ( stm.mon == 4 ){
SummerTime = true;
}

MT4で使えたStringConcatenate関数が使用できない、その代わりにMT5ではStringFormat関数が使えるはずだが

EAを動かしている時に、チャートの左上にコメントを表示させるときに、MT4では以下のようなプログラムを書いていました。

message = StringConcatenate(“時間” , Hour() , “時”);

Comment(message);// 実行結果⇒時間〇時

MT5ではStringConcatenate関数が使えないので、代わりにStringFormatを使用しました。

message = StringFormat(“時間” , stm.hour , “時”);

Comment(message);// 実行結果⇒時間〇時

なぜか最初の時間という文字だけ表示され、stm.hour以降の文字が表示されませんでした。

チャート上に表示させるコメントは無くても構わないので、そのままにして開発を進めました。

ちなみに関数や引数1個だけならコメント表示できます.

Comment(stm.hour);// 実行結果⇒時刻0~24

MT4で多用したClose[i]関数やOpen[i]関数が廃止に!MT5で使える代替関数は?

MT4ではClose[1] – Close[2]のように、1本前の足の終値であればClose[1]、2本前の足の終値であればClose[2]で簡単にレートを取得することができました。

しかし、MT5ではこの関数が廃止されており、MT4⇒MT5への移行の妨げになっています。

EAやインジケーターにとって重要な関数なので、この問題をクリアしなければなりません。

4~5時間情報を探し、ようやく見つけた解決策が以下です。

/* 以下 レート取得はiClose関数やiOpen関数を使用する
int shift=0; //– 0,1,2,3… 0を起点とした配列数
datetime time = iTime(Symbol(),Period(),shift);
double open = iOpen(Symbol(),Period(),shift);
double high = iHigh(Symbol(),Period(),shift);
double low = iLow(Symbol(),Period(),shift);
double close = iClose(NULL,PERIOD_CURRENT,shift);
long volume= iVolume(Symbol(),0,shift);
int bars = iBars(NULL,0);
*/

PERIOD_CURRENT⇒現在の時間軸(チャートの足)

shift⇒取得する足の値

iCloseの使用例

            Close_TimeScale_1 = iClose(NULL,PERIOD_CURRENT,1);
            Close_TimeScale_2 = iClose(NULL,PERIOD_CURRENT,2);

上記のプログラムでは、Close_TimeScale_1に1本前の足の終値がClose_TimeScale_2に2本前の足の終値が代入されます。

つまり、Close[1]Close_TimeScale_1 = iClose(NULL,PERIOD_CURRENT,1);で求めることができます。

MT4のEAをMT5に移植する最後の難関はポジション集計とオーダー関数

MT4のEAのポジション集計とオーダー関数は、そのままではMT5で使用することができません。

MQL5のOrderSendの関数は、MQL4のOrderSendとは別の仕組みで作られています。

簡単なプログラムであれば、MT5のオーダー関連のテンプレートをカスタマイズすることで対応可能です。

ナンピンマーチンゲール手法など複雑なオーダー処理が求められるプログラムともなると大変です。

現在のポジションの集計は下記のプログラムで対応しました。

// ———————–以下 保有ポジションの集計 ———————————-
//— 結果とリクエストの宣言
MqlTradeRequest request;
MqlTradeResult result;
int total=PositionsTotal(); // 保有ポジション数
//— 全ての保有ポジションの取捨
for(int i=total-1; i>=0; i–)
{
//— 注文のパラメータ
ulong position_ticket=PositionGetTicket(i); // ポジションチケット
string position_symbol=PositionGetString(POSITION_SYMBOL); // シンボル
int digits=(int)SymbolInfoInteger(position_symbol,SYMBOL_DIGITS); // 小数点以下の桁数
ulong magic=PositionGetInteger(POSITION_MAGIC); // ポジションのMagicNumber
double volume=PositionGetDouble(POSITION_VOLUME); // ポジションボリューム
ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); // ポジションタイプ
//— ポジション情報の出力
PrintFormat(“#%I64u %s %s %.2f %s [%I64d]”,
position_ticket,
position_symbol,
EnumToString(type),
volume,
DoubleToString(PositionGetDouble(POSITION_PRICE_OPEN),digits),
magic);
//— MagicNumberが一致している場合
//— MagicNumberが一致している場合
if(SelectPosition(MAGIC))
// {
//— リクエストと結果の値のゼロ化
ZeroMemory(request);
ZeroMemory(result);
//— 操作パラメータの設定
request.action =TRADE_ACTION_DEAL; // 取引操作タイプ
request.position =position_ticket; // ポジションチケット
request.symbol =position_symbol; // シンボル
request.volume =volume; // ポジションボリューム
request.deviation=5; // 価格からの許容偏差
request.magic =MAGIC; // ポジションのMagicNumber
//— ポジションタイプによる注文タイプと価格の設定
if(type==POSITION_TYPE_SELL && LongSign == true && UpdateOnOff == true)//ドテンロング(常にポジションを持つ)
{
request.price=SymbolInfoDouble(position_symbol,SYMBOL_ASK);
request.type =ORDER_TYPE_BUY;
// ———————–以下 決済注文——————————
ExtTrade.PositionClose(Symbol(), 3); //売り買い問わず、決済注文送信の形式は同じ。
Comment(“ショートポジションを決済買戻し”);
// ———————–以上 決済注文——————————
}
else if(type==POSITION_TYPE_BUY && ShortSign == true )//ドテンショート(常にポジションを持つ)
{
request.price=SymbolInfoDouble(position_symbol,SYMBOL_BID);
request.type =ORDER_TYPE_SELL;
// ———————–以下 決済注文——————————
ExtTrade.PositionClose(Symbol(), 3); //売り買い問わず、決済注文送信の形式は同じ。
Comment(“ロングポジションを決済売り”);
// ———————–以上 決済注文——————————
}

    //--- 決済情報の出力
 //   PrintFormat("Close #%I64d %s %s",position_ticket,position_symbol,EnumToString(type));
    //--- リクエストの送信
  //  if(!OrderSend(request,result))
  //    PrintFormat("OrderSend error %d",GetLastError()); // リクエストの送信に失敗した場合、エラーコードを出力
    //--- 操作情報 
 //   PrintFormat("retcode=%u  deal=%I64u  order=%I64u",result.retcode,result.deal,result.order);
    //---

}

// ———————–以上 保有ポジションの集計 ———————————-

int total=PositionsTotal(); // 保有ポジション数

totalがゼロなら保有ポジションは無いので、以下で新規オーダーをリクエストします。

//■□■□■□■□■ 新規注文 ■□■□■□■□■

if (total == 0 && LongSign == true ){
// ポジション保有していない場合(新規ロングオーダー処理を行う)
if(spread0 <= MaxSpread) {
//買い新規注文を送信する。
ExtTrade.PositionOpen(Symbol(), ORDER_TYPE_BUY, Lots, SymbolInfoDouble(Symbol(), SYMBOL_ASK), 0, 0);
Comment(“ロングオーダー”);
}
}
else if (total == 0 && ShortSign == true){
// ポジション保有していない場合(新規ショートオーダー処理を行う)
if(spread0 <= MaxSpread) {
//売り新規注文を送信する。
ExtTrade.PositionOpen(Symbol(), ORDER_TYPE_SELL, Lots, SymbolInfoDouble(Symbol(), SYMBOL_BID), 0, 0);
Comment(“ショートオーダー”);
}
}

以上の修正を加え、MT4のオリジナルEAをMT5で動かすところまでたどり着きました。

オーダー関連は、下記2サイトを参考にプログラムを組んでみました。

参考にしてください。

Qiita fxst24さんの記事
https://qiita.com/fxst24/items/d745594af8a391e6a60a

MQL5 リファレンス公式
https://www.mql5.com/ja/docs/constants/tradingconstants/enum_trade_request_actions

ポンド円の2020年12月~2021年2月のバックテスト結果

まだ粗削りなプログラムですが、どんどんカスタマイズしていきます。

最後までお読みいただきありがとうございます。

タイトルとURLをコピーしました