English Русский Deutsch
preview
初心者からエキスパートへ:Reporting EA - ワークフローの設定

初心者からエキスパートへ:Reporting EA - ワークフローの設定

MetaTrader 5 |
114 0
Clemence Benjamin
Clemence Benjamin

内容



はじめに

このコンセプトは、ブローカーから毎日送られてくる取引確認メールを受け取ったことがきっかけで生まれました。これらのサマリーは、取引活動の概要をきれいで専門的に整理して示してくれるだけでなく、統計的なパフォーマンス分析の可能性をも示していました。MetaTrader 5ターミナルを調べていく中で、現在のビルドには詳細なレポートを出力できる包括的なツールが搭載されていることがわかりました。HTMLおよびPDF形式でのエクスポートが可能ですが、自動配信や中央管理の機能は備わっていません。このディスカッションでは、取引レポートの役割を探り、関連する重要な用語を整理し、情報に基づいた意思決定を目指すトレーダーにとっての実用的な重要性を強調します。 

最終的には、MQL5とPythonなどの外部ツールを組み合わせたカスタムレポートシステムを実装することを目指します。このソリューションにより、詳細なレポートを生成し、複数のファイル形式での互換性を確保し、実用的かつ信頼性のある方法で自動配信をサポートします。

MetaTrader 5からエクスポートされるドキュメントを調べたところ、そこにはトレーダーにとって非常に価値のある洞察や事前計算された指標が含まれていることが明らかになりました。これらの情報は、取引判断や行動の修正に直接影響を与える可能性があります。

現在、MetaTrader 5のレポートは通常、手動で操作して取得されます。しかし、エキスパートアドバイザー(EA)を使用する場合、レポートの生成や配信をプログラム的に制御することが可能です。一部のブローカーは既に自動送信をおこなっていますが、本議論の目的は、ユーザー自身の好みに応じてレポートの配信頻度や内容をカスタマイズできるシステムを開発することです。

その解決策に向けて取り組む中で、私自身の経験を例として、取引レポートの実用的な重要性を示します。また、これらのレポートに含まれる一般的な用語を検討し、手動取引戦略やEAのパフォーマンス評価を改善するためにどのように活用できるかを議論します。

MetaTrader 5では、[表示]メニューから[レポート]を選択するか、ショートカットAlt+Eを使用して取引レポートにアクセスできます。レポートウィンドウには、取引活動のさまざまな側面が明確かつ整理された形式で表示されます。このウィンドウから、HTMLまたはPDF形式でレポートを保存することも可能です。

MetaTrader 5口座ターミナルレポートへのアクセス

MetaTrader 5でのレポートへのアクセス

上の図は、取引レポートに通常含まれる主要な要素の一部を示しています。この情報は非常に価値がありますが、多くのトレーダーはチャートや取引執行だけに注目し、パフォーマンス記録を定期的に見直すことを怠りがちです。レポートを正しく理解することで、規律を強化し、過去の活動から得られる洞察に基づく健全な取引マインドを育むことができます。

自分の取引レポートを確認した後、レポートに含まれる主要な用語を調査し、実践的な例と共にメモをまとめ、理解しやすくしました。次のセクションでは、5つの体系的な洞察を示し、それぞれが簡潔ながらも有意義な説明を提供します。これらは、後述する実装設計の基礎となります。技術的な構築段階に進むころには、レポートの概念をしっかり理解している状態を目指します。既に理解されている場合は、実装段階に直接進むことも可能です。


MQL5における取引レポートの理解

1. パフォーマンスサマリー

ROI(投資利益率)

  • 口座残高が初期資本に対してどれだけ増えたかを示します。
  • たとえば、初期資金5,000ドルから12,000ドルになった場合、140%の増加となり、リスクを取った1ドルが2.40ドルになったことを意味します。

ドローダウン

  • 高値から次の安値までの最大下落率を示します。
  • たとえば、資産が12,000ドルまで上昇した後、9,600ドルに下落した場合、20%の下落となり、回復前の最も大きな損失を示します。

アクティビティ指標

  • 取引のペースや一貫性を反映します。週あたりの取引数、成功率、平均保有期間などです。
  • たとえば、8週間で80回の取引をおこなった場合、1週間あたり10回、勝率が40%(32勝)、合計160日市場に滞在した場合の平均保有期間は2日となります。

シャープレシオ

  • ボラティリティ1単位あたりの超過リターンを示します。
  • たとえば、年利15%を両方返す2つのシステムを比較すると、日々±2%の変動をする方が、±6%の変動をするシステムよりシャープレシオが高くなり、より安定した資産曲線を示します。

プロフィットファクター

  • 総利益を総損失で割った比率で、勝者と敗者の効率を示します。
  • たとえば、勝ち取引で8,000ドル、損失で5,000ドルの場合、比率は1.6となり、失った1ドルに対して1.6ドルの利益が得られたことを意味します。

リカバリーファクター

  • 純利益を最大ドローダウンで割った比率です。
  • たとえば、戦略で4,000ドルの利益を出し、最悪時に1,000ドル下落した場合、リカバリーファクターは4となり、最も大きな損失の4倍の利益を上げたことを示します。

2. 損益内訳

