この記事の結論
MQL5でEAを開発するには、売買条件だけでなく、状態管理、リスク管理、注文前チェック、約定後管理を分けて設計する必要があります。
MetaTrader 5のEAは、主にOnInit、OnTick、OnDeinitを使って初期化、ティックごとの判定、終了処理を行います。
インジケータ値を使う場合は、ハンドルを作成し、CopyBufferで値を取得する流れになります。
実運用では、バックテスト結果だけで判断せず、スプレッド、約定、ブローカー仕様、フォワードテストで再現性を確認する必要があります。
1. MQL5のEA開発で設計が必要な理由
【結論】
MQL5のEA開発では、売買シグナルだけを作っても安定した運用設計にはなりません。
EAは、相場判定、リスク確認、注文処理、ポジション管理、停止条件を順番に処理する仕組みとして設計する必要があります。
EAは、条件が一致したら注文するだけのプログラムではありません。
実際のEAでは、取引可能な時間か、スプレッドが広すぎないか、必要証拠金が足りるか、既存ポジションがあるか、損失許容範囲を超えていないかを確認します。
MQL5のEA開発で重要なのは、判断処理と実行処理を分けることです。
シグナル判定と注文送信を同じ場所に詰め込むと、エラー時の原因が分かりにくくなります。
【定義】
EA設計とは、自動売買の処理を「判定」「確認」「実行」「管理」「停止」に分けて構成することです。
1.1 条件分岐だけでは不十分な理由
単純なEAでは、OnTick内で条件を確認してすぐに注文する構造になりがちです。
しかし、実運用ではティック更新のたびに同じ条件が何度も成立する場合があります。
そのため、EAには次のような状態管理が必要です。
- すでにポジションを保有しているか
- 同じ足で複数回エントリーしていないか
- 注文送信後の結果を確認したか
- 損失制限に達していないか
- 取引停止条件に該当していないか
MQL5のEAは、状態を持つプログラムとして設計すると、重複注文や想定外の連続取引を抑えやすくなります。
1.2 初心者が最初に分けるべき処理
初心者から中級者がEAを作る場合は、最初から複雑なクラス設計を目指す必要はありません。
まずは、処理の役割を関数単位で分けることが重要です。
基本的な分離は次の通りです。
- 相場認識
- フィルター判定
- シグナル判定
- ロット計算
- 注文前チェック
- 注文送信
- ポジション管理
- 決済判定
- エラーハンドリング
- ログ出力
この分離により、バックテストで問題が出たときに原因を特定しやすくなります。
2. EA全体の設計思想
【結論】
MQL5のEAは、ティックごとに全処理を実行するのではなく、必要な判定を段階的に通過させる構造にすると管理しやすくなります。
設計の中心は、取引するかどうかを決める前に、取引してよい状態かを確認することです。
EA全体の流れは、次の順番で考えると整理しやすくなります。
相場認識
↓
フィルター判定
↓
シグナル判定
↓
リスク確認
↓
注文前チェック
↓
注文送信
↓
約定後管理
↓
決済・停止判定
この流れでは、売買シグナルは中間処理の一部です。
シグナルより前に相場環境と取引可否を確認し、シグナルより後にリスクと注文条件を確認します。

