MQL4からMQL5へ変換してFX自動売買EAを移植する手順

二つの作業環境をつなぐ橋と部品を整理する移植作業のイメージ

MQL4からMQL5への変換は、拡張子を変える作業ではなく、MT4用EAの処理をMT5の仕様に合わせて移植する作業です。手元に編集できるソースと必要な利用権限があっても、指標の読み方や保有ポジションの管理が変わるため、コンパイルできただけでは完了しません。

FX自動売買の移植では、まず売買ルールを固定し、データ取得、シグナル、注文、決済の順に移し、同じ時刻の足と売買判断を照合します。この記事では、自作または改変・移植が認められたEAを対象に、変換前に整理するものと、結果がずれたときの確認順を説明します。実行ファイルだけを持つ場合や、購入品の改変可否が分からない場合は、先に提供元へMT5版と利用条件を確認してください。

この記事のポイント
  • ソースと依存ファイルを確認して移植できる範囲を決める
  • 指標の数値取得と注文・ポジションの管理を分けて直す
  • 発注しない照合から始めて元の売買ルールを保つ
  • 最初にずれた足と処理を特定して再検証する
目次

MQL4からMQL5へ変換するFX自動売買の設計

二つの異なる差し込み形状と接続部品を確認する手元
説明用の生成イメージです。

拡張子と変換できる範囲を確認する

MT4ではソースが.mq4、実行用ファイルが.ex4、MT5ではそれぞれ.mq5、.ex5です。.mq4を.mq5へ名前変更しても、記述された関数や売買処理がMQL5仕様へ書き換わるわけではありません。.ex4を.ex5へ変える方法でもMT5用の実行ファイルにはなりません。MetaEditor公式のコンパイル説明で、ソースから対応する実行形式を作る工程を確認できます。

最初に、メインの.mq4だけでなく、取り込んでいる.mqh、カスタム指標、DLL、設定ファイルなどを洗い出します。EA本体を直しても、呼び出す指標がMT4版のままなら同じ仕組みで値を読めるとは限りません。外部ファイルの仕様や権利が不明な箇所は、変換できたと仮定せず未解決の依存関係として扱います。

移植前の仕様は「どの足の何が成立したら、何ロットで入り、どの条件で閉じるか」を文章にします。例えば「確定足の終値が20期間単純移動平均を下から上へ抜け、自分のEAの保有がないときに買う」なら、足の確定時点、比較する前の足、保有の数え方まで定義します。ここが曖昧なままだと、修正したコードが元の戦略を再現したか判断できません。

MT4とMT5のどちらを選ぶかがまだ決まっていない場合は、MT4とMT5の違いとEA運用の選び方から、利用先の対応状況を確認できます。この先は、MT5へ移す目的と、扱うソースの範囲が決まっている場合の手順です。

イベントと価格取得を対応させる

古いMQL4コードではinit、start、deinitが使われている場合があります。MQL5では、初期化はOnInit、終了処理はOnDeinit、EAの新しいティックに反応する処理はOnTickへ役割を分けます。ただし、MQL4にもOnInitやOnTickを使うコードがあるため、すべてのEAで関数名の変更が必要とは限りません。現在のコードがどのイベントで何をしているかを先に読みます。

また、スクリプトの入口であるOnStartと、指標計算用のOnCalculateは、EAのOnTickと用途が異なります。startという名前だけを見て一律にOnTickへ置き換えず、元のプログラムがEA・指標・スクリプトのどれかを確かめます。引数と戻り値の型も正しくないとイベント処理として呼ばれません。定義はMQL5公式のイベント処理一覧と照合してください。

価格の取得も整理します。MQL4のBidやAskを同名の変数として残すのではなく、例えばMQL5のSymbolInfoTickで対象銘柄のMqlTickを取得し、bid・askを読みます。関数の成否を確かめ、取得できなかった価格をそのまま条件判定へ渡さない処理にします。SymbolInfoTickの公式仕様に、取得先の構造体と戻り値が示されています。