総利益と総損失

  • 勝ち取引と負け取引の合計を示し、コスト前の利益のベースを把握できます。
  • たとえば、勝ち取引15,000ドルに対し、負け取引6,000ドルであれば、総利益は9,000ドルとなります。

手数料と純利益

  • 総利益から手数料、スワップ、その他の費用を差し引いたものが実際の利益です。
  • たとえば、9,000ドルの総利益から1,200ドルの手数料を引くと、純利益は7,800ドルとなります。

月次推移

  • 月ごとの純利益をプロットすることで、パフォーマンスの変化を確認できます。
  • たとえば、1月に+4,000ドル、2月に+3,000ドル、3月に+800ドル、4月に-500ドルの場合、下降傾向が見え、注意が必要です。

3. リスク分析

最大ドローダウン

  • ピークから次の谷までの最大下落率を定義します。
  • たとえば、口座残高が20,000ドルから14,000ドルに下がった後に回復した場合、最大下落率は30%となります。

連勝と連敗

  • 連続して勝利または敗北した回数は、システムの安定性やトレーダー心理を測る指標です。
  • たとえば、連続7敗した場合や、5連勝した場合、それぞれが自信や資金管理、ポジションサイズに影響します。

Maximum Favorable Excursion (MFE)

  • 取引中に達した最大未実現利益を追跡します。
  • たとえば、あるポジションで最高600ドルの含み益を達成した場合です。

Maximum Adverse Excursion (MAE)

  • 決済前に発生した最大未実現損失を記録します。
  • たとえば、同じ取引で200ドルの含み損が発生した後に利益確定した場合、ストップロスの調整ポイントとして参考になります。

4. 銘柄別パフォーマンス

資産ごとの勝率

  • 各市場での勝率を確認し、優位性のある市場を把握できます。
  • たとえば、EURUSDは48%、USDJPYは60%の勝率で、後者の方が優位なシグナルが出やすいことを示しています。

利益貢献

  • 銘柄ごとの純利益から、どの資産が利益を生み出しているかを確認します。
  • たとえば、EURUSDで9,600ドルの利益、XAUUSDで1,100ドルの損失の場合、資金配分の参考になります。

集中リスク

  • 資本や取引の何割が特定の市場に偏っているかを示します。
  • たとえば、資金の40%がEURUSDに集中している場合、ユーロの急変動で口座全体に影響が出る可能性があります。

銘柄別プロフィットファクター

  • 各市場の総利益と総損失の比率を比較し、効率を把握します。
  • たとえば、USDJPYは1.8、AUDCADは0.9で、どの通貨ペアを優先するかの判断材料となります。

5. アクティビティと行動パターン

取引分布

  • ロング・ショートのバランスから方向性の偏りを確認します。
  • たとえば、ロング70%であれば、基本的に強気のポジションが多いことを示しますが、レンジ相場では不利になる可能性があります。

自動売買 vs 手動:

  • アルゴリズム取引と手動取引を比較して、真の優位性を確認します。
  • たとえば、純利益の65%が自動売買によるもので、35%が手動取引の場合、システムの強みを示しています。

時間分析

  • 時間帯や曜日ごとの結果を分解し、最適時間帯や注意すべき時間帯を特定します。
  • たとえば、損失の多くがGMT11:00〜12:00に発生している場合、この時間帯は取引を避けるのが良いでしょう。

スタイル指標

  • 平均保有期間や週あたりの取引量から、取引スタイルを把握できます。
  • たとえば、平均保有時間4時間、週あたり約25回の取引であれば、中程度のテンポのデイトレード戦略であることを示します。


実装

この段階では、ワークフローの構築に進みます。前のセクションで取引レポートの用語を深く理解していただいたおかげで、この部分も不慣れな概念が少なく、よりスムーズに理解できるでしょう。

本記事の目的を達成するために、データのエクスポートを処理し、必要なログを作成するEAを開発します。このEAは、MetaTrader 5 (MQL5)と、過去の取引データを処理して最終レポートをポータブルな形式で生成するPythonライブラリとの橋渡し役を果たします。これは MetaTrader 5ターミナルに組み込まれているレポートツールと同等の機能を提供することを目指しています。

まず、プロセス全体の流れを示すフローチャートを提示し、その後、必要なツールと環境設定を詳細に分解して説明します。本プロジェクトのすべてのコンポーネントはオープンソース技術をベースにしているため、誰でも利用可能です。

Reporting EAプロセスフロー

プロセスフロー

まず、MetaTrader 5がシステムにインストールされていることを確認してください。その後、Python環境の設定に進みます。Python環境の詳細な手順は後ほど説明します。以下の表は、このワークフローで使用する要件とツールを簡単にまとめたものです。

コンポーネント オープンソースツール 費用 実装メモ
データ抽出 MetaTrader 5 EA (ReporterEA.mq5) 無料 日付範囲フィルタ付きのカスタムCSVエクスポート
スケジューリングエンジン MetaTrader 5タイマーイベント(OnTimer()) 無料 MetaTrader 5ターミナル内での内部スケジュール
データ処理 Python 3.10+(Pandas、Matplotlib) 無料 EAからShellExecuteでトリガー
レポート配信 smtplib + Gmail SMTP 無料 Pythonスクリプトから1日あたり多くの無料メール送信可能
メンテナンス EA自動クリーンアップ機能 無料 MQL5/Pythonでのファイルローテーションとエラー処理


