MQL5ログファースト開発実務ノート|不具合調査しやすいEA・インジの作り方

EAファンクラブ

MQL5でEAやインジケーターを開発する時、後回しにされやすいのがログ設計です。

しかし、実際の開発・検証・販売後サポートでは、ログがないEAやインジほど原因調査が難しくなります。エントリーしない、決済しない、通知が届かない、パネルが表示されない、バックテストとリアルで挙動が違う。このような問題が起きた時、ログが不足していると「どこで止まったのか」を確認できません。

ログファースト開発とは、完成後に慌ててPrintを追加するのではなく、設計段階からどの層で、何が起きて、なぜ止まったのかを追えるようにしておく考え方です。

この記事では、MQL5のEA・インジ開発におけるログファースト設計を、開発実務ノートとして整理します。技術講座のように基礎から順番に説明する記事ではなく、開発依頼前・実装前・検証前・問い合わせ前に確認したい実務判断をまとめます。

完成EAソース全文、外部シート制御、認証、endpoint、token、URL実値、実運用set値、中核Entry条件、中核Trail/Nanpin判定、独自優位性のある売買判定式は公開しません。本記事は、投資判断や売買指示ではなく、MQL5開発で不具合調査しやすいログ設計を理解するための技術記事です。

この記事で扱う実務課題

項目この記事で扱う内容扱わない内容
目的不具合調査しやすいEA・インジのログ設計利益を狙う売買ロジック、具体的なEntry条件
主な対象Expertsログ、Journalログ、event / reason / detail、INIT、SELFCHECK、SNAP、HELP完成EAソース全文、実運用コード全文
設計観点検証、改修、問い合わせ、販売後サポート、長時間稼働確認認証ロジック、外部制御、実運用set値
コード例一般化したログhelper、ログ抑制、INIT / SELFCHECK例実売買条件、独自優位性のある判定式
読者MQL5開発者、EA改修依頼前ユーザー、検証担当者、販売前チェック担当者売買判断や推奨設定を知りたい人

なぜログファースト設計が必要になるのか

EAやインジの不具合相談では、次のような説明だけでは原因を特定できません。

  • EAがエントリーしません
  • 通知が届きません
  • パネルが消えました
  • バックテストでは動いたのにリアルでは動きません
  • たまに決済しません

これらの現象は、見た目は似ていても、原因がまったく違う場合があります。

現象原因の例必要なログ
エントリーしないsignal不成立、GATE_BLOCK、risk停止、外部停止、OrderSend失敗SIGNAL、GATE、RISK、ENTRY、ORDER
決済しないexit条件未成立、対象ポジションなし、close scope不一致、retcode失敗EXIT、POSITION_SNAPSHOT、CLOSE_RESULT
通知が届かない通知OFF、Webhook設定不備、通信失敗、送信抑制NOTIFY、WEBREQUEST、THROTTLE
表示が崩れるObject作成失敗、再描画過多、OnDeinit残存、prefix不一致UI_RENDER、OBJECT_AUDIT、DEINIT
バックテストとリアルで違う判定basis違い、tick挙動、外部制御、ログ抑制条件RUNTIME、BT_SUMMARY、BASIS

ログがなければ、これらをすべて「動かない」としか表現できません。ログファースト設計では、最初から原因を切り分けられるように、各責務でreason付きログを残します。

ログファースト開発の基本定義

ログファースト開発とは、MQL5のEA・インジにおいて、処理本体と同じくらい確認可能性を重視する開発方針です。

単にPrintを増やすことではありません。重要なのは、ログを次のように整理することです。

要素意味
layerどの責務のログかSIGNAL、GATE、ORDER、EXIT、UI、AUTH
event何が起きたかPASS、BLOCK、SKIP、FAIL、DONE
reasonなぜその結果になったかNO_SIGNAL、SPREAD_BLOCK、INVALID_VOLUME
detail補足情報side、logic_id、magic、retcode、count
time basisどの時刻基準かserver time、bar time、local time

