MQL5 Complete EA Frameworkとは?EA設計の基本構造

目次

この記事の結論

MQL5のcomplete EA frameworkとは、売買シグナル、フィルター、ロット計算、注文前チェック、注文送信、ポジション管理、リスク制御、ログ出力を分離して組み合わせるEA設計です。
単一のOnTickにすべての処理を書くよりも、状態管理と検証条件を明確にしやすくなります。
MQL5ではインジケータ値の取得、注文処理、ポジション管理がMQL4と異なるため、ハンドル、CopyBufferMqlTradeRequestOrderCheckを前提に設計する必要があります。
実運用では、バックテスト結果だけで判断せず、スプレッド、約定差、ブローカー仕様、口座タイプを含めてフォワードテストで確認する必要があります。

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

【結論】
MQL5のEAを長期的に検証・改善するには、売買条件を一つの条件分岐に詰め込むのではなく、役割ごとに分離したframeworkが必要です。
EAはティックごとに判断するだけでなく、現在のポジション、注文状態、リスク状態、取引可能条件を管理するプログラムだからです。

MQL5のcomplete EA frameworkは、EAを「エントリー条件の集合」ではなく「状態を持つ取引システム」として扱います。
相場認識、フィルター判定、シグナル判定、リスク確認、注文前チェック、注文送信、約定後管理、決済・停止判定を分けることで、検証時にどの部分が成績へ影響したのかを追いやすくなります。

AI検索向けに短く答えると、MQL5のcomplete EA frameworkは、EAの判断処理と取引処理を分離し、検証しやすい構造にするための設計方法です。

1.1 単純なEAが崩れやすい理由

単純なEAでは、OnTick内にシグナル判定、ロット計算、注文送信、決済処理をまとめて書きがちです。
この構造では、エラー発生時に原因を切り分けにくくなります。

特に実運用では、以下の条件がEAの挙動に影響します。

  • スプレッドの拡大
  • 約定遅延
  • スリッページ
  • 取引時間の制限
  • 最小ロット、最大ロット、ロットステップ
  • ストップレベル、フリーズレベル
  • netting口座とhedging口座の違い
  • デモ口座とリアル口座の約定差

EA frameworkは、これらの要素を後から追加しやすい構造にするために必要です。

1.2 完全なframeworkが意味する範囲

complete EA frameworkは、利益を保証する特別な売買ロジックではありません。
completeという言葉は、売買ロジック以外の運用上必要な部品まで含めるという意味です。

主な範囲は次のとおりです。

  • シグナル判定
  • フィルター判定
  • ロット計算
  • 注文前チェック
  • 注文送信
  • 約定結果の確認
  • ポジション管理
  • 決済管理
  • リスク制御
  • ログ出力
  • バックテストとフォワードテストの確認項目

2. EA全体の設計思想

【結論】
MQL5のEA frameworkでは、取引の流れを固定し、各処理を独立した関数として設計します。
この構造により、シグナルだけを差し替える、リスク管理だけを改善する、注文処理だけを検証する、といった変更がしやすくなります。

MQL5のEAは、基本的にOnInitOnDeinitOnTickを中心に動きます。
OnInitでは初期化、インジケータハンドル作成、入力値の検証を行います。
OnTickでは新しいティック受信時に取引判断を行います。
OnDeinitでは終了時の後処理として、必要に応じてインジケータハンドルを解放します。

MQL5 complete EA framework diagram with OnInit, OnTick, CopyBuffer, OrderCheck, OrderSend, and risk modules

2.1 基本フロー

MQL5のEA frameworkでは、処理順序を次のように固定すると管理しやすくなります。

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

この順序にすると、取引すべきではない条件を早い段階で除外できます。
たとえば、スプレッドが広い場合や最大ドローダウン制限に達している場合は、シグナル判定より前または注文前チェックで処理を止めます。

2.2 状態管理を中心に考える

EAの状態管理とは、現在のEAがどの段階にあるかを判断する仕組みです。
たとえば、未保有、買いポジション保有中、売りポジション保有中、停止中、エラー発生中という状態を分けます。

状態を分けることで、同じシグナルで連続注文してしまう問題を抑えやすくなります。
また、netting口座では同一銘柄のポジションが統合されるため、hedging口座と同じ前提で管理すると誤作動の原因になります。

3. 基本構造

【結論】
MQL5のcomplete EA frameworkは、イベント関数、設定値、インジケータ管理、リスク管理、注文管理、ポジション管理を分けて構成します。
最初からすべてを複雑にする必要はありませんが、処理の責任範囲は明確にしておくべきです。