Reporting EAの開発

この段階では、計画通りにEAの開発を開始します。各コードコンポーネントの役割と、それらがどのように連携して完全で機能的なシステムを構築するかを順を追って解説します。目標は、目的をスムーズに達成できる堅牢なEAを構築することです。開発プロセスを分かりやすく段階ごとに分けて説明するので、それぞれの要素が理解しやすく、最終成果物に意味のある形で寄与するようにします。

まず、MetaEditor 5で[ファイル]>[新規作成]を選び、[エキスパートアドバイザ(テンプレート)]を選択します。自動生成されたコードのうち、今回の開発目標に不要な部分は削除することをおすすめします。必要な部分だけに集中することで、作業が効率的になります。EAを段階的に構築していくので、以下の番号付きの手順に従ってください。

1. ファイルのメタデータとコンパイルディレクティブ

ファイルの先頭にあるプロパティディレクティブでは、EAのメタデータを宣言します。ここには、著作権情報やリンク情報、バージョン番号、厳密なコンパイルモードが含まれます。厳密モードでは型チェックやコンパイルルールが強化され、暗黙の型変換を禁止し、明示的な変換を要求することで、微妙なバグを防ぐ助けになります。

#property copyright "Clemence Benjamin"
#property link      "https://www.mql5.com/go?link=https://www.mql5.com/ja/users/billionaire2024/seller"
#property version   "1.00"
#property strict

2. 定数とWindows APIインポート

#define文では、よく使う定数値に対してシンボル名を作成します。たとえば、コンソールウィンドウを非表示にするSW_HIDEや、エラー確認用のINVALID_FILE_ATTRIBUTESなどです。続いて、#importを用いて2つのWindowsシステムライブラリをインポートします。kernel32.dllはファイル属性に関する関数(GetFileAttributesW)を提供し、shell32.dllは外部プロセスを実行する関数(ShellExecuteW)を提供します。これらのネイティブDLL関数を呼び出すことで、EAはMetaTrader 5の標準機能を拡張し、ファイルの存在確認やPythonインタープリターの起動をおこなえるようになります。

#define SW_HIDE                 0
#define INVALID_FILE_ATTRIBUTES 0xFFFFFFFF

//--- Windows API imports
#import "kernel32.dll"
uint   GetFileAttributesW(string lpFileName);
#import

#import "shell32.dll"
int    ShellExecuteW(int hwnd, string lpOperation, string lpFile, string lpParameters, string lpDirectory, int nShowCmd);
#import

3. 設定用ユーザー入力

入力項目を宣言することで、EAの設定ダイアログからカスタマイズ可能なパラメータをユーザーが指定できるようになります。ユーザーは、Python実行ファイルの絶対パス(PythonPath)、実行するPythonスクリプト(ScriptPath)、日次レポートを実行する時間(ReportHour、ReportMinute)、プッシュ通知を送るかどうか(EnableEmail)、および起動時に初回テストをおこなうかどうか(TestOnInit)を設定できます。これらを入力項目として公開することで、非プログラマでもソースコードを編集せずに挙動を調整できます。

//--- User inputs
input string PythonPath   = "C:\\Users\\BTA24\\AppData\\Local\\Programs\\Python\\Python312\\python.exe";
input string ScriptPath   = "C:\\Users\\BTA24\\Documents\\BENJC_TRADE_ADVISOR\\Scripts\\processor.py";
input int    ReportHour   = 15;    // Hour (24h) to run report
input int    ReportMinute = 55;    // Minute after the hour
input bool   EnableEmail  = true;  // Send push notification
input bool   TestOnInit   = true;  // Immediately run export+Python on init

4. グローバル状態の管理

1つのグローバル変数「lastRunTime」が、最後にレポートを正常に実行したタイムスタンプを保持します。TimeCurrent()とlastRunTimeを比較することで、タイマーコールバックが頻繁にチェックしても、レポートは1日1回だけ実行されるようになっています。

//--- Globals
datetime lastRunTime = 0;

5. 初期化ロジック(OnInit)

OnInit()関数は、すべての起動時ルーチンを実行します。まず、エキスパートログにステータスメッセージを出力します。Python実行ファイルとスクリプトの存在を確認し、見つからなければ警告を表示します。次に、MQL5\Filesディレクトリにダミーファイルを作成して書き込み権限を確認します。その後、EventSetTimer(30)によって、30秒ごとの定期タイマーを設定します。最後に、TestOnInitがtrueの場合、RunDailyExport()を即座に呼び出してフルのエクスポート&Python実行ワークフローを検証し、lastRunTimeを現在時刻で更新します。