ログは「たくさん出す」ことが目的ではありません。あとから見た時に、どの層で止まったか、何を確認すべきかが分かることが目的です。

ExpertsログとJournalログの使い分け

MT5では、主にExpertsログとJournalログを使って状態を確認します。

ログ主な確認対象見る場面
ExpertsログEA・インジが出したPrint、診断ログ、処理結果EAやインジの内部状態、不具合原因、判定理由の確認
JournalログMT5端末、接続、注文、チャート、環境側のログ接続状態、自動売買許可、端末側エラー、標準約定ログの確認

EAやインジの設計判断を確認する時は、Expertsログが中心です。一方で、MT5端末側の接続、取引許可、チャート操作、環境起因の問題はJournalログも確認します。

不具合調査では、Expertsログだけ、またはJournalログだけでは不足することがあります。特にOrderSend失敗、接続不安定、WebRequest、通知失敗、EA削除時の異常などは、両方を確認すると切り分けやすくなります。

INIT / SELFCHECK / SNAP / HELPの役割

ログファースト設計では、通常の処理ログだけでなく、起動時・自己診断・状態共有・ヘルプ導線も重要です。

区分役割確認できること
INIT起動時の初期化結果を確認するバージョン、symbol、timeframe、設定、初期化成功・失敗
SELFCHECK設定や環境の自己診断を行うロット不正、Magic不正、WebRequest未設定、Object状態
SNAP現在状態を要約して共有するruntime状態、ポジション数、設定状態、停止理由
HELP利用者が確認すべき項目を案内するログの見方、問い合わせ前に送る情報、設定確認

INITは起動時の状態確認、SELFCHECKは不正設定の早期検出、SNAPは問い合わせや検証時の状態共有、HELPは利用者が迷わないための案内です。

これらがないEAでは、不具合が出た時に「どの設定で動いていたのか」「起動時に何が失敗していたのか」「現在どの状態なのか」を確認しにくくなります。

理由付きログを残すべき代表箇所

MQL5開発では、次のような箇所にreason付きログを残すと、原因調査がしやすくなります。

ログ区分残す理由
SIGNALシグナル候補があるか確認するSIGNAL_OK、NO_SIGNAL
ENTRY_SKIP候補があるのに発注しない理由を確認するSPREAD_BLOCK、DUPLICATE_BLOCK、RISK_BLOCK
ORDER_FAILOrderSend失敗理由を確認するINVALID_VOLUME、NO_MONEY、INVALID_STOPS
EXIT_SKIP決済しない理由を確認するNO_POSITION、SCOPE_MISMATCH、EXIT_NOT_READY
OBJECT_AUDITObject残存や表示不具合を確認するRESIDUAL_IGNORE、CREATE_FAIL、DELETE_SKIP
WEBREQUEST外部連携の成否を確認するFETCH_OK、FETCH_FAIL、TIMEOUT
NOTIFY通知の送信結果を確認するSEND_OK、SEND_FAIL、THROTTLED

重要なのは、成功ログよりも見送り理由・失敗理由・停止理由です。正常に動いた時だけログが出る設計では、動かなかった時に原因を追えません。

実コード例1:event / reason / detailを分けるログhelper

以下は、設計判断を理解するために一般化した学習用コード例です。完成EAのソース全文ではありません。

// 学習用に一般化したログhelper例です。
// 実運用EAの完成ソースではありません。

bool CanWriteDiagLog()
{
   return true;
}

string SafeLogText(string value, string fallback)
{
   if(value == "")
      return fallback;

   if(StringFind(StringToLower(value), "token") >= 0)
      return "masked";

   if(StringFind(StringToLower(value), "endpoint") >= 0)
      return "masked";

   return value;
}

