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責務」

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


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シグナル監視
ENTRYOrderSend(注文処理)
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」

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