MQL5ステートマシンEA入門|設計・実装・注意点

目次

1. MQL5のステートマシンEAとは

【結論】
ステートマシンEAとは、「状態(state)ごとに処理を分け、条件成立で状態を切り替えることでトレードロジックを管理する設計手法」です。
複雑なEAでも再現性と可読性を維持できるのが最大の特徴です。

1.1 ステートマシンの基本概念

【結論】
ステートマシンは「今どの状態か」を明示的に管理することで、処理の分岐を整理する仕組みです。

【定義】
ステートマシンとは、「状態(state)と状態遷移(transition)によってシステムの動作を制御する設計モデル」です。

MQL5のEAにおいては、以下のような状態で分割します。

  • 待機状態(エントリー条件待ち)
  • エントリー状態(注文実行)
  • ポジション保有状態
  • 決済状態

従来のEAは、OnTick内でif文を多用して処理を分岐します。

if(条件A){
   // エントリー
}

if(条件B){
   // 決済
}

この構造はシンプルですが、条件が増えると以下の問題が発生します。

  • 条件が競合する(同時成立)
  • 処理順序に依存する
  • ロジックが追えなくなる

ステートマシンでは「状態ごとに処理を限定」します。

switch(state){
   case WAIT:
      // エントリー待ち
      break;

   case ENTRY:
      // 注文処理
      break;

   case POSITION:
      // 保有中ロジック
      break;

   case EXIT:
      // 決済処理
      break;
}

この設計により、「今何をすべきか」が明確になります。


1.2 MQL5 EAにおける役割

【結論】
ステートマシンは、EAの「判断ロジック」と「実行処理(execution)」を分離し、安定したトレードを実現するために使われます。

EAは以下の3つの要素で構成されます。

  • シグナル(売買判断)
  • 実行(OrderSendなどの注文)
  • 管理(ポジション・リスク管理)

ステートマシンを使うことで、それぞれを状態として分離できます。

例:

  • WAIT:シグナル待ち
  • ENTRY:OrderSend実行
  • POSITION:保有中(slippageやspread監視)
  • EXIT:決済

特に重要なのは、execution(注文処理)を独立させることです。

理由:

  • 約定失敗(off quotes / no prices)に対応できる
  • spread拡大時に注文を回避できる
  • 再試行ロジックを組み込める

初心者がよくやる失敗:

  • シグナルと注文を同時に書く
  • OrderSendを何度も呼んでしまう
  • ポジション状態を考慮しない

ステートマシンを使うと、

「1状態=1責務」

となるため、これらの問題を回避できます。

MQL5 state machine EA order execution flow showing WAIT, ENTRY, POSITION, and EXIT states, with OrderSend execution, spread filtering, position management, and state transitions visualized alongside trading chart and code logic for MetaTrader 5 Expert Advisor development


1.3 用語整理(初心者向け)

【結論】
最低限、「状態・遷移・トリガー」の3つを理解すれば実装できます。

  • state(状態)
    → EAの現在のフェーズ(例:待機・保有)
  • transition(遷移)
    → 状態を切り替える条件(例:価格到達、時間、indicator)
  • event(トリガー)
    → 遷移を引き起こす要因(OnTick、spread変化、execution結果)

具体例:

  • state:WAIT
  • event:価格が移動平均を上抜け
  • transition:WAIT → ENTRY

さらに実務では以下も重要です。

  • spread:スプレッド(売買コスト)
  • slippage:約定ズレ
  • execution:注文処理(OrderSend)

よくある誤解:

  • 「状態=条件」ではない
    → 状態は“今どこにいるか”、条件は“次にどこへ行くか”
  • 「状態は多いほど良い」ではない
    → 増やしすぎると逆に複雑化する

設計の基本ルール:

  • 状態は最小限にする
  • 遷移条件は明確にする
  • 1つの状態でやることは1つにする

2. なぜステートマシンEAが必要か

【結論】
ステートマシンは「複雑化したEAを制御可能にするための構造」です。
特に条件分岐が増えた時点で、従来のif文設計では再現性と安定性が崩れます。


2.1 従来のEA設計の問題点

