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のトレードは以下の流れです。
- シグナル発生(エントリー条件)
- 注文処理(OrderSend)
- 約定(execution)
- 保有管理
- 決済
従来の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は以下の流れで動きます。
- ティック(価格更新)が発生
- OnTickが呼ばれる
- 現在状態に応じた処理を実行
- 条件成立で状態遷移
つまり、
- 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」
という構造に近づきます。