void WriteDiagLog(string layer,
                  string side,
                  string eventName,
                  string reason,
                  string detail)
{
   if(!CanWriteDiagLog())
      return;

   string safeLayer  = SafeLogText(layer, "GENERAL");
   string safeSide   = SafeLogText(side, "NONE");
   string safeEvent  = SafeLogText(eventName, "UNKNOWN");
   string safeReason = SafeLogText(reason, "NO_REASON");
   string safeDetail = SafeLogText(detail, "no detail");

   Print("DIAG/", safeLayer,
         ": side=", safeSide,
         " event=", safeEvent,
         " reason=", safeReason,
         " detail=", safeDetail);
}

この例では、layer、side、event、reason、detailを分けています。ログを見る時に「どの層で」「どちら側で」「何が起きて」「なぜそうなったか」が追いやすくなります。

また、tokenやendpointなどの機密情報に見える文字列はマスクする考え方を入れています。実運用の認証情報、URL、APIキー、Webhook URLなどをログへそのまま出してはいけません。

実コード例2:ENTRY_SKIPとORDER_FAILを分ける

以下は、設計判断を理解するために一般化した学習用コード例です。完成EAのソース全文ではありません。

// 学習用に一般化したentry判断ログ例です。
// 実運用EAの完成ソースではありません。

struct EntryDecision
{
   bool allowed;
   string side;
   string reason;
   string route;
};

EntryDecision BuildEntryDecision()
{
   EntryDecision decision;
   decision.allowed = false;
   decision.side = "NONE";
   decision.reason = "NO_SIGNAL";
   decision.route = "SIGNAL_ROUTE_SAMPLE";

   // ここでは中核Entry条件は扱いません。
   // 実際のEAでは、signal / gate / risk を別責務で評価します。

   return decision;
}

void TraceEntryDecision(const EntryDecision &decision)
{
   if(!decision.allowed)
   {
      WriteDiagLog("ENTRY", decision.side, "SKIP", decision.reason, decision.route);
      return;
   }

   WriteDiagLog("ENTRY", decision.side, "READY", "ENTRY_READY", decision.route);
}

void TraceOrderFail(string side, string retcodeText, string detail)
{
   WriteDiagLog("ORDER", side, "FAIL", retcodeText, detail);
}

ENTRY_SKIPは、OrderSendへ進む前に止めた状態です。ORDER_FAILは、OrderSendまたは注文結果確認で失敗した状態です。

この2つを混同すると、「シグナルはあったのに発注前条件で止まった」のか、「注文を送ったが拒否された」のかが分からなくなります。

実コード例3:同一ログを出しすぎないログ抑制

以下は、設計判断を理解するために一般化した学習用コード例です。完成EAのソース全文ではありません。

// 学習用に一般化したログ抑制例です。
// 実運用EAの完成ソースではありません。

struct LogThrottleState
{
   string lastKey;
   datetime lastPrintTime;
};

LogThrottleState g_logThrottle;

bool CanPrintStateLog(string key, int intervalSeconds)
{
   datetime nowTime = TimeCurrent();

   if(g_logThrottle.lastKey != key)
   {
      g_logThrottle.lastKey = key;
      g_logThrottle.lastPrintTime = nowTime;
      return true;
   }

   if((nowTime - g_logThrottle.lastPrintTime) >= intervalSeconds)
   {
      g_logThrottle.lastPrintTime = nowTime;
      return true;
   }

   return false;
}

void WriteStateLog(string key,
                   string layer,
                   string eventName,
                   string reason)
{
   if(!CanPrintStateLog(key, 30))
      return;

   WriteDiagLog(layer, "NONE", eventName, reason, key);
}

ログは多ければよいわけではありません。同じ理由のログを毎tick出し続けると、重要な変化が埋もれます。

状態変化時だけ出す、一定秒数ごとに要約する、バックテストでは成功系を抑制するなど、用途に応じてログ粒度を分けることが重要です。

実コード例4:INIT / SELFCHECK / SNAPを分ける

以下は、設計判断を理解するために一般化した学習用コード例です。完成EAのソース全文ではありません。

// 学習用に一般化したINIT / SELFCHECK / SNAP例です。
// 実運用EAの完成ソースではありません。