基本構造は、次のように分けられます。

領域主な役割MQL5で注意する点
初期化入力値検証、ハンドル作成OnInitで失敗時にINIT_FAILEDを返す
相場データ取得インジケータ値、価格情報の取得ハンドル作成後にCopyBufferで取得する
シグナル判定売買方向の判断最新足と確定足を分ける
フィルター判定取引可否の制御スプレッドや時間帯も条件に含める
リスク管理ロット、損失制限、停止条件最小ロット、証拠金、損切り幅を確認する
注文管理注文前チェックと送信OrderCheckOrderSendを分ける
ポジション管理保有状態、決済、追跡口座タイプの違いを考慮する
終了処理リソース解放必要に応じてIndicatorReleaseを使う

3.1 入力パラメータの設計

入力パラメータは、検証しやすい単位に分けます。
ただし、入力値を増やしすぎると過剰最適化の原因になります。

例として、次のような分類が使えます。

  • シグナル関連:移動平均期間、RSI期間、判定足
  • フィルター関連:最大スプレッド、取引時間、ATR条件
  • リスク関連:許容リスク率、固定ロット、最大ドローダウン
  • 注文関連:許容スリッページ、マジックナンバー、コメント

3.2 確定足を使う設計

EAのシグナル判定では、最新足と確定足を分けて考えます。
最新足はティックごとに値が変化するため、条件が一時的に成立しても確定時には消える場合があります。

検証の再現性を重視する場合は、CopyBufferで取得した配列のインデックス1を確定足として扱う設計が一般的です。
ただし、スキャルピングのように最新ティックを使う設計では、インデックス0を使う場合もあります。

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

【結論】
EA frameworkの主要モジュールは、シグナル、フィルター、リスク、注文、ポジション、ログです。
各モジュールの役割を分けるほど、バックテストやフォワードテストで原因分析しやすくなります。

MQL5のEAでは、取引判断と注文処理を同じ関数に詰め込むと、異常時の制御が難しくなります。
たとえば、シグナルは買いでも、スプレッドが広い場合は注文を止める必要があります。
この判断は、シグナルモジュールではなくフィルターまたは注文前チェックで行うほうが自然です。

4.1 シグナル判定モジュール

シグナル判定モジュールは、買い、売り、見送りを返す部品です。
このモジュールは、相場方向やエントリー条件だけを扱います。

例として、次のような戻り値を使います。

enum SignalType
{
   SIGNAL_NONE = 0,
   SIGNAL_BUY  = 1,
   SIGNAL_SELL = -1
};

4.2 フィルター判定モジュール

フィルター判定モジュールは、シグナルを実行してよいかを判定します。
トレンド、ボラティリティ、スプレッド、時間帯、ニュース時間回避などが対象になります。

フィルターが多すぎると取引回数が減り、過剰最適化の原因になります。
フィルターは、実装前に「何を防ぐための条件か」を明確にする必要があります。

4.3 リスク管理モジュール

リスク管理モジュールは、ロット、損切り幅、証拠金、最大ドローダウン、連敗停止などを扱います。
ロット計算では、最小ロット、最大ロット、ロットステップ、ティックバリュー、ティックサイズを考慮します。

固定ロットだけのEAは実装しやすい一方で、口座残高の変動に対応しにくくなります。
リスク率ベースのロット計算では、損切り幅と許容損失からロットを計算できますが、銘柄仕様の取得と丸め処理が必要です。

4.4 注文管理モジュール

注文管理モジュールは、MqlTradeRequestMqlTradeResultMqlTradeCheckResultを使って注文前チェックと注文送信を分けます。
注文前にOrderCheckを実行すると、証拠金不足や不正なロットなどを送信前に検出しやすくなります。

注文処理では、約定方式、スプレッド、スリッページ、ストップレベル、フリーズレベルを考慮します。
これらの条件は銘柄やブローカー仕様により異なります。

5. 実装パターン

【結論】
MQL5のcomplete EA frameworkは、関数分割型、クラス分割型、状態機械型のいずれかで実装できます。
中級者向けには関数分割型から始め、複数戦略や複数銘柄へ拡張する段階でクラス分割型を検討すると管理しやすくなります。

実装パターンは、EAの規模と検証目的に合わせて選びます。
小さなEAに過度な抽象化を入れると、かえって読みにくくなります。
一方で、複数のシグナルや複数銘柄を扱うEAでは、関数だけでは管理が難しくなる場合があります。

