MQL5アルゴリズム取引EA設計ガイド|実装から運用まで

目次

この記事の結論

MQL5でMetaTrader 5向けのアルゴリズム取引EAを設計する場合、売買条件だけでなく、状態管理・リスク管理・注文前チェック・検証手順を分離して考える必要があります。
EAは、相場認識、フィルター判定、シグナル判定、ロット計算、注文送信、約定後管理を順番に処理する構造にすると保守しやすくなります。
MQL5ではインジケータ値を直接使うのではなく、ハンドルを作成し、CopyBufferで値を取得する設計が中心になります。
バックテスト結果は将来の利益を保証しないため、実運用前にはフォワードテスト、スプレッド条件、約定差、ブローカー仕様を確認する必要があります。

1. この設計が必要な理由

【結論】
MQL5のアルゴリズム取引EAでは、売買ロジックを一つの条件分岐にまとめると、検証・修正・実運用時の原因分析が難しくなります。
EA設計では、判断、注文、管理、停止条件を分離することで、挙動を追跡しやすくなります。

MQL5のEAは、新しいティックを受け取るたびにOnTickで処理されます。
単純なEAでは、OnTick内にエントリー条件と注文処理を直接書くこともできます。
しかし、実運用を想定するEAでは、スプレッド拡大、証拠金不足、約定拒否、ポジション保有状態、口座タイプの違いなどを考慮する必要があります。

【定義】
MQL5におけるEA設計とは、売買シグナルを注文処理へ直結させるのではなく、状態管理、リスク確認、注文前チェック、約定後管理を分けて構成する考え方です。

1.1 条件分岐だけでは実運用に弱い理由

売買条件だけでEAを作ると、以下のような問題が起きやすくなります。

  • ポジション保有中に重複エントリーする
  • スプレッド拡大時にも注文を送る
  • ロット制限を超えた注文を作る
  • 約定失敗後の再試行条件が曖昧になる
  • バックテストでは動くがリアル口座で挙動が変わる

MQL5のEAでは、注文の成否だけでなく、注文前の検証、約定後の状態更新、取引履歴との整合性を確認する設計が重要です。

1.2 EA設計で先に決めるべきこと

EAを実装する前に、少なくとも以下を決めます。

  • どの相場状態で取引するか
  • どの条件でエントリーを許可するか
  • どの条件でエントリーを止めるか
  • 1回あたりの許容リスクをどう決めるか
  • 既存ポジションをどう扱うか
  • 注文失敗時に再試行するか
  • 最大ドローダウン到達時に停止するか

アルゴリズム取引EAは、売買シグナルよりも先に、取引してよい状態かどうかを判定する構造が必要です。

2. EA全体の設計思想

【結論】
MQL5のEAは、相場認識から注文送信までを段階的に処理するパイプラインとして設計すると整理しやすくなります。
各段階を独立させることで、バックテスト結果の原因分析とフォワードテストでの修正がしやすくなります。

EA全体は、次の流れで考えます。

相場認識
↓
フィルター判定
↓
シグナル判定
↓
リスク確認
↓
注文前チェック
↓
注文送信
↓
約定後管理
↓
決済・停止判定

この流れにすると、どの段階で取引が拒否されたのかをログで確認しやすくなります。
また、シグナルの精度とリスク管理の問題を分けて検証できます。

MQL5 Expert Advisor architecture showing OnTick flow, risk control, OrderCheck, OrderSend, and module separation

2.1 OnInitOnTickOnDeinitの役割

MQL5のEAでは、主要な処理をイベント関数に分けます。

関数主な役割EA設計での使いどころ
OnInit初期化処理インジケータハンドル作成、設定値確認、初期状態の準備
OnTickティック受信時の処理シグナル判定、リスク確認、注文処理、ポジション管理
OnDeinit終了時の後処理ハンドル解放、終了ログ、状態保存
OnTradeTransaction注文・約定・ポジション変化の詳細処理約定結果の追跡、注文状態の同期
OnTimerタイマー処理低頻度の監視、複数銘柄チェック、定期ログ