時間足や注文種別の定数も、数字の値を流用せずPERIOD_H1など意味の分かる定数へ寄せます。価格や時刻の読み取りを一か所にまとめると、その後のシグナル照合で入力が同じか確認しやすくなります。細かな表記を直す作業と、売買するタイミングを変える作業を同時に進めないことがポイントです。

役割ごとに分けた小さな部品を順に確認する机
説明用の生成イメージです。

指標はハンドルと値取得を分ける

代表的な違いがiMAです。MQL4のiMAは指定した足の移動平均値を返しますが、MQL5のiMAは指標を扱うためのハンドルを返します。ハンドルは移動平均の価格ではありません。戻り値をdoubleの変数へ入れて数値として比較できても、それが欲しかった指標値とは限らない点に注意します。

MQL4で「iMA(NULL,0,20,0,MODE_SMA,PRICE_CLOSE,1)」と書いた場合、末尾の1は読む足の位置です。MQL5では、まずiMA(_Symbol,_Period,20,0,MODE_SMA,PRICE_CLOSE)でハンドルを作り、別にCopyBufferでバッファ0の開始位置1から必要な値を読みます。iMAのma_shiftは線の横方向のずれであり、読む足の指定とは別です。MQL4のiMAとMQL5のiMAの引数・戻り値を比較すると確認できます。

通常はOnInitでハンドルを作り、INVALID_HANDLEなら初期化を失敗させます。計算できたデータ量をBarsCalculatedで確認し、CopyBufferの戻り値が要求件数と一致したときだけ値を使います。準備中や取得失敗を「指標値が0」「条件不成立」に置き換えると、移植前後の違いが隠れてしまいます。使用を終えたハンドルの解放にはIndicatorReleaseを使います。

CopyBufferの開始位置0は形成中の現在足、1は一つ前の足です。複数件取得する際は、古い要素が物理メモリの先頭に置かれる仕様と、配列の添字の読み方を区別します。移植直後は一件だけ取得して、足時刻と値の対応を確認してから件数を増やすと混乱を減らせます。仕様はCopyBufferとBarsCalculatedの公式説明を参照できます。

カスタム指標を使うEAでは、その指標のMT5版と入力・バッファの対応も必要です。MQL4側の呼び出し条件を整理したい場合は、iCustomで同じ足の指標値を照合する手順を補助にできます。MQL5の呼び出しはハンドル方式なので、MQL4の末尾引数をそのままコピーする方法とは分けてください。

注文・約定・ポジションを分ける

売買処理では、関数名の置き換え以上に「何を数え、何を変更するか」の見直しが必要です。MQL5では、注文は売買の依頼、約定は実行された取引、ポジションは現在保有している状態として区別します。一つの注文と一つのポジションが、いつも同じ意味の番号になる前提を持ち込まないようにします。

スクロールできます
移植する処理MQL4で見かける書き方MQL5で整理する対象
保有数の確認OrdersTotalとOrderSelectで注文を走査保有ポジションと未約定注文を分けて確認
新規注文引数を並べたOrderSendMqlTradeRequest/MqlTradeResult、または標準のCTrade
決済・変更選択した注文のチケットで処理対象ポジションか未約定注文かを先に確定
履歴の分析決済済み注文を参照注文履歴と約定履歴の目的を分ける

MQL4のOrdersTotalは成行・未約定注文の数を返します。一方、MQL5のOrdersTotalを保有数の代わりに使うと、ポジションを持っているのに「0だから新規発注してよい」と誤判定するおそれがあります。MQL4のOrdersTotalとMQL5のOrdersTotalを別仕様として読み、ポジションの確認処理を独立させましょう。

依頼の封筒と処理中の部品と完成した組立品を分けた様子
説明用の生成イメージです。

さらに、MT5には同一銘柄を一つのポジションへまとめるネッティング方式と、複数ポジションを持てるヘッジング方式があります。例えば独立した買い二件を個別決済するEAを、ネッティング口座へ同じ意味のまま移せるとは限りません。両建てや複数ロジックを前提にしているなら、利用予定口座の方式とEAの設計が合うかを先に確かめます。

