MQL5の基本構造|OnInit・OnTick・注文関数を最小コードで理解
MQL5でEAを書くときに必ず登場するOnInit・OnTick・OnDeinitの役割と、注文を出すCTrade/MqlTradeRequestの使い方を、動く最小サンプルコードで解説します。
PR当ページにはプロモーション(アフィリエイト広告)が含まれます。順位・評価は公開の評価基準に基づき編集部が独立して決定しています。EAの成績はすべて過去の検証結果であり、将来の利益を保証するものではありません。海外FX業者は金融庁未登録です。
この記事の目次
MQL5のEAは、覚えるべき骨格がとても小さい言語です。実際には「起動時に1回呼ばれる OnInit()」「値動きのたびに呼ばれる OnTick()」「終了時に呼ばれる OnDeinit()」の3つを押さえ、そこに注文の出し方を1種類足せば、最小限のEAは完成します。この記事では、その骨格と最小サンプルコードを示し、初学者がつまずきやすい箇所を先回りして整理します。
✅ 結論
MQL5のEAは「イベントハンドラ(OnInit / OnTick / OnDeinit)」+「注文処理」の2層で理解できます。注文は標準ライブラリの CTrade クラスを使えば数行で書けます。MQL4のコードは移植ではなく書き直しが必要です。学習用コードをそのまま実口座で動かさないでください。
MQL5プログラムの3つの型
MetaEditorで新規作成すると、作るものを3種類から選びます。最初に混乱しやすいので、役割を分けて覚えます。
| 種別 | 拡張子 | 置き場所 | 呼ばれ方 | 主な用途 |
|---|---|---|---|---|
| エキスパートアドバイザ(EA) |
|
| ティックごと( | 自動売買 |
| カスタムインジケーター |
|
| 再計算ごと( | チャートへの描画 |
| スクリプト |
|
| 実行時に1回( | 一括決済などの単発処理 |
EAだけが OnTick() を持ちます。ファイルの配置先を間違えるとナビゲーターに表示されないため、必ずMT5の「ファイル」→「データフォルダを開く」から辿ってください。
イベントハンドラ一覧と、最初に使う3つ
MQL5のEAは「イベントが起きたら関数が呼ばれる」という設計です。公式リファレンスでは次のように定義されています(出典: MQL5 Reference - Program Running / Event Handling 、2026年9月24日確認)。
| ハンドラ | シグネチャ | 呼ばれるタイミング(公式の記述) |
|---|---|---|
|
|
| 「EAまたはインジケーターが読み込まれた直後にInitイベントが生成される」 |
|
|
| 終了処理。 |
|
|
| 「銘柄の新しいティックを受信したときにEAに対してのみ生成される」 |
|
|
|
|
|
|
| 注文・ポジション・履歴に変化があったとき |
|
|
| 取引トランザクションの詳細を受け取る |
|
|
| キーボード・マウス・オブジェクト操作 |
|
|
| バックテスト終了後。カスタム最適化基準を返す |
最初に書くEAで必要なのは上3つだけです。OnTimer 以下は、通知機能やポジション監視を作り込む段階で登場します。
💡 ポイント
OnInit() が INIT_FAILED を返すと、EAはチャートから外れます。逆にここで何も検証しないと、インジケーターのハンドル生成に失敗したまま OnTick() が回り続け、「エラーは出ないが一度も注文しない」という最も気づきにくい状態になります。
注文を出す2つの方法
MQL5で発注する方法は大きく2つあります。
方法1: MqlTradeRequest 構造体を直接組む(低レベル)
MqlTradeRequest に必要な項目を詰めて OrderSend() に渡します。主なフィールドは次の通りです(出典: MQL5 Reference - MqlTradeRequest 、2026年9月24日確認)。
| フィールド | 型 | 公式の説明 |
|---|---|---|
|
|
| Trade operation type(取引操作の種別) |
|
|
| Expert Advisor ID (magic number) |
|
|
| Trade symbol |
|
|
| Requested volume for a deal in lots |
|
|
| Price |
|
|
| Stop Loss level / Take Profit level of the order |
|
|
| Maximal possible deviation from the requested price |
|
|
| Order type |
|
|
| Order execution type |
|
|
| Order comment |
MQL4の OrderSend() が引数の羅列だったのに対し、MQL5は構造体を組み立ててから送る設計です。この違いが、MQL4とMQL5が互換でない最大の理由のひとつです。
方法2: CTrade クラスを使う(標準ライブラリ)
公式リファレンスは CTrade を「取引関数へ簡単にアクセスするためのクラス(a class for easy access to the trade functions)」と説明しています(出典: MQL5 Reference - CTrade 、2026年9月24日確認)。#include <Trade\Trade.mqh> で読み込み、Buy() / Sell() / PositionClose() などを呼ぶだけで発注できます。学習の最初は、こちらから入るほうが挫折しにくい構成です。
| よく使うメソッド | 役割 |
|---|---|
|
| 成行で新規ポジションを持つ |
|
| 待機注文を置く |
|
| SL/TPを変更する |
|
| 決済・部分決済 |
|
| マジックナンバーを設定する |
|
| 許容スリッページを設定する |
|
| 銘柄が許可する約定タイプを自動選択する |
⚠️ 注意
MT5は注文ごとに約定ポリシー(FOK / IOC / RETURN)を指定します。業者が許可していないポリシーを指定すると、リターンコード 10030 TRADE_RETCODE_INVALID_FILL で必ず弾かれます。海外FX業者でMT5のEAが動かない原因として最頻出のため、SetTypeFillingBySymbol() を使うか、SYMBOL_FILLING_MODE を自分で確認してください。
最小サンプル:移動平均クロスEA
ここまでの要素を1本にまとめた学習用コードです。実運用を想定したものではありません。
//+------------------------------------------------------------------+
//| MinimalMaCross.mq5 学習用サンプル(実運用向けではありません) |
//+------------------------------------------------------------------+
#property copyright "EA総合研究所"
#property version "1.00"
#include <Trade\Trade.mqh>
input int InpFastPeriod = 12; // 短期EMAの期間
input int InpSlowPeriod = 48; // 長期EMAの期間
input double InpLots = 0.01; // ロット
input int InpStopPoints = 300; // 損切り幅(ポイント)
input int InpTakePoints = 600; // 利確幅(ポイント)
input ulong InpMagic = 20260924; // マジックナンバー
CTrade trade;
int hFast = INVALID_HANDLE;
int hSlow = INVALID_HANDLE;
datetime lastBarTime = 0;
//--- 起動時に1回だけ呼ばれる
int OnInit()
{
hFast = iMA(_Symbol, PERIOD_CURRENT, InpFastPeriod, 0, MODE_EMA, PRICE_CLOSE);
hSlow = iMA(_Symbol, PERIOD_CURRENT, InpSlowPeriod, 0, MODE_EMA, PRICE_CLOSE);
if(hFast == INVALID_HANDLE || hSlow == INVALID_HANDLE)
{
Print("インジケーターハンドルの作成に失敗しました");
return(INIT_FAILED); // ここで止めないと空回りする
}
trade.SetExpertMagicNumber(InpMagic);
trade.SetDeviationInPoints(20);
trade.SetTypeFillingBySymbol(_Symbol);
return(INIT_SUCCEEDED);
}
//--- 終了時に1回だけ呼ばれる
void OnDeinit(const int reason)
{
IndicatorRelease(hFast);
IndicatorRelease(hSlow);
PrintFormat("EAを終了します(理由コード: %d)", reason);
}
//--- ティックごとに呼ばれる
void OnTick()
{
// (1) 足が確定したときだけ判定する
datetime bar = iTime(_Symbol, PERIOD_CURRENT, 0);
if(bar == lastBarTime)
return;
lastBarTime = bar;
// (2) 直近3本分の移動平均を配列に取り出す
double fast[], slow[];
if(CopyBuffer(hFast, 0, 0, 3, fast) < 3) return;
if(CopyBuffer(hSlow, 0, 0, 3, slow) < 3) return;
ArraySetAsSeries(fast, true);
ArraySetAsSeries(slow, true);
// index 1 = 直前の確定足、index 2 = そのひとつ前
bool goldenCross = (fast[2] <= slow[2] && fast[1] > slow[1]);
bool deadCross = (fast[2] >= slow[2] && fast[1] < slow[1]);
// (3) 自分のポジションがあれば何もしない
if(HasMyPosition())
return;
// (4) 発注する
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
if(goldenCross)
trade.Buy(InpLots, _Symbol, ask,
ask - InpStopPoints * point,
ask + InpTakePoints * point, "MA cross long");
else if(deadCross)
trade.Sell(InpLots, _Symbol, bid,
bid + InpStopPoints * point,
bid - InpTakePoints * point, "MA cross short");
}
//--- このEAのマジックナンバーを持つポジションがあるか
bool HasMyPosition()
{
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
ulong ticket = PositionGetTicket(i);
if(ticket == 0) continue;
if(PositionGetString(POSITION_SYMBOL) != _Symbol) continue;
if(PositionGetInteger(POSITION_MAGIC) != (long)InpMagic) continue;
return(true);
}
return(false);
} コードの読みどころ
iMA()はOnInit()で1回だけ呼ぶ。 MQL5のインジケーター関数は値ではなく「ハンドル(整数ID)」を返します。OnTick()の中で毎回呼ぶとハンドルが増え続け、メモリを圧迫します。値の取得はCopyBuffer()で行います。ArraySetAsSeries(arr, true)で時系列順にする。 これを入れないと配列のindex 0が最も古い足になり、判定が逆転します。初学者の典型的なバグです。index 1を見る。 index 0は形成中の足で、値が刻々と変わります。確定足で判定するために index 1 と index 2 を比べています。- マジックナンバーで自分の注文だけを数える。 同一口座で複数のEAや裁量トレードを併用する場合、この判定がないとロット計算や決済が崩壊します。設計の考え方は マジックナンバーの決め方 で整理しています。
このコードに足りないもの(実運用との距離)
学習用サンプルと実運用EAの差は、ロジックではなく「例外処理の量」です。最低限、次の項目が必要になります。
| 不足している処理 | 何が起きるか | 対処の方向 |
|---|---|---|
| ロットの丸め | 最小ロット・刻み値に合わず |
|
| ストップレベルの確認 | SL/TPが近すぎて |
|
| 価格の正規化 | 桁数が合わず注文が通らない |
|
| 発注失敗時のリトライ | 一時的な回線断・リクオートで取引機会を落とす | リターンコードを見て限定的に再送する |
| 取引時間・ニュースのフィルタ | 指標発表時やロールオーバー時に想定外の約定をする | サーバー時刻とGMTオフセットを踏まえて時間帯を制御する |
| 最大ポジション数・最大DDの上限 | 想定外のロット膨張を止められない | 口座全体の安全弁として実装する |
サーバー時刻の扱いは、時間帯フィルタを作るときに必ず引っかかる論点です。 MT4/MT5のサーバー時間とGMTオフセット を先に読んでおくと、手戻りが減ります。
MQL4との違いを1枚で
すでにMQL4を触ったことがある人向けに、書き換えが必要な箇所をまとめます。
| 論点 | MQL4 | MQL5 |
|---|---|---|
| 発注 |
|
|
| ポジションの参照 |
|
|
| インジケーター値 |
|
|
| 両建て | 常に可能 | 口座タイプ(ヘッジング/ネッティング)に依存 |
| 約定ポリシー | 概念なし | FOK / IOC / RETURN を指定 |
| 言語機能 | 手続き型中心 | クラス・継承・テンプレートを全面採用 |
「MT4/MT5両対応」と書かれたEAは、実体としては別々に書かれた2本のプログラムです。したがってバックテスト結果も一致しません。購入検討時は両方の実績が個別に提示されているかを見てください。この論点は MT4とMT5の違い でも整理しています。
なお、MetaQuotes社はMT4の保守を縮小しており、国内でもMT4提供を終了する業者が出ています。これから学ぶならMQL5を選ぶ合理性が高い状況です( MT4のサポート終了と今後 )。
よくある失敗
🚨 危険
学習用コードをいきなりリアル口座で動かすことです。MQL5のコンパイルが通ることと、注文が意図通りに出ることはまったく別です。必ずデモ口座で最低1回、エントリーから決済までを通してログを読んでください。
- バックテストの数字を鵜呑みにする。 パラメータを動かしていれば、過去データに合う組み合わせは必ず見つかります。それが将来も機能する保証はありません。判別方法は カーブフィッティングの見抜き方 にまとめています。
- エラーを握りつぶす。
trade.Buy()の戻り値を確認せず放置すると、発注が全部失敗していても気づけません。trade.ResultRetcode()をログに出す習慣をつけてください。 - いきなり複雑にする。 最初の1本は「移動平均クロス+固定SL/TP」で十分です。複雑なロジックほど検証が難しく、どこが悪いのか切り分けられなくなります。
- コードを書かずに完成品を探し始める。 それ自体は悪くありませんが、目的が「自作」なら順序が逆になります。全体の進め方は EA自作の完全ロードマップ を参照してください。
まとめ
MQL5の学習コストは、想像されているより低い部類です。OnInit() でハンドルを用意し、OnTick() で確定足を見て判断し、CTrade で発注する——この骨格さえ掴めば、あとは例外処理を足していく作業になります。
次のステップとして、コードを書く前に全体像を掴みたい方は EAを自作する完全ロードマップ を、生成AIを使った書き方を試したい方は 生成AIでEAを作る手順と限界 を、コードを書かない選択肢を検討したい方は ノーコードEA作成ツールの比較 をあわせてご覧ください。書いたEAを検証する段階に進んだら、 バックテストの正しいやり方 が次の関門になります。
よくある質問
Q.MQL4のコードをMQL5にコピーすれば動きますか?
Q.OnTick()の中に処理を全部書いてはいけないのですか?
Q.サンプルコードをそのまま実運用に使えますか?
Q.コンパイルは通るのに注文が出ません。どこを見ればいいですか?
Q.MQL5を学ぶのに最初に読むべき公式ドキュメントはどれですか?
関連記事
EAを自作する完全ロードマップ|MQL5入門から検証・販売までの8工程
更新: 2026年9月24日
EA開発・自作生成AIでEAを作る手順と限界|ChatGPTで書けること・書けないこと
更新: 2026年9月24日
EA開発・自作ノーコードのEA作成ツール比較|料金・出力形式・日本語対応の違い
更新: 2026年9月24日
EA開発・自作EA開発の外注費用の相場|依頼先5種の比較と発注仕様書テンプレート
更新: 2026年9月24日
EA開発・自作自作EAを販売する方法|MQL5・GogoJungleの手数料と法的な注意点
更新: 2026年9月24日
基礎知識・始め方EA(FX自動売買)とは|注文が出るまでの仕組みを6段階で理解する
更新: 2026年9月24日