【結論】
if文ベースのEAは、小規模では有効ですが、条件が増えると破綻しやすい構造になります。

一般的なEAは以下のように書かれます。

if(エントリー条件){
   OrderSend(...);
}

if(決済条件){
   PositionClose(...);
}

一見問題なさそうですが、実務では次の問題が発生します。

  • 条件の競合(同時に成立する)
  • 実行順序に依存する(上に書いた条件が優先される)
  • 状態が不明確(今ポジションを持っているのか分かりにくい)

さらに深刻なのは、再現性の崩壊です。

例:

  • テストではエントリー→決済の順に動いた
  • 実運用では決済条件が先に成立していた

このような「条件の順番依存」は、バックテストと実運用の乖離を生みます。

初心者がよくやる失敗:

  • ポジション確認をせずにOrderSendする
  • 同一Tickで複数回注文する
  • スプレッド(spread)を考慮しない

結果として、

  • 無駄なエントリー
  • 意図しない決済
  • executionエラー(off quotes, no prices)

が発生します。


2.2 ステートマシン導入のメリット

【結論】
ステートマシンは「処理の順序を固定し、ロジックの再現性を保証する」ために有効です。

主なメリット:

  • ロジックが状態単位で分離される
  • 条件の競合が発生しない
  • デバッグが容易になる

具体的には、

「WAIT状態ではエントリーしか行わない」
「POSITION状態では決済しか行わない」

という制約を設けます。

これにより、

  • 不要なOrderSendが防止される
  • ポジション管理が明確になる
  • slippageやspreadの影響を局所化できる

重要ポイント:

  • 状態が違えば処理も違う
  • 同時に複数の処理は走らない

これはEAの安定性に直結します。

さらに、検証面でもメリットがあります。

  • ロジック単位でテスト可能
  • バグの発生箇所を特定しやすい
  • フォワードテストと一致しやすい

2.3 トレードとの関係(実務視点)

【結論】
ステートマシンは「トレード判断」と「注文実行(execution)」を分離するための設計です。

EAのトレードは以下の流れです。

  1. シグナル発生(エントリー条件)
  2. 注文処理(OrderSend)
  3. 約定(execution)
  4. 保有管理
  5. 決済

従来のEAではこれが混在します。

問題点:

  • execution失敗時の処理が曖昧
  • slippageによるズレを考慮できない
  • spread拡大時に誤発注する

ステートマシンではこれを分離します。

例:

  • WAIT → シグナル監視
  • ENTRY → OrderSendのみ実行
  • POSITION → 保有管理
  • EXIT → 決済

この設計により、

  • 注文失敗時に再試行できる
  • market closed時の処理を制御できる
  • execution結果に応じて分岐できる

注意点:

  • 状態遷移条件を曖昧にしない
  • execution結果(成功・失敗)を必ず判定する
  • スプレッドフィルターをENTRY前に入れる

よくある失敗:

  • ENTRY状態で条件判定を続けてしまう
  • 状態を更新し忘れる
  • エラー時の遷移が未定義

3. MQL5でのステートマシンEAの作り方

【結論】
MQL5でのステートマシンEAは「状態をenumで定義し、OnTick内でswitch制御する」だけで実装できます。
最小構成でも実用的なEAを構築可能です。


3.1 実装手順

【結論】
以下の4ステップで実装すれば、安定した状態管理ができます。

手順:

  • 状態をenumで定義する
  • 現在の状態を変数で保持する
  • OnTickでswitch文を使う
  • 条件成立で状態を更新する

手順① 状態を定義する

enum State {
   WAIT,       // エントリー待ち
   ENTRY,      // 注文処理
   POSITION,   // ポジション保有中
   EXIT        // 決済処理
};

ポイント:

  • 状態名は役割ベースで命名する
  • 最初は4〜5個に抑える(増やしすぎはNG)

手順② 現在状態を管理する

State current_state = WAIT;

注意点:

  • 初期状態は必ず定義する
  • グローバル変数で管理する(OnTickごとに保持するため)

手順③ OnTickで制御する