int OnInit()
{
   Print(">> Reporting EA initializing…");

   // Verify Python executable
   if(GetFileAttributesW(PythonPath) == INVALID_FILE_ATTRIBUTES)
      Print("!! Python executable not found at: ", PythonPath);
   else
      Print("✔ Found Python at: ", PythonPath);

   // Verify Python script
   if(GetFileAttributesW(ScriptPath) == INVALID_FILE_ATTRIBUTES)
      Print("!! Python script not found at:   ", ScriptPath);
   else
      Print("✔ Found script at:   ", ScriptPath);

   // Test write permission
   int h = FileOpen("test_perm.txt", FILE_WRITE|FILE_COMMON|FILE_ANSI);
   if(h==INVALID_HANDLE)
      Print("!! Cannot write to MQL5\\Files directory!");
   else
   {
      FileWrite(h, "OK");
      FileClose(h);
      FileDelete("test_perm.txt");
      Print("✔ Write permission confirmed.");
   }

   // Set timer
   EventSetTimer(30);
   Print(">> Timer set to 30 seconds.");

   // Test run on init
   if(TestOnInit)
   {
      Print(">> Test mode: running initial export.");
      RunDailyExport();
      lastRunTime = TimeCurrent();
   }

   return(INIT_SUCCEEDED);
}

6. 初期化解除ロジック(OnDeinit)

EAが削除されたりプラットフォームが終了する際にOnDeinit()が呼ばれます。この関数は、タイマーを停止し(EventKillTimer())、終了メッセージをログに出力します。タイマーリソースを適切に解放することで、孤立したコールバックやクラッシュを防ぎます。

void OnDeinit(const int reason)
{
   EventKillTimer();
   Print(">> Reporting EA deinitialized.");
}

7. スケジューリング用タイマーコールバック(OnTimer)

30秒ごとにOnTimer()が実行され、MqlDateTime構造体を使って現在の時刻を取得します。設定されたレポート時刻(ReportHour、ReportMinute)に達しているか、かつ最後の実行から24時間以上経過しているかを確認します。この二重チェックにより、レポートは毎日1回、指定時刻以降に必ず実行されます。

void OnTimer()
{
   MqlDateTime dt; TimeToStruct(TimeCurrent(), dt);

   if(dt.hour==ReportHour && dt.min>=ReportMinute && (TimeCurrent()-lastRunTime)>86400)
   {
      RunDailyExport();
      lastRunTime = TimeCurrent();
   }
}

8. 主なワークフロー:エクスポートとPython実行(RunDailyExport)

  1. この関数は、EAのレポート機能の主要ステップをまとめています。
  2. まず、TerminalInfoStringを使用して、MetaTrader 5のMQL5\Filesディレクトリの絶対パスを取得します。
  3. 次に、現在の日付を取得し、ドットを削除した文字列を用いて、CSVファイルとログファイルのファイル名を生成します。
  4. 過去30日分の取引履歴をCSVに書き出すためにExportHistoryToCSV()を呼び出します。エクスポートが失敗した場合は処理を中断します。
  5. 次に、Python実行ファイル、スクリプト、CSVファイル名、ログファイル名を組み合わせたコマンド文字列を作成します。空白を含むパスでも正しく処理されるようにStringFormatで適切に引用符で囲み、標準出力と標準エラーをログファイルにリダイレクトします。
  6. EA内のShellExecute()ラッパーを使って「cmd.exe /c <pythonCmd>」を実行し、戻り値の整数コードをログに記録します。
  7. その後、Pythonプロセスの完了を待つために3秒間の待機を入れます(Sleep(3000))。
  8. ログファイルの存在を確認し、存在する場合は行ごとに読み込んでエキスパートログに出力します。
  9. 最後に、CSVのパスを含む通知メッセージを作成し、EnableEmailがtrueの場合はSendNotification()を通じてユーザーのモバイル端末に送信されます。

void RunDailyExport()
{
   string filesDir = TerminalInfoString(TERMINAL_DATA_PATH) + "\\MQL5\\Files\\";
   
   string dateStr = TimeToString(TimeCurrent(), TIME_DATE);
   StringReplace(dateStr, ".", "");
   
   string csvName = "History_" + dateStr + ".csv";
   string logName = "ProcLog_" + dateStr + ".txt";
   
   string csvFull  = filesDir + csvName;
   string logFull  = filesDir + logName;

   // 3) Export CSV
   if(!ExportHistoryToCSV(csvName))
   {
      Print("!! CSV export failed: ", csvFull);
      return;
   }
   Print("✔ CSV exported: ", csvFull);

   // 4) Build Python command
   string pythonCmd = StringFormat(
      "\"%s\" \"%s\" \"%s\" >> \"%s\" 2>&1",
      PythonPath,
      ScriptPath,
      csvFull,
      logFull
   );
   string fullCmd = "/c " + pythonCmd;
   PrintFormat("→ Launching: cmd.exe %s", fullCmd);

   // 5) Execute
   int result = ShellExecute(" " + fullCmd);
   PrintFormat("← ShellExecute returned: %d", result);

   // 6) Wait
   Sleep(3000);

   // 7) Read log
   if(GetFileAttributesW(logFull) == INVALID_FILE_ATTRIBUTES)
      Print("!! Log file not created: ", logFull);
   else
   {
      Print("=== Python Log Start ===");
      int fh = FileOpen(logName, FILE_READ|FILE_COMMON|FILE_TXT);
      while(fh!=INVALID_HANDLE && !FileIsEnding(fh))
         Print("PY: ", FileReadString(fh));
      if(fh!=INVALID_HANDLE) FileClose(fh);
      Print("=== Python Log End ===");
   }

   // 8) Notification
   string msg = "Report & log generated: " + csvFull;
   Print(msg);
   if(EnableEmail) SendNotification(msg);
}

