最終更新: 2026年6月
EMAクロスはFXのEA入門として最も基礎的なロジックだ。「短期EMAが長期EMAを上抜けたらBUY」というシンプルな条件なので、MQL4の学習にも最適で、筆者もこのコードを起点にEA開発を覚えた。本稿では、EMAクロスEAの実装コードをMQL4で一から解説し、バックテストでよくある失敗パターンと最適化の考え方まで掘り下げる。
EMAクロスEAの基本ロジック
EMA(指数移動平均)クロスの売買ルールはシンプルだ。
- ゴールデンクロス(BUY): 短期EMAが長期EMAを下から上に抜けたとき
- デッドクロス(SELL): 短期EMAが長期EMAを上から下に抜けたとき
MT5向けのMQL5と異なり、MT4のMQL4ではiMA()関数で移動平均値を取得する。書式は以下の通りだ。
double iMA(
string symbol, // 通貨ペア(Null=現在のチャート)
int timeframe, // 時間足(0=現在の時間足)
int ma_period, // 期間
int ma_shift, // シフト(通常0)
int ma_method, // 計算方式(1=EMA)
int applied_price,// 適用価格(0=終値)
int shift // バー番号(0=現在足、1=1本前)
)
完全なMQL4コード
以下が、EMAクロスEAのシンプルな実装コードだ。コピーしてEMA_Cross_EA.mq4というファイル名でMT4のMQL4エディター(MetaEditorを起動してNew Fileから作成)に貼り付けることで動作確認できる。
//+------------------------------------------------------------------+
//| EMA Cross EA — シンプル実装 |
//| 短期EMAが長期EMAをクロスしたときに売買 |
//+------------------------------------------------------------------+
#property strict
// 入力パラメータ
input int FastPeriod = 12; // 短期EMA期間
input int SlowPeriod = 26; // 長期EMA期間
input double LotSize = 0.1; // ロット数
input int StopLoss = 50; // 損切り(pips)
input int TakeProfit = 100; // 利確(pips)
input int MagicNumber = 20260001; // EA識別番号
//+------------------------------------------------------------------+
//| OnTick() — ティック毎に実行 |
//+------------------------------------------------------------------+
void OnTick()
{
// 足が確定しているかチェック(新しい足が開いた瞬間のみ処理)
static datetime lastBarTime = 0;
if(Time[0] == lastBarTime) return;
lastBarTime = Time[0];
// EMA値の取得
double fastEMA_current = iMA(NULL, 0, FastPeriod, 0, MODE_EMA, PRICE_CLOSE, 0);
double fastEMA_prev = iMA(NULL, 0, FastPeriod, 0, MODE_EMA, PRICE_CLOSE, 1);
double slowEMA_current = iMA(NULL, 0, SlowPeriod, 0, MODE_EMA, PRICE_CLOSE, 0);
double slowEMA_prev = iMA(NULL, 0, SlowPeriod, 0, MODE_EMA, PRICE_CLOSE, 1);
// 既存ポジションの確認
bool hasPosition = false;
for(int i = 0; i < OrdersTotal(); i++)
{
if(OrderSelect(i, SELECT_BY_POS) && OrderMagicNumber() == MagicNumber)
{
hasPosition = true;
break;
}
}
// ゴールデンクロス判定(前足では短期<長期、現在足では短期>長期)
bool goldenCross = (fastEMA_prev < slowEMA_prev) && (fastEMA_current > slowEMA_current);
// デッドクロス判定
bool deadCross = (fastEMA_prev > slowEMA_prev) && (fastEMA_current < slowEMA_current);
double point = MarketInfo(Symbol(), MODE_POINT);
int digits = (int)MarketInfo(Symbol(), MODE_DIGITS);
double multiplier = (digits == 3 || digits == 5) ? 10 : 1; // 5桁通貨ペア対応
// BUYエントリー
if(goldenCross && !hasPosition)
{
double sl = Ask - StopLoss * point * multiplier;
double tp = Ask + TakeProfit * point * multiplier;
int ticket = OrderSend(Symbol(), OP_BUY, LotSize, Ask, 3, sl, tp,
"EMA Cross EA", MagicNumber, 0, clrBlue);
if(ticket < 0)
Print("OrderSend Error: ", GetLastError());
}
// SELLエントリー
if(deadCross && !hasPosition)
{
double sl = Bid + StopLoss * point * multiplier;
double tp = Bid - TakeProfit * point * multiplier;
int ticket = OrderSend(Symbol(), OP_SELL, LotSize, Bid, 3, sl, tp,
"EMA Cross EA", MagicNumber, 0, clrRed);
if(ticket < 0)
Print("OrderSend Error: ", GetLastError());
}
}
コードの重要ポイント解説
1. 足確定チェック(lastBarTime)
OnTick()はティクごとに呼ばれるため、同じ足で何度も判定が走るとクロス条件が誤検出されやすい。Time[0]の変化を監視して「新しい足が開いたときだけ」処理するのが基本だ。
2. 5桁通貨ペア対応(multiplier)
現代の多くのブローカーは5桁クォート(例: USD/JPY = 145.000形式)を使っている。MQL4のMODE_POINTは1pip=0.0001(4桁)として計算されるため、5桁の場合は×10が必要だ。
3. MagicNumber
複数のEAを同時運用するときに自分のEAのオーダーを識別するための番号。EAごとにユニークな値を設定する。
Claudeと会話しながらインジケータが作れるhedgrow-fxでは、このようなMQL4コードの設計・改造をAIとの対話で進めることができる。
よくある実装ミスとデバッグ
ミス1: 現在足(shift=0)で判定する
// 悪い例(確定前の足で判定してしまう)
double fast_now = iMA(NULL, 0, FastPeriod, 0, MODE_EMA, PRICE_CLOSE, 0);
double slow_now = iMA(NULL, 0, SlowPeriod, 0, MODE_EMA, PRICE_CLOSE, 0);
if(fast_now > slow_now) // ← 足確定前に何度も条件を満たす可能性
shift=0(現在足)での比較だけでクロスを判定すると、1本の足の間に何十回もクロス条件が成立する。shift=1(1本前の確定足)と組み合わせてクロスを検出するのが正しい設計だ。
ミス2: ロット数のハードコード
ロット数を固定値にしていると、口座残高に対して過大なリスクを取ることになる。実務的には「口座残高の何%か」で計算するリスクベースのロット算出を実装すべきだ。
// リスクベースのロット計算例(口座残高の2%リスク)
double riskPercent = 2.0;
double accountBalance = AccountBalance();
double riskAmount = accountBalance * riskPercent / 100;
double lotSize = riskAmount / (StopLoss * MarketInfo(Symbol(), MODE_TICKVALUE) * multiplier);
lotSize = NormalizeDouble(lotSize, 2); // ロット数を小数点2桁に丸める
ミス3: ストップレベル違反
ブローカーには「最小ストップレベル(STOPLEVEL)」が設定されており、現在レートからの最小距離より近いSL/TPは拒否される。
// ストップレベル確認
double minStop = MarketInfo(Symbol(), MODE_STOPLEVEL) * point;
if(StopLoss * point * multiplier < minStop)
{
Print("Warning: StopLoss is below minimum stop level");
return;
}
バックテストと最適化の進め方
ステップ1: MT4のStrategy Testerでの実行
MT4メニュー「表示」→「ストラテジーテスター」を開く。設定は以下を推奨する。
| 設定項目 | 推奨値 | |---|---| | テストモデル | 全ティック | | スプレッド | 実際のブローカーのスプレッドに設定(デフォルト20は高め) | | テスト期間 | 最低2年以上 | | 通貨ペア | EUR/USD または USD/JPYから始める |
「コントロールポイント」や「始値のみ」モードはバックテストが速い反面、精度が落ちる。EMAクロスEAは価格の一瞬の動きを見るロジックではないので、精度重視で「全ティック」を推奨する。
ステップ2: パラメータ最適化
MT4のStrategy Testerで「最適化」タブを開き、FastPeriodとSlowPeriodの範囲を設定して実行する。
典型的な最適化範囲の例:
| パラメータ | 最小 | 最大 | ステップ | |---|---|---|---| | FastPeriod | 5 | 25 | 1 | | SlowPeriod | 20 | 60 | 1 | | StopLoss | 30 | 100 | 10 | | TakeProfit | 60 | 200 | 20 |
ステップ3: 過最適化を避ける
最適化で出てくる「最良パラメータ」をそのまま採用するのは危険だ。そのパラメータが過去の特定相場にだけ有効な「偶然の一致」の可能性がある。
確認すべきこと:
- ±2ずつパラメータをずらしても安定したPFを維持するか(ロバスト性チェック)
- 異なる通貨ペアでも同様のPFが出るか
- 直近6ヶ月のウォークフォワードテストを通過するか
EMAクロス単体のPFはEUR/USDの典型的な1〜4時間足で1.1〜1.3程度が現実的な期待値だ。それ以上のPFが出ている場合は過最適化を疑う。
EMAクロスEAの改良アイデア
シンプルなEMAクロスにロジックを追加することで実用性が上がる。
- ADXフィルター追加: ADXが25以上のトレンド相場のみエントリー(レンジ相場での偽クロスを削減)
- トレーリングストップ: 利益が一定以上になったらSLをブレークイーブンに移動
- 時間フィルター: 東京・ロンドン・NYセッションのみエントリーを許可
よくある質問(FAQ)
Q: EMAの期間(FastPeriod/SlowPeriod)はどの値が最適ですか? A: 「最適な値」は通貨ペアと時間足によって変わります。よく使われるのは12/26(MACDと同じ期間)ですが、バックテストで自分が使う通貨ペアと時間足に対して最適化することを推奨します。過去最適化に注意し、ウォークフォワードテストで確認してください。
Q: MT4のEMAクロスEAはMT5(MQL5)でも使えますか?
A: MQL4とMQL5は別の言語仕様です。関数名や記法が異なるため、そのままでは動きません。MQL5版ではCopyBuffer()を使ったインジケーター値の取得方法が主流です。
Q: EMAクロスEAで実際に利益を出せますか? A: バックテスト上では利益が出るパラメータを見つけられる場合がありますが、FX取引には損失リスクが伴います。EMAクロス単体のシグナルは「ダマシ」(フォルスシグナル)が多いレンジ相場では損失が積み重なりやすいです。実運用前に十分な期間のフォワードテストと資金管理の設計が必要です。
Q: OrderSendのスリッページ(第3引数の3)は何を意味しますか? A: スリッページとは、指定価格と実際の約定価格のずれを許容するpips数です。値が大きいほど注文が通りやすくなりますが、想定外の価格で約定するリスクも高まります。3pipsはバランスのよい設定ですが、ブローカーのスプレッドに合わせて調整してください。
免責事項: 本記事のコードはサンプルであり、実運用での利益を保証するものではありません。FX取引には元本割れを含む損失リスクがあります。実運用前にデモ口座での動作確認を必ず行ってください。