void OnTick()
{
   switch(current_state)
   {
      case WAIT:
         // エントリー条件チェック
         break;

      case ENTRY:
         // 注文処理
         break;

      case POSITION:
         // 保有管理
         break;

      case EXIT:
         // 決済処理
         break;
   }
}

重要ポイント:

  • 1状態=1処理に限定する
  • 他の状態の処理を混ぜない

手順④ 状態遷移を実装する

if(エントリー条件){
   current_state = ENTRY;
}
if(注文成功){
   current_state = POSITION;
}
if(決済条件){
   current_state = EXIT;
}
if(ポジションなし){
   current_state = WAIT;
}

ポイント:

  • 「いつ状態が変わるか」を明確にする
  • 遷移条件は必ず1つに絞る

3.2 サンプルコード(最小構成)

【結論】
以下のコードで「動くステートマシンEA」の最小形になります。

enum State {
   WAIT,
   ENTRY,
   POSITION,
   EXIT
};

State current_state = WAIT;

void OnTick()
{
   double spread = (SymbolInfoDouble(_Symbol, SYMBOL_ASK) - SymbolInfoDouble(_Symbol, SYMBOL_BID)) / _Point;

   switch(current_state)
   {
      case WAIT:
         if(エントリー条件 && spread < 20) // spreadフィルター
         {
            current_state = ENTRY;
         }
         break;

      case ENTRY:
         if(OrderSend(...) > 0) // 注文成功
         {
            current_state = POSITION;
         }
         else
         {
            current_state = WAIT; // 失敗時は戻す
         }
         break;

      case POSITION:
         if(決済条件)
         {
            current_state = EXIT;
         }
         break;

      case EXIT:
         if(PositionClose(...))
         {
            current_state = WAIT;
         }
         break;
   }
}

実務ポイント:

  • spread制御をENTRY前に入れる
  • execution結果で状態遷移する
  • エラー時の戻り先を定義する

3.3 状態遷移の設計例

【結論】
状態遷移は「トレードの流れそのもの」をそのまま表現すればOKです。

基本フロー:

WAIT → ENTRY → POSITION → EXIT → WAIT

実務で使うフィルター例

エントリー前:

  • spreadチェック(コスト回避)
  • 時間フィルター(ロンドン・NY時間)
  • 指標回避

保有中:

  • slippage影響の確認
  • トレーリングストップ
  • DD(ドローダウン)監視

決済時:

  • 利確・損切り
  • 異常終了(market closed)

よくある失敗

  • 状態を更新し忘れる
    → 無限ループ・停止
  • ENTRYで何度もOrderSendする
    → 重複注文
  • POSITIONでエントリー条件を再チェック
    → ロジック崩壊
  • execution失敗を無視する
    → 実運用で破綻

設計のコツ

  • 「今やるべきことだけを書く」
  • 「未来の状態を意識する」
  • 「例外処理(失敗時)を必ず書く」

4. ステートマシンEAの仕組み

【結論】
ステートマシンEAは「常に1つの状態だけを持ち、イベント発生時にのみ状態を遷移させる」ことで、処理の一貫性と再現性を担保します。
この構造が、複雑なEAでも安定して動作する理由です。


4.1 状態遷移モデルの基本構造

【結論】
ステートマシンは「有限状態機械(FSM)」であり、状態は常に1つだけ存在します。

基本構造:

  • 状態(State)= 現在のフェーズ
  • 遷移(Transition)= 状態を切り替える条件
  • 入力(Input)= 価格・時間・indicatorなど

重要な原則:

  • 同時に複数状態にはならない
  • 状態ごとに処理が固定される
  • 遷移は条件成立時のみ発生する

イメージ:

WAIT → ENTRY → POSITION → EXIT → WAIT

この構造により、

  • 処理の順序が固定される
  • 意図しない分岐が発生しない
  • ロジックの流れが明確になる

4.2 イベント駆動との関係

【結論】
MQL5のEAは「イベント駆動(event-driven)」で動作し、OnTickがトリガーになります。

EAは以下の流れで動きます。

  1. ティック(価格更新)が発生
  2. OnTickが呼ばれる
  3. 現在状態に応じた処理を実行
  4. 条件成立で状態遷移

つまり、

  • OnTick = イベント発生
  • 条件判定 = 遷移トリガー