void PrintInitSummary()
{
   WriteDiagLog("INIT", "NONE", "START",
                "INIT_BEGIN",
                "version=sample symbol=" + _Symbol);
}

bool RunSelfCheck()
{
   bool ok = true;

   if(_Symbol == "")
   {
      WriteDiagLog("SELFCHECK", "NONE", "NG",
                   "EMPTY_SYMBOL",
                   "symbol is empty");
      ok = false;
   }

   if(ok)
   {
      WriteDiagLog("SELFCHECK", "NONE", "OK",
                   "BASIC_CHECK_OK",
                   "startup checks passed");
   }

   return ok;
}

void PrintRuntimeSnap(string stateText)
{
   WriteDiagLog("SNAP", "NONE", "STATE",
                "RUNTIME_SNAPSHOT",
                stateText);
}

INITは起動時の状態確認、SELFCHECKは設定や環境の自己診断、SNAPは現在状態の要約です。

この3つを分けると、起動時に失敗したのか、設定が不正なのか、現在のruntime状態が止まっているのかを切り分けやすくなります。

ログを後付けにしない理由

開発終盤に「不具合が出たのでログを足す」という進め方では、ログが断片的になりやすくなります。

後付けログで起きやすい問題は次の通りです。

問題内容対策
ログ名が揺れる同じ意味のログが別名で出るevent / reason名を固定する
成功ログだけ増える失敗時や見送り時の情報がないBLOCK / SKIP / FAILを残す
層が分からないsignalなのかexecutionなのか不明layerを明示する
機密情報が混ざるURL、token、口座情報を出してしまうマスク方針を先に決める
ログ過多になる毎tick大量に出て検証しづらいthrottleやsummaryを使う

ログは、処理が完成してから追加するものではなく、設計段階から確認項目として組み込む方が安全です。

開発版と配布版でログ粒度を分ける

AdminDevや開発検証版では、原因調査のために詳細ログが必要です。一方で、購入者向けの配布版やUserLive版では、詳細すぎるログは混乱やログ過多につながります。

ログ方針目的
AdminDev詳細ログを多めに出す開発、検証、原因調査
検証版確認対象に必要なログを出す特定機能の動作確認
UserLive要約ログと重要エラー中心購入者運用、サポート問い合わせ
バックテスト成功系はsummary化し、失敗・block中心検証速度と再現性

開発版と配布版でログ粒度を分ける場合でも、ログ名やreason名はできるだけ揃えると、サポート時に比較しやすくなります。

ログに出してよい情報・出してはいけない情報

ログは不具合調査に必要ですが、何でも出してよいわけではありません。

出してよい情報出してはいけない情報
symbol、timeframe、side、logic_id口座番号の実値
event、reason、retcode、エラー分類token、APIキー、認証情報
ロットの検証用値、件数、ON/OFF状態endpoint、Webhook URL、GAS URL
Object数、prefix、cleanup方針顧客情報、購入者情報
設定不備の有無、マスク済み状態実運用set値、実口座成績

問い合わせ時にログを送る場合も、口座番号、トークン、URL、APIキー、Webhook、GAS URL、顧客情報などは必ずマスクしてください。

問い合わせ前に送るべきログ

EAやインジの不具合調査を依頼する場合、次の情報があると確認しやすくなります。

資料確認する理由
ExpertsログEA・インジが出した診断ログ、reason、処理結果を確認するため
JournalログMT5端末側の接続、操作、標準ログを確認するため
使用setファイル設定値と再現条件を確認するため
スクリーンショットチャート表示、パネル表示、Object状態を確認するため
再現手順どの操作で問題が起きたか確認するため
発生時刻ログ上の該当箇所を探すため
銘柄・時間足symbol仕様、timeframe、表示状態を確認するため

「動きません」だけでは調査できません。最低限、発生時刻、銘柄、時間足、Expertsログ、Journalログ、使用setファイル、スクリーンショットを整理してください。