9. CSV生成(ExportHistoryToCSV)

このヘルパー関数は、取引履歴を自動的にCSVファイルへエクスポートします。過去30日間の履歴を(HistorySelectを使用)選択し、各ディールチケットを繰り返し処理して、HistoryDealGet*関数群を使ってプロパティ(時間、タイプ、銘柄、数量、価格、利益、手数料、スワップ)を取得し、カンマ区切りの値としてFileWriteで書き込みます。ヘッダー行を出力した後、ループ内で各行をDoubleToStringおよびTimeToStringを使用して構築し、数値の精度とタイムスタンプ形式の一貫性を確保します。FileOpenの適切なエラーチェックにより、サイレントな失敗を防ぎます。

bool ExportHistoryToCSV(string filename)
{
   datetime end   = TimeCurrent();
   datetime start = end - 2592000; // last 30 days

   HistorySelect(start, end);
   int total = HistoryDealsTotal();

   int fh = FileOpen(filename, FILE_WRITE|FILE_CSV|FILE_COMMON|FILE_ANSI, ",");
   if(fh==INVALID_HANDLE)
   {
      Print("!! FileOpen failed for: ", filename);
      return(false);
   }

   FileWrite(fh, "Ticket,Time,Type,Symbol,Volume,Price,Profit,Commission,Swap");

   for(int i=0; i<total; i++)
   {
      ulong deal = HistoryDealGetTicket(i);
      if(deal==0) continue;

      long    tr = HistoryDealGetInteger(deal, DEAL_TIME);
      datetime t = (datetime)tr;
      int     tp = (int)HistoryDealGetInteger(deal, DEAL_TYPE);

      string  sym = HistoryDealGetString (deal, DEAL_SYMBOL);
      double  vol = HistoryDealGetDouble (deal, DEAL_VOLUME);
      double  prc = HistoryDealGetDouble (deal, DEAL_PRICE);
      double  pf  = HistoryDealGetDouble (deal, DEAL_PROFIT);
      double  cm  = HistoryDealGetDouble (deal, DEAL_COMMISSION);
      double  sw  = HistoryDealGetDouble (deal, DEAL_SWAP);

      FileWrite(fh,
         deal,
         TimeToString(t, TIME_DATE|TIME_SECONDS),
         tp,
         sym,
         DoubleToString(vol,2),
         DoubleToString(prc,5),
         DoubleToString(pf,2),
         DoubleToString(cm,2),
         DoubleToString(sw,2)
      );
   }

   FileClose(fh);
   return(true);
}

10. Shellコマンドラッパー(ShellExecute)

ShellExecute関数は、インポートされたShellExecuteW API呼び出しの薄いラッパーとして機能します。cmd.exeの呼び出しを標準化し、ネイティブAPIの複雑さを隠すとともに、常にSW_HIDEを使用してコンソールウィンドウを非表示にします。整数の戻り値を返すことで、EAは外部コマンドの起動エラーを検出してログに記録できるようになります。

int ShellExecute(string command)
{
   return(ShellExecuteW(0, "open", "cmd.exe", command, NULL, SW_HIDE));
}


Python処理スクリプトの開発

まず、Pythonのセットアップと必要なライブラリのインストールをおこないます。最初にコマンドプロンプトを開き、必要なインストールコマンドを実行します。その後、テキストエディタでPythonスクリプトを準備します。私は個人的にオープンソースのNotepad++を好んで使用していますが、お好みのPython IDEを利用して構いません。

セットアップ

1. まずPython側を準備します。Python 3.x(例:3.10 または 3.12)の最新版をインストールし、プロジェクトフォルダ内で仮想環境を作成し、有効化します。

python -m venv venv  

source venv/Scripts/activate    # Windows  

# or  

source venv/bin/activate        # macOS/Linux  

2. 仮想環境を有効化したら、次のコマンドで必要なパッケージをインストールします。

pip install pandas fpdf

  • pandasはCSVの解析とデータ分析を担当する
  • FPDF(または他のPDFライブラリ)はレポートを生成する

3. メール通知を送信する場合は、yagmailなどのSMTPライブラリを追加でインストールするか、Python標準のsmtplibを使用します。 

これでPythonスクリプトを開発する準備が整いました。以下の手順に沿って、各部分を順に実装していきます。

1. スクリプトヘッダーとインポート

スクリプトはUnixスタイルのシバンから始まり、それに続いて主要なライブラリをインポートします。

  • sys、os、tracebackはOSとの連携や引数処理、エラー出力に使用される
  • pandasはデータの読み込みと操作に使用される
  • datetimeとtimedeltaは日付計算に使用される
  • fpdfパッケージのFPDFはPDFレポートを生成する

#!/usr/bin/env python

import sys, os, traceback

import pandas as pd

from datetime import datetime, timedelta

from fpdf import FPDF

2. 主なワークフロー:引数の検証とファイルチェック

main(csv_path)関数が全体の制御をおこないます。処理対象のCSVファイル名を出力し、すぐにそのファイルが存在するかどうかを確認します。 存在しない場合はFileNotFoundErrorを発生させます。これは、MQL5 EA側がPython実行ファイルやスクリプトの存在を事前に確認する処理と対応しています。