となります。

例:

void OnTick()
{
   switch(current_state)
   {
      case WAIT:
         if(価格が条件を満たす)
            current_state = ENTRY;
         break;
   }
}

ここで重要なのは、

「イベントは常に発生するが、遷移は条件成立時だけ」

という点です。

この設計により、

  • 不要な処理を防げる
  • CPU負荷を抑えられる
  • ロジックの誤動作を防げる

4.3 トレード処理との分離構造

【結論】
ステートマシンEAでは「判断ロジック」と「注文実行(execution)」を分離することで、実運用の安定性を確保します。

従来の問題:

  • シグナル発生と同時にOrderSend
  • execution失敗時の処理が曖昧
  • slippage・spreadを考慮しない

ステートマシンでは役割を分けます。

状態 役割
WAIT シグナル監視
ENTRY OrderSend(注文処理)
POSITION 保有管理
EXIT 決済

これにより、

  • execution失敗 → 再試行 or WAITへ戻る
  • spread拡大 → ENTRY遷移を抑制
  • market closed → 状態維持

といった制御が可能になります。


execution分離の具体例

case ENTRY:
   if(spread < 20)
   {
      if(OrderSend(...) > 0)
         current_state = POSITION;
      else
         current_state = WAIT;
   }
   break;

ポイント:

  • spreadチェックを事前に行う
  • execution結果で状態を分岐する
  • 成功・失敗を必ず処理する

よくある設計ミス

  • executionをWAITで行う
    → 状態の意味が崩れる
  • POSITIONでOrderSendする
    → 二重注文の原因
  • エラー時の遷移未定義
    → 状態固定・停止

なぜこの構造が安定するのか

理由はシンプルです。

  • 状態ごとに処理が限定される
  • 処理の順序が固定される
  • 例外処理が明示できる

結果として、

  • 再現性が高い(バックテストと一致)
  • デバッグが容易
  • 実運用で破綻しにくい

5. 他のEA設計手法との比較

【結論】
小規模EAはif文で十分ですが、条件が増える場合はステートマシン、さらに拡張性を求めるならモジュラー設計が適しています。
目的に応じて設計手法を選ぶことが重要です。


5.1 比較対象となる設計手法

【結論】
比較すべきは「if文ベース」「ステートマシン」「モジュラーEA」の3種類です。

それぞれの特徴:

  • if文ベースEA
    → 条件分岐のみで構築する最もシンプルな方法
  • ステートマシンEA
    → 状態(state)で処理を管理する構造化設計
  • モジュラーEA(modular design)
    → 機能ごとに分割し、再利用性を高める設計

5.2 比較(構造・性能・実務観点)

【結論】
ステートマシンは「制御構造」、モジュラーは「構成構造」であり、役割が異なります。

比較観点ごとに整理します。


可読性(コードの理解しやすさ)

  • if文
    → 条件が増えると急激に悪化(ネスト地獄)
  • ステートマシン
    → 状態単位で分離されるため安定
  • モジュラー
    → ファイル単位で分離されるため高い

再現性(バックテストと実運用の一致)

  • if文
    → 条件順序依存でズレやすい
  • ステートマシン
    → 状態遷移で順序固定されるため高い
  • モジュラー
    → 設計次第(単体では担保されない)

拡張性(ロジック追加のしやすさ)

  • if文
    → 追加するたびに崩れる
  • ステートマシン
    → 状態追加で対応可能
  • モジュラー
    → 非常に高い(部品追加)

デバッグ性(バグ特定のしやすさ)

  • if文
    → どこで壊れているか分かりにくい
  • ステートマシン
    → 状態単位で追跡可能
  • モジュラー
    → モジュール単位で追跡可能

execution(注文処理)との相性

  • if文
    → 混在しやすく事故が起きる
  • ステートマシン
    → ENTRY状態で分離可能(最適)
  • モジュラー
    → 分離可能だが設計依存

5.3 比較まとめ(実務判断)

【結論】
「規模」と「複雑さ」で選ぶのが最も合理的です。