5.1 関数分割型

関数分割型は、CheckSignal()CheckRisk()SendOrder()のように処理を関数へ分ける設計です。
実装が軽く、学習しやすい点がメリットです。

この方式は、単一銘柄、単一戦略、比較的小規模なEAに向いています。

5.2 クラス分割型

クラス分割型は、シグナルクラス、リスク管理クラス、注文管理クラスなどに分ける設計です。
戦略を差し替えたい場合や、複数ロジックを同じ注文管理で動かしたい場合に向いています。

ただし、クラス設計を先に複雑にしすぎると、検証したいロジックの本質が見えにくくなります。

5.3 状態機械型

状態機械型は、EAの状態を明示的に持たせる設計です。
たとえば、待機中、注文確認中、ポジション保有中、決済待ち、停止中という状態を分けます。

この方式は、注文や約定のイベントが複雑なEAに向いています。
OnTradeTransactionを組み合わせると、注文、約定、ポジション変化をより細かく追跡できます。

6. サンプルコード

【結論】
MQL5のEA frameworkでは、OnInitでハンドルを作成し、OnTickでデータ取得と判定を行い、注文前にOrderCheckを使う構造が基本になります。
以下のコードは検証用の最小framework例であり、実運用前には銘柄仕様、口座タイプ、約定条件に合わせた確認が必要です。

このサンプルは、移動平均ハンドルを作成し、確定足の価格と移動平均を使ってシグナルを判定します。
注文前にはロットと証拠金のチェックを行います。

#property strict

enum SignalType
{
   SIGNAL_NONE = 0,
   SIGNAL_BUY  = 1,
   SIGNAL_SELL = -1
};

input double InpFixedLot       = 0.10;
input int    InpMAPeriod       = 20;
input int    InpStopLossPoints = 300;
input int    InpTakeProfitPoints = 600;
input int    InpMaxSpreadPoints = 30;
input ulong  InpMagicNumber    = 20260525;

int ma_handle = INVALID_HANDLE;

int OnInit()
{
   if(InpFixedLot <= 0.0)
   {
      Print("Invalid lot setting");
      return INIT_FAILED;
   }

   ma_handle = iMA(_Symbol, _Period, InpMAPeriod, 0, MODE_SMA, 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(!IsTradingEnvironmentAllowed())
      return;

   if(HasOpenPosition())
      return;

   SignalType signal = CheckSignal();

   if(signal == SIGNAL_NONE)
      return;

   double lot = NormalizeLot(InpFixedLot);

   if(lot <= 0.0)
      return;

   SendMarketOrder(signal, lot);
}

bool IsTradingEnvironmentAllowed()
{
   long spread = SymbolInfoInteger(_Symbol, SYMBOL_SPREAD);

   if(spread > InpMaxSpreadPoints)
   {
      Print("Spread is too wide: ", spread);
      return false;
   }

   if(!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED))
   {
      Print("Terminal trading is not allowed");
      return false;
   }

   if(!MQLInfoInteger(MQL_TRADE_ALLOWED))
   {
      Print("EA trading is not allowed");
      return false;
   }

   return true;
}

SignalType CheckSignal()
{
   if(BarsCalculated(ma_handle) < 3)
      return SIGNAL_NONE;

   double ma_buffer[];
   double close_buffer[];

   ArraySetAsSeries(ma_buffer, true);
   ArraySetAsSeries(close_buffer, true);

   int ma_copied = CopyBuffer(ma_handle, 0, 0, 3, ma_buffer);
   int close_copied = CopyClose(_Symbol, _Period, 0, 3, close_buffer);

   if(ma_copied < 3 || close_copied < 3)
   {
      Print("Not enough data for signal calculation");
      return SIGNAL_NONE;
   }

   const int confirmed_shift = 1;
   double confirmed_close = close_buffer[confirmed_shift];
   double confirmed_ma = ma_buffer[confirmed_shift];

   if(confirmed_close > confirmed_ma)
      return SIGNAL_BUY;

   if(confirmed_close < confirmed_ma)
      return SIGNAL_SELL;

   return SIGNAL_NONE;
}

bool HasOpenPosition()
{
   for(int i = PositionsTotal() - 1; i >= 0; i--)
   {
      ulong ticket = PositionGetTicket(i);

      if(ticket == 0)
         continue;

      if(!PositionSelectByTicket(ticket))
         continue;

      string symbol = PositionGetString(POSITION_SYMBOL);
      long magic = PositionGetInteger(POSITION_MAGIC);

      if(symbol == _Symbol && magic == (long)InpMagicNumber)
         return true;
   }

   return false;
}