MQL5のEAでは、OnTickが中心になります。
ただし、初期化や後処理までOnTickに詰め込むと、状態が不安定になりやすくなります。

2.2 状態管理を中心に置く

EAの状態は、現在の相場だけでなく、EA自身が何をしている途中かも含みます。

例として、以下のような状態を持たせます。

  • 取引可能状態
  • 新規注文待機中
  • ポジション保有中
  • 決済待機中
  • 連敗停止中
  • ドローダウン停止中
  • 取引時間外

状態管理を入れると、同じシグナルが連続して発生しても、EAが無制限に注文を送る問題を抑えやすくなります。

3. 基本構造

【結論】
MQL5のアルゴリズム取引EAは、初期化、データ取得、判定、注文前確認、注文送信、管理処理を分けて実装します。
特にインジケータを使う場合は、OnInitでハンドルを作成し、OnTickCopyBufferを使って値を取得します。

MQL5では、iMAiATRなどのインジケータ関数は、多くの場合インジケータ値そのものではなくハンドルを返します。
EAは、そのハンドルを使ってCopyBufferで必要なバッファ値を取得します。

3.1 最小構成の考え方

EAの最小構成は以下です。

#property strict

int OnInit()
{
   return INIT_SUCCEEDED;
}

void OnDeinit(const int reason)
{
}

void OnTick()
{
}

実運用を意識する場合は、この最小構成に以下を追加します。

  • パラメータ検証
  • インジケータハンドル作成
  • データ取得失敗時の処理
  • ロット計算
  • ポジション確認
  • 注文前のOrderCheck
  • 注文結果のログ出力
  • 停止条件の管理

3.2 インジケータ値を使う基本構造

移動平均線を使うEAでは、次のような構造になります。

#property strict

int ma_handle = INVALID_HANDLE;

int OnInit()
{
   ma_handle = iMA(_Symbol, _Period, 20, 0, MODE_SMA, PRICE_CLOSE);

   if(ma_handle == INVALID_HANDLE)
   {
      Print("Failed to create moving average handle");
      return INIT_FAILED;
   }

   return INIT_SUCCEEDED;
}

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

void OnTick()
{
   double ma_values[];
   ArraySetAsSeries(ma_values, true);

   int copied = CopyBuffer(ma_handle, 0, 0, 3, ma_values);
   if(copied < 3)
   {
      Print("CopyBuffer failed or not enough data");
      return;
   }

   double current_ma = ma_values[0];
   double closed_ma  = ma_values[1];

   Print("Current MA: ", current_ma, " Closed MA: ", closed_ma);
}

このコードでは、ma_values[0]が最新足、ma_values[1]が直近の確定足です。
売買判定では、未確定の最新足を使うとティックごとに条件が変わるため、確定足を使う設計も検討します。

4. 主要モジュールの役割

【結論】
EAは、シグナル判定、フィルター判定、ロット計算、注文処理、ポジション管理、リスク制御を別々の役割として設計します。
役割を分けることで、ロジック変更時に他の処理へ影響しにくくなります。

主要モジュールは、以下のように分けます。

モジュール役割主な確認項目
相場認識トレンド、レンジ、ボラティリティを見る移動平均線、ATR、ADX、上位足
フィルター判定取引してよい相場だけを残すスプレッド、時間帯、ボラティリティ
シグナル判定エントリー方向を決めるクロス、ブレイク、反転条件
ロット計算許容リスクに応じて数量を決める最小ロット、最大ロット、ロットステップ
注文前チェック注文が妥当か確認する証拠金、ストップレベル、取引可否
注文送信取引リクエストを送るMqlTradeRequestMqlTradeResult
約定後管理結果とEA状態を同期する約定価格、エラー、ポジション状態
リスク制御取引停止条件を管理するドローダウン、連敗、日次損失

MQL5のEA設計では、注文送信より前に、取引してよい状態かどうかを判定する層を置くことが重要です。

4.1 シグナル判定とフィルター判定を分ける

シグナル判定は、買いまたは売りの候補を作る処理です。
フィルター判定は、その候補を採用してよいかを確認する処理です。