仕様書、setファイル、ログ、スクリーンショットを整理する場合は、次のページも参考にしてください。

MT5開発依頼前に用意する資料まとめ|仕様書・setファイル・ログ・スクリーンショット

ログ過多を防ぐ設計

ログファースト開発は、ログを無制限に増やすことではありません。

特にOnTickで動くEAでは、毎tick同じログを出すと、数分でログが読めなくなります。バックテストでは、ログ出力そのものが検証速度を落とす原因にもなります。

対策内容
状態変化時だけ出す前回reasonと変わった時だけログを出す
一定間隔で出す同じ状態が続く場合は30秒ごと、1分ごとなどに抑制する
summary化する成功系の大量ログは件数や最終状態にまとめる
失敗系を優先するFAIL、BLOCK、NG、INVALIDを確認しやすくする
検証版だけ詳細化するUserLiveでは重要ログだけに絞る

読めないログは、ログがないのと同じです。ログは量ではなく、追跡しやすさを優先します。

よくある失敗例

失敗1:成功時だけログを出している

成功時だけログを出すと、失敗した時や見送った時に何が起きたのか分かりません。特にENTRY_SKIP、GATE_BLOCK、ORDER_FAIL、EXIT_SKIPなどは、失敗調査で重要です。

失敗2:NO_SIGNALとGATE_BLOCKを混同している

シグナルがない状態と、シグナルはあるが安全条件で止めた状態は違います。NO_SIGNAL、GATE_BLOCK、RISK_BLOCK、ENTRY_SKIPを分けて出す必要があります。

失敗3:OrderSendの失敗理由を残していない

注文が通らない場合は、OrderSendの戻り値だけでなく、retcode、GetLastError、request概要、server commentを確認できるようにします。

失敗4:WebRequestや通知失敗を売買失敗と混同する

通知が失敗しても、売買本体が失敗したとは限りません。通知層、外部通信層、売買層は別ログで確認します。

失敗5:毎tick同じログを出し続ける

ログ過多になると、重要なエラーや状態変化を見落とします。同じ理由のログは抑制し、状態変化や一定間隔のsummaryで出す方が実務的です。

失敗6:機密情報をログへ出している

endpoint、token、Webhook URL、GAS URL、口座番号、顧客情報、購入者情報をログへ出してはいけません。問い合わせ用ログでも、機密情報はマスクします。

失敗7:INITやSELFCHECKがない

起動時に何が有効で、どの設定が不正で、どの機能が停止しているのか分からないEAは、販売後サポートが難しくなります。INIT、SELFCHECK、SNAPを用意しておくと確認しやすくなります。

導入前・開発依頼前に整理する情報

ログファースト設計のEA・インジを開発または改修する場合、次の情報を整理しておくと仕様確認がスムーズになります。

  • どの状態をログで追いたいか
  • signal、GATE、risk、execution、exitのどこで止まったかを確認したいか
  • Expertsログに出す項目
  • Journalログで見る項目
  • INITで確認したい項目
  • SELFCHECKで検出したい不正設定
  • SNAPで問い合わせ時に共有したい状態
  • HELPで利用者へ案内したい確認手順
  • 開発版と配布版でログ粒度を分けるか
  • バックテスト時にログをsummary化するか
  • 機密情報をどこでマスクするか
  • 問い合わせ時に送るログと送ってはいけない情報

ログ設計は、後から追加するよりも、設計段階で決めておく方が安全です。特に、販売や配布を前提にするEA・インジでは、利用者が自己確認しやすいログ導線を用意しておくと、サポート時のやり取りを減らせます。

関連する技術講座・確認ページ

ページ確認できること
技術講座ハブMQL5やMT5開発に関する講座一覧
MQL5デバッグ・ログファースト開発完全ガイドログ確認、デバッグ、原因調査の基本
MQL5エラーコード辞典エラーコードや失敗理由の確認
MQL5ファイル操作・CSVログ出力完全ガイドログ保存、CSV出力、検証記録の基本
MQL5長時間稼働・安定化完全ガイド長時間稼働、ログ過多、安定化の確認
MT5 EA診断・ログ確認ツールで確認できること診断補助ツールで確認できる項目
EAのログを問い合わせ前に確認する方法問い合わせ前に確認するログと整理項目
MT5開発依頼前に用意する資料まとめ仕様書、setファイル、ログ、スクリーンショットの整理