def main(csv_path):

    print(f"Processing CSV: {csv_path}")

    if not os.path.isfile(csv_path):

        raise FileNotFoundError(f"CSV not found: {csv_path}")

3. CSVの読み込みと解析

pandas.read_csvを使用して、EAが出力した取引履歴CSVを読み込みます。次に、Time列をpd.to_datetimeでdatetime型オブジェクトに変換し、時間に基づく計算が正確におこなえるようにします。この処理は、EAがTimeToStringを使って時刻を整形している点と対応しています。

# 1. Load & parse

    df = pd.read_csv(csv_path)

    df['Time'] = pd.to_datetime(df['Time'])

4. コンピューティング概要分析

スクリプトは主要なパフォーマンス指標をまとめた辞書を作成します。

  • date:当日の日付を表す文字列
  • net_profit:Profit列の合計
  • trade_count:DataFrame内の行の合計数
  • top_symbol:groupbyとidxmaxを使用して求めた、累積利益が最も高い銘柄

これらの指標はEAのCSV内容と一致し、PDFレポートにエクスポート内容をそのまま要約できるようにします。

 # 2. Analytics

    report = {

        'date'       : datetime.now().strftime("%Y-%m-%d"),

        'net_profit' : df['Profit'].sum(),

        'trade_count': len(df),

        'top_symbol' : df.groupby('Symbol')['Profit'].sum().idxmax()

    }

5. PDFレポートの生成

スクリプトは、CSVと同じMQL5\Filesディレクトリ内に出力パスを構築し、日付を付けたPDFファイル名を作成します。次に、generate_pdf(report, pdf_file)を呼び出します。この処理は、EAがPythonの出力をログとして記録し、生成物(CSVおよびPDF)を共通のFilesフォルダに配置するという想定と整合しています。

# 3. Generate PDF

    dirpath = os.path.dirname(csv_path)

    pdf_file = os.path.join(dirpath, f"Report_{report['date']}.pdf")

    generate_pdf(report, pdf_file)


    print(f"PDF written: {pdf_file}")

    return 0

6. FPDFによるPDFの構築

generate_pdf関数はFPDFのシンプルなAPIを使用します。ドキュメントを作成し、ページを追加し、フォントを設定して、各指標を1行ずつ書き込みます。ln=Trueパラメータにより、自動的に改行されます。このモジュール化されたヘルパー関数により、PDFの書式処理をデータロジックから分離することができます。

def generate_pdf(report, output_path):

    pdf = FPDF()

    pdf.add_page()

    pdf.set_font("Arial", size=12)

    pdf.cell(0, 10, f"Report Date: {report['date']}", ln=True)

    pdf.cell(0, 10, f"Total Trades: {report['trade_count']}", ln=True)

    pdf.cell(0, 10, f"Net Profit:    ${report['net_profit']:.2f}", ln=True)

    pdf.cell(0, 10, f"Top Symbol:    {report['top_symbol']}", ln=True)

    pdf.output(output_path)

7. メンテナンス:古いレポートのクリーンアップ

ディスク容量の肥大化を防ぐため、clean_old_reports関数は指定日数(デフォルトでは30日)より古いPDFを削除します。この関数は、EAがスクリプトを呼び出したときに曜日が日曜日(weekday() == 6)である場合のみ実行されます。スクリプトはsys.argv[1]で受け取ったCSVパスを基に正しいディレクトリを特定します。この保守処理は、EAのファイル命名規則や24時間単位の実行制御ロジックと対応しています。

def clean_old_reports(days=30):

    now = datetime.now()

    cutoff = now - timedelta(days=days)

    dirpath = os.path.dirname(sys.argv[1])

    for fname in os.listdir(dirpath):

        if fname.startswith("Report_") and fname.endswith(".pdf"):

            full = os.path.join(dirpath, fname)

            if datetime.fromtimestamp(os.path.getmtime(full)) < cutoff:

                os.remove(full)

                print(f"Deleted old report: {full}")

8. スクリプトのエントリポイントとエラー処理

if __name__ == "__main__": ブロックでは、引数がちょうど1つ(CSVファイルのフルパス)であることを強制します。この呼び出しはtry/exceptで囲まれており、例外が発生した場合にはトレースバックを出力し、 非ゼロの終了コードで終了します。これは、EAがPythonの標準出力および標準エラーをキャプチャし、スクリプト内で発生したエラーを自らのログに出力する動作と一致しています。オプションの保守処理は、終了前に毎週実行されます。

if __name__ == "__main__":

    if len(sys.argv) != 2:

        print("Usage: processor.py <full_csv_path>")

        sys.exit(1)

    try:

        ret = main(sys.argv[1])

        # Optional maintenance

        if datetime.now().weekday() == 6:

            clean_old_reports(30)

        sys.exit(ret)

    except Exception as e:

        print("ERROR:", e)

        traceback.print_exc()

        sys.exit(1)