例として、移動平均クロスをシグナルにし、ATRやスプレッドをフィルターにする設計があります。

  • シグナル判定:短期移動平均線が長期移動平均線を上抜けた
  • フィルター判定:スプレッドが許容範囲内である
  • リスク確認:許容損失内のロットである
  • 注文前チェック:証拠金とストップレベルに問題がない

シグナルとフィルターを分離すると、取引回数が減った理由や成績が変化した理由を分析しやすくなります。

4.2 ロット計算で確認する項目

ロット計算では、単純な固定ロットだけでなく、銘柄仕様と口座状態を確認します。

  • 最小ロット
  • 最大ロット
  • ロットステップ
  • 証拠金
  • 許容リスク
  • 損切り幅
  • 口座残高
  • 有効証拠金
  • ティックバリュー
  • ティックサイズ

ロットが銘柄仕様に合わない場合、注文は拒否されることがあります。
許容リスクに基づくロット計算でも、最終的には最小ロット、最大ロット、ロットステップに丸める必要があります。

5. 実装パターン

【結論】
MQL5のEA実装では、処理を関数単位に分け、OnTickを全体の制御役にすると見通しがよくなります。
注文処理では、OrderSendの前にOrderCheckでリクエストの妥当性を確認します。

実装パターンとしては、OnTickにすべてを書くのではなく、関数を分けます。

OnTick
├─ データ更新
├─ ポジション確認
├─ 取引可能条件の確認
├─ シグナル判定
├─ ロット計算
├─ 注文前チェック
└─ 注文送信

この構造では、処理の途中で条件を満たさなければ早期に終了できます。

5.1 OnTickを制御役にする

OnTickは、各モジュールを呼び出す入口にします。

void OnTick()
{
   if(!UpdateMarketData())
      return;

   if(!IsTradingAllowedNow())
      return;

   if(HasOpenPosition())
   {
      ManageOpenPosition();
      return;
   }

   int signal = GetEntrySignal();
   if(signal == 0)
      return;

   double lot = CalculateRiskBasedLot();
   if(lot <= 0.0)
      return;

   SendCheckedMarketOrder(signal, lot);
}

この例は設計用の骨組みです。
実際のEAでは、各関数の中で銘柄仕様、口座状態、スプレッド、取引時間、エラー内容を確認します。

5.2 注文前チェックを入れる

MQL5で注文を送る場合、MqlTradeRequestに注文内容を作り、OrderCheckで妥当性を確認してからOrderSendを実行します。

bool SendCheckedMarketOrder(const int signal, const double lot)
{
   MqlTradeRequest request;
   MqlTradeCheckResult check;
   MqlTradeResult result;

   ZeroMemory(request);
   ZeroMemory(check);
   ZeroMemory(result);

   request.action = TRADE_ACTION_DEAL;
   request.symbol = _Symbol;
   request.volume = lot;
   request.type = (signal > 0) ? ORDER_TYPE_BUY : ORDER_TYPE_SELL;
   request.price = (signal > 0)
                   ? SymbolInfoDouble(_Symbol, SYMBOL_ASK)
                   : SymbolInfoDouble(_Symbol, SYMBOL_BID);
   request.deviation = 20;
   request.type_filling = ORDER_FILLING_FOK;

   if(request.price <= 0.0)
   {
      Print("Invalid order price");
      return false;
   }

   if(!OrderCheck(request, check))
   {
      Print("OrderCheck failed. retcode=", check.retcode);
      return false;
   }

   if(check.retcode != TRADE_RETCODE_DONE)
   {
      Print("OrderCheck rejected. retcode=", check.retcode);
      return false;
   }

   if(!OrderSend(request, result))
   {
      Print("OrderSend failed. retcode=", result.retcode);
      return false;
   }

   if(result.retcode != TRADE_RETCODE_DONE &&
      result.retcode != TRADE_RETCODE_PLACED)
   {
      Print("OrderSend not completed. retcode=", result.retcode);
      return false;
   }

   Print("Order sent. ticket=", result.order);
   return true;
}

