MQL5重複エントリー防止を実コードで解説|Duplicate Gate・同一バー制御・in-flight lock
MQL5 EAでは、エントリー条件そのものが正しくても、実装上の制御が不足していると重複エントリーが起きることがあります。
たとえば、同じバー内で何度もOnTickが呼ばれる、ボタンを連打する、OrderSend直後にポジション反映が遅れる、発注失敗後に同じ条件を何度も再評価する、BUYとSELLの管理状態が混ざる。こうした状態を放置すると、想定より多いポジションが建つ原因になります。
この記事では、MQL5 EAの重複エントリー防止を、学習用に一般化したコード断片で解説します。完成EAソース全文、外部シート制御、認証、endpoint、token、URL、実運用set値、中核エントリー条件は公開しません。
扱うのは、Duplicate Gate、同一バー制御、in-flight lock、cooldown、同方向重複防止、reason付きログです。売買判断そのものではなく、EAが同じ条件で何度も発注しないための安全設計を整理します。
- この記事で扱う範囲
- 重複エントリーが起きる主な原因
- Duplicate Gateとは
- signalとduplicate gateを分ける理由
- 同一バー制御の考え方
- in-flight lockとは
- cooldownの考え方
- 実コード断片1:side別のEntry Gate状態を持つ
- 実コード断片2:現在バー時刻を取得する
- 実コード断片3:Duplicate Gateで発注可否を確認する
- 実コード断片4:発注試行をmarkする
- 実コード断片5:OnTickからDuplicate Gateを呼ぶ
- 実コード断片6:UI request連打を防ぐ
- よくある失敗例
- ログで確認するポイント
- 開発依頼前に整理する情報
- 公開しない情報
- FAQ
- 関連ページ
- まとめ
この記事で扱う範囲
| 項目 | この記事で扱う内容 | 扱わない内容 |
|---|---|---|
| 目的 | 同一バー・同一方向・同一requestの重複発注を防ぐ設計 | 利益を狙う売買ロジック、具体的なエントリー条件 |
| 主な構造 | Duplicate Gate、same bar guard、in-flight lock、cooldown | 完成EAソース全文、実運用コード全文 |
| 設計対象 | OrderSend前のentry guard、発注中状態、失敗後処理、ログ | 外部制御、認証、実運用set値 |
| コード例 | 学習用に簡略化した短いコード断片 | 中核エントリー条件、独自優位性のある判定式 |
| 確認対象 | DUPLICATE_GATE、SAME_BAR_BLOCK、IN_FLIGHT、COOLDOWN | 推奨ロット、推奨銘柄、売買判断 |
重複エントリーが起きる主な原因
MQL5 EAで重複エントリーが起きる原因は、シグナル条件だけではありません。OnTickの呼び出し頻度、注文結果反映、ボタン操作、発注後の状態管理が関係します。
| 原因 | 起きる問題 | 改善方針 |
|---|---|---|
| 同じバー内でOnTickが何度も動く | 同じシグナルで複数回発注する | last entry barを記録する |
| OrderSend直後にポジション反映が遅れる | まだポジションなしと判断して再送する | in-flight lockを持つ |
| ボタンを連打する | UI requestが複数回処理される | request処理後に即clearし、cooldownを入れる |
| BUY / SELLを同じ状態変数で管理する | 方向別の制御が崩れる | side別にgate状態を分ける |
| 発注失敗後の再試行が無制限 | 短時間に何度もOrderSendする | retry対象とcooldownを分ける |
| position snapshotが古い | 実際の保有状態と判断がずれる | snapshot取得時刻とreasonをログに残す |
重複エントリー防止では、シグナルが出たかどうかよりも、そのシグナルで今発注してよい状態かを分けて確認することが重要です。
Duplicate Gateとは
Duplicate Gateとは、発注処理に進む前に、同じ条件・同じ方向・同じバー・同じrequestで再度エントリーしないように確認する入口です。
Duplicate Gateで確認する代表的な項目です。
- 同じバーで同じ方向へすでに発注していないか
- 現在OrderSend中、または結果反映待ちではないか
- 直近発注からcooldown秒数が経過しているか
- すでに同じ方向のポジションを保有していないか
- 同じUI requestを再処理していないか
- 前回失敗理由が即再試行してよい種類か
Duplicate Gateは、売買シグナルの良し悪しを判定する層ではありません。発注直前の安全確認として扱います。
signalとduplicate gateを分ける理由
EA設計では、signalとduplicate gateを混同しないことが重要です。
| 層 | 役割 | 例 |
|---|---|---|
| signal | エントリー候補があるかを評価する | BUY候補、SELL候補、NO_SIGNAL |
| gate | 候補があっても実行してよいか確認する | spread、position、same bar、cooldown |
| execution | 注文requestを作り、OrderSendへ進む | MqlTradeRequest、MqlTradeResult |
| log | 候補・見送り・実行・失敗理由を残す | SIGNAL_OK、GATE_BLOCK、SEND_FAIL |
シグナルが成立していても、同じバーで既に発注済みなら見送る必要があります。これは「シグナル不成立」ではなく、「duplicate gateで止めた」という扱いです。
同一バー制御の考え方
バー確定型EAでは、同じバーで同じ方向へ何度も発注しないようにすることが重要です。
たとえば、BUY条件が成立したバーで1回発注したら、そのバーが変わるまでBUYの再発注を止めます。SELLも同様に、方向別に最後に発注したバー時刻を記録します。
| 状態 | 扱い |
|---|---|
| BUY発注済みバーと現在バーが同じ | BUY再発注を止める |
| SELL発注済みバーと現在バーが同じ | SELL再発注を止める |
| BUY発注済みだがSELLは未発注 | 設計方針に応じてSELL側を別判定にする |
| バーが変わった | 同一バー制御を次バーへ進める |
BUYとSELLを同じ変数で管理すると、方向別制御が曖昧になります。sideごとに状態を持つ方が確認しやすくなります。
in-flight lockとは
in-flight lockとは、OrderSendを呼んでから結果反映や後処理が完了するまで、同じ経路の再発注を止める状態です。
OrderSend直後は、ポジション一覧への反映がEA側の次処理と完全に同期しない場合があります。その一瞬に「まだポジションがない」と判断して再度OrderSendへ進むと、重複発注の原因になります。
in-flight lockでは、次のような状態を持ちます。
- 現在発注中か
- どのsideの発注か
- どのバーで発注したか
- いつ発注したか
- どのrouteから発注したか
- 解除条件は何か
in-flight lockは、注文成功時だけでなく、失敗時にも解除タイミングを明確にする必要があります。
cooldownの考え方
cooldownは、直近発注や直近失敗から一定時間、再発注を止める制御です。
同一バー制御だけでは不十分な場面があります。たとえば、リアルタイム型EAやボタンクリック型EAでは、同じバー内でなくても短時間に連続操作が起きる場合があります。
| 制御 | 主な目的 |
|---|---|
| same bar guard | 同じシグナルバーでの再発注防止 |
| cooldown | 短時間連続発注や連打の防止 |
| in-flight lock | 注文中・反映待ちの再送防止 |
| position gate | 既存ポジション保有中の新規発注制御 |
| retry gate | 失敗後の再試行条件を制御 |
どれか1つだけで重複を防ぐのではなく、用途ごとに分けて設計すると安全です。
実コード断片1:side別のEntry Gate状態を持つ
以下は、実際のEAで使う考え方を学習用に簡略化したコード例です。完成EAのソース全文ではありません。
// 学習用に一般化したEntry Gate状態例です。
// 実運用EAの完成ソースではありません。
enum EntrySide
{
ENTRY_SIDE_BUY = 0,
ENTRY_SIDE_SELL = 1
};
struct EntryGateState
{
datetime lastEntryBarTime;
datetime lastAttemptTime;
bool inFlight;
string lastRoute;
string lastReason;
};
EntryGateState g_buyGate;
EntryGateState g_sellGate;
void ResetEntryGateState(EntryGateState &gate)
{
gate.lastEntryBarTime = 0;
gate.lastAttemptTime = 0;
gate.inFlight = false;
gate.lastRoute = "NONE";
gate.lastReason = "INIT";
}
void InitEntryGates()
{
ResetEntryGateState(g_buyGate);
ResetEntryGateState(g_sellGate);
Print("DIAG/DUPLICATE_GATE: event=INIT",
" reason=GATE_STATE_RESET");
}この例では、BUY側とSELL側で別々のEntryGateStateを持っています。方向別に状態を分けることで、BUYの発注履歴とSELLの発注履歴を混同しにくくなります。
このコードの役割
| 処理 | 役割 |
|---|---|
| EntrySide | BUY側とSELL側を明示する |
| EntryGateState | 重複発注防止に必要な状態をまとめる |
| lastEntryBarTime | 最後に発注したバー時刻を記録する |
| lastAttemptTime | 最後に発注を試みた時刻を記録する |
| inFlight | OrderSend中または反映待ち状態を示す |
| InitEntryGates | 起動時にgate状態を初期化する |
実コード断片2:現在バー時刻を取得する
以下は、同一バー制御で使う現在バー時刻を取得する学習用コード例です。
// 学習用に一般化した現在バー時刻取得例です。
// 実運用EAの完成ソースではありません。
datetime GetCurrentBarTime()
{
datetime barTime = iTime(_Symbol, PERIOD_CURRENT, 0);
if(barTime == 0)
{
Print("DIAG/DUPLICATE_GATE: event=BAR_TIME_FAIL",
" reason=ITIME_ZERO");
}
return barTime;
}
bool IsSameBar(datetime a, datetime b)
{
if(a == 0 || b == 0)
return false;
return (a == b);
}同一バー制御では、TimeCurrentではなく、対象チャートのバー時刻を基準にする方が確認しやすい場面があります。
このコードの役割
| 処理 | 役割 |
|---|---|
| iTime | 現在チャートのバー時刻を取得する |
| BAR_TIME_FAIL | バー時刻が取れなかった状態をログへ残す |
| IsSameBar | 2つのバー時刻が同じか判定する |
バー時刻が取得できない場合に、そのまま発注へ進むのではなく、reason付きで見送る設計にすると安全です。
実コード断片3:Duplicate Gateで発注可否を確認する
以下は、OrderSendへ進む前に、同一バー・in-flight・cooldownを確認する学習用コード例です。中核エントリー条件は含めていません。
// 学習用に一般化したDuplicate Gate例です。
// 実運用EAの完成ソースではありません。
EntryGateState* ResolveGateBySide(EntrySide side)
{
if(side == ENTRY_SIDE_BUY)
return &g_buyGate;
return &g_sellGate;
}
string EntrySideToText(EntrySide side)
{
return (side == ENTRY_SIDE_BUY ? "BUY" : "SELL");
}
bool CanPassDuplicateGate(EntrySide side,
datetime currentBarTime,
int cooldownSeconds,
string routeName)
{
EntryGateState* gate = ResolveGateBySide(side);
string sideText = EntrySideToText(side);
datetime nowTime = TimeCurrent();
if(currentBarTime == 0)
{
gate.lastReason = "BAR_TIME_NOT_READY";
Print("DIAG/DUPLICATE_GATE: side=", sideText,
" event=BLOCK",
" reason=", gate.lastReason,
" route=", routeName);
return false;
}
if(gate.inFlight)
{
gate.lastReason = "IN_FLIGHT";
Print("DIAG/DUPLICATE_GATE: side=", sideText,
" event=BLOCK",
" reason=", gate.lastReason,
" route=", routeName);
return false;
}
if(IsSameBar(gate.lastEntryBarTime, currentBarTime))
{
gate.lastReason = "SAME_BAR_ALREADY_ENTRY";
Print("DIAG/DUPLICATE_GATE: side=", sideText,
" event=BLOCK",
" reason=", gate.lastReason,
" bar=", TimeToString(currentBarTime, TIME_DATE | TIME_MINUTES),
" route=", routeName);
return false;
}
if(gate.lastAttemptTime > 0 &&
(nowTime - gate.lastAttemptTime) < cooldownSeconds)
{
gate.lastReason = "COOLDOWN";
Print("DIAG/DUPLICATE_GATE: side=", sideText,
" event=BLOCK",
" reason=", gate.lastReason,
" elapsed=", (nowTime - gate.lastAttemptTime),
" route=", routeName);
return false;
}
gate.lastReason = "PASS";
Print("DIAG/DUPLICATE_GATE: side=", sideText,
" event=PASS",
" route=", routeName);
return true;
}この例では、発注に進む前に、バー時刻、in-flight、同一バー、cooldownを確認しています。
このコードの役割
| 処理 | 役割 |
|---|---|
| ResolveGateBySide | BUY / SELL別のgate状態を取り出す |
| BAR_TIME_NOT_READY | バー時刻が取得できない時に止める |
| IN_FLIGHT | 発注中・反映待ちの再送を止める |
| SAME_BAR_ALREADY_ENTRY | 同じバー内の同方向再Entryを止める |
| COOLDOWN | 短時間の連続発注を止める |
| PASS | Duplicate Gateを通過したことをログへ残す |
Duplicate Gateで止めた場合は、シグナル不成立ではなく、発注前安全条件で止めたものとしてログに残します。
実コード断片4:発注試行をmarkする
以下は、OrderSendへ進む直前に、gate状態へ発注試行中であることを記録する学習用コード例です。
// 学習用に一般化した発注試行mark例です。
// 実運用EAの完成ソースではありません。
void MarkEntryAttemptStart(EntrySide side,
datetime currentBarTime,
string routeName)
{
EntryGateState* gate = ResolveGateBySide(side);
string sideText = EntrySideToText(side);
gate.inFlight = true;
gate.lastAttemptTime = TimeCurrent();
gate.lastRoute = routeName;
gate.lastReason = "ATTEMPT_START";
Print("DIAG/DUPLICATE_GATE: side=", sideText,
" event=ATTEMPT_START",
" bar=", TimeToString(currentBarTime, TIME_DATE | TIME_MINUTES),
" route=", routeName);
}
void MarkEntryAttemptSuccess(EntrySide side,
datetime currentBarTime,
string routeName)
{
EntryGateState* gate = ResolveGateBySide(side);
string sideText = EntrySideToText(side);
gate.inFlight = false;
gate.lastEntryBarTime = currentBarTime;
gate.lastAttemptTime = TimeCurrent();
gate.lastRoute = routeName;
gate.lastReason = "ENTRY_SUCCESS";
Print("DIAG/DUPLICATE_GATE: side=", sideText,
" event=ENTRY_SUCCESS",
" bar=", TimeToString(currentBarTime, TIME_DATE | TIME_MINUTES),
" route=", routeName);
}
void MarkEntryAttemptFail(EntrySide side,
string routeName,
string failReason)
{
EntryGateState* gate = ResolveGateBySide(side);
string sideText = EntrySideToText(side);
gate.inFlight = false;
gate.lastAttemptTime = TimeCurrent();
gate.lastRoute = routeName;
gate.lastReason = failReason;
Print("DIAG/DUPLICATE_GATE: side=", sideText,
" event=ENTRY_FAIL",
" reason=", failReason,
" route=", routeName);
}この例では、発注開始、成功、失敗を別々に記録しています。OrderSendへ進む前にin-flightを立て、成功または失敗後に解除します。
このコードの役割
| 処理 | 役割 |
|---|---|
| MarkEntryAttemptStart | 発注試行開始時にin-flightを立てる |
| MarkEntryAttemptSuccess | 発注成功後に同一バー発注済みとして記録する |
| MarkEntryAttemptFail | 発注失敗後にin-flightを解除し、失敗理由を残す |
| lastEntryBarTime | 同一バー再発注防止に使う |
| lastAttemptTime | cooldown制御に使う |
発注成功時だけでなく、失敗時にも状態を更新することが重要です。失敗後にin-flightが残り続けると、以後の発注が止まったままになります。
実コード断片5:OnTickからDuplicate Gateを呼ぶ
以下は、OnTick側からsignal候補を受け取り、Duplicate Gateを通過した場合だけexecution確認へ進む学習用コード例です。実際のエントリー条件やOrderSend本体は含めていません。
// 学習用に一般化したOnTick接続例です。
// 実運用EAの完成ソースではありません。
struct EntryCandidate
{
bool ready;
EntrySide side;
string routeName;
string reason;
};
EntryCandidate BuildEntryCandidate()
{
EntryCandidate candidate;
candidate.ready = false;
candidate.side = ENTRY_SIDE_BUY;
candidate.routeName = "SIGNAL_ROUTE_SAMPLE";
candidate.reason = "NO_SIGNAL";
// 実際のEAでは、ここでsignal評価を行います。
// 中核エントリー条件はこの記事では扱いません。
return candidate;
}
void RouteToExecutionCheck(const EntryCandidate &candidate,
datetime currentBarTime)
{
Print("DIAG/ENTRY_ROUTE: side=", EntrySideToText(candidate.side),
" event=ROUTE_TO_EXECUTION_CHECK",
" route=", candidate.routeName);
// 実際のEAでは、ここでOrderSend前precheckやexecution層へ渡します。
// この記事では実発注処理は扱いません。
}
void OnTick()
{
EntryCandidate candidate = BuildEntryCandidate();
if(!candidate.ready)
{
Print("DIAG/ENTRY: event=SKIP",
" reason=", candidate.reason);
return;
}
datetime currentBarTime = GetCurrentBarTime();
if(!CanPassDuplicateGate(candidate.side,
currentBarTime,
10,
candidate.routeName))
{
return;
}
MarkEntryAttemptStart(candidate.side,
currentBarTime,
candidate.routeName);
RouteToExecutionCheck(candidate,
currentBarTime);
// 実際のEAではOrderSend結果に応じて
// MarkEntryAttemptSuccess または MarkEntryAttemptFail を呼びます。
}この例では、signal候補、duplicate gate、execution確認を分けています。エントリー条件が成立しても、gateを通過しなければexecutionへ進みません。
このコードの役割
| 処理 | 役割 |
|---|---|
| BuildEntryCandidate | Entry候補を作る。中核条件はこの記事では扱わない |
| CanPassDuplicateGate | 重複発注防止の安全確認を行う |
| MarkEntryAttemptStart | execution確認へ進む前にin-flightを立てる |
| RouteToExecutionCheck | OrderSend前precheckやexecution層へ渡す入口 |
| MarkEntryAttemptSuccess / Fail | OrderSend結果に応じてgate状態を更新する |
このように、signal、duplicate gate、executionを分けると、どの段階で止まったかをExpertsログで確認しやすくなります。
実コード断片6:UI request連打を防ぐ
パネルEAや裁量補助EAでは、ボタン連打による重複requestにも注意が必要です。
// 学習用に一般化したUI request重複防止例です。
// 実運用EAの完成ソースではありません。
datetime g_lastUiRequestTime = 0;
int g_uiRequestCooldownSeconds = 2;
bool CanAcceptUiRequest(string objectName)
{
datetime nowTime = TimeCurrent();
if(g_lastUiRequestTime > 0 &&
(nowTime - g_lastUiRequestTime) < g_uiRequestCooldownSeconds)
{
Print("DIAG/UI_REQUEST: event=BLOCK",
" reason=UI_COOLDOWN",
" object=", objectName);
return false;
}
g_lastUiRequestTime = nowTime;
Print("DIAG/UI_REQUEST: event=ACCEPT",
" object=", objectName);
return true;
}UI requestのcooldownは、OrderSendのretry制御とは別です。クリック連打を受けないためのUI層の制御として扱います。
このコードの役割
| 処理 | 役割 |
|---|---|
| g_lastUiRequestTime | 最後にUI requestを受けた時刻を記録する |
| UI_COOLDOWN | 短時間の連続クリックを止める |
| ACCEPT | UI requestを受け付けたことをログへ残す |
ボタン操作は、OnChartEventから直接発注へ進めず、UI requestとして受け取り、Duplicate Gateやexecution precheckへ渡す構造にします。
よくある失敗例
失敗1:シグナル成立だけでOrderSendへ進む
シグナルが成立していても、同一バーで既に発注済み、in-flight中、cooldown中であれば、OrderSendへ進むべきではありません。signalとduplicate gateを分ける必要があります。
失敗2:BUYとSELLを同じ発注履歴で管理する
方向別の状態を分けないと、BUYの履歴がSELL側の制御へ影響したり、逆にSELLの履歴でBUYが止まったりします。side別にgate状態を持つ方が安全です。
失敗3:OrderSend失敗後にin-flightを解除していない
OrderSend失敗時にin-flightを解除しないと、EAが発注中のまま固定され、以後の発注が止まり続ける可能性があります。
失敗4:失敗後に無制限retryする
価格変動、ロット不正、証拠金不足、市場クローズなどを同じ扱いでretryすると危険です。retry対象と即停止対象を分ける必要があります。
失敗5:UIボタン連打をそのまま処理する
ボタンを連打された場合に、同じrequestを連続処理すると重複発注につながります。UI request側にもcooldownや処理済みclearが必要です。
失敗6:ログにblock reasonがない
Duplicate Gateで止めた理由がログに出ていないと、シグナル不成立なのか、同一バー制御なのか、in-flightなのか分かりません。reasonを固定名で出します。
ログで確認するポイント
重複エントリー防止の問題を確認する時は、Expertsログで次の情報を見ます。
| ログ | 見るポイント |
|---|---|
| DUPLICATE_GATE INIT | 起動時にgate状態が初期化されているか |
| DUPLICATE_GATE PASS | 発注前の重複防止チェックを通過したか |
| SAME_BAR_ALREADY_ENTRY | 同じバー内の再発注を止めているか |
| IN_FLIGHT | 発注中・反映待ちの再送を止めているか |
| COOLDOWN | 短時間の連続発注を止めているか |
| ATTEMPT_START | OrderSend前に発注試行状態をmarkしているか |
| ENTRY_SUCCESS | 成功時に発注済みバーを記録しているか |
| ENTRY_FAIL | 失敗時にin-flightを解除し、理由を残しているか |
ログ確認の基本は、次のページも参考にしてください。
開発依頼前に整理する情報
EAの重複発注防止を開発・改修する場合、次の情報を先に整理しておくと仕様のすれ違いを減らせます。
- バー確定型か、リアルタイム反応型か
- 同一バー内で同方向再Entryを許可するか
- BUY / SELLを方向別に管理するか
- ポジション保有中の追加Entryを許可するか
- OrderSend直後のin-flight lockを使うか
- 発注失敗後のcooldown秒数
- retry対象にするretcode
- UIボタン連打への対策
- 手動Entryと自動Entryの扱い
- Duplicate Gateのログ粒度
仕様書、setファイル、ログ、スクリーンショットを整理する場合は、次のページも確認してください。
MT5開発依頼前に用意する資料まとめ|仕様書・setファイル・ログ・スクリーンショット
公開しない情報
この記事では、MQL5の重複エントリー防止を学ぶために、公開可能な範囲だけを一般化して解説しています。以下は公開しません。
- 完成EAソース全文
- 外部シート参照による動作制御ロジック
- 外部シートCSV取得、解析、時間枠、方向制御ロジック
- 認証、口座許可判定、購入者管理ロジック
- endpoint、token、URL、Google Sheet ID、Webhook URL、GAS URL
- APIキー、認証トークン、口座番号、サーバー名
- 実運用set値
- 中核エントリー条件
- 中核Trail / Nanpin判定
- 独自優位性のある売買判定式
- 利益保証、勝率保証、推奨ロット、推奨銘柄、推奨エントリー
本記事は、投資判断や売買指示ではなく、MQL5開発におけるDuplicate Gate、同一バー制御、in-flight lock、cooldownの考え方を理解するための技術解説です。
FAQ
Duplicate Gateとは何ですか?
OrderSendへ進む前に、同じ方向・同じバー・同じrequestで重複発注しないよう確認する安全確認層です。signal評価とは別に設計します。
同じバーで再エントリーしないようにするには何を記録しますか?
方向別にlastEntryBarTimeを記録します。BUYとSELLを分け、現在バー時刻と最後に発注したバー時刻が一致する場合は同方向の再Entryを止めます。
in-flight lockはなぜ必要ですか?
OrderSend直後は、ポジション一覧への反映や後処理が完全に終わっていない場合があります。その間に再度OrderSendへ進まないよう、発注中・反映待ち状態を持つためです。
cooldownと同一バー制御は同じですか?
別です。同一バー制御はバー単位の再発注防止、cooldownは秒数ベースの連続処理防止です。ボタン連打や短時間retry対策にはcooldownが有効です。
OrderSend失敗後はすぐretryしてよいですか?
すべてをretryするのは危険です。価格変動のような再評価候補と、ロット不正、証拠金不足、市場クローズのような設定・環境確認対象を分ける必要があります。
UIボタン操作でもDuplicate Gateは必要ですか?
必要です。ボタンクリックはUI requestとして受け取り、その後にDuplicate Gate、precheck、executionを通す設計が安全です。OnChartEventから直接発注する構造は避けます。
このコードは完成EAとして使えますか?
いいえ。この記事のコード例は、重複エントリー防止の考え方を理解するために簡略化した学習用コードです。完成EAとしてそのまま使うことは想定していません。
実際のEAソース全文は公開されていますか?
公開していません。完成EAソース全文、外部シート制御、認証、endpoint、token、URL、実運用set値、中核エントリー条件は公開対象外です。
関連ページ
| ページ | 確認できること |
|---|---|
| MQL5 OrderSend結果ログを実コードで解説 | OrderSend前後のrequest、result、retcode確認 |
| MQL5ログファースト設計を実コードで解説 | Duplicate Gateのblock reasonをログで追う考え方 |
| MQL5 EAの基本イベント構造を実コードで解説 | OnTickからentry guardへ進む責務分離 |
| MQL5パネルUI・チャートObject表示を実コードで解説 | UI requestとexecutionを分ける設計 |
| MQL5 Multi-Logic EA設計を実コードで解説 | ロジック別のposition snapshotとentry管理 |
| MT5のログ確認方法|Experts・Journalの見方 | ExpertsログとJournalログの基本確認 |
| MT5開発依頼前に用意する資料まとめ|仕様書・setファイル・ログ・スクリーンショット | 開発相談前に整理する資料 |
| 不具合報告・調査依頼について | 不具合相談前に送る情報 |
| 免責事項 | 投資判断、損益、利用上の注意に関する確認 |
| 投資助言を行わない方針 | 売買助言ではなく技術支援として扱う方針 |
まとめ
MQL5 EAの重複エントリー防止では、シグナル条件だけでなく、OrderSendへ進む直前の安全確認を設計することが重要です。
特に、次の4点を分けておくと、同一バー内の再発注、OrderSend直後の再送、ボタン連打、無制限retryを防ぎやすくなります。
- same bar guard:同じバーで同方向へ再発注しない
- in-flight lock:OrderSend中・反映待ちの再送を止める
- cooldown:短時間の連続発注やクリック連打を止める
- reason付きログ:なぜ発注しなかったかをExpertsログで追えるようにする
シグナルが成立しているのに発注しない場合でも、それが不具合とは限りません。Duplicate Gateで同一バー、in-flight、cooldown、position状態などにより安全側で止めている可能性があります。
完成EAの中核エントリー条件を公開しなくても、Duplicate Gate、同一バー制御、in-flight lock、cooldownの考え方を理解しておくことで、EAの重複発注、誤発注、連続発注、不具合調査を切り分けやすくなります。