ヘッジング方式でもPositionSelect(symbol)だけで全保有を処理したことにはなりません。公式仕様では、その銘柄のうち最小チケットのポジションが選ばれます。複数件を扱う設計ならチケット単位で対象を選び、銘柄とマジックナンバーなどで自分のEAの管理対象か確認します。詳しくはPositionSelectの公式説明を参照してください。ネッティングで複数EAが同じ銘柄を共有する場合は、識別番号を付けるだけで保有を独立させられるとは考えないことも大切です。

データから決済へ順番に移植する

実装は、価格・指標を読める状態、売買シグナルだけを出す状態、発注できる状態、決済と異常時処理までできる状態の順に進めると切り分けやすくなります。初日から一括変換して実口座へ入れると、誤った値の取得と誤った注文の扱いが重なり、どちらから直すべきか分かりにくくなります。

発注部分を移すときは、MQL5のOrderSendはMqlTradeRequestとMqlTradeResultを受け取る別の書式だと確認します。戻り値がtrueでも約定完了を保証しません。result.retcodeを確認し、必要に応じて取引イベントや実際の保有状態まで追います。公式のOrderSendの説明には、送信の受け付けと取引の実行を分ける必要が示されています。

CTradeを使えば標準ライブラリで売買処理を組めますが、元のEAと同じ戦略になることまでは保証されません。例えばBuyの成否確認でも、戻り値だけでなく取引サーバーの結果コードと約定情報を調べます。CTradeのBuy公式説明に従い、失敗した注文を成功済みとして内部状態へ反映しないようにします。

工程ごとに部品を一つずつ組み立てる作業台
説明用の生成イメージです。

ロット刻み、最小・最大数量、ストップの最小距離、許可される注文や約定方式は、移植先の銘柄から取得して照合します。元コードの固定値を残したまま拒否されたからといって、損切りなどの制限を外して通す方法では原因の解決になりません。取得項目はMQL5公式の銘柄プロパティ一覧で確認できます。

変換ツールやAIは、候補コードの作成や関数の洗い出しを助ける道具として使えます。ただし、未対応関数を空の処理にする、注文失敗を無視する、元にない再試行を追加する、といった変更がないかレビューが必要です。外部サービスへ渡す前には、コードの共有権限と、埋め込まれた口座情報・キー・独自ロジックの扱いも確認します。最終判断は、生成された説明の自信ではなく、仕様と実際の照合結果で行います。

MQL4からMQL5へ変換した後の検証

同じ条件で二つの部品を並べて比較する検証イメージ
説明用の生成イメージです。

比較条件をそろえて基準を作る

最初の比較は、利益を増やす最適化ではなく、元のルールを保てたかの確認です。MT4側で使っていた入力値を固定し、MT5側も対応する値にします。移植と同時に移動平均の期間や損切り幅を変更すると、違いが変換によるものか、戦略の変更によるものか判別できません。

スクロールできます
そろえる条件確認内容違うときの扱い
EAと入力値ソースの版、期間、判定する足、数量、売買時間変更箇所を分離してから比較
価格データ銘柄、履歴の範囲、足時刻、価格の欠損同じ価格入力の区間を先に選ぶ
口座と銘柄仕様口座方式、契約サイズ、数量刻み、通貨、取引時間完全一致しない条件を明示
テスト条件対象期間、モデル、スプレッド、手数料、スワップ異なる費用やティックを混ぜて評価しない
初期状態保有なしで開始するか、起動直後の判定方法開始条件を合わせてやり直す

MT4とMT5で同じ銘柄名と期間を選べても、配信元の価格、ティック、タイムゾーン、日足の区切りなどが同じとは限りません。入力データの違うテストで損益が一致しないことだけを、移植失敗の証拠にはしないでください。可能な範囲で同じ足時刻とOHLCを照合し、比較できる区間と差の残る条件を分けます。

MT5のストラテジーテスターには複数のモデルや設定があります。使える範囲の詳細はMetaTrader 5公式のテスト手順を確認します。具体的な操作はMT5でEAをバックテストする設定と結果の確認手順で補えます。ここでは設定画面を一巡するより、移植前後で何を同一条件として比べるかを重視します。