このコードは検証用のサンプルです。
実運用では、銘柄ごとの約定方式、ストップレベル、フリーズレベル、取引時間、netting口座とhedging口座の違いを確認する必要があります。

6. サンプルコード

【結論】
MQL5のEAサンプルは、シグナル判定だけでなく、データ取得失敗、既存ポジション、ロット制限、注文前チェックを含めると実装意図が明確になります。
以下のコードは、移動平均線の方向を使う簡略化した設計例です。

このサンプルは、EA設計の骨組みを示すためのものです。
特定の銘柄や時間足での運用を指示するものではありません。
パラメータは、銘柄、時間足、ブローカー条件、検証目的に応じて調整が必要です。

#property strict

input int    InpMAPeriod      = 50;
input double InpRiskLot       = 0.10;
input int    InpMaxSpreadPts  = 30;

int ma_handle = INVALID_HANDLE;

int OnInit()
{
   if(InpMAPeriod <= 1)
   {
      Print("Invalid MA period");
      return INIT_PARAMETERS_INCORRECT;
   }

   ma_handle = iMA(_Symbol, _Period, InpMAPeriod, 0, MODE_EMA, PRICE_CLOSE);
   if(ma_handle == INVALID_HANDLE)
   {
      Print("Failed to create MA handle");
      return INIT_FAILED;
   }

   return INIT_SUCCEEDED;
}

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

void OnTick()
{
   if(!IsSpreadAcceptable())
      return;

   if(HasOpenPosition())
      return;

   int signal = GetMASignal();
   if(signal == 0)
      return;

   double lot = NormalizeLot(InpRiskLot);
   if(lot <= 0.0)
      return;

   SendCheckedMarketOrder(signal, lot);
}

bool IsSpreadAcceptable()
{
   long spread = SymbolInfoInteger(_Symbol, SYMBOL_SPREAD);
   if(spread <= 0 || spread > InpMaxSpreadPts)
   {
      Print("Spread filter blocked trading. spread=", spread);
      return false;
   }
   return true;
}

bool HasOpenPosition()
{
   return PositionSelect(_Symbol);
}

int GetMASignal()
{
   double ma_values[];
   double close_values[];

   ArraySetAsSeries(ma_values, true);
   ArraySetAsSeries(close_values, true);

   if(BarsCalculated(ma_handle) < 3)
   {
      Print("MA is not ready");
      return 0;
   }

   int copied_ma = CopyBuffer(ma_handle, 0, 0, 3, ma_values);
   int copied_close = CopyClose(_Symbol, _Period, 0, 3, close_values);

   if(copied_ma < 3 || copied_close < 3)
   {
      Print("Not enough data for signal");
      return 0;
   }

   double closed_close = close_values[1];
   double closed_ma = ma_values[1];

   if(closed_close > closed_ma)
      return 1;

   if(closed_close < closed_ma)
      return -1;

   return 0;
}

double NormalizeLot(const double requested_lot)
{
   double min_lot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
   double max_lot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
   double step    = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);

   if(min_lot <= 0.0 || max_lot <= 0.0 || step <= 0.0)
   {
      Print("Invalid volume specification");
      return 0.0;
   }

   double lot = MathMax(min_lot, MathMin(max_lot, requested_lot));
   lot = MathFloor(lot / step) * step;
   lot = NormalizeDouble(lot, 2);

   if(lot < min_lot)
   {
      Print("Lot is below minimum after normalization");
      return 0.0;
   }

   return lot;
}