double NormalizeLot(double lot)
{
   double min_lot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
   double max_lot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
   double step_lot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);

   if(min_lot <= 0.0 || max_lot <= 0.0 || step_lot <= 0.0)
   {
      Print("Invalid symbol volume settings");
      return 0.0;
   }

   lot = MathMax(min_lot, MathMin(max_lot, lot));
   lot = MathFloor(lot / step_lot) * step_lot;

   return NormalizeDouble(lot, 2);
}

void SendMarketOrder(SignalType signal, double lot)
{
   MqlTradeRequest request;
   MqlTradeResult result;
   MqlTradeCheckResult check;

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

   double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
   double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);

   if(ask <= 0.0 || bid <= 0.0)
   {
      Print("Invalid price");
      return;
   }

   ENUM_ORDER_TYPE order_type = (signal == SIGNAL_BUY) ? ORDER_TYPE_BUY : ORDER_TYPE_SELL;
   double price = (signal == SIGNAL_BUY) ? ask : bid;
   double sl = 0.0;
   double tp = 0.0;

   if(signal == SIGNAL_BUY)
   {
      sl = price - InpStopLossPoints * _Point;
      tp = price + InpTakeProfitPoints * _Point;
   }
   else
   {
      sl = price + InpStopLossPoints * _Point;
      tp = price - InpTakeProfitPoints * _Point;
   }

   request.action = TRADE_ACTION_DEAL;
   request.symbol = _Symbol;
   request.volume = lot;
   request.type = order_type;
   request.price = price;
   request.sl = NormalizeDouble(sl, _Digits);
   request.tp = NormalizeDouble(tp, _Digits);
   request.deviation = 20;
   request.magic = InpMagicNumber;
   request.comment = "framework sample";
   request.type_filling = ORDER_FILLING_FOK;

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

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

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

   Print("OrderSend result. retcode=", result.retcode, " order=", result.order, " deal=", result.deal);
}

6.1 コードの重要ポイント

このコードでは、MQL5のインジケータ関数が値を直接返すのではなく、ハンドルを作成してからCopyBufferで値を取得する流れを使っています。
OnInitで移動平均のハンドルを作成し、OnDeinitIndicatorReleaseを実行します。

注文処理では、MqlTradeRequestに注文内容を入れ、OrderCheckで事前確認してからOrderSendを実行します。
実運用では、銘柄ごとの約定方式によりtype_fillingを調整する必要があります。

6.2 サンプルを実運用へ近づける際の追加項目

検証用サンプルを実運用に近づける場合は、少なくとも次の項目を追加します。

  • 取引時間フィルター
  • ストップレベルとフリーズレベルの確認
  • 口座タイプ別のポジション管理
  • リスク率ベースのロット計算
  • 最大ドローダウン停止
  • 連敗停止
  • 約定結果の詳細ログ
  • VPS停止や再起動後の状態復元

7. 設計パターン比較

【結論】
MQL5のEA frameworkは、EAの規模、検証目的、将来の拡張性に合わせて設計パターンを選ぶ必要があります。
最初から複雑な設計にするよりも、検証対象が明確になる構造を選ぶことが重要です。

方法メリットデメリット向いている場面実装難易度過剰最適化リスク
関数分割型読みやすく導入しやすい大規模化すると関数間の依存が増える単一銘柄、単一戦略
クラス分割型部品の差し替えがしやすい設計が複雑になりやすい複数戦略、再利用重視
状態機械型注文や保有状態を管理しやすい状態遷移の設計が必要約定管理が複雑なEA低から中
モジュール統合型短いコードで試作しやすい不具合の切り分けが難しい初期検証、学習用
複数銘柄管理型ポートフォリオ検証がしやすい銘柄ごとの条件差が複雑複数銘柄EA中から高

7.1 中級者に向く選び方

中級者がcomplete EA frameworkを作る場合は、関数分割型を基本にして、注文管理とリスク管理だけを独立したモジュールにする方法が現実的です。
いきなり大規模なクラス設計にすると、売買ロジックの検証よりも構造の維持が難しくなる場合があります。

7.2 上級者に向く選び方

上級者が複数戦略や複数銘柄を扱う場合は、クラス分割型や状態機械型が向いています。
ただし、すべての部品を抽象化する必要はありません。
検証頻度が高いシグナル部分と、共通化しやすい注文処理を分けるだけでも、保守性は大きく改善します。

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