まず発注しないコードで値を照合する

次は、現在のチャートの一つ前の足について、20期間の単純移動平均を一件読むMQL5の観察用EA例です。売買注文は含みません。自作EAの判定へ組み込む前に、MT4側で同じ銘柄・時間足・足時刻を選び、同じ移動平均設定の値と対応するか確認するための小さな入口です。

このコードは解説用で、この環境ではMetaEditorでのコンパイルやMT5での実行は確認していません。手元の版でコンパイル結果を確かめ、発注しない検証環境で使ってください。期間20や表示桁数は例示であり、推奨する売買条件や精度の保証ではありません。

接続前の機器を単独で点検する手元
説明用の生成イメージです。
#property strict
int maHandle = INVALID_HANDLE;
datetime lastLogged = 0;

int OnInit()
{
   maHandle = iMA(_Symbol, _Period, 20, 0, MODE_SMA, PRICE_CLOSE);
   if(maHandle == INVALID_HANDLE) return INIT_FAILED;
   return INIT_SUCCEEDED;
}

void OnTick()
{
   datetime bar = iTime(_Symbol, _Period, 1);
   if(bar == 0 || bar == lastLogged) return;
   if(BarsCalculated(maHandle) < 21) return;

   double value[1];
   ResetLastError();
   int copied = CopyBuffer(maHandle, 0, 1, 1, value);
   int error = GetLastError();
   if(copied != 1)
   {
      Print("CopyBuffer unavailable: ", copied, " error=", error);
      return;
   }
   if(iTime(_Symbol, _Period, 1) != bar) return;

   Print("bar=", TimeToString(bar, TIME_DATE|TIME_MINUTES),
         " ma=", DoubleToString(value[0], 12));
   lastLogged = bar;
}

void OnDeinit(const int reason)
{
   if(maHandle != INVALID_HANDLE) IndicatorRelease(maHandle);
}

lastLoggedへ時刻を入れるのは、取得に成功してからです。先に「この足は処理済み」とすると、データの準備が間に合わなかった足を再確認できなくなります。また、取得前後の足時刻が違う場合は出力を見送ります。これは指標計算全体を完全に固定する仕組みではなく、処理中に対象の足が変わった状態を比較へ混ぜにくくするための確認です。

本体へ戻す際は、移動平均だけでなく終値や前の足の値も同じ時刻で確認します。クロス判定なら直近の確定足とその一つ前の足をそろえ、単に「今は上にある」ことと「下から上へ抜けた」ことを混同しません。複数件の値取得へ拡張した時点で、添字と足時刻の対応ももう一度確かめます。

新規注文から例外処理まで試す

価格とシグナルが対応したら、デモ口座またはテスターで売買処理を段階的に確認します。「一度買えた」だけでは、移植に必要な決済や管理の確認が残ります。元のEAが備える処理ごとに、発生条件、操作対象、期待する変化を決め、該当する場面を用意します。次の表は検証項目の例であり、実測結果ではありません。

正常な部品と動きが止まった部品を別に置いて点検する様子
説明用の生成イメージです。
スクロールできます
確認場面期待する動きの例見落としやすい箇所
保有なしで条件成立予定した一件だけ発注同じシグナルでの二重発注
注文が失敗失敗状態のまま原因を確認成功済みフラグや無制限再送
一部数量を決済意図した対象と数量だけ変化別チケットの決済や数量刻み
指値・逆指値が残る新規保有と未約定注文を区別OrdersTotalだけでの保有判定
再起動・再接続既存保有と処理状況を再確認内部変数が消えた後の追加注文
複数件の保有自分の管理対象だけ処理銘柄だけで一件を選ぶ処理

発注の直後に内部の保有フラグだけを立てる設計では、実際の約定や部分約定との食い違いが起こり得ます。反対に、ポジションに反映されるまで毎ティック新規注文を送る処理も避けたいところです。送信中・受け付け・約定・拒否などを区別し、元のEAがどの状態で次の発注を許していたかを確認します。