判断基準:

  • 小規模(条件2〜3個)
    → if文で十分
  • 中規模(条件増加・フィルターあり)
    → ステートマシンが最適
  • 大規模(複数戦略・複数通貨)
    → ステートマシン+モジュラー設計

実務での最適構成

最も多い成功パターン:

  • 制御:ステートマシン
  • 機能:モジュール分割

例:

  • state:WAIT / ENTRY / POSITION / EXIT
  • モジュール:
    • シグナル生成
    • spreadフィルター
    • execution管理
    • リスク管理(lot / DD)

よくある誤解

  • 「モジュラー設計だけで十分」
    → 状態制御がないとロジックが破綻する
  • 「ステートマシンは大規模専用」
    → 中規模から効果が出る
  • 「if文でも同じことができる」
    → 可能だが再現性が落ちる

設計の本質

  • ステートマシン=時間軸の制御
  • モジュラー=構造の分離

この2つは競合ではなく補完関係です。

6. よくある失敗と注意点

【結論】
ステートマシンEAの失敗は「状態設計の曖昧さ」と「遷移管理のミス」に集中します。
特に「状態の増やしすぎ」「遷移条件の不明確さ」「execution例外未処理」は実運用で破綻要因になります。


6.1 状態が増えすぎる問題

【結論】
状態は最小限に抑えないと、逆に可読性と保守性が悪化します。

ありがちな例:

WAIT, ENTRY_READY, ENTRY_WAIT, ENTRY_EXEC,
POSITION_HOLD, POSITION_CHECK, EXIT_READY, EXIT_EXEC

問題点:

  • 状態の意味が重複する
  • 遷移パターンが爆発する
  • バグの特定が困難になる

対策:

  • 1状態=1責務に限定する
  • 似た状態は統合する

推奨構成:

WAIT → ENTRY → POSITION → EXIT

補足:

  • 細かい分岐は「状態内のif」で処理する
  • 状態を増やす前にロジックを整理する

6.2 遷移条件の曖昧さ

【結論】
遷移条件は「1つの明確な条件」に限定しないと、競合や誤動作が発生します。

NG例:

if(条件A || 条件B){
   current_state = ENTRY;
}

問題:

  • どの条件で遷移したか分からない
  • 意図しないタイミングで遷移する

改善例:

if(条件A){
   current_state = ENTRY;
}

または

if(条件A){
   reason = SIGNAL_A;
   current_state = ENTRY;
}

実務ポイント:

  • 遷移条件はログ出力できるようにする
  • spread / slippage / 時間条件は分離する

6.3 状態遷移漏れ・固定化

【結論】
状態を更新しないと、EAはその状態で停止します(無限ループ)。

典型例:

case ENTRY:
   if(OrderSend(...) > 0){
      // 状態更新を忘れている
   }
   break;

結果:

  • ENTRY状態に固定
  • 毎TickでOrderSend実行
  • 重複注文・資金破壊

対策:

if(OrderSend(...) > 0){
   current_state = POSITION;
} else {
   current_state = WAIT;
}

チェックポイント:

  • 全ての分岐で状態が決まるか
  • 失敗時の遷移があるか

6.4 execution(注文処理)の扱いミス

【結論】
executionは必ず「成功・失敗」を分岐しないと、実運用で破綻します。

よくあるエラー:

  • off quotes(価格なし)
  • no prices(価格取得失敗)
  • market closed(市場停止)
  • requote(価格変動)

NG例:

OrderSend(...);
current_state = POSITION;

問題:

  • 実際には注文が通っていない
  • 状態だけ進んでしまう

正しい例:

int result = OrderSend(...);

if(result > 0){
   current_state = POSITION;
} else {
   current_state = WAIT;
}

実務ポイント:

  • execution結果を必ず確認する
  • リトライ回数を制限する
  • spread異常時は遷移させない

6.5 実運用でのリスク

【結論】
ステートマシンでも「市場環境リスク(spread・slippage・流動性)」を考慮しないと意味がありません。

注意すべき要素:

  • spread急拡大(指標時)
  • slippage増加(約定遅延)
  • execution拒否(流動性不足)

対策:

  • ENTRY前にspreadフィルター
  • execution失敗時はWAITに戻す
  • 時間フィルター(ロンドン・NY)

