最終更新: 2026年6月
「EAを自分で作りたい」と思ったとき、最初の壁になるのがMQL5という言語だ。PythonやJavaScriptと比べて日本語情報が少なく、何から手をつけてよいかわからないという声をよく聞く。
本記事では、MQL5の基本構造を解説しつつ、「移動平均クロスでエントリー」というシンプルなEAを一から作る手順を示す。コードをコピーして動かせるように書いてある。
免責事項: 本記事は技術情報の提供を目的としています。FX取引には元本割れのリスクがあります。サンプルEAが利益を保証するものではありません。必ずデモ口座で十分なテストを行ってください。
MQL5の基本構造:3つのイベント関数
MQL5で書いたEAは、特定のタイミングで自動的に呼び出される「イベント関数」を中心に構成される。主要な3つを押さえておけば、基本的なEAは書ける。
| 関数 | 呼び出しタイミング | 主な用途 |
|---|---|---|
| OnInit() | EAをチャートにセットしたとき(1回のみ) | 変数の初期化・インジケーターハンドルの作成 |
| OnTick() | 価格が動くたびに(毎ティック) | 売買ロジックの実行 |
| OnDeinit() | EAを停止・削除したとき(1回のみ) | ハンドルの解放・クリーンアップ |
EAの動作フロー:
チャートにEAをセット
↓ OnInit() が1回実行
価格が動く
↓ OnTick() が毎回実行(ここで売買判断)
EA停止・チャート削除
↓ OnDeinit() が1回実行
最小限のEAテンプレート
MetaEditorでEAファイルを新規作成すると自動生成されるテンプレートを確認しておこう。
//+------------------------------------------------------------------+
//| EA名: MinimalEA.mq5 |
//+------------------------------------------------------------------+
#property copyright "your name"
#property version "1.00"
// EAの初期化
int OnInit()
{
Print("EA起動");
return(INIT_SUCCEEDED);
}
// EAの終了処理
void OnDeinit(const int reason)
{
Print("EA停止");
}
// 毎ティック実行される売買ロジック
void OnTick()
{
// ここに売買ロジックを書く
}
Print() はMetaEditorのログに出力する関数だ。デバッグ時に非常に役立つので積極的に使う。
移動平均クロスEAの実装
実際に動くEAとして、「短期移動平均が長期移動平均を上抜けたら買い、下抜けたら売り」というゴールデンクロス/デッドクロス戦略を実装する。
//+------------------------------------------------------------------+
//| EA名: MA_Cross_EA.mq5 |
//| 戦略: 移動平均クロスでエントリー |
//+------------------------------------------------------------------+
#property copyright "your name"
#property version "1.00"
#include <Trade\Trade.mqh> // 注文クラスをインポート
// 入力パラメーター(バックテスト時に変更可能)
input int FastMA_Period = 10; // 短期MA期間
input int SlowMA_Period = 30; // 長期MA期間
input double LotSize = 0.01; // ロット数
input int Slippage = 10; // スリッページ許容(ポイント)
// グローバル変数
CTrade trade; // 注文オブジェクト
int fastMA_handle; // 短期MAのハンドル
int slowMA_handle; // 長期MAのハンドル
//+------------------------------------------------------------------+
//| 初期化 |
//+------------------------------------------------------------------+
int OnInit()
{
// 移動平均インジケーターのハンドルを作成
fastMA_handle = iMA(_Symbol, _Period, FastMA_Period, 0, MODE_SMA, PRICE_CLOSE);
slowMA_handle = iMA(_Symbol, _Period, SlowMA_Period, 0, MODE_SMA, PRICE_CLOSE);
// ハンドルの作成に失敗した場合は停止
if(fastMA_handle == INVALID_HANDLE || slowMA_handle == INVALID_HANDLE)
{
Print("MAハンドルの作成に失敗");
return(INIT_FAILED);
}
trade.SetDeviationInPoints(Slippage);
Print("MA_Cross_EA 起動完了");
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| 終了処理 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
IndicatorRelease(fastMA_handle);
IndicatorRelease(slowMA_handle);
Print("MA_Cross_EA 停止");
}
//+------------------------------------------------------------------+
//| メイン処理(毎ティック) |
//+------------------------------------------------------------------+
void OnTick()
{
// 新しい足が開いた瞬間だけ処理する(毎ティックは不要)
static datetime lastBarTime = 0;
datetime currentBarTime = iTime(_Symbol, _Period, 0);
if(currentBarTime == lastBarTime) return;
lastBarTime = currentBarTime;
// MAの値を取得(直前の確定足: index=1)
double fastMA_arr[2], slowMA_arr[2];
if(CopyBuffer(fastMA_handle, 0, 0, 2, fastMA_arr) < 2) return;
if(CopyBuffer(slowMA_handle, 0, 0, 2, slowMA_arr) < 2) return;
double fastMA_now = fastMA_arr[1]; // 直前足のMA値
double fastMA_prev = fastMA_arr[0]; // 2本前のMA値
double slowMA_now = slowMA_arr[1];
double slowMA_prev = slowMA_arr[0];
// ポジション保有数を確認
int positions = PositionsTotal();
// ゴールデンクロス(短期が長期を上抜け)→ 買い
if(fastMA_prev <= slowMA_prev && fastMA_now > slowMA_now)
{
if(positions == 0) // ポジションなしのとき
{
trade.Buy(LotSize, _Symbol, 0, 0, 0, "MA_Cross_Buy");
Print("買いエントリー / 短期MA:", fastMA_now, " / 長期MA:", slowMA_now);
}
}
// デッドクロス(短期が長期を下抜け)→ 売り
if(fastMA_prev >= slowMA_prev && fastMA_now < slowMA_now)
{
if(positions == 0) // ポジションなしのとき
{
trade.Sell(LotSize, _Symbol, 0, 0, 0, "MA_Cross_Sell");
Print("売りエントリー / 短期MA:", fastMA_now, " / 長期MA:", slowMA_now);
}
}
}
コードの重要ポイント解説
iMA() でMAハンドルを作成する
fastMA_handle = iMA(_Symbol, _Period, FastMA_Period, 0, MODE_SMA, PRICE_CLOSE);
_Symbol: 現在のチャートの通貨ペア_Period: 現在のチャートの時間足FastMA_Period: MA期間(入力パラメーター)MODE_SMA: 単純移動平均(他にEMA、WMAなど)PRICE_CLOSE: 終値を使用
CopyBuffer() でMAの値を取得する
CopyBuffer(fastMA_handle, 0, 0, 2, fastMA_arr)
index=0 が最新足、index=1 が1本前(直前の確定足)。「直前の確定足」を使うことで、未確定足のMAに引っ張られる誤判定を防ぐ。
新しい足でのみ処理する
static datetime lastBarTime = 0;
datetime currentBarTime = iTime(_Symbol, _Period, 0);
if(currentBarTime == lastBarTime) return;
毎ティックで売買判断をすると無駄な処理と誤判定が増える。「足が開いた瞬間だけ」チェックするのが基本だ。
MetaEditorでのビルドと実行手順
- MT5を起動 →「ツール」→「MetaEditor」
- MetaEditorで「ファイル」→「新規作成」→「エキスパートアドバイザー(テンプレート)」
- コードを貼り付けて「コンパイル(F7)」
- コンパイルエラーが出た場合は「エラー」タブで確認
- コンパイル成功後、MT5のナビゲーターウィンドウの「エキスパートアドバイザー」に表示される
- チャートにドラッグ&ドロップでセット
- 設定画面で「アルゴリズム取引を許可」にチェック
バックテストの実施
実装したEAをまずバックテストで評価する。
- MT5メニュー →「表示」→「ストラテジーテスター」
- 「エキスパートアドバイザー」欄で作成したEAを選択
- 通貨ペア・期間を設定(推奨: 過去2〜3年のデータ)
- 「スタート」でバックテスト実行
評価の基本指標:
- プロフィットファクター(PF) 1.5以上を目安とする(詳細は別記事)
- 最大ドローダウン 20%以下
- 取引回数 100回以上(統計的有意性のため)
この移動平均クロスEAは極めてシンプルで、実際の相場ではトレンド相場でしか有効でない。横ばい相場(レンジ)では損失が積み重なる。あくまで「構造を理解するための習作」として使用してほしい。
Claudeと会話しながらインジケータが作れる[hedgrow-fx]はこちら: https://hedgrow-fx.com/
MQL5とMQL4の主な違い(移行者向け)
MQL4を使ったことがある人向けに、MQL5との主な違いを示す。
| 項目 | MQL4 | MQL5 |
|---|---|---|
| インジケーター値の取得 | iMA(NULL, 0, 10, ...) で直接取得 | iMA()でハンドル作成 → CopyBuffer()で取得 |
| 注文の出し方 | OrderSend() | CTradeクラスの Buy()/Sell() |
| ポジション確認 | OrdersTotal() | PositionsTotal() |
| 配列インデックス | デフォルト逆順(0=最新) | 必要に応じてArraySetAsSeries()で設定 |
MQL4に慣れていると、インジケーター値の取得方法の変化が最も戸惑うポイントだ。「ハンドルを作ってからCopyBufferで読む」という2段階の仕組みを覚えれば、大半のパターンに対応できる。
まとめ
MQL5 EA制作の要点:
- EAは
OnInit()→OnTick()→OnDeinit()の3関数で構成される - インジケーターは
iMA()でハンドルを作り、CopyBuffer()で値を取得する - 毎ティックではなく「新しい足の開始時」に判断するのが基本
- 完成したら必ずMetaEditorでコンパイル → バックテストの順で検証する
よくある質問(FAQ)
Q: MQL5の学習にどのくらい時間がかかりますか? A: プログラミング経験がある場合は基本的な構文理解に1〜2週間、シンプルなEAが書けるようになるまで1ヶ月程度が目安です。Pythonなどの経験があれば構文の理解は早いですが、EAの設計パターン(ハンドル管理など)は独自の学習が必要です。
Q: MQL5とPythonはどちらから始めるべきですか? A: MT5上で直接動くEAを作りたいならMQL5、機械学習や外部システムと連携したいならPythonが向いています。両方使えると選択肢が広がりますが、どちらか一方を深める方が最初は効果的です。
Q: 移動平均クロスEAは実際の運用で使えますか? A: 単純な移動平均クロスは多くのトレーダーが知っている手法であるため、単独では統計的な優位性を持ちにくいです。追加フィルター(ボラティリティフィルター・市場状態判定など)を組み合わせて改良する前提でご利用ください。
Q: コンパイルエラーが出て動きません。どうすればいいですか? A: MetaEditorのエラータブに表示されるエラーメッセージと行番号を確認してください。よくあるエラーは変数の型不一致、セミコロン忘れ、ハンドルの作成失敗などです。
Q: バックテスト結果が良くても実運用で負けるのはなぜですか? A: バックテストは過去データへの過学習が起きやすく、スプレッドやスリッページの計算が不完全な場合があります。ウォークフォワードテストやデモ口座での前進検証を行ってから本番移行を判断してください。
著者: 金融工学出身システムトレーダー