FAQ

ログファースト設計にしないとEAは動かないのですか?

EA自体はログが少なくても動く場合があります。ただし、不具合調査、改修、検証、販売後サポートが難しくなります。特にMQL5 EAでは、signal、GATE、risk、execution、exitのどこで止まったかをログで追える設計が重要です。

初心者でもこの記事の内容を理解する必要がありますか?

すべてを実装できる必要はありません。ただし、EAやインジの不具合相談をする場合は、Expertsログ、Journalログ、setファイル、スクリーンショットを整理する重要性を理解しておくと、調査が進めやすくなります。

開発依頼前に最低限どのログを整理すべきですか?

最低限、発生前後のExpertsログ、Journalログ、使用setファイル、スクリーンショット、発生時刻、銘柄、時間足、再現手順を整理してください。token、URL、口座番号などの機密情報は必ずマスクしてください。

ExpertsログとJournalログはどちらを送ればよいですか?

EAやインジの内部状態を確認するにはExpertsログが重要です。MT5端末側の接続、操作、環境、標準約定ログを確認するにはJournalログも必要です。不具合内容によっては両方を確認します。

ログが多すぎる場合はどうすればよいですか?

同じ理由のログを毎tick出さず、状態変化時だけ出す、一定間隔で出す、summary化するなどの抑制が必要です。開発版では詳細、配布版では重要ログ中心にするなど、版ごとに粒度を分けます。

商品化・配布前には追加で何を確認すべきですか?

INIT、SELFCHECK、SNAP、HELPの導線、ログ粒度、機密情報マスク、UserLive版でのログ抑制、問い合わせ時に提出してもらう情報を確認します。販売後サポートで読めるログになっているかも重要です。

ログにURLやtokenを出してもよいですか?

出してはいけません。endpoint、token、Webhook URL、GAS URL、APIキー、口座番号、顧客情報はログやスクリーンショットへ出さないようにします。問い合わせ時も必ずマスクしてください。

実装コードがなくてもログ設計の相談はできますか?

可能です。どの状態を確認したいか、どの不具合を切り分けたいか、問い合わせ時に何を共有したいかが整理されていれば、ログ設計の相談は進めやすくなります。

関連する開発実務ノート

ログファースト設計は、EA設計、長時間稼働、バックテスト、商品化前チェックの土台になります。原因調査しやすい構成にするため、関連する設計ノートもあわせて確認してください。

まとめ

MQL5のEA・インジ開発では、ログを後付けのデバッグ手段として扱うのではなく、設計段階から確認可能性を組み込むことが重要です。

特に、次の4点を分けると、不具合調査と販売後サポートがしやすくなります。

  • event:何が起きたか
  • reason:なぜその結果になったか
  • detail:確認に必要な補足情報
  • layer:signal、GATE、risk、execution、exit、UIなど、どの責務のログか

ログファースト開発では、成功ログだけでなく、見送り理由、失敗理由、停止理由を残します。NO_SIGNAL、GATE_BLOCK、RISK_BLOCK、ENTRY_SKIP、ORDER_FAIL、EXIT_SKIPを分けておくことで、EAが動かなかった時の原因を追いやすくなります。

また、INIT、SELFCHECK、SNAP、HELPを用意しておくと、起動時の状態、不正設定、現在状態、問い合わせ前の確認手順を整理しやすくなります。

完成EAの中核ロジックを公開しなくても、ログファースト設計の考え方を理解しておくことで、開発依頼、既存EA改修、検証、不具合調査、販売後サポートの品質を上げやすくなります。

ABOUT ME
記事URLをコピーしました