例:

if(spread < 20 && 時間条件OK){
   current_state = ENTRY;
}

6.6 よくある設計ミスまとめ

【結論】
以下の3つを守れば、致命的なバグはほぼ防げます。

重要ルール:

  • 状態は最小限にする
  • 遷移条件を明確にする
  • execution結果で必ず分岐する

補足:

  • ログ出力(Print)で状態を確認する
  • バックテストだけでなくフォワード検証を行う

7. 実務での使いどころ

【結論】
ステートマシンEAは「複数条件を段階的に処理する戦略」で最大の効果を発揮します。
特に、エントリー・保有・決済の制御が重要な戦略ではほぼ必須の設計です。


7.1 向いている戦略

【結論】
「条件が多い」「状態が変化する」戦略ほど、ステートマシンの効果が大きくなります。

代表例:

  • トレンドフォロー
    → エントリー → トレーリング → 決済の段階制御
  • ブレイクアウト
    → レンジ監視 → ブレイク確認 → エントリー → 利確
  • 複数フィルター型
    → spread / 時間 / indicator を順番にチェック

具体例:トレンドフォロー

状態構成:

WAIT → ENTRY → POSITION → EXIT

処理内容:

  • WAIT:移動平均クロス監視
  • ENTRY:OrderSend実行
  • POSITION:トレーリングストップ
  • EXIT:決済

ポイント:

  • 各フェーズでやることが明確
  • ロジックの再現性が高い

具体例:フィルター型EA

エントリー条件を分解:

  • spread < 許容値
  • 時間帯OK(ロンドン・NY)
  • indicator条件成立

ステートマシンではこれを段階化できます。

例:

WAIT(条件監視)
 → ENTRY(execution)
 → POSITION(管理)

メリット:

  • 無駄な計算を減らせる
  • 条件の優先順位が明確

7.2 向いていないケース

【結論】
単純なロジックや超短期戦略では、ステートマシンの恩恵は限定的です。

適さないケース:

  • 条件が1〜2個の単純EA
  • ワンショット型エントリー(即決済)
  • 超短期スキャルピング

理由:

  • 状態管理のオーバーヘッドが増える
  • execution遅延(slippage影響)が大きい
  • 設計コストに対してメリットが小さい

代替手段:

  • if文ベースのシンプル設計
  • 軽量ロジック(高速優先)

7.3 実運用設計例(重要)

【結論】
実運用では「状態+リスク管理+フィルター」の組み合わせが必須です。


基本構成

WAIT
 → ENTRY
 → POSITION
 → EXIT

リスク管理の組み込み

  • lotサイズ制御(資金管理)
  • 最大ポジション数制限
  • ドローダウン(DD)制御

例:

if(DDが閾値超過){
   current_state = WAIT;
}

フィルター設計(実務重要)

ENTRY前に必ず入れる:

  • spreadフィルター
    → コスト異常回避
  • 時間フィルター
    → 流動性の低い時間帯を回避
  • 指標回避
    → 急変動リスク回避

例:

if(spread < 20 && 時間条件OK){
   current_state = ENTRY;
}

execution制御

  • OrderSend成功確認
  • 失敗時の再試行 or WAIT復帰
  • slippage許容範囲設定

実務での重要ポイント

  • 「エントリーしない判断」が最も重要
  • 状態を使って“トレード回避”を実装する
  • executionの不確実性を前提に設計する

7.4 成功パターン(実務視点)

【結論】
成功しているEAは「状態で制御し、フィルターで守る」構造になっています。

典型構成:

  • 状態管理:ステートマシン
  • シグナル:indicator / price action
  • フィルター:spread / 時間 / 指標
  • execution:安全処理
  • リスク管理:lot / DD

よくある失敗

  • フィルターを入れない
    → 実運用で崩壊
  • 状態だけ作って中身が曖昧
    → 意味がない
  • executionを軽視
    → 約定エラー多発

実務結論

  • 「状態」で流れを制御
  • 「フィルター」でリスクを抑制
  • 「execution」で実行品質を担保

この3つが揃って初めて安定したEAになります。

8. 応用:高度なステートマシン設計