MetaTrader 5 EAとPythonスクリプトの相互作用

  1. ファイル名の規則:EAは日付形式(History_YYYYMMDD.csv)のCSVファイル名を生成し、Pythonスクリプトはそのファイルを指す1つの引数を受け取ります。
  2. ディレクトリの整合性:両者はMetaTrader 5のMQL5\Filesフォルダで動作し、ファイルのやり取りをシームレスにおこないます。
  3. エラーの伝播:EAはPythonの標準出力および標準エラーをタイムスタンプ付きログファイルにリダイレクトします。スクリプト内で発生した例外(たとえばCSVの欠如や解析エラー)は、EAのログリーダーによって捕捉され、エキスパートログに出力されます。
  4. スケジューリング:EAの24時間タイマーがPythonの実行を制御し、スクリプト自体は入力を処理する以外に状態を保持せず、EAが適切なタイミングで呼び出す設計になっています。
  5. メンテナンスの調整:PDFの週次クリーンアップはスクリプト内でおこなわれますが、日曜日にのみ実行されるよう設計されており、EA側の週次実行ロジックと一致しています。


テスト

このセクションでは、Reporting EAをMetaTrader 5のチャート上に配置します。Windows環境では、外部プロセスの実行を許可するために「DLLのインポートを許可する」設定を有効にすることが重要です。テスト中、EAはその目的を正常に達成しました。すなわち、取引履歴をCSVファイルとしてエクスポートし、そのデータを処理するPythonスクリプトを自動的に実行しました。スクリプトは必要なレポート指標を生成し、それらを整ったPDFドキュメントとして出力します。このPDFはメール送信にも、後で確認・保管するためのアーカイブにも利用できます。

Reporting EAのデプロイ

Reporting EAのデプロイ

Reporting EAのエキスパートログ

2025.07.24 20:44:57.061 Reporting EA (GBPJPY.0,M1)      >> Reporting EA initializing…
2025.07.24 20:44:57.061 Reporting EA (GBPJPY.0,M1)      !! Python executable not found at: C:\path_to\python.exe
2025.07.24 20:44:57.061 Reporting EA (GBPJPY.0,M1)      !! Python script not found at:   C:\path_to\reports_processor.py
2025.07.24 20:44:57.062 Reporting EA (GBPJPY.0,M1)      ✔ Write permission confirmed.
2025.07.24 20:44:57.062 Reporting EA (GBPJPY.0,M1)      >> Timer set to 30 seconds.
2025.07.24 20:44:57.062 Reporting EA (GBPJPY.0,M1)      >> Test mode: running initial export.
2025.07.24 20:44:57.063 Reporting EA (GBPJPY.0,M1)      ✔ CSV exported: C:\TERMINAL_PATH\MQL5\Files\History_20250724.csv
2025.07.24 20:44:57.063 Reporting EA (GBPJPY.0,M1)      → Launching: cmd.exe /c "C:\path_to\python.exe" "C:\path_to\reports_processor.py" "C:\TERMINAL_PATH\MQL5\Files\History_20250724.csv" >> "C:\TERMINAL_PATH\MQL5\Files\ProcLog_20250724.txt" 2>&1
2025.07.24 20:44:57.124 Reporting EA (GBPJPY.0,M1)      ← ShellExecute returned: 42
2025.07.24 20:45:00.124 Reporting EA (GBPJPY.0,M1)      !! Log file not created: C:\Users\TERMINAL_PATH\MQL5\Files\ProcLog_20250724.txt
2025.07.24 20:45:00.124 Reporting EA (GBPJPY.0,M1)      Report & log generated: C:\Users\TERMINAL_PATH\Files\History_20250724.csv

上記のエキスパートログは、Reporting EAの初期化試行を示しています。この際、システムは指定されたPython実行ファイルおよびスクリプトを見つけることができませんでした。これは、デモンストレーションやプレースホルダーとしてコード内のファイルパスが意図的に変更されていた(例:C:\path_to\python.exeやC:\path_to\reports_processor.py)ことが原因です。その結果、EAはPythonスクリプトを実行できず、想定されていたログ出力(ProcLog_20250724.txt)も生成されませんでした。それにもかかわらず、EAは書き込み権限の確認には成功し、取引履歴をCSVファイルとして正常にエクスポートしました。

このテストは、EA内で正しいファイルパスを設定することの重要性を示しています。Pythonインタープリタおよび処理スクリプトの実際の場所を正確に指定することで、レポート生成の一連の処理を途切れなく実行できます。常に有効で絶対パスの指定を確認し、ローカル環境に適した設定をおこなうことで、このような問題を回避し、レポートツールの機能を最大限に活用してください。


結論

本記事では、取引レポートの理解、実用的なワークフローの構築、そしてカスタム取引レポートをPDFで生成するためのツール開発に焦点を当てました。生成されたPDFをメールで送信する最終段階については、本稿の範囲を超えるため、今後の発表にて取り上げる予定です。一方、エクスポートされたCSVを基にしたPDF生成プロセスは、Pythonライブラリを用いて問題なく実行できることが確認されました。グラフ表示や高度なレポート機能などのさらなる拡張は、次回のディスカッションで紹介される予定です。

EAと対応するPythonスクリプトの両方が完成したことで、今後さらに多くの機能を実現できる基盤が整いました。要約すると、このプロジェクトは、スケジュールに基づいたカスタマイズ可能な取引レポートを、明確さに重点を置いて受け取るという課題を解決するものです。会計管理があらゆるビジネスに不可欠であるのと同様に、取引における定期的なレポート作成も不可欠です。それはパフォーマンスへの意識を高め、規律を促し、トレーダーとしての心理的成長を支える重要な要素となります。