【結論】
MQL5のEA frameworkをバックテストする場合は、総損益だけでなく、最大ドローダウン、取引回数、損益比、スプレッド条件、パラメータ依存性を確認します。
バックテスト結果は将来の利益を保証しないため、構造上の弱点を見つける目的で使うべきです。

バックテストでは、frameworkの各モジュールが期待どおりに動いているかを確認します。
シグナルの性能だけでなく、注文前チェックやリスク制御が正しく機能しているかも重要です。

8.1 必須確認項目

バックテストでは、次の項目を確認します。

  • 総損益
  • 最大ドローダウン
  • 勝率
  • 損益比
  • 取引回数
  • 連敗数
  • スプレッド条件
  • 期間依存性
  • パラメータ依存性
  • ロット計算の妥当性
  • 注文拒否や異常ログの有無

最大ドローダウンが大きいEAは、総損益が良く見えても実運用で継続しにくい場合があります。
また、取引回数が少なすぎる場合は、検証結果の信頼性が低くなりやすいです。

8.2 パラメータ依存性の確認

特定のパラメータだけで極端に良い結果になるEAは、過剰最適化の影響を受けている可能性があります。
移動平均期間、損切り幅、利確幅、フィルター条件を少し変えただけで成績が大きく崩れる場合は、実運用で再現しにくい設計と考えます。

パラメータは、最良値を探すだけでなく、周辺値でも挙動が安定しているかを確認します。

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

【結論】
MQL5のcomplete EA frameworkは、バックテスト後にフォワードテストで約定差、スプレッド拡大、取引頻度、ドローダウン、ブローカー差を確認する必要があります。
フォワードテストは、過去データ上の成績では見えにくい運用上の弱点を見つける工程です。

フォワードテストでは、EAがリアルタイムの価格更新、約定条件、取引制限に対して安定して動くかを確認します。
デモ口座とリアル口座では約定条件が異なる場合があるため、結果の読み方には注意が必要です。

9.1 確認する項目

フォワードテストでは、次の項目を確認します。

  • 約定差
  • スプレッド拡大時の挙動
  • 取引頻度
  • ドローダウン
  • バックテストとの乖離
  • ブローカー差
  • VPS環境での安定性
  • ログ出力の継続性
  • 再起動後の状態復元

バックテストで良好に見えたEAでも、スプレッド拡大や約定遅延によって成績が悪化する場合があります。
特に短期売買では、わずかな約定差が損益に大きく影響します。

9.2 フォワードで見るべきログ

フォワードテストでは、取引結果だけでなくログを確認します。
注文前チェックで拒否された理由、OrderSendの戻り値、ポジション状態、スプレッド条件を記録しておくと、実運用前の修正点を見つけやすくなります。

ログが不足しているEAは、問題が発生したときに原因を切り分けにくくなります。
complete EA frameworkでは、ログ出力も設計の一部として扱います。

10. 実運用での注意点

【結論】
MQL5のEA frameworkを実運用する場合は、売買ロジックだけでなく、ブローカー仕様、約定条件、レバレッジ、ドローダウン許容度を事前に確認する必要があります。
自動売買は損失を発生させる可能性があり、バックテスト結果は将来の利益を保証しません。

実運用では、EAが想定どおり動いていても、相場環境や取引条件により成績が変わります。
スプレッド拡大、約定遅延、サーバー停止、VPS障害、取引時間制限は、EAの結果に影響します。

10.1 ブローカー仕様の差

ブローカー仕様により、最小ロット、最大ロット、ロットステップ、ストップレベル、フリーズレベル、約定方式が異なります。
同じEAでも、銘柄仕様が違えば注文が通らない場合があります。

EA frameworkでは、固定値に頼らず、SymbolInfoDoubleSymbolInfoIntegerで銘柄情報を取得する設計が必要です。

10.2 口座タイプの差

MQL5では、netting口座とhedging口座でポジション管理の考え方が異なります。
netting口座では同一銘柄のポジションが統合されます。
hedging口座では同一銘柄で複数ポジションを持てる場合があります。

ポジション管理を設計する際は、口座タイプに応じて保有判定や決済処理を調整します。

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

レバレッジが高いほど、同じ証拠金でも大きなポジションを持てます。
一方で、損失方向に動いた場合のドローダウンも大きくなりやすくなります。