【結論】
実務レベルでは「単一状態」だけでなく、「複数状態の並列管理」「サブステート」「モジュール連携」を組み合わせることで、複雑な戦略にも対応できます。
ここが差別化ポイントになります。


8.1 マルチステート管理(複数ポジション対応)

【結論】
複数ポジションや複数通貨を扱う場合は、「状態を1つだけ持つ設計」では不十分になり、個別に状態を管理する必要があります。

単一状態の問題:

  • 複数ポジションを区別できない
  • 通貨ペアごとの制御ができない
  • 同時トレードが破綻する

対策:

  • シンボルごとに状態を持つ
  • ポジションごとに状態を持つ

例(シンボル単位):

struct TradeState {
   string symbol;
   State state;
};

TradeState states[];

ポイント:

  • EURUSDとUSDJPYで別々に管理する
  • 同時に複数の状態が存在する

実務での使いどころ

  • マルチ通貨EA
  • ポートフォリオ運用
  • ヘッジ戦略

注意点

  • 状態数が爆発しやすい
  • メモリ・処理負荷が増える
  • 同期ミスが発生しやすい

対策:

  • 管理単位を明確にする(通貨 or ポジション)
  • 不要な状態は削除する

8.2 サブステート設計(状態の階層化)

【結論】
1つの状態の中をさらに分解することで、複雑なロジックを整理できます。

例:

ENTRY状態を分解

ENTRY
 ├─ CHECK(条件確認)
 ├─ EXECUTE(OrderSend)
 └─ VERIFY(約定確認)

コード例:

enum EntryState {
   CHECK,
   EXECUTE,
   VERIFY
};

EntryState entry_state = CHECK;

メリット:

  • execution処理を細かく制御できる
  • slippage・spread対応が柔軟
  • デバッグしやすい

よくある活用例

  • 注文リトライ制御
  • 指値・成行の切り替え
  • executionエラー対応

注意点

  • 深くしすぎると複雑化
  • 初心者は1階層で十分

8.3 モジュール化との統合

【結論】
最も強力な構成は「ステートマシン(制御)+モジュール(機能)」の組み合わせです。

役割分担:

  • ステートマシン
    → 処理の流れ(いつ何をするか)
  • モジュール
    → 機能の実装(どうやるか)

構成例

State Machine
 ├─ Signal Module(シグナル生成)
 ├─ Filter Module(spread / 時間)
 ├─ Execution Module(OrderSend)
 └─ Risk Module(lot / DD)

コードイメージ:

case WAIT:
   if(CheckSignal() && CheckFilter())
      current_state = ENTRY;
   break;

case ENTRY:
   if(ExecuteOrder())
      current_state = POSITION;
   break;

メリット

  • 再利用性が高い
  • テストしやすい
  • ロジック変更が容易

実務ポイント

  • モジュールは単機能にする
  • stateから直接ロジックを書かない
  • executionは必ず専用関数化

8.4 高度設計での注意点

【結論】
高度化すると「設計負債」が発生しやすく、シンプルさを維持することが最重要です。

よくある失敗:

  • 状態+サブ状態+モジュールで過剰設計
  • 依存関係が複雑化
  • バグの追跡が困難

対策:

  • まず単一ステートで完成させる
  • 必要になってから分割する
  • ログを必ず出力する

実務判断

  • 小規模:単一ステート
  • 中規模:ステート+フィルター
  • 大規模:ステート+モジュール

本質

  • 状態で「流れ」を制御
  • モジュールで「処理」を分離

この分離が、長期運用できるEAを作ります。

9. FAQ(よくある質問)

【結論】
ステートマシンEAは「状態で制御する設計」であり、初心者でも段階的に導入できます。
ここでは実装・運用で頻出する疑問を短く整理します。


9.1 ステートマシンEAとは何ですか?

【結論】
状態(state)と状態遷移(transition)でトレードロジックを管理する設計手法です。

  • 状態ごとに処理を限定する
  • 条件成立で次の状態に移る
    → 複雑なEAでも再現性を保てます

9.2 初心者でも使えますか?

【結論】
シンプルな4状態(WAIT / ENTRY / POSITION / EXIT)から始めれば十分実装可能です。