重要な学び

学び 説明
1. モジュラー設計 CSVエクスポート処理(MQL5)とレポート生成処理(Python)を分離することで、保守性が向上し、それぞれのコンポーネントを独立して発展させることができます。
2. 堅牢なエラー処理 ファイルパスの検証、Python側での例外処理、エラーの記録により、システムが予期せぬ停止を防ぎ、問題を容易にデバッグできるようにします。
3. 多言語統合 ShellExecuteを用いて外部スクリプトを呼び出すことで、取引プラットフォームが外部ライブラリやエコシステムの強力な機能を活用できることを示しています。
4. 自動スケジューリング MQL5のタイマーコールバックを利用して日次エクスポートを実行することで、手動操作を不要にし、レポートの一貫性と信頼性を高めます。
5.ログの集中管理 MetaTrader 5の[エキスパート]タブおよび外部テキストファイルにログを書き出すことで、ワークフローの各ステップを明確に把握できます。
6. 環境検証 初期化時にPython実行ファイルおよびスクリプトの存在を確認することで、実行時のトラブルを防ぎ、ユーザーに必要なセットアップ手順を示します。
7. オープンソースツール 無料で広く利用されているライブラリ(pandas、FPDF)や標準APIを使用することで、導入のハードルを下げ、コミュニティによる協力を促進します。
8. ユーザー設定可能なパラメータ パス、スケジュール時間、通知設定などを入力パラメータとして公開することで、EAを多様な取引環境に柔軟に適応させることができます。


添付ファイル

ファイル名 バージョン 説明
reporting_processor.py
取引履歴のCSVを読み込み、サマリー解析(純利益、取引数、トップ銘柄)を計算し、FPDFでPDFレポートを生成し、必要に応じて古いレポートを削除するオプションを備えたPythonスクリプト
Reporting EA.mq5 1.0 過去30日分の取引履歴をCSVにエクスポートし、processor.pyを呼び出して終了コードを取得し、生成されたPDFの有無を確認してプッシュ通知を送信するMetaTrader 5 EA

目次に戻る

MetaQuotes Ltdにより英語から翻訳されました。
元の記事: https://www.mql5.com/en/articles/18882

添付されたファイル |
Reporting_EA.mq5 (15.06 KB)
MQL5で自己最適化エキスパートアドバイザーを構築する(第10回):行列分解 MQL5で自己最適化エキスパートアドバイザーを構築する(第10回):行列分解
行列分解は、データの特性を理解するために用いられる数学的手法です。行と列で整理された大規模な市場データに行列分解を適用することで、市場のパターンや特性を明らかにすることができます。行列分解は非常に強力なツールであり、本記事ではMetaTrader 5のターミナル内でMQL5 APIを活用し、市場データをより深く分析する方法を紹介します。
知っておくべきMQL5ウィザードのテクニック(第77回):ゲーターオシレーターとA/Dオシレーターの使用 知っておくべきMQL5ウィザードのテクニック(第77回):ゲーターオシレーターとA/Dオシレーターの使用
ビル・ウィリアムズが開発したゲーターオシレーター(Gator Oscillator)とA/Dオシレーター(Accumulation/Distribution Oscillator)は、MQL5のエキスパートアドバイザー(EA)内で調和的に活用できるインジケーターペアの一例です。ゲーターオシレーターはトレンドを確認するために使用し、A/Dオシレーターは出来高を通じてそのトレンドを検証する補助指標として機能します。本記事では、これら2つのインジケーターの組み合わせについて、MQL5ウィザードを活用して構築およびテストをおこない、その有効性を検証します。
プライスアクション分析ツールキットの開発(第34回):高度なデータ取得パイプラインを用いた生の市場データからの予測モデル構築 プライスアクション分析ツールキットの開発(第34回):高度なデータ取得パイプラインを用いた生の市場データからの予測モデル構築
突然のマーケットスパイクを見逃したり、それが発生したときに対応が間に合わなかったことはありませんか。ライブイベントを予測する最良の方法は、過去のパターンから学ぶことです。本記事では、MetaTrader 5で履歴データを取得し、それをPythonに送信して保存するスクリプトの作成方法を紹介します。これにより、スパイク検知システムの基礎を構築できます。以下で各ステップを詳しく見ていきましょう。
取引システムの構築(第1回):定量的なアプローチ 取引システムの構築(第1回):定量的なアプローチ
多くのトレーダーは短期的なパフォーマンスに基づいて戦略を評価し、利益を生むシステムであっても早い段階で手放してしまうことがよくあります。しかし、長期的な収益性は、最適化された勝率とリスクリワードレシオ(RRR: Reward-to-Risk Ratio)によって形成されるポジティブな期待値、そして規律あるポジションサイジングに依存しています。これらの原則は、バックテストの結果をもとにPythonでモンテカルロシミュレーションをおこなうことで検証することができ、戦略が時間の経過とともに堅牢であるか、もしくは破綻する可能性が高いかを評価するうえで役立ちます。