2.1 OnInit、OnTick、OnDeinitの役割
MQL5のEAでは、主に次のイベント関数を使います。
| 関数 | 役割 | EA開発での使いどころ |
|---|---|---|
OnInit | 初期化処理 | インジケータハンドル作成、初期値設定 |
OnTick | 新しいティック受信時の処理 | シグナル判定、注文判定、ポジション管理 |
OnDeinit | 終了時の後処理 | ハンドル解放、終了ログ出力 |
OnTimer | タイマーイベント処理 | 一定間隔の監視処理 |
OnTradeTransaction | 注文や約定の詳細イベント処理 | 約定結果や注文状態の追跡 |
EA記事では、基本的にOnTickが中心になります。
ただし、インジケータを使う場合はOnInitでハンドルを作成し、終了時にOnDeinitで解放する構造が自然です。
2.2 MQL4風の書き方と混同しない
MQL5では、多くのインジケータ関数が値を直接返すのではなく、インジケータハンドルを返します。
その後、CopyBufferでバッファ値を取得します。
たとえば移動平均線を使うEAでは、iMAでハンドルを作り、CopyBufferで現在値や確定足の値を取得します。
この流れを理解しないままMQL4風に書くと、値が取得できない、ハンドルが無効になる、配列の向きを誤るといった問題が起きやすくなります。
3. MQL5 EAの基本構造
【結論】
MQL5のEAは、OnInitで準備し、OnTickで判定し、OnDeinitで後処理する構造を基本にします。
インジケータを使う場合は、ハンドル作成、データ取得、ハンドル解放を明確に分ける必要があります。
最小構造は次のようになります。
#property strict
int OnInit()
{
return INIT_SUCCEEDED;
}
void OnDeinit(const int reason)
{
}
void OnTick()
{
}
この構造に、相場判定、リスク確認、注文処理、決済処理を追加していきます。
3.1 インジケータハンドルを使う基本構造
移動平均線などのインジケータ値を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 MA handle");
return INIT_FAILED;
}
return INIT_SUCCEEDED;
}
void OnDeinit(const int reason)
{
if(ma_handle != INVALID_HANDLE)
{
IndicatorRelease(ma_handle);
}
}
void OnTick()
{
double ma_values[];
ArraySetAsSeries(ma_values, true);
if(BarsCalculated(ma_handle) < 3)
{
Print("MA data is not ready");
return;
}
int copied = CopyBuffer(ma_handle, 0, 0, 3, ma_values);
if(copied < 3)
{
Print("CopyBuffer failed or not enough MA data");
return;
}
double current_ma = ma_values[0];
double confirmed_ma = ma_values[1];
Print("Current MA: ", current_ma, " Confirmed MA: ", confirmed_ma);
}
このコードでは、最新足の値と確定足の値を分けています。
最新足はティックごとに変化するため、売買判定には確定足を使う設計も検討できます。
3.2 最新足と確定足の違い
最新足は、現在形成中のローソク足です。
ティック更新によって値が変わるため、条件が一時的に成立してから消える場合があります。
確定足は、すでに終了したローソク足です。
確定足を使うと、判定の再現性を確認しやすくなります。
EAのシグナル設計では、最新足を使うか確定足を使うかを明確に決める必要があります。
4. 主要モジュールの役割
【結論】
EAは、シグナル判定だけでなく、リスク管理、ロット計算、注文前チェック、ポジション管理を別モジュールとして扱うと保守しやすくなります。
処理を分けることで、検証時にどの条件が成績へ影響したかを確認しやすくなります。
EAの主要モジュールは、次のように分けられます。
| モジュール | 役割 | 主な確認項目 |
|---|---|---|
| 相場認識 | トレンドやレンジを判定する | 移動平均線、ADX、ATR、上位足 |
| フィルター判定 | 取引しない条件を除外する | スプレッド、時間帯、ボラティリティ |
| シグナル判定 | 売買方向を決める | クロス、ブレイク、反転条件 |
| ロット計算 | 注文数量を決める | 最小ロット、最大ロット、ロットステップ |
| 注文前チェック | 注文可能か確認する | 証拠金、ストップレベル、取引許可 |
| 注文送信 | 実際に注文を出す | MqlTradeRequest、OrderSend |
| ポジション管理 | 保有中の状態を管理する | 損切り、利確、トレーリング |
| 停止制御 | 取引を止める条件を管理する | 日次損失、最大ドローダウン |
4.1 リスク管理モジュール
リスク管理では、1回の取引で許容する損失、日次損失、最大ドローダウンを扱います。
バックテストで利益が出ていても、ドローダウンが大きすぎるEAは実運用で継続しにくくなります。
主な管理項目は次の通りです。
- 1回の取引あたりの許容損失
- 連敗時の停止条件
- 日次または週次の損失上限
- 有効証拠金の低下
- レバレッジによる変動幅
バックテスト結果は将来の利益を保証しません。
実運用前には、フォワードテストでドローダウンと約定差を確認する必要があります。
4.2 ロット計算モジュール
ロット計算では、単純な固定ロットだけでなく、口座残高、許容リスク、損切り幅、銘柄仕様を考慮します。
ロット計算で確認する項目は次の通りです。
- 最小ロット
- 最大ロット
- ロットステップ
- 必要証拠金
- 口座残高
- 有効証拠金
- 損切り幅
- ティックバリュー
- ティックサイズ
ロットが銘柄仕様に合っていない場合、注文は失敗します。
注文前にロットを正規化し、必要に応じてOrderCheckで確認します。
5. 実装パターン
【結論】
MQL5のEA実装では、最初に単一シンボルのシンプルな構造を作り、その後でフィルター、ロット計算、ポジション管理を追加する進め方が現実的です。
最初から複数通貨や複雑な最適化を入れると、問題の原因を切り分けにくくなります。
実装パターンは、目的に応じて選びます。
5.1 単一シンボルEA
単一シンボルEAは、_Symbolと_Periodを中心に処理します。
最初のEA開発では、単一シンボルから始めると検証しやすくなります。
向いている用途は次の通りです。
- 初めてのEA開発
- シグナル条件の検証
- インジケータ取得の練習
- 注文処理の確認
5.2 複数シンボルEA
複数シンボルEAでは、銘柄ごとにハンドル、価格、ポジション、取引条件を管理します。
単一シンボルEAよりも状態管理が複雑になります。
銘柄ごとの確認項目は次の通りです。
- スプレッド
- 最小ロット
- 最大ロット
- ロットステップ
- 取引時間
- ストップレベル
- フリーズレベル
- 必要証拠金
複数シンボルEAでは、ある銘柄のエラーが他の銘柄の処理に影響しないように設計する必要があります。
5.3 netting口座とhedging口座の違い
MQL5では、口座タイプによってポジション管理が変わります。
netting口座では、同一銘柄のポジションは基本的に1つに集約されます。
hedging口座では、同一銘柄で複数ポジションを持てる場合があります。
EAでポジションを管理する場合は、口座タイプを前提にした設計が必要です。
同じ注文ロジックでも、口座タイプにより保有状態の見え方が変わる場合があります。
6. サンプルコード
【結論】
EAのサンプルコードでは、シグナル判定、ロット計算、注文前チェック、注文送信を分けて書くと理解しやすくなります。
注文処理では、MqlTradeRequest、MqlTradeResult、MqlTradeCheckResultを使い、送信前にOrderCheckで確認します。
次のコードは、移動平均線を使った検証用の簡易EA構造です。
実運用を前提にした完成版ではなく、設計単位を理解するためのサンプルです。
#property strict
input double RiskLots = 0.10;
input int FastMAPeriod = 10;
input int SlowMAPeriod = 30;
input int StopLossPoints = 300;
input int TakeProfitPoints = 600;
int fast_ma_handle = INVALID_HANDLE;
int slow_ma_handle = INVALID_HANDLE;
int OnInit()
{
fast_ma_handle = iMA(_Symbol, _Period, FastMAPeriod, 0, MODE_SMA, PRICE_CLOSE);
slow_ma_handle = iMA(_Symbol, _Period, SlowMAPeriod, 0, MODE_SMA, PRICE_CLOSE);
if(fast_ma_handle == INVALID_HANDLE || slow_ma_handle == INVALID_HANDLE)
{
Print("Failed to create MA handles");
return INIT_FAILED;
}
return INIT_SUCCEEDED;
}
void OnDeinit(const int reason)
{
if(fast_ma_handle != INVALID_HANDLE)
IndicatorRelease(fast_ma_handle);
if(slow_ma_handle != INVALID_HANDLE)
IndicatorRelease(slow_ma_handle);
}
void OnTick()
{
if(PositionSelect(_Symbol))
return;
int signal = GetSignal();
if(signal == 0)
return;
double lot = NormalizeLot(RiskLots);
if(lot <= 0.0)
{
Print("Invalid lot size");
return;
}
if(!CheckSpread())
return;
SendMarketOrder(signal, lot);
}
int GetSignal()
{
double fast_ma[];
double slow_ma[];
ArraySetAsSeries(fast_ma, true);
ArraySetAsSeries(slow_ma, true);
if(BarsCalculated(fast_ma_handle) < 3 || BarsCalculated(slow_ma_handle) < 3)
return 0;
int fast_copied = CopyBuffer(fast_ma_handle, 0, 0, 3, fast_ma);
int slow_copied = CopyBuffer(slow_ma_handle, 0, 0, 3, slow_ma);
if(fast_copied < 3 || slow_copied < 3)
{
Print("CopyBuffer failed or not enough data");
return 0;
}
bool buy_signal = fast_ma[1] > slow_ma[1] && fast_ma[2] <= slow_ma[2];
bool sell_signal = fast_ma[1] < slow_ma[1] && fast_ma[2] >= slow_ma[2];
if(buy_signal)
return 1;
if(sell_signal)
return -1;
return 0;
}
bool CheckSpread()
{
long spread_points = SymbolInfoInteger(_Symbol, SYMBOL_SPREAD);
if(spread_points > 30)
{
Print("Spread is too wide: ", spread_points);
return false;
}
return true;
}
double NormalizeLot(double lot)
{
double min_lot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
double max_lot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
double lot_step = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
if(lot < min_lot)
lot = min_lot;
if(lot > max_lot)
lot = max_lot;
lot = MathFloor(lot / lot_step) * lot_step;
return NormalizeDouble(lot, 2);
}
void SendMarketOrder(int 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);
double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
request.action = TRADE_ACTION_DEAL;
request.symbol = _Symbol;
request.volume = lot;
request.deviation = 20;
request.magic = 123456;
if(signal > 0)
{
request.type = ORDER_TYPE_BUY;
request.price = ask;
request.sl = ask - StopLossPoints * point;
request.tp = ask + TakeProfitPoints * point;
}
else
{
request.type = ORDER_TYPE_SELL;
request.price = bid;
request.sl = bid + StopLossPoints * point;
request.tp = bid - TakeProfitPoints * point;
}
if(!OrderCheck(request, check))
{
Print("OrderCheck failed. Retcode: ", check.retcode);
return;
}
if(!OrderSend(request, result))
{
Print("OrderSend failed. Retcode: ", result.retcode);
return;
}
Print("OrderSend completed. Order: ", result.order, " Deal: ", result.deal);
}
6.1 サンプルコードの確認ポイント
このサンプルでは、移動平均線のハンドルをOnInitで作成し、CopyBufferで確定足の値を取得しています。
注文前には、スプレッドとロットを確認し、OrderCheckで注文条件を検査しています。
実運用向けに拡張する場合は、次の処理を追加します。
- 取引可能時間の確認
- ストップレベルの確認
- フリーズレベルの確認
- 証拠金不足時の処理
- 連続注文の防止
- 日次損失上限
- 約定後の状態管理
- エラー内容に応じたログ出力
6.2 注文コードで省略してはいけない確認
注文コードでは、OrderSendの成功だけを見ても十分ではありません。
約定方式、スプレッド、ロット、ストップレベル、証拠金、口座タイプにより、注文結果は変わる場合があります。
注文処理では、少なくとも次の項目を確認します。
- 取引が許可されているか
- 銘柄が取引可能か
- ロットが銘柄仕様に合っているか
- ストップロスとテイクプロフィットが近すぎないか
- 必要証拠金が足りるか
- 既存ポジションと矛盾しないか
- netting口座とhedging口座の前提が合っているか
7. 設計パターン比較
【結論】
EA設計には複数の進め方がありますが、初心者から中級者は、単純な条件分岐型から始めて、状態管理型へ発展させる流れが扱いやすいです。
複雑な設計ほど保守性は上がる一方で、実装難易度と検証負荷も上がります。
| 方法 | メリット | デメリット | 向いている場面 | 実装難易度 |
|---|---|---|---|---|
| 条件分岐型 | 作り始めやすい | 処理が増えると崩れやすい | 学習初期、検証用EA | 低 |
| 関数分離型 | 原因を切り分けやすい | 関数設計が必要 | 単一シンボルEA | 中 |
| 状態管理型 | 重複注文や停止条件を扱いやすい | 状態遷移の設計が必要 | 実運用を想定したEA | 中 |
| モジュール分割型 | 保守しやすい | ファイル構成が複雑になりやすい | 中規模以上のEA | 高 |
| 複数シンボル管理型 | 複数銘柄を扱える | 銘柄ごとの仕様差が複雑 | ポートフォリオ型EA | 高 |
7.1 初心者に向く設計
初心者には、関数分離型が向いています。OnTickにすべてを書くのではなく、シグナル判定、ロット計算、注文処理を関数として分けます。
関数分離型にすると、バックテスト結果が悪い場合でも、シグナルが原因なのか、フィルターが原因なのか、注文条件が原因なのかを確認しやすくなります。
7.2 実運用を想定する設計
実運用を想定する場合は、状態管理型が必要になります。
EAは、保有中、待機中、停止中、注文確認中といった状態を持つためです。
状態管理を入れると、次のような制御がしやすくなります。
- 同じ足で再エントリーしない
- 連敗後に取引を停止する
- 日次損失到達後に停止する
- 注文送信後の結果を確認する
- ポジション保有中は新規注文を制限する
8. バックテストで確認すべき項目
【結論】
バックテストでは、総損益だけでなく、最大ドローダウン、取引回数、損益比、期間依存性、パラメータ依存性を確認する必要があります。
バックテスト結果は将来の利益を保証しないため、結果の再現性を確認する材料として扱います。
バックテストで確認する項目は次の通りです。
| 項目 | 確認する理由 | 注意点 |
|---|---|---|
| 総損益 | 全体の収支を確認する | 単独で判断しない |
| 最大ドローダウン | 資金減少の大きさを見る | 許容範囲を事前に決める |
| 勝率 | 取引の成功割合を見る | 勝率だけで判断しない |
| 損益比 | 平均利益と平均損失の関係を見る | 勝率と組み合わせて確認する |
| 取引回数 | 統計の安定性を見る | 少なすぎる場合は判断しにくい |
| 連敗数 | 精神的・資金的な負荷を見る | ロット設計に影響する |
| スプレッド条件 | コストの影響を見る | 固定条件だけで判断しない |
| 期間依存性 | 特定期間だけ強くないかを見る | 複数期間で確認する |
| パラメータ依存性 | 過剰最適化を避ける | 周辺値でも確認する |
8.1 過剰最適化を避ける確認
過剰最適化とは、特定の過去データに合わせすぎた設定になることです。
過去データでは良く見えても、別期間や実運用では崩れやすくなります。
過剰最適化を避けるには、次の確認が必要です。
- パラメータを少し変えても結果が大きく崩れないか
- 複数の期間で極端な差が出ないか
- 取引回数が少なすぎないか
- スプレッドを広げても挙動が破綻しないか
- 損切り幅や利確幅が特定値に依存しすぎていないか
8.2 バックテストで見落としやすい点
バックテストでは、約定条件やスプレッド条件が実運用と異なる場合があります。
そのため、成績が良く見えても、リアル口座で同じ結果になるとは限りません。
特に短期売買EAでは、スプレッド拡大、スリッページ、約定遅延の影響が大きくなります。
バックテストでは、取引コストに対する耐性を確認する必要があります。
9. フォワードテストで確認すべき項目
【結論】
フォワードテストでは、バックテストで作ったEAが現在の相場と実際の約定条件でどのように動くかを確認します。
特に、約定差、スプレッド拡大、取引頻度、ドローダウン、VPS環境での安定性を確認します。
フォワードテストで確認する項目は次の通りです。
- 約定差
- スプレッド拡大時の挙動
- 取引頻度
- 最大ドローダウン
- バックテストとの乖離
- ブローカー差
- VPS環境での安定性
- ログのエラー内容
- 取引停止条件の動作
9.1 デモ口座とリアル口座の違い
デモ口座とリアル口座では、約定条件やスプレッド条件が異なる場合があります。
デモ口座で問題なく動いても、リアル口座では約定遅延やスリッページの影響を受けることがあります。
フォワードテストでは、ログを残して、注文送信時刻、価格、約定結果、エラーコードを確認します。
9.2 VPS環境で確認すること
EAを継続稼働させる場合は、VPS環境の安定性も確認します。
端末の停止、接続断、再起動、時刻ずれがあると、EAの動作に影響する場合があります。
確認する項目は次の通りです。
- MetaTrader 5が継続稼働しているか
- 自動売買が有効になっているか
- ログに通信エラーがないか
- 再起動後にハンドルが再作成されるか
- 取引時間外に不要な注文を出していないか
10. 実運用での注意点
【結論】
MQL5 EAを実運用する場合は、バックテスト結果よりも、スプレッド、約定、ブローカー仕様、ドローダウン管理を重視する必要があります。
EAの成績は、市場環境、取引条件、レバレッジ、パラメータ設定により変動します。
実運用では、次のリスクを考慮します。
- バックテストと実運用は一致しない
- スプレッド拡大で成績が悪化する場合がある
- 約定遅延やスリッページが発生する場合がある
- 過剰最適化はフォワードで崩れやすい
- パラメータ依存が強いロジックは再現性が低くなりやすい
- ドローダウン許容度を事前に決める必要がある
- ブローカー仕様によりEAの挙動が変わることがある
- デモ口座とリアル口座で約定条件が異なる場合がある
10.1 レバレッジとドローダウン
レバレッジが高いほど、同じ価格変動でも資金への影響が大きくなりやすくなります。
ロットを大きくすると利益の変動幅だけでなく、損失の変動幅も大きくなります。
EAでは、最大ドローダウンを事前に想定し、取引停止条件を設けることが重要です。
損失制限がないEAは、相場急変時に想定以上の資金減少を起こす場合があります。
10.2 ブローカー仕様の差
ブローカーや銘柄により、最小ロット、最大ロット、ロットステップ、ストップレベル、フリーズレベル、取引可能時間が異なります。
同じEAでも、ブローカー条件により注文結果や成績が変わる場合があります。
実運用前には、使用する銘柄の取引条件をEA内で確認し、条件に合わない注文を送らない設計にします。
11. よくある設計ミス
【結論】
MQL5 EAの設計ミスで多いのは、OnTickに処理を詰め込みすぎること、CopyBufferの取得失敗を無視すること、注文前チェックを省略することです。
これらのミスは、バックテストでは見えにくく、実運用で問題になる場合があります。
よくある設計ミスは次の通りです。
OnTick内に全処理を書く- インジケータハンドルの作成失敗を確認しない
CopyBufferの取得件数を確認しない- 最新足と確定足を混同する
- 同じ足で何度も注文する
- 既存ポジションを確認しない
- ロット制限を無視する
OrderCheckを使わない- スプレッド拡大を無視する
- netting口座とhedging口座を区別しない
- バックテストの総損益だけで判断する
11.1 CopyBuffer関連のミス
CopyBufferは、要求した本数を常に取得できるとは限りません。
データが不足している場合やハンドルが無効な場合、期待より少ない件数になることがあります。
そのため、戻り値を確認し、必要な本数を取得できない場合は処理を中断します。
取得失敗を無視すると、未初期化の値で売買判定を行う可能性があります。
11.2 注文処理関連のミス
注文処理では、OrderSendだけを呼び出して結果確認を省略する設計が危険です。
ロット、証拠金、ストップレベル、取引許可、口座タイプを確認しないと、注文失敗の原因が分かりにくくなります。
注文前にはOrderCheckを使い、注文送信後にはMqlTradeResultの結果を確認します。
12. まとめ
【結論】
MQL5のEA開発では、売買ロジックよりも先に、EA全体の処理構造を設計することが重要です。
状態管理、リスク管理、注文前チェック、検証手順を分けることで、問題を切り分けやすいEAになります。
MQL5 EAの基本は、OnInitで準備し、OnTickで判定し、OnDeinitで後処理する構造です。
インジケータ値を使う場合は、ハンドルを作成し、CopyBufferで値を取得し、必要に応じてIndicatorReleaseで解放します。
注文処理では、MqlTradeRequest、MqlTradeResult、MqlTradeCheckResultを使い、OrderSendの前にOrderCheckを行う設計が実用的です。
バックテストとフォワードテストでは、総損益だけでなく、ドローダウン、スプレッド、約定差、ブローカー仕様の影響を確認します。
EA開発では、利益を前提にするのではなく、検証しやすく、問題を特定しやすく、リスクを管理しやすい構造を作ることが重要です。
FAQ
MQL5でEAを開発するとき、最初に何を設計すべきですか?
最初に設計すべきものは、売買シグナルではなくEA全体の処理の流れです。相場認識、フィルター判定、リスク確認、注文前チェック、注文送信、ポジション管理を分けると、後から検証しやすくなります。
MQL5のEAではOnTickだけを書けば動きますか?
OnTickだけでも簡単な処理は動きますが、実用的なEAではOnInitとOnDeinitも重要です。インジケータハンドルの作成はOnInit、ハンドル解放などの後処理はOnDeinitで行う構造が自然です。
MQL5でインジケータ値を取得する基本的な流れは何ですか?
MQL5では、インジケータ関数でハンドルを作成し、CopyBufferでバッファ値を取得する流れになります。取得前にはハンドルの有効性とデータ本数を確認し、取得件数が不足する場合は売買判定を中断します。
EA開発でOrderCheckは必要ですか?
注文前にOrderCheckを使うと、証拠金、ロット、ストップレベルなどの条件を事前に確認しやすくなります。OrderSendだけに依存すると、注文失敗の原因を切り分けにくくなります。
固定ロットだけでEAを作ってもよいですか?
固定ロットは実装しやすい方式ですが、口座残高や損切り幅の変化に対応しにくい面があります。実運用を想定する場合は、最小ロット、最大ロット、ロットステップ、許容リスク、証拠金を考慮する必要があります。
バックテストで利益が出ればEAを実運用できますか?
バックテスト結果だけで実運用を判断するのは危険です。スプレッド、約定遅延、スリッページ、ブローカー仕様により、実運用の結果はバックテストと異なる場合があります。
フォワードテストでは何を確認すべきですか?
フォワードテストでは、約定差、スプレッド拡大時の挙動、取引頻度、ドローダウン、バックテストとの乖離を確認します。VPS環境で稼働させる場合は、接続安定性とログのエラーも確認します。
MQL5 EAでよくある初心者の失敗は何ですか?
よくある失敗は、OnTickに処理を詰め込みすぎること、CopyBufferの戻り値を確認しないこと、注文前チェックを省略することです。これらはバックテストでは見えにくく、実運用で問題になる場合があります。