ポイント:

  • まずは最小構成で動かす
  • 徐々にフィルター(spread / 時間)を追加する
  • いきなり高度設計にしない

9.3 if文ベースのEAとの違いは?

【結論】
if文は「条件で分岐」、ステートマシンは「状態で制御」です。

違い:

  • if文:処理が混在しやすい
  • ステートマシン:状態ごとに分離される

結果:

  • ステートマシンの方が再現性が高い
  • デバッグが容易になる

9.4 パフォーマンス(速度)は落ちますか?

【結論】
通常のEAではほぼ影響はありません。むしろ無駄な処理が減り安定します。

理由:

  • 不要な条件判定が減る
  • 状態ごとに処理が限定される

注意:

  • 超短期スキャルピングでは影響が出る可能性あり(slippage影響)

9.5 どのくらいの規模で必要になりますか?

【結論】
条件分岐が増えた時点で導入を検討すべきです。

目安:

  • 条件2〜3個 → 不要
  • 条件4〜5個以上 → 導入推奨
  • フィルターあり → ほぼ必須

9.6 MT4(MQL4)でも使えますか?

【結論】
同じ設計はMQL4でもそのまま使えます。

違い:

  • 言語仕様は多少異なる
  • しかし構造(state管理)は同じ

9.7 バグは本当に減りますか?

【結論】
状態ごとに処理が分離されるため、バグの発生範囲が限定されます。

効果:

  • 原因特定が容易
  • 再現性が高い
  • 修正が局所化できる

9.8 executionエラー(注文失敗)にはどう対応しますか?

【結論】
ENTRY状態で「成功・失敗」を必ず分岐し、失敗時はWAITに戻します。

例:

if(OrderSend(...) > 0){
   current_state = POSITION;
} else {
   current_state = WAIT;
}

重要:

  • executionは常に失敗する前提で設計する
  • spread / slippageを事前にチェックする

10. まとめ

【結論】
ステートマシンEAは「状態でトレードを制御することで再現性と安定性を確保する設計」です。
中規模以上のEAでは、実質的に必須のアーキテクチャです。


10.1 本記事の要点

【結論】
重要ポイントは以下の3点です。

  • 状態で処理を分離する
  • 遷移条件を明確にする
  • execution結果で必ず分岐する

補足:

  • 「1状態=1責務」を守る
  • 状態は最小限にする
  • 例外処理(失敗時)を必ず定義する

10.2 実務での判断基準

【結論】
EAの規模と複雑さに応じて、導入判断を行うのが最も合理的です。

判断基準:

  • 小規模(単純ロジック)
    → if文で十分
  • 中規模(複数条件・フィルターあり)
    → ステートマシン導入推奨
  • 大規模(複数戦略・複数通貨)
    → ステートマシン+モジュラー設計

10.3 実運用での最適構成

【結論】
安定しているEAは「状態・フィルター・execution」を分離しています。

推奨構成:

  • 状態管理:ステートマシン
  • シグナル:indicator / price action
  • フィルター:spread / 時間 / 指標
  • execution:OrderSend管理
  • リスク管理:lot / ドローダウン(DD)

重要:

  • 「エントリーしない判断」が最も価値がある
  • executionの不確実性を前提に設計する

10.4 導入ステップ(実践用)

【結論】
以下の手順で導入すれば、失敗リスクを最小化できます。

手順:

  • ① WAIT / ENTRY / POSITION / EXITを実装
  • ② シンプルなエントリー条件を組む
  • ③ execution成功判定を追加
  • ④ spreadフィルターを追加
  • ⑤ 時間フィルターを追加
  • ⑥ リスク管理(lot / DD)を追加

ポイント:

  • 一度に全部作らない
  • 段階的に拡張する
  • 常にバックテスト+フォワード検証を行う

10.5 最終結論

【結論】
ステートマシンは「EAの再現性」を担保するための中核技術です。

  • ロジックの一貫性を維持できる
  • 実運用での事故を減らせる
  • 検証結果と実トレードのズレを最小化できる

結果として、

「検証できるEA」=「勝ちやすいEA」

という構造に近づきます。