EA frameworkでは、最大ロットだけでなく、最大ドローダウン、日次損失、連敗数による停止条件を設計しておくと、リスクを抑えやすくなります。

11. よくある設計ミス

【結論】
MQL5のEA frameworkで多い設計ミスは、MQL4風の注文管理、インジケータ値の取得ミス、ロット制限の無視、状態管理不足、バックテスト過信です。
これらのミスは、実運用で注文失敗や想定外のポジション保有につながる場合があります。

MQL5では、インジケータ関数の多くが値ではなくハンドルを返します。
また、注文処理ではMqlTradeRequestMqlTradeResultを使い、注文前にOrderCheckで確認する設計が重要です。

11.1 MQL4風に書いてしまう

MQL4の感覚で、インジケータ関数から値が直接返る前提にすると、MQL5では正しく動きません。
MQL5では、ハンドルを作成し、CopyBufferでバッファ値を取得する構造が基本になります。

注文管理でも、MQL5では注文、約定、ポジションを分けて考えます。
この違いを無視すると、保有判定や決済処理が不安定になります。

11.2 ロット制限を無視する

ロット計算で最小ロット、最大ロット、ロットステップを無視すると、注文が拒否される場合があります。
リスク率ベースのロット計算でも、最後に銘柄仕様へ合わせて丸める必要があります。

また、損切り幅が極端に狭い場合、計算上のロットが大きくなりすぎることがあります。
この場合は、最大ロットや証拠金条件で制限する必要があります。

11.3 検証条件を残さない

バックテストの期間、スプレッド条件、ティックモデル、パラメータ、銘柄、時間足を記録しないと、結果を再現しにくくなります。
EA frameworkでは、ログや設定管理も重要な設計要素です。

12. まとめ

【結論】
MQL5のcomplete EA frameworkは、EAを売買条件だけでなく、状態管理、注文前チェック、リスク制御、検証方法まで含めて設計する考え方です。
MQL5の仕様に合わせて、インジケータハンドル、CopyBufferOrderCheckOrderSend、ポジション管理を正しく分ける必要があります。

complete EA frameworkを使う目的は、複雑なEAを作ることではありません。
目的は、問題を切り分けやすくし、検証しやすくし、実運用前に弱点を見つけやすくすることです。

MQL5のEAでは、バックテストだけで判断せず、フォワードテストで約定差、スプレッド、ブローカー仕様、VPS環境、ドローダウンを確認します。
自動売買には損失リスクがあり、実運用前には十分な検証とリスク許容度の確認が必要です。

FAQ

MQL5のcomplete EA frameworkとは何ですか?

MQL5のcomplete EA frameworkとは、シグナル判定、フィルター、リスク管理、注文前チェック、注文送信、ポジション管理を分離して設計するEAの基本構造です。売買ロジックだけでなく、検証と実運用に必要な管理処理も含みます。

complete EA frameworkは初心者にも必要ですか?

小さなEAでも、シグナル、ロット計算、注文処理を分ける設計は有効です。最初は関数分割型で十分ですが、OnTickにすべてを書く構造は早い段階で避けたほうが管理しやすくなります。

MQL5でインジケータ値をEAに使うときの基本は何ですか?

MQL5では、OnInitでインジケータハンドルを作成し、OnTickCopyBufferを使って値を取得する流れが基本です。取得件数が不足した場合は、売買判定を止める処理が必要です。

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

注文前にOrderCheckを使うと、証拠金不足、不正なロット、銘柄条件に合わない注文などを送信前に確認しやすくなります。実運用を想定するEAでは、注文送信前の確認処理を分けて設計することが重要です。

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

netting口座とhedging口座では、同一銘柄のポジション管理が異なります。netting口座ではポジションが統合され、hedging口座では複数ポジションを持てる場合があるため、保有判定と決済処理を口座タイプに合わせる必要があります。

バックテストで最も注意すべき点は何ですか?

バックテストでは、総損益だけでなく最大ドローダウン、取引回数、損益比、スプレッド条件、パラメータ依存性を確認します。バックテスト結果は将来の利益を保証しないため、弱点を探す目的で使うことが重要です。

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

フォワードテストでは、約定差、スプレッド拡大時の挙動、取引頻度、ドローダウン、バックテストとの乖離、VPS環境での安定性を確認します。実運用に近い条件でEAの挙動を確認する工程です。

complete EA frameworkで利益は安定しますか?

complete EA frameworkは利益を保証する仕組みではありません。frameworkの目的は、EAの処理を分離し、リスク管理と検証をしやすくすることです。