bool SendCheckedMarketOrder(const int signal, const double lot)
{
   MqlTradeRequest request;
   MqlTradeCheckResult check;
   MqlTradeResult result;

   ZeroMemory(request);
   ZeroMemory(check);
   ZeroMemory(result);

   request.action = TRADE_ACTION_DEAL;
   request.symbol = _Symbol;
   request.volume = lot;
   request.type = (signal > 0) ? ORDER_TYPE_BUY : ORDER_TYPE_SELL;
   request.price = (signal > 0)
                   ? SymbolInfoDouble(_Symbol, SYMBOL_ASK)
                   : SymbolInfoDouble(_Symbol, SYMBOL_BID);
   request.deviation = 20;
   request.type_filling = ORDER_FILLING_FOK;

   if(request.price <= 0.0)
   {
      Print("Invalid market price");
      return false;
   }

   if(!OrderCheck(request, check))
   {
      Print("OrderCheck call failed. retcode=", check.retcode);
      return false;
   }

   if(check.retcode != TRADE_RETCODE_DONE)
   {
      Print("OrderCheck rejected request. retcode=", check.retcode);
      return false;
   }

   if(!OrderSend(request, result))
   {
      Print("OrderSend call failed. retcode=", result.retcode);
      return false;
   }

   if(result.retcode != TRADE_RETCODE_DONE &&
      result.retcode != TRADE_RETCODE_PLACED)
   {
      Print("OrderSend rejected. retcode=", result.retcode);
      return false;
   }

   Print("Order accepted. order=", result.order, " deal=", result.deal);
   return true;
}

このサンプルでは、CopyBufferの取得件数を確認し、BarsCalculatedでインジケータ計算の準備状況を確認しています。
また、注文送信前にOrderCheckを使い、ロットは銘柄仕様に合わせて丸めています。

7. 設計パターン比較

【結論】
MQL5のEA設計には、単純な条件分岐型、モジュール分割型、状態管理型、複数銘柄管理型があります。
実運用を意識する場合は、状態管理型またはモジュール分割型の方が検証しやすくなります。

方法メリットデメリット向いている場面実装難易度実運用での注意点
条件分岐型実装が簡単処理が増えると原因分析が難しい学習用、単純な検証重複注文や例外処理不足に注意
モジュール分割型保守しやすい関数設計が必要中規模EA、検証用EA関数間の状態共有を明確にする
状態管理型挙動を制御しやすい設計が複雑になりやすい実運用を想定するEA中〜高状態遷移ログを残す
複数銘柄管理型ポートフォリオ検証に使いやすいデータ取得と注文管理が複雑複数通貨EA銘柄ごとの仕様差を確認する
リスク制御中心型ドローダウン管理を組み込みやすい取引機会が減る場合がある資金管理重視のEA停止条件の過剰最適化に注意

設計パターンは、EAの目的と検証段階に応じて選びます。
最初から複雑にしすぎると、どの条件が成績に影響したのか分かりにくくなります。

7.1 学習段階ではモジュール分割型が扱いやすい

中級者がEA設計を学ぶ場合、モジュール分割型が扱いやすいです。
シグナル、フィルター、注文処理、リスク管理を関数として分ければ、検証時に差し替えやすくなります。

7.2 実運用を意識するなら状態管理を追加する

実運用では、EAが現在どの状態にあるかを明確にします。
たとえば、ドローダウン停止中なのか、取引時間外なのか、ポジション保有中なのかを区別します。

状態を区別しないEAは、同じシグナルに対して意図しない注文を送る可能性があります。

8. バックテストで確認すべき項目

【結論】
バックテストでは、総損益だけでなく、最大ドローダウン、取引回数、連敗数、スプレッド条件、パラメータ依存性を確認します。
成績が一部の期間や設定に強く依存するEAは、フォワードテストで崩れやすくなります。

バックテストは、EAの構造が期待どおりに動くかを確認する工程です。
利益の見込みを断定する工程ではありません。

8.1 必ず見るべき指標

確認すべき項目は以下です。

  • 総損益
  • 最大ドローダウン
  • 勝率
  • 損益比
  • 取引回数
  • 連敗数
  • 平均保有時間
  • スプレッド条件
  • 期間依存性
  • パラメータ依存性

勝率が高くても、損益比が悪いEAは大きな損失で成績が崩れる場合があります。
取引回数が少なすぎるEAは、統計的な再現性を判断しにくくなります。

8.2 過剰最適化を避ける視点

過剰最適化は、過去データに合わせすぎた設定が将来の相場で機能しにくくなる状態です。
パラメータを細かく調整しすぎると、バックテスト上の成績だけが改善される場合があります。