取引の変化をOnTradeTransactionで扱う場合も、一回の依頼に対して複数のイベントが生じ得ます。一回呼ばれたらすべて完了したと仮定せず、種類と対象を確認して内部状態へ反映します。OnTradeTransactionの公式説明には、取引依頼とイベントの関係が示されています。発注方式を変えたら、失敗時だけでなく正常時の流れも照合しましょう。

再起動の確認では、チャートを開き直した直後に新規注文が増えないか、既存ポジションの決済条件が失われないかを見ます。元のEAがメモリ内の変数に頼っていた場合は、MT5へ移す機会に状態の復元方法を明確にします。ここで仕様を改善するなら「元の動作の再現」と「追加変更」を分け、比較する版を混ぜないようにします。

損益より最初の不一致を調べる

結果が違ったら、総利益の大小より、最初に売買判断が分かれた足を探します。対象時刻、入力価格、指標値、条件の真偽、管理中の保有、送った依頼、返された結果の順に並べると、どの段階からずれたかを絞れます。比較用の出力に口座番号や秘密情報を含める必要はありません。

例えば、MT4では10時の確定足で買いシグナル、MT5では10時の足でシグナルなしになったとします。先に同じ10時を見ているか、足のOHLCが同じか、移動平均の期間・適用価格・参照位置が同じかを確認します。値が同じなのに判断だけ違う場合に、クロスの不等号や、前回状態を保存する順序へ調査を進めます。これは原因を説明するための仮例です。

一方、シグナル時刻は同じで約定価格だけ違うなら、売買判断を作り直す前にスプレッド、ティック、約定条件を見ます。約定後から保有数が違うなら、口座方式、分割された約定、対象チケットの選択を調べます。「成績が似るまで期間を変える」という直し方では、誤りが偶然見えなくなった可能性を排除できません。

許容差を決める場合は、比較する値の単位と戦略の境界を説明できるようにします。小数の表示末尾の差であっても、価格が指標を超えたかを判定する境界付近では売買が変わります。共通の何桁・何pipsなら合格という値を置くより、なぜその差が生じ、判定に影響するかを先に確認しましょう。

並べた金属部品のうち形が異なる一つを拡大鏡で確認する説明用イメージ
説明用の生成イメージです。

修正後は、ずれた区間だけでなく、正常だった注文と決済も再確認します。買いの処理を直して売りの処理に影響していないか、ヘッジングで一件だけ閉じる変更が全決済へ波及していないか、といった点です。未解決の差が残るなら、収益が良く見えても移植完了とは扱わず、比較条件をそろえられない部分とコード上の未確認部分を区別します。

MQL4からMQL5への変換を終える条件

MQL4からMQL5への変換を終えたと言えるのは、エラーが消えたときだけではなく、意図したデータを読み、同じルールで判断し、予定する口座方式で注文と決済を扱えると確認できたときです。コンパイル、処理の一致、運用環境への適合をそれぞれ確認すると、残っている作業が明確になります。

  • ソース・依存ファイル・移植する権限を確認している
  • 指標の値と参照した足時刻を対応させている
  • 注文・約定・ポジションと管理対象を区別している
  • 正常時だけでなく失敗・再起動時の処理も確かめている
  • 差の原因と残る制約を説明できる

まだ価格や指標が合わないなら、発注処理を追加せず読み取りへ戻ります。シグナルは合うが注文が違うなら、依頼と結果、口座・銘柄仕様を照合します。必要な動作が対応した後は、入力値を固定して別の区間を試し、リアルタイムのデモ環境で重複発注や再起動後の状態も観察してください。

なお、移植で同じルールを再現できることと、将来利益が出ることは別の評価です。過去の成績に合うように条件を変更した場合は、新しい戦略として検証し直す必要があります。実口座での約定や費用がデモと一致する保証もありません。FX自動売買には損失リスクがあるため、原因不明の差を残したまま資金を投入せず、まず検証できる状態を整えましょう。

よかったらシェアしてね!
目次