以下の傾向がある場合は注意します。

  • 特定の期間だけ極端に成績がよい
  • パラメータを少し変えると成績が大きく崩れる
  • 取引回数が少ないのに成績が極端によい
  • スプレッドを広げると急に悪化する
  • 損切りや利確が銘柄の値動きに合っていない

バックテストでは、最良の数値だけでなく、条件を少し変えたときの安定性を確認します。

9. フォワードテストで確認すべき項目

【結論】
フォワードテストでは、バックテストで見えにくい約定差、スプレッド拡大、取引頻度、VPS環境での安定性を確認します。
バックテストとフォワードテストの結果が完全に一致するとは限りません。

フォワードテストは、過去データではなく、現在進行中の相場でEAの挙動を確認する工程です。
実運用前には、デモ口座や小さな条件で挙動を確認する必要があります。

9.1 フォワードテストで見る項目

確認すべき項目は以下です。

  • 約定差
  • スプレッド拡大時の挙動
  • 取引頻度
  • ドローダウン
  • バックテストとの乖離
  • ブローカー差
  • VPS環境での安定性
  • 注文拒否の頻度
  • ログの分かりやすさ

バックテストでは約定条件が単純化される場合があります。
リアルタイム環境では、スリッページ、約定遅延、取引時間制限、ブローカーごとの約定方式が影響します。

9.2 デモ口座とリアル口座の違い

デモ口座とリアル口座では、約定条件が異なる場合があります。
特に、スプレッド、約定速度、注文拒否、流動性の違いはEAの成績に影響します。

フォワードテストでは、損益だけでなく、EAが想定どおりに停止し、想定どおりに注文を見送っているかを確認します。

10. 実運用での注意点

【結論】
MQL5のEAを実運用する場合は、スプレッド、約定、レバレッジ、ドローダウン、ブローカー仕様、口座タイプの違いを考慮します。
バックテストで良い結果が出ても、実運用で同じ結果になるとは限りません。

実運用では、EAが技術的に動くことと、運用条件に耐えられることを分けて考えます。
アルゴリズム取引では、想定外の相場変動や約定条件の変化により、損失が拡大する場合があります。

10.1 スプレッドと約定条件

スプレッドが広がると、エントリー直後の含み損が大きくなります。
短期売買EAでは、スプレッド拡大が成績に強く影響する場合があります。

約定遅延やスリッページも確認が必要です。
特に経済指標発表時や市場流動性が低い時間帯では、想定価格で約定しない場合があります。

10.2 netting口座とhedging口座

MQL5では、口座タイプによってポジション管理の考え方が変わります。

  • netting口座:同一銘柄のポジションが基本的に集約される
  • hedging口座:同一銘柄で複数ポジションを持てる

ポジション管理EAでは、この違いを考慮する必要があります。
PositionSelectだけで十分か、チケット単位の管理が必要かは、口座タイプとEAの目的によって変わります。

10.3 レバレッジとドローダウン

レバレッジが高いほど、同じ値動きでも損益変動が大きくなりやすいです。
ロットを大きくすると、最大ドローダウンや連敗時の資金減少も大きくなります。

EAには、日次損失、最大ドローダウン、連敗回数、証拠金維持率などを使った停止条件を入れる設計が有効です。
ただし、停止条件も過去データに合わせすぎると、過剰最適化の原因になります。

11. よくある設計ミス

【結論】
MQL5のEA設計で多い失敗は、シグナルと注文処理を直結させること、注文前チェックを省略すること、ロット制限を無視することです。
実運用を想定するEAでは、失敗時に何を記録し、どの状態へ戻すかを決めておく必要があります。

11.1 CopyBufferの失敗を無視する

CopyBufferは、常に期待件数を返すとは限りません。
データ不足、ハンドル作成失敗、計算未完了などで、取得件数が不足する場合があります。

取得件数を確認せずに配列へアクセスすると、誤ったシグナルや実行時エラーの原因になります。

11.2 最新足だけで判定する

最新足はティックごとに値が変わります。
最新足だけで判定すると、同じローソク足内でシグナルが出たり消えたりする場合があります。

確定足を使うか、最新足を使うかは、EAの目的に応じて決めます。
ただし、検証時にはどちらを使っているかを明確にする必要があります。

11.3 OrderSendの結果だけを見る

OrderSendの呼び出しが成功しても、取引が意図どおり完了したとは限りません。
MqlTradeResultretcodeを確認し、注文が成立したのか、配置されたのか、拒否されたのかを判定します。

注文前にはOrderCheckを使い、証拠金や取引条件を確認します。

11.4 ログが不足している

ログが不足しているEAは、バックテストやフォワードテストで原因分析が難しくなります。
最低限、以下を記録します。

  • シグナルが発生した理由
  • フィルターで拒否した理由
  • ロット計算結果
  • OrderCheckの結果
  • OrderSendの結果
  • ポジション状態
  • 停止条件の発動理由

ログは多すぎても読みづらくなります。
実装段階では詳細に出し、安定後は重要イベントに絞る設計が扱いやすいです。

12. まとめ

【結論】
MQL5でMetaTrader 5向けのアルゴリズム取引EAを作る場合、売買条件だけでなく、状態管理、注文前チェック、リスク制御、検証手順を含めて設計します。
EAをモジュール化すると、バックテストとフォワードテストで問題点を切り分けやすくなります。

MQL5のEA設計では、OnInitで初期化し、OnTickで判断と管理を行い、OnDeinitで後処理を行う構造が基本です。
インジケータ値はハンドルとCopyBufferを使って取得し、取得件数や確定足の扱いを明確にします。

注文処理では、MqlTradeRequestMqlTradeCheckResultMqlTradeResultを使い、OrderCheckOrderSendの結果を確認します。
実運用では、スプレッド、約定差、ロット制限、口座タイプ、ブローカー仕様、ドローダウンリスクを考慮する必要があります。

バックテストはEAの構造確認に有効ですが、将来の利益を保証するものではありません。
実運用前には、フォワードテストで再現性と安定性を確認する必要があります。

FAQ

MQL5のアルゴリズム取引EA設計とは何ですか?

MQL5のアルゴリズム取引EA設計とは、売買条件、リスク管理、注文前チェック、ポジション管理、停止条件を分けて構成することです。単純なエントリー条件だけではなく、EA全体の状態を管理する考え方が重要です。

MQL5ではインジケータ値をどのように取得しますか?

MQL5では、多くのインジケータ関数でハンドルを作成し、CopyBufferでバッファ値を取得します。取得件数が不足する場合があるため、戻り値を確認してから値を使います。

OnTickには何を書くべきですか?

OnTickには、データ更新、取引可否の確認、シグナル判定、リスク確認、注文処理、ポジション管理を呼び出す制御処理を書きます。すべての詳細処理を直接書くより、関数に分けると保守しやすくなります。

OrderSendの前にOrderCheckは必要ですか?

注文前にはOrderCheckで証拠金や取引条件を確認する設計が有効です。OrderSendだけに依存すると、注文拒否の原因を切り分けにくくなります。

netting口座とhedging口座でEA設計は変わりますか?

netting口座とhedging口座では、同一銘柄のポジション管理方法が変わります。netting口座ではポジションが集約されやすく、hedging口座では複数ポジション管理が必要になる場合があります。

バックテストで重視すべき項目は何ですか?

バックテストでは、総損益だけでなく、最大ドローダウン、取引回数、連敗数、損益比、スプレッド条件、パラメータ依存性を確認します。成績が一部の条件に強く依存するEAは、フォワードテストで崩れやすくなります。

フォワードテストでは何を確認しますか?

フォワードテストでは、約定差、スプレッド拡大、取引頻度、ドローダウン、バックテストとの乖離、VPS環境での安定性を確認します。バックテストと実運用では条件が異なる場合があります。

EAを実運用する前に注意すべきことは何ですか?

実運用前には、スプレッド、約定条件、ブローカー仕様、口座タイプ、レバレッジ、ドローダウン許容度を確認します。バックテスト結果は将来の利益を保証しないため、フォワードテストで挙動を確認する必要があります。