English Deutsch
preview
MQL5取引ツールキット(第8回):コードベースにHistory Manager EX5ライブラリを実装して使用する方法

MQL5取引ツールキット(第8回):コードベースにHistory Manager EX5ライブラリを実装して使用する方法

MetaTrader 5トレーディング |
144 3
Wanateki Solutions LTD
Kelvin Muturi Muigua

はじめに

これまでの記事では、MetaTrader 5の取引履歴を効率的に処理するために設計された、強力かつ包括的な「History Manager EX5」ライブラリの開発手順を紹介してきました。このライブラリは、クローズ済みポジション、未決注文、取引履歴といったあらゆる種類の履歴情報を、簡単にスキャン、取得、並べ替え、分類、フィルターできるよう設計されています。今回の記事では、これまでに構築した基盤を活かして、このHistory ManagerライブラリをMQL5プロジェクトに効率よく統合するための最終ステップを紹介します。

EX5ライブラリで利用可能な各関数については、わかりやすい解説と実用的なサンプルコードを交えて詳しく紹介します。これらの具体的な使用例は、各関数の動作理解に役立つだけでなく、実際の取引戦略や分析ツールへの応用方法も示しています。実装スキルを高めたい初心者の方にも、ワークフローの最適化を目指す上級開発者の方にも、このガイドを通じて、History Managerライブラリの持つポテンシャルを最大限に活用するための知識と手法を提供します。この記事を読み終えるころには、この多機能ライブラリを自信を持って導入し、取引履歴をより効率的に管理できるようになっているはずです。

MQL5でHistory Managerを使用する利点

以下は、History ManagerをMQL5プロジェクトに統合する主な利点です。

  • 簡単なデータ取得:このライブラリは、取引、注文、ポジション、未決注文などの取引履歴データを、最小限のコードで直感的に取得できる機能を提供します。これにより、複雑かつ煩雑な実装作業を省略できます。
  • 統一されたインターフェイス:すべての取引履歴データに対して、単一で一貫性のあるインターフェースからアクセスできるため、さまざまな種類の取引活動を効率的に管理・分析できます。
  • 関数による時間節約:1行の関数呼び出しで重要な取引データに素早くアクセスでき、開発時間を大幅に短縮し、戦略の実装に集中できます。
  • 自動データ処理:履歴データの取得、並べ替え、フィルターを自動化することで、作業効率が向上し、ワークフローがスムーズになります。
  • エラーの少ないデータ処理:手動による実装で起こりやすいミスを回避し、正確な取引履歴の取得を実現します。
  • 包括的なデータカバレッジ:クローズ済みポジションから未決注文まで、あらゆる種類の取引履歴に対応しており、データの取りこぼしを防ぎます。
  • 詳細な情報の取得GetLastClosedPositionData、GetLastFilledPendingOrderData、GetLastClosedProfitablePositionDataなどの関数により、取引の詳細情報を取得でき、より深い分析と正確な意思決定が可能になります。
  • カスタマイズ可能なフィルター銘柄、マジックナンバー、時間範囲などで履歴をフィルターでき、目的に応じた絞り込み分析がおこなえます。
  • 簡単な実装:このライブラリは、最小限のセットアップで既存のMQL5プロジェクトにシームレスに統合できるよう設計されています。
  • スケーラビリティ:小規模なスクリプトから大規模な取引システムまで、あらゆる規模のプロジェクトに柔軟に対応できます。
  • ニーズに合わせて適応可能:モジュール設計により、必要な機能だけを選んで使用できるため、さまざまな取引スタイルや戦略に適応可能です。
  • 機能の拡張性:開発者は、既存の関数を基にカスタム機能を追加することで、独自の取引要件に応じたソリューションを構築できます。
  • 事前構築済みのソリューション:ライブラリに含まれる関数を活用すれば、取引履歴管理ツールの開発にかかる時間やコストを大幅に削減できます。
  • あらゆるスキルレベルに対応:シンプルで分かりやすい設計により、初心者から熟練の開発者まで、誰でも扱いやすいライブラリです。
  • データに基づく意思決定:豊富な履歴データにアクセスできるため、取引戦略の開発や改善時に、より根拠のある判断がおこなえます。
  • 過去データによるバックテスト:過去の取引履歴を取得して戦略を検証できるため、戦略の信頼性と安定性を確保できます。
  • クリーンで読みやすいコード:ライブラリの関数は、保守性の高い、読みやすいコードを実現するよう設計されています。これにより、将来的な更新や管理も容易になります。



History Manager EX5ライブラリのインポートと設定

History Manager EX5ライブラリの機能を使用する前に、MQL5プロジェクトにライブラリを適切にインポートし、セットアップする必要があります。このセクションでは、スムーズかつ手間のかからないセットアップをおこなうために、その手順を段階的に解説します。

MQL5プロジェクトでHistoryManager.ex5ライブラリファイルを利用するには、まずこのファイルをダウンロードし、MetaTrader 5のインストールフォルダ内にある正しいディレクトリへ配置する必要があります。MetaTrader5ターミナルから[ツール]>[MetaQuotes言語エディタ]に移動するか、F4を押して、以下の手順に従ってMetaEditorを起動します。

  • 手順1:必要なディレクトリを作成します。

ルートMQL5ディレクトリにあるライブラリフォルダ内に、まだ存在しない場合はサブディレクトリ「\Wanateki\Toolkit\HistoryManager」を作成します。
MQL5インストールフォルダの完全なパスは「MQL5\Libraries\Wanateki\Toolkit\HistoryManager」です。

  • 手順2:HistoryManager.ex5バイナリファイルをダウンロードします。

この記事の一番下または最後までスクロールし、添付されているHistoryManager.ex5ファイルを見つけてダウンロードします。ファイルを手順1で作成したHistoryManagerフォルダに配置します。
Librariesフォルダのディレクトリ構成は以下のようになります。

HistoryManager.ex5実行ライブラリファイルを保存するディレクトリ

  • 手順3  :ヘッダーライブラリファイルを作成します。

1. MetaEditor IDEで、[新規作成]メニュー項目ボタンを使用してMQLウィザードを起動します。

MQL5ウィザード新規ファイル


2.  [インクルード(*.mqh)]オプションを選択し、[次へ]をクリックします。

MQL5ウィザード新しいインクルードファイルのセットアップ

3. [インクルードファイルウィンドウの一般プロパティ]で、[名前:]入力ボックスを見つけます。すべてのテキストをクリアし、パス「Include\Wanateki\Toolkit\HistoryManager\HistoryManager.mqh」を入力して、インクルードファイルのディレクトリと名前を指定します。

MQL5ウィザード新しいインクルードファイルディレクトリの設定

4.. [完了]ボタンを押すと、ライブラリヘッダーファイルが生成されます。



History Managerヘッダーファイル(HistoryManager.mqh)の実装

HistoryManager.mqhライブラリヘッダーの空のインクルードファイルが正常に作成されたので、次の手順では、その機能を定義する必要なコンポーネントを入力します。これには、情報を効率的に管理および保存するためのデータ構造の追加、反復タスクを簡素化してコードの読みやすさを向上させるためのマクロディレクティブの組み込み、およびHistoryManager.ex5機能と対話するためのコアインターフェイスとして機能するライブラリ関数のインポートと宣言が含まれます。

#propertyリンクの下で、まずグローバルスコープでDealData、OrderData、PositionData、およびPendingOrderDataデータ構造体を宣言します。これらの構造体は、さまざまな取引履歴プロパティを保存する役割を担い、コードベースのどの部分からでもアクセスできるようになります。

struct DealData
  {
  // Add all the DealData members here
  }
  
struct OrderData
  {
  // Add all the OrderData members here
  } 
  
struct PositionData
  {
  // Add all the PositionData members here
  }
  
struct PendingOrderData
  {
  // Add all the PendingOrderData members here
  }

次に、重要な期間を秒単位で表す定数またはマクロをいくつか定義します。これらには、NOW、ONE_DAY、ONE_WEEK、ONE_MONTH、ONE_YEAR、EPOCH、TODAY、THIS_WEEK、THIS_MONTH、THIS_YEARが含まれ、時間関連の計算が簡素化され、コードの読みやすさが向上します。

#define NOW datetime(TimeCurrent())
#define ONE_DAY datetime(TimeCurrent() - PeriodSeconds(PERIOD_D1))
#define ONE_WEEK datetime(TimeCurrent() - PeriodSeconds(PERIOD_W1))
#define ONE_MONTH datetime(TimeCurrent() - PeriodSeconds(PERIOD_MN1))
#define ONE_YEAR datetime(TimeCurrent() - (PeriodSeconds(PERIOD_MN1) * 12))
#define EPOCH 0 // 1st Jan 1970
//--
#define TODAY 12
#define THIS_WEEK 13
#define THIS_MONTH 14
#define THIS_YEAR 15

また、空の文字列を格納するための文字列マクロ「ALL_SYMBOLS」も作成します。これは、すべての銘柄に対して指定された履歴を処理することを示すシグナルとして機能します。さらに、ALL_POSITIONSALL_ORDERSALL_DEALS整数マクロを定義します。これらにより、処理する注文取引ポジション履歴の種類を指定できます。

#define ALL_SYMBOLS ""
#define ALL_POSITIONS 1110
#define ALL_ORDERS 1111
#define ALL_DEALS 1112

必要なデータ構造体をすべて作成し、重要なプリプロセッサディレクティブまたはマクロを定義したので、次はHistoryManager.ex5ライブラリをインポートします。これをおこなうには、#importディレクティブに続いて、EX5ライブラリが配置されているフォルダパスを使用します。

#import "Wanateki/Toolkit/HistoryManager/HistoryManager.ex5"

#importディレクティブの後に、ライブラリ関数の宣言を追加し、最後に#importの終了ディレクティブを挿入して、HistoryManager.mqhヘッダーファイルを完成させます。

#import "Wanateki/Toolkit/HistoryManager/HistoryManager.ex5"
//--
void PrintDealsHistory(datetime fromDateTime, datetime toDateTime);
void PrintOrdersHistory(datetime fromDateTime, datetime toDateTime);
void PrintPositionsHistory(datetime fromDateTime, datetime toDateTime);
void PrintPendingOrdersHistory(datetime fromDateTime, datetime toDateTime);

//--
bool GetDealsData(DealData &dealsData[], datetime fromDateTime, datetime toDateTime, string symbol, ulong magic);
bool GetOrdersData(OrderData &ordersData[], datetime fromDateTime, datetime toDateTime, string symbol, ulong magic);
bool GetPositionsData(PositionData &positionsData[], datetime fromDateTime, datetime toDateTime, string symbol, ulong magic);
bool GetPendingOrdersData(PendingOrderData &pendingOrdersData[], datetime fromDateTime, datetime toDateTime, string symbol, ulong magic);
//--

// Add all the other function declarations here...

#import

以下は、HistoryManager.mqhインクルードファイルを構成する主要なコードセグメントです。このヘッダーファイルには、HistoryManagerEX5ライブラリをMQL5プロジェクトにインポートおよび統合するために必要なすべてのリソースが含まれています。ソースファイルの先頭でこのファイルをインクルードすることで、ライブラリのすべてのデータ構造と関数にすぐにアクセスできるようになります。記事の末尾には、完全なHistoryManager.mqhソースファイルもダウンロード用に添付されています。

struct DealData
  {
   ulong             ticket;
   ulong             magic;
   ENUM_DEAL_ENTRY   entry;
   ENUM_DEAL_TYPE    type;
   ENUM_DEAL_REASON  reason;
   ulong             positionId;
   ulong             order;
   string            symbol;
   string            comment;
   double            volume;
   double            price;
   datetime          time;
   double            tpPrice;
   double            slPrice;
   double            commission;
   double            swap;
   double            profit;
  };  
//--
struct OrderData
  {
   datetime                timeSetup;
   datetime                timeDone;
   datetime                expirationTime;
   ulong                   ticket;
   ulong                   magic;
   ENUM_ORDER_REASON       reason;
   ENUM_ORDER_TYPE         type;
   ENUM_ORDER_TYPE_FILLING typeFilling;
   ENUM_ORDER_STATE        state;
   ENUM_ORDER_TYPE_TIME    typeTime;
   ulong                   positionId;
   ulong                   positionById;
   string                  symbol;
   string                  comment;
   double                  volumeInitial;
   double                  priceOpen;
   double                  priceStopLimit;
   double                  tpPrice;
   double                  slPrice;
  };
//--
struct PositionData
  {
   ENUM_POSITION_TYPE type;
   ulong              ticket;
   ENUM_ORDER_TYPE    initiatingOrderType;
   ulong              positionId;
   bool               initiatedByPendingOrder;
   ulong              openingOrderTicket;
   ulong              openingDealTicket;
   ulong              closingDealTicket;
   string             symbol;
   double             volume;
   double             openPrice;
   double             closePrice;
   datetime           openTime;
   datetime           closeTime;
   long               duration;
   double             commission;
   double             swap;
   double             profit;
   double             tpPrice;
   double             slPrice;
   int                tpPips;
   int                slPips;
   int                pipProfit;
   double             netProfit;
   ulong              magic;
   string             comment;
  };
//--
struct PendingOrderData
  {
   string                  symbol;
   ENUM_ORDER_TYPE         type;
   ENUM_ORDER_STATE        state;
   double                  priceOpen;
   double                  tpPrice;
   double                  slPrice;
   int                     tpPips;
   int                     slPips;
   ulong                   positionId;
   ulong                   ticket;
   datetime                timeSetup;
   datetime                expirationTime;
   datetime                timeDone;
   ENUM_ORDER_TYPE_TIME    typeTime;
   ulong                   magic;
   ENUM_ORDER_REASON       reason;
   ENUM_ORDER_TYPE_FILLING typeFilling;
   string                  comment;
   double                  volumeInitial;
   double                  priceStopLimit;
  };
//--
#define NOW datetime(TimeCurrent())
#define ONE_DAY datetime(TimeCurrent() - PeriodSeconds(PERIOD_D1))
#define ONE_WEEK datetime(TimeCurrent() - PeriodSeconds(PERIOD_W1))
#define ONE_MONTH datetime(TimeCurrent() - PeriodSeconds(PERIOD_MN1))
#define ONE_YEAR datetime(TimeCurrent() - (PeriodSeconds(PERIOD_MN1) * 12))
#define EPOCH 0 // 1st Jan 1970
//--
#define TODAY 12
#define THIS_WEEK 13
#define THIS_MONTH 14
#define THIS_YEAR 15
//--
#define ALL_SYMBOLS ""
#define ALL_POSITIONS 1110
#define ALL_ORDERS 1111
#define ALL_DEALS 1112
//--

#import "Wanateki/Toolkit/HistoryManager/HistoryManager.ex5"
//--
void PrintDealsHistory(datetime fromDateTime, datetime toDateTime);
void PrintOrdersHistory(datetime fromDateTime, datetime toDateTime);
void PrintPositionsHistory(datetime fromDateTime, datetime toDateTime);
void PrintPendingOrdersHistory(datetime fromDateTime, datetime toDateTime);

//--
bool GetDealsData(DealData &dealsData[], datetime fromDateTime, datetime toDateTime, string symbol, ulong magic);
bool GetOrdersData(OrderData &ordersData[], datetime fromDateTime, datetime toDateTime, string symbol, ulong magic);
bool GetPositionsData(PositionData &positionsData[], datetime fromDateTime, datetime toDateTime, string symbol, ulong magic);
bool GetPendingOrdersData(PendingOrderData &pendingOrdersData[], datetime fromDateTime, datetime toDateTime, string symbol, ulong magic);
//--

bool GetDealsData(DealData &dealsData[], datetime fromDateTime, datetime toDateTime);
bool GetOrdersData(OrderData &ordersData[], datetime fromDateTime, datetime toDateTime);
bool GetPositionsData(PositionData &positionsData[], datetime fromDateTime, datetime toDateTime);
bool GetPendingOrdersData(PendingOrderData &pendingOrdersData[], datetime fromDateTime, datetime toDateTime);

//--
bool GetAllDealsData(DealData &dealsData[]);
bool GetAllOrdersData(OrderData &ordersData[]);
bool GetAllPositionsData(PositionData &positionsData[]);
bool GetAllPendingOrdersData(PendingOrderData &pendingOrdersData[]);
//--
bool GetAllDealsData(DealData &dealsData[], string symbol, ulong magic);
bool GetAllOrdersData(OrderData &ordersData[], string symbol, ulong magic);
bool GetAllPositionsData(PositionData &positionsData[], string symbol, ulong magic);
bool GetAllPendingOrdersData(PendingOrderData &pendingOrdersData[], string symbol, ulong magic);

//--
bool GetLastClosedPositionData(PositionData &lastClosedPositionInfo);
bool LastClosedPositionType(ENUM_POSITION_TYPE &lastClosedPositionType);
bool LastClosedPositionVolume(double &lastClosedPositionVolume);
bool LastClosedPositionSymbol(string &lastClosedPositionSymbol);
bool LastClosedPositionTicket(ulong &lastClosedPositionTicket);
bool LastClosedPositionProfit(double &lastClosedPositionProfit);
bool LastClosedPositionNetProfit(double &lastClosedPositionNetProfit);
bool LastClosedPositionPipProfit(int &lastClosedPositionPipProfit);
bool LastClosedPositionClosePrice(double &lastClosedPositionClosePrice);
bool LastClosedPositionOpenPrice(double &lastClosedPositionOpenPrice);
bool LastClosedPositionSlPrice(double &lastClosedPositionSlPrice);
bool LastClosedPositionTpPrice(double &lastClosedPositionTpPrice);
bool LastClosedPositionSlPips(int &lastClosedPositionSlPips);
bool LastClosedPositionTpPips(int &lastClosedPositionTpPips);
bool LastClosedPositionOpenTime(datetime &lastClosedPositionOpenTime);
bool LastClosedPositionCloseTime(datetime &lastClosedPositionCloseTime);
bool LastClosedPositionSwap(double &lastClosedPositionSwap);
bool LastClosedPositionCommission(double &lastClosedPositionCommission);
bool LastClosedPositionInitiatedByPendingOrder(bool &lastClosedPositionInitiatedByPendingOrder);
bool LastClosedPositionInitiatingOrderType(ENUM_ORDER_TYPE &lastClosedPositionInitiatingOrderType);
bool LastClosedPositionId(ulong &lastClosedPositionId);
bool LastClosedPositionOpeningOrderTicket(ulong &lastClosedPositionOpeningOrderTicket);
bool LastClosedPositionOpeningDealTicket(ulong &lastClosedPositionOpeningDealTicket);
bool LastClosedPositionClosingDealTicket(ulong &lastClosedPositionClosingDealTicket);
bool LastClosedPositionMagic(ulong &lastClosedPositionMagic);
bool LastClosedPositionComment(string &lastClosedPositionComment);
bool LastClosedPositionDuration(long &lastClosedPositionDuration);

//--
bool GetLastClosedProfitablePositionData(PositionData &lastClosedProfitablePositionInfo);
bool GetLastClosedLossPositionData(PositionData &lastClosedLossPositionData);

//--
bool GetLastFilledPendingOrderData(PendingOrderData &getLastFilledPendingOrderData);
bool LastFilledPendingOrderType(ENUM_ORDER_TYPE &lastFilledPendingOrderType);
bool LastFilledPendingOrderSymbol(string &lastFilledPendingOrderSymbol);
bool LastFilledPendingOrderTicket(ulong &lastFilledPendingOrderTicket);
bool LastFilledPendingOrderPriceOpen(double &lastFilledPendingOrderPriceOpen);
bool LastFilledPendingOrderSlPrice(double &lastFilledPendingOrderSlPrice);
bool LastFilledPendingOrderTpPrice(double &lastFilledPendingOrderTpPrice);
bool LastFilledPendingOrderSlPips(int &lastFilledPendingOrderSlPips);
bool LastFilledPendingOrderTpPips(int &lastFilledPendingOrderTpPips);
bool LastFilledPendingOrderTimeSetup(datetime &lastFilledPendingOrderTimeSetup);
bool LastFilledPendingOrderTimeDone(datetime &lastFilledPendingOrderTimeDone);
bool LastFilledPendingOrderExpirationTime(datetime &lastFilledPendingOrderExpirationTime);
bool LastFilledPendingOrderPositionId(ulong &lastFilledPendingOrderPositionId);
bool LastFilledPendingOrderMagic(ulong &lastFilledPendingOrderMagic);
bool LastFilledPendingOrderReason(ENUM_ORDER_REASON &lastFilledPendingOrderReason);
bool LastFilledPendingOrderTypeFilling(ENUM_ORDER_TYPE_FILLING &lastFilledPendingOrderTypeFilling);
bool LastFilledPendingOrderTypeTime(datetime &lastFilledPendingOrderTypeTime);
bool LastFilledPendingOrderComment(string &lastFilledPendingOrderComment);

//--
bool GetLastCanceledPendingOrderData(PendingOrderData &getLastCanceledPendingOrderData);
bool LastCanceledPendingOrderType(ENUM_ORDER_TYPE &lastCanceledPendingOrderType);
bool LastCanceledPendingOrderSymbol(string &lastCanceledPendingOrderSymbol);
bool LastCanceledPendingOrderTicket(ulong &lastCanceledPendingOrderTicket);
bool LastCanceledPendingOrderPriceOpen(double &lastCanceledPendingOrderPriceOpen);
bool LastCanceledPendingOrderSlPrice(double &lastCanceledPendingOrderSlPrice);
bool LastCanceledPendingOrderTpPrice(double &lastCanceledPendingOrderTpPrice);
bool LastCanceledPendingOrderSlPips(int &lastCanceledPendingOrderSlPips);
bool LastCanceledPendingOrderTpPips(int &lastCanceledPendingOrderTpPips);
bool LastCanceledPendingOrderTimeSetup(datetime &lastCanceledPendingOrderTimeSetup);
bool LastCanceledPendingOrderTimeDone(datetime &lastCanceledPendingOrderTimeDone);
bool LastCanceledPendingOrderExpirationTime(datetime &lastCanceledPendingOrderExpirationTime);
bool LastCanceledPendingOrderPositionId(ulong &lastCanceledPendingOrderPositionId);
bool LastCanceledPendingOrderMagic(ulong &lastCanceledPendingOrderMagic);
bool LastCanceledPendingOrderReason(ENUM_ORDER_REASON &lastCanceledPendingOrderReason);
bool LastCanceledPendingOrderTypeFilling(ENUM_ORDER_TYPE_FILLING &lastCanceledPendingOrderTypeFilling);
bool LastCanceledPendingOrderTypeTime(datetime &lastCanceledPendingOrderTypeTime);
bool LastCanceledPendingOrderComment(string &lastCanceledPendingOrderComment);

//*
//--
bool GetLastClosedPositionData(PositionData &lastClosedPositionInfo, string symbol, ulong magic);
bool LastClosedPositionType(ENUM_POSITION_TYPE &lastClosedPositionType, string symbol, ulong magic);
bool LastClosedPositionVolume(double &lastClosedPositionVolume, string symbol, ulong magic);
bool LastClosedPositionSymbol(string &lastClosedPositionSymbol, string symbol, ulong magic);
bool LastClosedPositionTicket(ulong &lastClosedPositionTicket, string symbol, ulong magic);
bool LastClosedPositionProfit(double &lastClosedPositionProfit, string symbol, ulong magic);
bool LastClosedPositionNetProfit(double &lastClosedPositionNetProfit, string symbol, ulong magic);
bool LastClosedPositionPipProfit(int &lastClosedPositionPipProfit, string symbol, ulong magic);
bool LastClosedPositionClosePrice(double &lastClosedPositionClosePrice, string symbol, ulong magic);
bool LastClosedPositionOpenPrice(double &lastClosedPositionOpenPrice, string symbol, ulong magic);
bool LastClosedPositionSlPrice(double &lastClosedPositionSlPrice, string symbol, ulong magic);
bool LastClosedPositionTpPrice(double &lastClosedPositionTpPrice, string symbol, ulong magic);
bool LastClosedPositionSlPips(int &lastClosedPositionSlPips, string symbol, ulong magic);
bool LastClosedPositionTpPips(int &lastClosedPositionTpPips, string symbol, ulong magic);
bool LastClosedPositionOpenTime(datetime &lastClosedPositionOpenTime, string symbol, ulong magic);
bool LastClosedPositionCloseTime(datetime &lastClosedPositionCloseTime, string symbol, ulong magic);
bool LastClosedPositionSwap(double &lastClosedPositionSwap, string symbol, ulong magic);
bool LastClosedPositionCommission(double &lastClosedPositionCommission, string symbol, ulong magic);
bool LastClosedPositionInitiatingOrderType(ENUM_ORDER_TYPE &lastClosedPositionInitiatingOrderType, string symbol, ulong magic);
bool LastClosedPositionId(ulong &lastClosedPositionId, string symbol, ulong magic);
bool LastClosedPositionInitiatedByPendingOrder(bool &lastClosedPositionInitiatedByPendingOrder, string symbol, ulong magic);
bool LastClosedPositionOpeningOrderTicket(ulong &lastClosedPositionOpeningOrderTicket, string symbol, ulong magic);
bool LastClosedPositionOpeningDealTicket(ulong &lastClosedPositionOpeningDealTicket, string symbol, ulong magic);
bool LastClosedPositionClosingDealTicket(ulong &lastClosedPositionClosingDealTicket, string symbol, ulong magic);
bool LastClosedPositionMagic(ulong &lastClosedPositionMagic, string symbol, ulong magic);
bool LastClosedPositionComment(string &lastClosedPositionComment, string symbol, ulong magic);
bool LastClosedPositionDuration(long &lastClosedPositionDuration, string symbol, ulong magic);

//--
bool GetLastClosedProfitablePositionData(PositionData &lastClosedProfitablePositionInfo, string symbol, ulong magic);
bool GetLastClosedLossPositionData(PositionData &lastClosedLossPositionData, string symbol, ulong magic);

//--
bool GetLastFilledPendingOrderData(PendingOrderData &lastFilledPendingOrderData, string symbol, ulong magic);
bool LastFilledPendingOrderType(ENUM_ORDER_TYPE &lastFilledPendingOrderType, string symbol, ulong magic);
bool LastFilledPendingOrderSymbol(string &lastFilledPendingOrderSymbol, string symbol, ulong magic);
bool LastFilledPendingOrderTicket(ulong &lastFilledPendingOrderTicket, string symbol, ulong magic);
bool LastFilledPendingOrderPriceOpen(double &lastFilledPendingOrderPriceOpen, string symbol, ulong magic);
bool LastFilledPendingOrderSlPrice(double &lastFilledPendingOrderSlPrice, string symbol, ulong magic);
bool LastFilledPendingOrderTpPrice(double &lastFilledPendingOrderTpPrice, string symbol, ulong magic);
bool LastFilledPendingOrderSlPips(int &lastFilledPendingOrderSlPips, string symbol, ulong magic);
bool LastFilledPendingOrderTpPips(int &lastFilledPendingOrderTpPips, string symbol, ulong magic);
bool LastFilledPendingOrderTimeSetup(datetime &lastFilledPendingOrderTimeSetup, string symbol, ulong magic);
bool LastFilledPendingOrderTimeDone(datetime &lastFilledPendingOrderTimeDone, string symbol, ulong magic);
bool LastFilledPendingOrderExpirationTime(datetime &lastFilledPendingOrderExpirationTime, string symbol, ulong magic);
bool LastFilledPendingOrderPositionId(ulong &lastFilledPendingOrderPositionId, string symbol, ulong magic);
bool LastFilledPendingOrderMagic(ulong &lastFilledPendingOrderMagic, string symbol, ulong magic);
bool LastFilledPendingOrderReason(ENUM_ORDER_REASON &lastFilledPendingOrderReason, string symbol, ulong magic);
bool LastFilledPendingOrderTypeFilling(ENUM_ORDER_TYPE_FILLING &lastFilledPendingOrderTypeFilling, string symbol, ulong magic);
bool LastFilledPendingOrderTypeTime(datetime &lastFilledPendingOrderTypeTime, string symbol, ulong magic);
bool LastFilledPendingOrderComment(string &lastFilledPendingOrderComment, string symbol, ulong magic);

//--
bool GetLastCanceledPendingOrderData(PendingOrderData &lastCanceledPendingOrderData, string symbol, ulong magic);
bool LastCanceledPendingOrderType(ENUM_ORDER_TYPE &lastCanceledPendingOrderType, string symbol, ulong magic);
bool LastCanceledPendingOrderSymbol(string &lastCanceledPendingOrderSymbol, string symbol, ulong magic);
bool LastCanceledPendingOrderTicket(ulong &lastCanceledPendingOrderTicket, string symbol, ulong magic);
bool LastCanceledPendingOrderPriceOpen(double &lastCanceledPendingOrderPriceOpen, string symbol, ulong magic);
bool LastCanceledPendingOrderSlPrice(double &lastCanceledPendingOrderSlPrice, string symbol, ulong magic);
bool LastCanceledPendingOrderTpPrice(double &lastCanceledPendingOrderTpPrice, string symbol, ulong magic);
bool LastCanceledPendingOrderSlPips(int &lastCanceledPendingOrderSlPips, string symbol, ulong magic);
bool LastCanceledPendingOrderTpPips(int &lastCanceledPendingOrderTpPips, string symbol, ulong magic);
bool LastCanceledPendingOrderTimeSetup(datetime &lastCanceledPendingOrderTimeSetup, string symbol, ulong magic);
bool LastCanceledPendingOrderTimeDone(datetime &lastCanceledPendingOrderTimeDone, string symbol, ulong magic);
bool LastCanceledPendingOrderExpirationTime(datetime &lastCanceledPendingOrderExpirationTime, string symbol, ulong magic);
bool LastCanceledPendingOrderPositionId(ulong &lastCanceledPendingOrderPositionId, string symbol, ulong magic);
bool LastCanceledPendingOrderMagic(ulong &lastCanceledPendingOrderMagic, string symbol, ulong magic);
bool LastCanceledPendingOrderReason(ENUM_ORDER_REASON &lastCanceledPendingOrderReason, string symbol, ulong magic);
bool LastCanceledPendingOrderTypeFilling(ENUM_ORDER_TYPE_FILLING &lastCanceledPendingOrderTypeFilling, string symbol, ulong magic);
bool LastCanceledPendingOrderTypeTime(datetime &lastCanceledPendingOrderTypeTime, string symbol, ulong magic);
bool LastCanceledPendingOrderComment(string &lastCanceledPendingOrderComment, string symbol, ulong magic);

//--
string BoolToString(bool boolVariable);
datetime GetPeriodStart(int periodType);

#import
//+------------------------------------------------------------------+



History Manager EX5ライブラリの実践的な実装と概要

ここではライブラリ関数をカテゴリごとに整理しながら、その機能や使い方を簡単なユースケースを交えて紹介します。途中で、それぞれの役割を説明し、さまざまなタスクを達成するためにどのように使用できるかを示す簡単な使用例を示します。

1. 指定した期間の取引履歴を出力する関数

このカテゴリの関数は、指定した日時範囲の取引履歴をMetaTrader 5のターミナルログに直接出力します。戻り値のないvoid型で、履歴の対象期間を指定するためのdatetime型の引数を2つ受け取ります。 これは迅速な確認やデバッグに非常に便利です。

関数プロトタイプ定義 説明 使用例
void PrintDealsHistory(
   datetime fromDateTime,
   datetime toDateTime
);


指定された時間範囲内のすべての取引の詳細を出力
// Print the deals history for the last 24 hours (1 day)
PrintDealsHistory(ONE_DAY, NOW);
void PrintOrdersHistory(
   datetime fromDateTime,
   datetime toDateTime
);

指定された時間範囲内のすべての注文の詳細を出力
// Print the orders history for the last 24 hours (1 day)
PrintOrdersHistory(ONE_DAY, NOW);


void PrintPositionsHistory(
   datetime fromDateTime,
   datetime toDateTime
);


指定された時間範囲内のすべての決済済みポジションの詳細を出力
// Print the positions history for the last 24 hours (1 day)
PrintPositionsHistory(ONE_DAY, NOW);
void PrintPendingOrdersHistory(
   datetime fromDateTime,
   datetime toDateTime
);

指定された時間範囲内のすべての未決注文の詳細を出力
// Print the pending orders history for the last 24 hours (1 day)
PrintPendingOrdersHistory(ONE_DAY, NOW);


2. 指定した期間の取引履歴データを取得する関数

これらの関数を使用すると、指定された期間の銘柄マジックナンバーでフィルターされた取引履歴データをプログラムで取得できます。取得されたデータはデータ構造体配列に保存され、さらに分析や処理が可能になります。

関数プロトタイプ定義 説明 使用例
bool GetDealsData(
   DealData &dealsData[], // [out]
   datetime fromDateTime,
   datetime toDateTime,
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);


指定された時間範囲内の取引データを検索して取得します。さらに、取得したデータを銘柄やマジックナンバーでフィルターするオプションも提供しており、よりターゲットを絞った処理が可能になります。
// Print the total account net profit for the last 7 days
DealData dealsData[];
if(
   GetDealsData(
      dealsData,
      ONE_WEEK, NOW,
      ALL_SYMBOLS, 0
   ) &&
   ArraySize(dealsData) > 0
)
  {
   double totalGrossProfit = 0.0,
          totalSwap = 0.0,
          totalCommission = 0.0;
   int totalDeals = ArraySize(dealsData);
   for(int k = 0; k < totalDeals; k++)
     {
      if(dealsData[k].entry == DEAL_ENTRY_OUT)
        {
         totalGrossProfit += dealsData[k].profit;
         totalSwap += dealsData[k].swap;
         totalCommission += dealsData[k].commission;
        }
     }
   double totalExpenses = totalSwap + totalCommission;
   double totalNetProfit = totalGrossProfit - MathAbs(totalExpenses);

   Print("-------------------------------------------------");
   Print(
      "Account No: ", AccountInfoInteger(ACCOUNT_LOGIN),
      " [ 7 DAYS NET PROFIT ]"
   );
   Print(
      "Total Gross Profit: ",
      DoubleToString(totalGrossProfit, 2),
      " ", AccountInfoString(ACCOUNT_CURRENCY)
   );
   Print(
      "Total Swap: ", DoubleToString(totalSwap, 2),
      " ", AccountInfoString(ACCOUNT_CURRENCY)
   );
   Print(
      "Total Commission: ", DoubleToString(totalCommission, 2),
      " ", AccountInfoString(ACCOUNT_CURRENCY)
   );
   Print(
      "Total Net Profit: ",
      DoubleToString(totalNetProfit, 2), " ",
      AccountInfoString(ACCOUNT_CURRENCY)
   );
  }
bool GetOrdersData(
   OrderData &ordersData[], // [out]
   datetime fromDateTime,
   datetime toDateTime,
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

指定された時間範囲内の注文データを照会して取得します。さらに、取得したデータを銘柄やマジックナンバーでフィルターするオプションも提供します。
// Print the total BUY Orders filled in the last 7 days
OrderData ordersData[];
if(
   GetOrdersData(ordersData, ONE_WEEK, NOW) &&
   ArraySize(ordersData) > 0
)
  {
   int totalBuyOrdersFilled = 0,
       totalOrders = ArraySize(ordersData);
   for(int w = 0; w < totalOrders; w++)
     {
      if(ordersData[w].type == ORDER_TYPE_BUY)
         ++totalBuyOrdersFilled;
     }
   Print("");
   Print("-------------------------------------------------");
   Print("Account No: ", AccountInfoInteger(ACCOUNT_LOGIN));
   Print(totalBuyOrdersFilled, " BUY Orders Filled in the last 7 days!");
  }


bool GetPositionsData(
   PositionData &positionsData[], // [out]
   datetime fromDateTime,
   datetime toDateTime,
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);


指定された時間範囲内の決済済みポジション履歴データを検索して取得します。取得したデータを銘柄やマジックナンバーの値でフィルターするオプションを提供します。
// Print total pips earned in last 24hrs for specified symbol and magic
string symbol = _Symbol;
long magic = 0;
PositionData positionsData[];
if(
   GetPositionsData(positionsData, ONE_DAY, NOW, symbol, magic) &&
   ArraySize(positionsData) > 0
)
  {
   int totalPipsEarned = 0,
       totalPositions = ArraySize(positionsData);
   for(int k = 0; k < totalPositions; k++)
     {
      totalPipsEarned += positionsData[k].pipProfit;
     }
   Print("");
   Print("-------------------------------------------------");
   Print("Account No: ", AccountInfoInteger(ACCOUNT_LOGIN));
   Print(
      totalPipsEarned, " pips earned in the last 24hrs for ", symbol,
      " with magic no. ", magic
   );
  }

 
bool GetPendingOrdersData(
   PendingOrderData &pendingOrdersData[], // [out]
   datetime fromDateTime,
   datetime toDateTime,
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

指定された時間範囲内の未決注文データ履歴を取得します。また、未決注文履歴データを銘柄やマジックナンバーでフィルターするオプションも提供します。
// Print total number of buy and sell stops filled for symbol and magic
// in the last 7 days
string symbol = _Symbol;
long magic = 0;
PendingOrderData pendingOrdersData[];
if(
   GetPendingOrdersData(pendingOrdersData, ONE_WEEK, NOW, symbol, magic) &&
   ArraySize(pendingOrdersData) > 0
)
  {
   int totalBuyStopsFilled = 0, totalSellStopsFilled = 0,
       totalPendingOrders = ArraySize(pendingOrdersData);
   for(int k = 0; k < totalPendingOrders; k++)
     {
      if(pendingOrdersData[k].type == ORDER_TYPE_BUY_STOP)
         ++totalBuyStopsFilled;
      if(pendingOrdersData[k].type == ORDER_TYPE_SELL_STOP)
         ++totalSellStopsFilled;
     }
   Print("");
   Print("-------------------------------------------------");
   Print("Account No: ", AccountInfoInteger(ACCOUNT_LOGIN), ", Magic No = ", magic);
   Print(
      symbol, " --> Total Filled - (Buy Stops = ", totalBuyStopsFilled,
      ") (Sell Stops = ", totalSellStopsFilled, ") in the last 7 days."
   );
  }


3. 過去のすべての取引を取得する関数

これらの関数は、特定の時間範囲を指定することなく、口座内のすべての利用可能な取引履歴データを取得するための包括的な方法を提供します。オプションで銘柄マジックナンバーによるフィルターも適用可能です。

関数プロトタイプ定義
説明
使用例
bool GetAllDealsData(
   DealData &dealsData[], // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

すべての取引データを取得すると同時に、銘柄やマジックナンバーで取引履歴データをフィルターするオプションも提供します。
// Find and list total deposited funds in the account
DealData dealsData[];
if(GetAllDealsData(dealsData) && ArraySize(dealsData) > 0)
  {
   double totalDeposits = 0.0;
   int totalDeals = ArraySize(dealsData);
   Print("");
   for(int k = 0; k < totalDeals; k++)
     {
      if(dealsData[k].type == DEAL_TYPE_BALANCE)
        {
         totalDeposits += dealsData[k].profit;
         Print(
            dealsData[k].profit, " ", AccountInfoString(ACCOUNT_CURRENCY),
            " --> Cash deposit on: ", dealsData[k].time
         );
        }
     }
   Print("-------------------------------------------------");
   Print(
      "Account No: ", AccountInfoInteger(ACCOUNT_LOGIN),
      " Total Cash Deposits: ", totalDeposits, " ", 
      AccountInfoString(ACCOUNT_CURRENCY)
   );
  }

bool GetAllOrdersData(
   OrderData &ordersData[], // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

すべての注文データを取得すると同時に、銘柄やマジックナンバーで注文履歴をフィルターするオプションも提供します。
// Find if the account has ever gotten a Stop Out/Margin Call
OrderData ordersData[];
if(GetAllOrdersData(ordersData) && ArraySize(ordersData) > 0)
  {
   int totalStopOuts = 0;
   int totalOrders = ArraySize(ordersData);
   Print("");
   for(int k = 0; k < totalOrders; k++)
     {
      if(ordersData[k].reason == ORDER_REASON_SO)
        {
         ++totalStopOuts;
         Print(
            EnumToString(ordersData[k].type),
            " --> on: ", ordersData[k].timeDone
         );
        }
     }
   Print("-------------------------------------------------");
   Print("Account No: ", AccountInfoInteger(ACCOUNT_LOGIN));
   Print("Total STOP OUT events: ", totalStopOuts);
  }

bool GetAllPositionsData(
   PositionData &positionsData[], // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

すべてのポジション履歴データを取得すると同時に、銘柄やマジックナンバーで決済済みポジションデータをフィルターするオプションも提供します。
// Find the average trade duration in seconds
PositionData positionsData[];
if(GetAllPositionsData(positionsData) && ArraySize(positionsData) > 0)
  {
   long totalTradesDuration = 0; 
   int totalPositions = ArraySize(positionsData);
   Print("");
   for(int k = 0; k < totalPositions; k++)
     {
      totalTradesDuration += positionsData[k].duration;
     }
   long averageTradesDuration = totalTradesDuration / totalPositions;
   Print("-------------------------------------------------");
   Print("Account No: ", AccountInfoInteger(ACCOUNT_LOGIN));
   Print("Average trade duration: ", averageTradesDuration, " seconds.");
  }

bool GetAllPendingOrdersData(
   PendingOrderData &pendingOrdersData[], // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

すべての未決注文データを取得すると同時に、銘柄やマジックナンバーで未決注文履歴データをフィルターするオプションも提供します。
// Find the total expired pending orders in the account
PendingOrderData pendingOrdersData[];
if(GetAllPendingOrdersData(pendingOrdersData) && ArraySize(pendingOrdersData) > 0)
  {
   int totalExpiredPendingOrders = 0;
   int totalPendingOrders = ArraySize(pendingOrdersData);
   Print("");
   Print("-- EXPIRED PENDING ORDERS --");
   for(int k = 0; k < totalPendingOrders; k++)
     {
      if(pendingOrdersData[k].state == ORDER_STATE_EXPIRED)
        {
         ++totalExpiredPendingOrders;
         Print("Symbol = ", pendingOrdersData[k].symbol);
         Print("Time Setup = ", pendingOrdersData[k].timeSetup);
         Print("Ticket = ", pendingOrdersData[k].ticket);
         Print("Price Open = ", pendingOrdersData[k].priceOpen);
         Print(
            "SL Price = ", pendingOrdersData[k].slPrice,
            ", TP Price = ", pendingOrdersData[k].tpPrice
         );
         Print("Expiration Time = ", pendingOrdersData[k].expirationTime);
         Print("");
        }
     }
   Print("-------------------------------------------------");
   Print("Account No: ", AccountInfoInteger(ACCOUNT_LOGIN));
   Print("Total Expired Pending Orders: ", totalExpiredPendingOrders);
  }


4. 直近に決済されたポジションを分析する関数

これらの関数は、直近で決済されたポジションに関する詳細情報を取得するために設計されています。損益、取引ロット数、クローズ日時など、各ポジションの重要な要素を把握することができます。 各関数にはそれぞれ固有の用途があり、直近の取引に関する重要な情報へアクセスできるようになっています。また、処理対象のポジション履歴データを銘柄やマジック ナンバーでフィルターすることも可能です。

関数プロトタイプ定義
説明
使用例
bool GetLastClosedPositionData(
   PositionData &lastClosedPositionInfo, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

関連する詳細すべてを含む、直近で決済されたポジションの完全なスナップショットを取得します。結果を銘柄やマジックナンバーでフィルターするオプションがあります。
// Get the last closed position in the account
PositionData lastClosedPositionInfo;
if(
   GetLastClosedPositionData(lastClosedPositionInfo) &&
   lastClosedPositionInfo.ticket > 0
)
  {
   // Process the last closed position data
   Print("---LAST CLOSED POSITION--");
   Print("Symbol: ", lastClosedPositionInfo.symbol);
   Print("Type: ", EnumToString(lastClosedPositionInfo.type));
   Print("Open Time: ", lastClosedPositionInfo.openTime);
   Print("Close Time: ", lastClosedPositionInfo.closeTime);
   Print("Profit: ", lastClosedPositionInfo.profit);
   // Place more position properties analysis code....
  }
//-
// Get the last closed position for GBPUSD and magic 0
PositionData lastClosedPositionInfo;
string symbol = "GBPUSD";
if(
   GetLastClosedPositionData(lastClosedPositionInfo, symbol, 0) &&
   lastClosedPositionInfo.ticket > 0
)
  {
   // Process the last closed position data
   Print("---LAST CLOSED POSITION FOR ", symbol, " --");
   Print("Symbol: ", lastClosedPositionInfo.symbol);
   Print("Type: ", EnumToString(lastClosedPositionInfo.type));
   Print("Open Time: ", lastClosedPositionInfo.openTime);
   Print("Close Time: ", lastClosedPositionInfo.closeTime);
   Print("Profit: ", lastClosedPositionInfo.profit);
   // Place more position properties analysis code....
  }


bool LastClosedPositionType(
   ENUM_POSITION_TYPE &lastClosedPositionType, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

直近のポジションが買い取引であったか売り取引であったかを明らかにします。銘柄やマジックナンバーでデータをフィルターするオプションがあります。
// Get the last closed position type in the account
ENUM_POSITION_TYPE lastClosedPositionType;
LastClosedPositionType(lastClosedPositionType);
Print(
   "Account's last closed position type: ",
   EnumToString(lastClosedPositionType)
);
//--
// Get the last closed position type for EURUSD and magic 0
ENUM_POSITION_TYPE lastClosedPositionType;
LastClosedPositionType(lastClosedPositionType, "EURUSD", 0);
Print(
   "EURUSD: last closed position type: ",
   EnumToString(lastClosedPositionType)
);

bool LastClosedPositionVolume(
   double &lastClosedPositionVolume, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

直近で決済されたポジションの取引量を提供します。銘柄やマジックナンバーでデータをフィルターするオプションがあります。
// Get the last closed position volume in the account
double lastClosedPositionVolume;
LastClosedPositionVolume(lastClosedPositionVolume);
Print(
   "Account's last closed position volume: ",
   lastClosedPositionVolume
);
//--
// Get the last closed position volume for GBPUSD and magic 0
double lastClosedPositionVolume;
LastClosedPositionVolume(lastClosedPositionVolume, "GBPUSD", 0);
Print(
   "GBPUSD: last closed position volume: ",
   lastClosedPositionVolume
);

bool LastClosedPositionSymbol(
   string &lastClosedPositionSymbol, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

直近で決済されたポジションの銘柄を取得します。銘柄やマジックナンバーで結果をフィルターするオプションがあります。
// Get the last closed position's symbol in the account
string lastClosedPositionSymbol;
LastClosedPositionSymbol(lastClosedPositionSymbol);
Print(
   lastClosedPositionSymbol, " is the last closed position symbol ", 
   "in the account"
);
//--
// Get the last closed position's symbol for magic 0
string lastClosedPositionSymbol;
LastClosedPositionSymbol(lastClosedPositionSymbol, ALL_SYMBOLS, 0);
Print(
   lastClosedPositionSymbol, " is the last closed position symbol ",
   "for magic no: 0."
);

bool LastClosedPositionTicket(
   ulong &lastClosedPositionTicket, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

直近で決済されたポジションのチケット番号を取得します。銘柄やマジックナンバーで結果をフィルターするオプションがあります。
// Get the last closed position's ticket in the account
long lastClosedPositionTicket;
LastClosedPositionTicket(lastClosedPositionTicket);
Print(
   "Account's last closed position's ticket: ",
   lastClosedPositionTicket
);
//--
// Get the last closed position's ticket for EURUSD and magic 0
long lastClosedPositionTicket;
LastClosedPositionTicket(lastClosedPositionTicket, "EURUSD", 0);
Print(
   "EURUSD: last closed position's ticket: ",
   lastClosedPositionTicket
);

bool LastClosedPositionProfit(
   double &lastClosedPositionProfit, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

直近の取引によって生成された粗利益を出力します。銘柄やマジックナンバーでデータをフィルターするオプションがあります。
// Get the last closed position's profit in the account
double lastClosedPositionProfit;
LastClosedPositionProfit(lastClosedPositionProfit);
Print(
   "Account's last closed position's profit: ",
   lastClosedPositionProfit, " ", AccountInfoString(ACCOUNT_CURRENCY)
);
//--
// Get the last closed position's profit for EURUSD and magic 0
//double lastClosedPositionProfit;
LastClosedPositionProfit(lastClosedPositionProfit, "EURUSD", 0);
Print(
   "EURUSD: last closed position's profit: ",
   lastClosedPositionProfit, " ", AccountInfoString(ACCOUNT_CURRENCY)
);

以下は、直近で決済されたたポジションのプロパティを取得する、残りのライブラリ関数です。実装の詳細については、上記のコード例を参照してください。これには、LastClosedPositionVolumeLastClosedPositionTypeなどの関数が含まれます。これらはすべて同様のアプローチに従います。

関数プロトタイプ定義
説明
bool LastClosedPositionNetProfit(
   double &lastClosedPositionNetProfit, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

スワップと手数料を考慮して、直近の取引の純利益を計算します。銘柄やマジックナンバーでデータをフィルターするオプションがあります。
bool LastClosedPositionPipProfit(
   int &lastClosedPositionPipProfit, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

直近で決済されたポジションの利益をpips単位で取得します。データは銘柄やマジックナンバーでフィルターできます。
bool LastClosedPositionClosePrice(
   double &lastClosedPositionClosePrice, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

ポジションの決済価格を取得します。結果は銘柄やマジックナンバーでフィルターできます。
bool LastClosedPositionOpenPrice(
   double &lastClosedPositionOpenPrice, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

ポジションが最初に開かれた価格を取得します。オプションで、結果を銘柄やマジックナンバーでフィルターできます。
bool LastClosedPositionSlPrice(
   double &lastClosedPositionSlPrice, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

直近で決済されたポジションに設定されたストップロス価格を取得します。結果は銘柄やマジックナンバーでフィルターできます。
bool LastClosedPositionTpPrice(
   double &lastClosedPositionTpPrice, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

直近で決済された取引に割り当てられたテイクプロフィット価格を提供します。結果は銘柄やマジックナンバーでフィルターできます。
bool LastClosedPositionSlPips(
   int &lastClosedPositionSlPips, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

直近で決済されたポジションのストップロス距離をpips単位で示します。結果は銘柄やマジックナンバーでフィルターできます。
bool LastClosedPositionTpPips(
   int &lastClosedPositionTpPips, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

直近で決済された取引のテイクプロフィット距離をpips単位で表示します。オプションで、結果を銘柄やマジックナンバーでフィルターできます。
bool LastClosedPositionOpenTime(
   datetime &lastClosedPositionOpenTime, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);


直近で決済されたポジションが開かれたときのタイムスタンプを取得します。結果は銘柄やマジックナンバーでフィルターできます。
bool LastClosedPositionCloseTime(
   datetime &lastClosedPositionCloseTime, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

直近で決済されたポジションが決済されたときのタイムスタンプを取得します。オプションで、結果を銘柄やマジックナンバーでフィルターできます。
bool LastClosedPositionSwap(
   double &lastClosedPositionSwap, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

直近で決済されたポジションに関連付けられたスワップ値を示します。オプションで、結果を銘柄やマジックナンバーでフィルターできます。
bool LastClosedPositionCommission(
   double &lastClosedPositionCommission, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

直近で決済された取引に対して請求された手数料を取得します。結果は銘柄やマジックナンバーでフィルターできます。
bool LastClosedPositionInitiatingOrderType(
   ENUM_ORDER_TYPE &lastClosedPositionInitiatingOrderType, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

直近で決済されたポジションを開始した注文の種類を識別します。オプションで、結果を銘柄やマジックナンバーでフィルターできます。
bool LastClosedPositionId(
   ulong &lastClosedPositionId, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

直近で決済されたポジションの一意の識別子を取得します。symbolとmagicはオプションであり、結果をフィルターする必要がある場合にのみ必要です。
bool LastClosedPositionInitiatedByPendingOrder(
   bool &lastClosedPositionInitiatedByPendingOrder, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);


直近で決済されたポジションが未決注文によってトリガーまたは開始されたかどうかを確認します。オプションで、結果を銘柄やマジックナンバーでフィルターできます。
bool LastClosedPositionOpeningOrderTicket(
   ulong &lastClosedPositionOpeningOrderTicket, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

ポジションを開いた注文のチケット番号を提供します。オプションで、結果を銘柄やマジックナンバーでフィルターできます。
bool LastClosedPositionOpeningDealTicket(
   ulong &lastClosedPositionOpeningDealTicket, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

ポジションを開始した取引のチケット番号を取得します。  結果を銘柄やマジックナンバーでフィルターするオプションがあります。
bool LastClosedPositionClosingDealTicket(
   ulong &lastClosedPositionClosingDealTicket, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

ポジションを決済した取引のチケット番号を取得します。結果を銘柄やマジックナンバーでフィルターするオプションがあります。
bool LastClosedPositionMagic(
   ulong &lastClosedPositionMagic, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

直近で決済されたポジションに関連付けられたマジックナンバーを示します。 結果を銘柄やマジックナンバーでフィルターするオプションがあります。
 
bool LastClosedPositionComment(
   string &lastClosedPositionComment, // [Out]
   string symbol,  // Optional parameter
   ulong magic // Optional parameter
);

直近で決済された取引に添付されたコメントやメモを取得します。  結果を銘柄やマジックナンバーでフィルターするオプションがあります。
 
bool LastClosedPositionDuration(
   long &lastClosedPositionDuration, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

ポジションがオープンのままであった合計期間(秒数)を計算します。 結果を銘柄やマジックナンバーでフィルターするオプションがあります。


5. 直近で決済された勝ち・負けポジションを分析する関数

直近で決済された勝ち・負けポジションのプロパティを取得したい場合、History Managerライブラリにはこの目的に特化した2つの関数が用意されています。これらの関数を使うことで、1回の関数呼び出しで関連するすべての詳細情報に迅速にアクセスでき、直近に決済されたポジションを収益性に基づいて分析できます。このようにして得られる重要なデータは、取引パフォーマンスの評価や戦略の改善に役立ちます。さらに、特定の銘柄マジックナンバーによる絞り込みも可能なため、特定の取引に焦点を当てて、個別の戦略や資産ごとのパフォーマンスをより効果的に評価できます。

関数プロトタイプ定義 説明 使用例
bool GetLastClosedProfitablePositionData(
   PositionData &lastClosedProfitablePositionInfo, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

利益を上げて決済した直近のポジションの詳細とプロパティを取得します。オプションで、結果を銘柄やマジックナンバーでフィルターできます。
// Get the symbol, ticket, and net and pip profit of
// the last closed profitable position
PositionData lastClosedProfitablePosition;
if(
   GetLastClosedProfitablePositionData(lastClosedProfitablePosition) &&
   lastClosedProfitablePosition.ticket > 0
)
  {
   Print("-------------------------------------------------");
   Print(
      lastClosedProfitablePosition.symbol,
      " --> LAST CLOSED PROFITABLE POSITION"
   );
   Print("Ticket = ", lastClosedProfitablePosition.ticket);
   Print(
      "Net Profit = ", lastClosedProfitablePosition.netProfit, " ",
      AccountInfoString(ACCOUNT_CURRENCY)
   );
   Print("Pip Profit = ", lastClosedProfitablePosition.pipProfit);
  }
//--
// Get the ticket, and net and pip profit of
// the last closed profitable position for EURUSD and magic 0
PositionData lastClosedProfitablePosition;
if(
   GetLastClosedProfitablePositionData(
      lastClosedProfitablePosition, "EURUSD", 0
   ) &&
   lastClosedProfitablePosition.ticket > 0
)
  {
   Print("-------------------------------------------------");
   Print("EURUSD --> LAST CLOSED PROFITABLE POSITION");
   Print("Ticket = ", lastClosedProfitablePosition.ticket);
   Print(
      "Net Profit = ", lastClosedProfitablePosition.netProfit, " ",
      AccountInfoString(ACCOUNT_CURRENCY)
   );
   Print("Pip Profit = ", lastClosedProfitablePosition.pipProfit);
  }

bool GetLastClosedLossPositionData(
   PositionData &lastClosedLossPositionData,  // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

決済したか損失となった、直近のポジションの詳細とプロパティを取得します。オプションで、結果を銘柄やマジックナンバーでフィルターできます。
// Get the symbol, ticket, and net and pip profit of
// the last closed loss position
PositionData lastClosedLossPosition;
if(
   GetLastClosedLossPositionData(lastClosedLossPosition) &&
   lastClosedLossPosition.ticket > 0
)
  {
   Print("-------------------------------------------------");
   Print(
      lastClosedLossPosition.symbol,
      " --> LAST CLOSED LOSS POSITION"
   );
   Print("Ticket = ", lastClosedLossPosition.ticket);
   Print(
      "Net Profit = ", lastClosedLossPosition.netProfit, " ",
      AccountInfoString(ACCOUNT_CURRENCY)
   );
   Print("Pip Profit = ", lastClosedLossPosition.pipProfit);
  }
//--
// Get the ticket, and net and pip profit of
// the last closed loss position for GBPUSD and magic 0
PositionData lastClosedLossPosition;
if(
   GetLastClosedLossPositionData(
      lastClosedLossPosition, "GBPUSD", 0
   ) &&
   lastClosedLossPosition.ticket > 0
)
  {
   Print("-------------------------------------------------");
   Print("GBPUSD --> LAST CLOSED LOSS POSITION");
   Print("Ticket = ", lastClosedLossPosition.ticket);
   Print(
      "Net Profit = ", lastClosedLossPosition.netProfit, " ",
      AccountInfoString(ACCOUNT_CURRENCY)
   );
   Print("Pip Profit = ", lastClosedLossPosition.pipProfit);
  }


6. 直近で約定した未決注文とキャンセルされた未決注文を分析する関数

直近で約定またはキャンセルされた保留注文に関する詳細情報を取得するために、History Managerライブラリには専用の関数が用意されています。これらの関数を使用することで、1回の関数呼び出しで関連する注文情報をすべて取得でき、未決注文の実行状況やキャンセル理由の分析が容易になります。これらの関数は、注文処理の評価、実行効率の把握、取引戦略の見直しに役立つ重要なデータを提供します。また、特定の銘柄マジックナンバーによるフィルター機能も備えており、特定の注文に焦点を当てて、過去の正確なデータに基づいたアプローチの最適化が可能です。

直近で約定・キャンセルされた未決注文を処理する関数は、直近で決済されたポジション履歴を処理する関数と同様の方法でインポート・実装されているため、本節では関数プロトタイプと簡単な説明のみにとどめます。これらの関数の実装例が必要な場合は、上記の「直近で決済されたポジションを分析する関数」セクションを参照してください。

直近で約定した保留注文の詳細情報を取得するには、GetLastFilledPendingOrderData関数を使用することで、注文の実行に関するすべての関連プロパティを取得できます。また、特定の属性のみが必要な場合は、以下の専用関数を利用することで、個別の情報を抽出することも可能です。

関数プロトタイプ定義 説明
bool GetLastFilledPendingOrderData(
   PendingOrderData &lastFilledPendingOrderData, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

直近の未決注文に関する詳細をすべて取得し、注文がどのように実行されたかの全体像を示します。
bool LastFilledPendingOrderType(
   ENUM_ORDER_TYPE &lastFilledPendingOrderType, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

注文タイプを取得し、それが買いストップ、売り指値、または別の保留中の注文バリアントであるかどうかを判断するのに役立ちます。
bool LastFilledPendingOrderSymbol(
   string &lastFilledPendingOrderSymbol, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

取引商品を識別し、特定の資産に関連付けられた注文に集中できるようにします。
bool LastFilledPendingOrderTicket(
   ulong &lastFilledPendingOrderTicket, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

特定の実行済み注文の参照や追跡に不可欠な、一意の注文チケットを提供します。
bool LastFilledPendingOrderPriceOpen(
   double &lastFilledPendingOrderPriceOpen, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

注文がトリガーされた価格を取得します。これはエントリー条件を分析するために重要です。
bool LastFilledPendingOrderSlPrice(
   double &lastFilledPendingOrderSlPrice, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);
bool LastFilledPendingOrderTpPrice(
   double &lastFilledPendingOrderTpPrice, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

これらの関数はそれぞれストップロスとテイクプロフィットのレベルを返すので、リスク管理設定を評価できます。
bool LastFilledPendingOrderSlPips(
   int &lastFilledPendingOrderSlPips, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);
bool LastFilledPendingOrderTpPips(
   int &lastFilledPendingOrderTpPips, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

これらの関数は、ストップロスとテイクプロフィットの距離をpips単位で表し、取引のリスクと報酬の比率をより明確に表示します。
bool LastFilledPendingOrderTimeSetup(
   datetime &lastFilledPendingOrderTimeSetup, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);
bool LastFilledPendingOrderTimeDone(
   datetime &lastFilledPendingOrderTimeDone, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

LastFilledPendingOrderTimeSetup関数は注文がいつ出されたかを記録し、LastFilledPendingOrderTimeDone関数は注文が実行された時刻を記録します。これは、未決注文が設定されてからトリガーまたは約定されるまでの期間を分析するのに役立ちます。
bool LastFilledPendingOrderExpirationTime(
   datetime &lastFilledPendingOrderExpirationTime, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

有効期限をチェックして提供します。時間に敏感な取引戦略に役立ちます。
bool LastFilledPendingOrderPositionId(
   ulong &lastFilledPendingOrderPositionId, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

注文を対応するポジションにリンクし、正確な追跡を保証するために重要なポジションIDを取得します。
bool LastFilledPendingOrderMagic(
   ulong &lastFilledPendingOrderMagic, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

マジックナンバーを取得し、自動化戦略または取引ボットに基づいて注文をフィルターできるようにします。
bool LastFilledPendingOrderReason(
   ENUM_ORDER_REASON &lastFilledPendingOrderReason, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

実行の理由をキャプチャし、システムによって開始された注文処理または手動でおこなわれた注文処理に関する洞察を提供します。
bool LastFilledPendingOrderTypeFilling(
   ENUM_ORDER_TYPE_FILLING &lastFilledPendingOrderTypeFilling, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);
bool LastFilledPendingOrderTypeTime(
   datetime &lastFilledPendingOrderTypeTime, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

LastFilledPendingOrderTypeFilling関数とLastFilledPendingOrderTypeTime関数は、それぞれ注文充填方法と時間モデルを定義し、実行分析に役立ちます。
bool LastFilledPendingOrderComment(
   string &lastFilledPendingOrderComment, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

直近で約定された未決注文の関連コメントを取得します。これは、取引のラベル付けや分類に役立ちます。

同様に、直近でキャンセルされた未決注文を調べる必要がある場合は、GetLastCanceledPendingOrderData関数を1回の呼び出しで使用してすべての詳細を取得します。あるいは、次の特殊な関数を使用して個々のプロパティを抽出することもできます。

関数プロトタイプ定義 説明
bool GetLastCanceledPendingOrderData(
   PendingOrderData &lastCanceledPendingOrderData, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

すべてのプロパティと属性を含む、直近でキャンセルされた未決注文の包括的な記録を提供します。
bool LastCanceledPendingOrderType(
   ENUM_ORDER_TYPE &lastCanceledPendingOrderType, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

直近でキャンセルされた未決注文のタイプを取得して指定します。
bool LastCanceledPendingOrderSymbol(
   string &lastCanceledPendingOrderSymbol, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

直近でキャンセルされた未決注文の取引銘柄を取得して識別し、対象を絞った分析を可能にします。
bool LastCanceledPendingOrderTicket(
   ulong &lastCanceledPendingOrderTicket, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

直近でキャンセルされた未決注文の固有のチケット番号を参照用に提供します。
bool LastCanceledPendingOrderPriceOpen(
   double &lastCanceledPendingOrderPriceOpen, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

直近でキャンセルされた未決注文の当初の予定エントリー価格を取得して保存します。
bool LastCanceledPendingOrderSlPrice(
   double &lastCanceledPendingOrderSlPrice, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);
bool LastCanceledPendingOrderTpPrice(
   double &lastCanceledPendingOrderTpPrice, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

LastCanceledPendingOrderSlPrice関数とLastCanceledPendingOrderTpPrice関数は、直近でキャンセルされた未決注文のストップロスとテイクプロフィットの価格レベルを取得します。
bool LastCanceledPendingOrderSlPips(
   int &lastCanceledPendingOrderSlPips, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);
bool LastCanceledPendingOrderTpPips(
   int &lastCanceledPendingOrderTpPips, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

LastCanceledPendingOrderSlPips関数とLastCanceledPendingOrderTpPips関数は、直近でキャンセルされた未決注文のストップロスとテイクプロフィットの距離をpips単位で表します。
bool LastCanceledPendingOrderTimeSetup(
   datetime &lastCanceledPendingOrderTimeSetup, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);
bool LastCanceledPendingOrderTimeDone(
   datetime &lastCanceledPendingOrderTimeDone, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

LastCanceledPendingOrderTimeSetup関数は、直近でキャンセルされた未決注文が出された時刻を提供し、LastCanceledPendingOrderTimeDone関数は、キャンセルによって削除された時刻を記録します。
bool LastCanceledPendingOrderExpirationTime(
   datetime &lastCanceledPendingOrderExpirationTime, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

キャンセルされた未決注文の有効期限が設定された時刻を取得して保存します。
bool LastCanceledPendingOrderMagic(
   ulong &lastCanceledPendingOrderMagic, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

直近でキャンセルされた未決注文のに関連付けられたマジックナンバーを取得して保存し、自動化された戦略識別子に基づいてフィルターできるようにします。
bool LastCanceledPendingOrderReason(
   ENUM_ORDER_REASON &lastCanceledPendingOrderReason, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

直近でキャンセルされた未決注文の注文理由を取得し、どのプラットフォームから注文が開始されたかを識別できるようにします。
bool LastCanceledPendingOrderTypeFilling(
   ENUM_ORDER_TYPE_FILLING &lastCanceledPendingOrderTypeFilling, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);
bool LastCanceledPendingOrderTypeTime(
   datetime &lastCanceledPendingOrderTypeTime, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

LastCanceledPendingOrderTypeFilling関数とLastCanceledPendingOrderTypeTime関数は、直近でキャンセルされた未決注文の執行と時間タイプの設定を取得して保存します。
bool LastCanceledPendingOrderComment(
   string &lastCanceledPendingOrderComment, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

追跡目的で、直近でキャンセルされた未決注文を開いたときに保存されたユーザー定義のコメントを取得します。


7. ユーティリティ関数
関数プロトタイプ定義 説明
string BoolToString(bool boolVariable);

ブール値を文字列(TRUEまたはFALSE)に変換することで、可読性やログ出力のしやすさを向上させます。
 
datetime GetPeriodStart(int periodType);

入力されたタイプに応じて、年、月、週(日曜日から始まる)、日で開始時刻を表すdatetime値を返します。ヘッダーファイルから定義済みのマクロTODAYTHIS_WEEKTHIS_MONTHTHIS_YEAR)を入力として受け入れます。これらの期間の日時値を取得するプロセスを簡素化し、1行のコードで実行できるようにします。

次のセクションでは、History Managementライブラリを活用して有益な取引分析を生成する実践的な例を紹介します。さらに、この履歴ライブラリを活用して、新規取引の実行に最適なロット数やポジションの方向を判断するEAを開発します。これにより、過去の取引データを自動売買システムに効果的に組み込む方法を示し、戦略の実行力と意思決定の質を向上させる手法を明らかにします。


EAや銘柄のプロフィットファクター、総損益、および1回の取引あたりの平均利益・平均損失を算出する方法

MetaTrader5でEAや取引戦略のパフォーマンスを評価する際、最も重要な指標の一つがプロフィットファクターです。プロフィットファクターは、一定期間における粗利益と粗損失の比率を表しており、戦略の収益性を把握するのに非常に有効です。

この値が高いほど、戦略が損失よりも多くの利益を生み出していることを意味し、健全な取引システムと見なされます。逆に、プロフィットファクターが低い場合は、戦略の有効性が乏しい可能性があり、最適化や改善の必要があることを示唆します。

プロフィットファクターは、以下の式で計算されます。
Profit Factor = Gross Loss / Gross Profit​

ここで

  • Gross Profit(粗利益)は、利益が出たすべての取引から得られた合計金額を指します。
  • Gross Loss(粗損失)は、損失となったすべての取引から失われた合計金額です。

プロフィットファクターが1より大きい場合、粗利益が粗損失を上回っているため、その戦略は利益を生み出していることを意味します。プロフィットファクターが1の場合は、粗利益と粗損失が同じであり、損益分岐点にある状態を示します。プロフィットファクターが1未満であれば、粗損失が粗利益を上回っているため、戦略は損失を出していることになります。

このプロフィットファクターの理解と計算は、トレーダーや開発者が取引戦略の有効性やパフォーマンスを正しく評価し、適切な意思決定をおこなううえで非常に重要です。

この例では、HistoryManager.ex5ライブラリを活用し、MQL5コード内でこの計算をいかに簡単に実装できるかを示します。

まず、新しいEAを作成し、ファイル名をGetProfitFactor.mq5とします。フォルダパス「Experts\Wanateki\HistoryManager\GetProfitFactor.mq5」に保存します。なお、この保存先フォルダはヘッダーファイル(ライブラリ関数プロトタイプ定義)をインクルードする際のパス指定に影響するため重要です。

GetProfitFactor.mq5 EAは、粗利益・粗損失・プロフィットファクターといった重要指標を計算し、取引戦略のパフォーマンス分析を支援します。

最初に、HistoryManager.ex5ライブラリをインクルードし、解析対象の銘柄名を指定するための列挙型を定義します。このsymbolName列挙型により、現在のチャートの銘柄か、口座内のすべての銘柄かを選択できるようになります。さらに、マジックナンバーの入力と組み合わせることで、特定の銘柄やEAに絞ったフィルターが可能になります。

#include <Wanateki/Toolkit/HistoryManager/HistoryManager.mqh>
//--
enum symbolName
  {
   CURRENT_CHART_SYMBOL,
   ALL_ACCOUNT_SYMBOLS,
  };

次に、EAユーザーが出力をフィルターするために使用する入力パラメータを定義します。

//--- input parameters
input ulong  magicNo = 0;          //Magic Number (0 to disable)
input symbolName getSymbolName = ALL_ACCOUNT_SYMBOLS;

計算結果を保存し、結果を表示するために使用する変数を初期化します。

string currency = " " + AccountInfoString(ACCOUNT_CURRENCY);
double totalGrossProfit = 0.0, totalGrossLoss = 0.0,
       averageGrossProfit = 0.0, averageGrossLoss = 0.0,
       averageProfitOrLossPerTrade = 0.0,
       profitFactor = 0.0;
int totalTrades = 0,
    totalLossPositions = 0, totalProfitPositions = 0;
string symbol, printedSymbol, profitFactorSummery,
       commentString;

OnInit関数では、switch文を使用して、分析する銘柄を決定します。銘柄が識別されたら、プロフィットファクターを計算するCalcProfitFactor関数を呼び出します。EAが読み込まれたときの最初のタスクとして、Comment関数を使用してすべての結果をチャートに表示します。

int OnInit()
  {
//---
   switch(getSymbolName)
     {
      case CURRENT_CHART_SYMBOL:
         symbol = _Symbol;
         break;
      case ALL_ACCOUNT_SYMBOLS:
         symbol = ALL_SYMBOLS;
         break;
      default:
         symbol = ALL_SYMBOLS;
     }
   printedSymbol = symbol;
   if(symbol == "")
      printedSymbol = "ALL_SYMBOLS";
//--
   CalcProfitFactor();
   Comment(commentString);
//---
   return(INIT_SUCCEEDED);
  }

先に進む前に、CalcProfitFactor関数を実装しておきましょう。この関数には、GetProfitFactor EAの主要なロジックが集約されています。 

まずはCalcProfitFactor関数のシグネチャ(関数定義)を記述し、その後すべての変数を初期値にリセットします。これは、以前の計算結果が現在の分析に影響を及ぼさないようにするためです。

   totalGrossProfit = 0.0;
   totalGrossLoss = 0.0;
   averageProfitOrLossPerTrade = 0.0;
   averageGrossProfit = 0.0;
   averageGrossLoss = 0.0;
   profitFactor = 0.0;
   totalTrades = 0;
   totalLossPositions = 0;
   totalProfitPositions = 0;

次に、GetAllPositionsData関数を使用して過去の取引データを取得します。この関数は、指定された銘柄マジックナンバーに基づいて、すべての取引ポジション情報をpositionsData配列に格納します。また、取得に成功したかどうかを確認するために、この関数の戻り値がtrueであること、そして配列のサイズが0を超えていることをチェックします。これは、計算に必要な取引情報が有効であることを確認するために不可欠なステップです。

if(GetAllPositionsData(positionsData, symbol, magicNo) && ArraySize(positionsData) > 0)
     {
      //--
     }

次に、positionsData配列内の各取引をループして、総損益を計算します。各取引に対して、利益が0を超えているかを確認し、利益がある場合はその取引を「利益のある取引」と判断します。その場合、totalProfitPositionsカウンタをインクリメントし、利益額をtotalGrossProfitに加算します。一方、利益がゼロ以下の場合は「損失のある取引」と判断し、totalLossPositionsカウンタをインクリメントして、損失額の絶対値をtotalGrossLossに加算します。このループ処理により、すべての取引から得られた粗利益と粗損失を集計することができます。

      totalTrades = ArraySize(positionsData);
      for(int r = 0; r < totalTrades; r++)
        {
         if(positionsData[r].profit > 0) // profitable trade
           {
            ++totalProfitPositions;
            totalGrossProfit += positionsData[r].profit;
           }
         else  // loss trade
           {
            ++totalLossPositions;
            totalGrossLoss += MathAbs(positionsData[r].profit);
           }
        }
      // Calculate the profit factor and other data
      if(totalGrossProfit > 0 || totalGrossLoss > 0)
         averageProfitOrLossPerTrade = NormalizeDouble(
                                          (totalGrossProfit + totalGrossLoss) / totalTrades, 2
                                       );
      if(totalGrossProfit > 0)
         averageGrossProfit = NormalizeDouble(
                                 (totalGrossProfit / totalProfitPositions), 2
                              );
      if(totalGrossLoss > 0)
         averageGrossLoss = NormalizeDouble(
                               (totalGrossLoss / totalLossPositions), 2
                            );
      //--
      if(totalGrossLoss == 0.0)
         profitFactor = 0.0; // Avoid division by zero, indicating no losses
      profitFactor = totalGrossProfit / totalGrossLoss;
     }

総損益を集計した後、次に各種パフォーマンス指標を計算します。まず、平均損益(1取引あたりの損益)を、総損益の合計を全取引数で割ることで求めます。次に、平均粗利益は、利益が出た取引の数で粗利益を割って算出します。同様に、平均粗損失は、総損益の合計を損失が出た取引の数で割って求めます。最後に、粗利益を粗損失で割ってプロフィットファクターを計算します。これらの指標を通じて、取引戦略の全体的なパフォーマンスを多角的に評価することができます。

   profitFactorSummery = "Profit Factor = " + DoubleToString(profitFactor, 2);
   if(profitFactor > 2.0)
     {
      profitFactorSummery = profitFactorSummery +
                            "\nThe trading strategy is HIGHLY PROFITABLE and efficient.";
     }
   else
      if(profitFactor > 1.5)
        {
         profitFactorSummery = profitFactorSummery +
                               "\nThe trading strategy is profitable and well-balanced.";
        }
      else
         if(profitFactor > 1.0)
           {
            profitFactorSummery = profitFactorSummery +
                                  "\nThe trading strategy is slightly profitable but may need improvement.";
           }
         else
            if(profitFactor == 1.0)
              {
               profitFactorSummery = profitFactorSummery +
                                     "\nThe strategy is break-even with no net gain or loss.";
              }
            else
              {
               profitFactorSummery = profitFactorSummery +
                                     "\nThe trading strategy is unprofitable and needs optimization.";
              }

プロフィットファクターを分析することで、取引戦略のパフォーマンスを総括した文字列(サマリー)を生成します。以下は、プロフィットファクターの数値に基づいた解釈です。

  • プロフィットファクター > 2.0:戦略は非常に収益性が高く、効率的です。
  • プロフィットファクターが 1.0 ~ 1.5 の間:わずかに利益が出ていますが、さらなる改善の余地があります。
  • プロフィットファクター = 1.0:損益がちょうど均衡しており、収支はゼロの状態です。
  • プロフィットファクター < 1.0:損失が利益を上回っており、戦略の見直しや最適化が必要です。

この分析により、戦略の全体的な有効性をすばやく把握できます。

最後に、すべての算出済み指標とサマリーを含んだ詳細なコメント文字列を生成します。この文字列は、分析対象の銘柄マジックナンバー、総取引数、利益が出た取引数と損失が出た取引数、総損益、1取引あたりの平均損益、平均総損益、さらにプロフィットファクターの評価サマリーが含まれています。

以下に、すべてのコードセグメントを含む完全なCalcProfitFactor関数を示します。

void CalcProfitFactor()
  {
   totalGrossProfit = 0.0;
   totalGrossLoss = 0.0;
   averageProfitOrLossPerTrade = 0.0;
   averageGrossProfit = 0.0;
   averageGrossLoss = 0.0;
   profitFactor = 0.0;
   totalTrades = 0;
   totalLossPositions = 0;
   totalProfitPositions = 0;
//--
   PositionData positionsData[];
   if(GetAllPositionsData(positionsData, symbol, magicNo) && ArraySize(positionsData) > 0)
     {
      totalTrades = ArraySize(positionsData);
      for(int r = 0; r < totalTrades; r++)
        {
         if(positionsData[r].profit > 0) // profitable trade
           {
            ++totalProfitPositions;
            totalGrossProfit += positionsData[r].profit;
           }
         else  // loss trade
           {
            ++totalLossPositions;
            totalGrossLoss += MathAbs(positionsData[r].profit);
           }
        }
      // Calculate the profit factor and other data
      if(totalGrossProfit > 0 || totalGrossLoss > 0)
         averageProfitOrLossPerTrade = NormalizeDouble(
                                          (totalGrossProfit + totalGrossLoss) / totalTrades, 2
                                       );
      if(totalGrossProfit > 0)
         averageGrossProfit = NormalizeDouble(
                                 (totalGrossProfit / totalProfitPositions), 2
                              );
      if(totalGrossLoss > 0)
         averageGrossLoss = NormalizeDouble(
                               (totalGrossLoss / totalLossPositions), 2
                            );
      //--
      if(totalGrossLoss == 0.0)
         profitFactor = 0.0; // Avoid division by zero, indicating no losses
      profitFactor = totalGrossProfit / totalGrossLoss;
     }

// Analyze the Profit Factor result
   profitFactorSummery = "Profit Factor = " + DoubleToString(profitFactor, 2);
   if(profitFactor > 2.0)
     {
      profitFactorSummery = profitFactorSummery +
                            "\nThe trading strategy is HIGHLY PROFITABLE and efficient.";
     }
   else
      if(profitFactor > 1.5)
        {
         profitFactorSummery = profitFactorSummery +
                               "\nThe trading strategy is profitable and well-balanced.";
        }
      else
         if(profitFactor > 1.0)
           {
            profitFactorSummery = profitFactorSummery +
                                  "\nThe trading strategy is slightly profitable but may need improvement.";
           }
         else
            if(profitFactor == 1.0)
              {
               profitFactorSummery = profitFactorSummery +
                                     "\nThe strategy is break-even with no net gain or loss.";
              }
            else
              {
               profitFactorSummery = profitFactorSummery +
                                     "\nThe trading strategy is unprofitable and needs optimization.";
              }

   commentString =
      "\n\n-----------------------------------------------------------------------------------------------------" +
      "\n  HistoryManager.ex5 --- PROFIT FACTOR ANALYTICS ---" +
      "\n-----------------------------------------------------------------------------------------------------" +
      "\n   -> Symbol   = " + printedSymbol +
      "\n   -> Magic No = " + IntegerToString(magicNo) +
      "\n-----------------------------------------------------------------------------------------------------" +
      "\n-----------------------------------------------------------------------------------------------------" +
      "\n" + profitFactorSummery +
      "\n-----------------------------------------------------------------------------------------------------" +
      "\n-----------------------------------------------------------------------------------------------------" +
      "\n   -> Total Trades Analysed   = " + IntegerToString(totalTrades) +
      "\n   -> Total Profitable Trades = " + IntegerToString(totalProfitPositions) +
      "\n   -> Total Loss Trades       = " + IntegerToString(totalLossPositions) +
      "\n   --------------------------------------------------------" +
      "\n   -> Total Gross Profit = " + DoubleToString(totalGrossProfit, 2) + currency +
      "\n   -> Total Gross Loss   = -" + DoubleToString(totalGrossLoss, 2) + currency +
      "\n   ----------------------------------" +
      "\n   -> Total Gross (Profit - Loss) = " + DoubleToString(totalGrossProfit - totalGrossLoss, 2) + currency +
      "\n   --------------------------------------------------------" +
      "\n   -> Average Profit or Loss Per Trade = (-/+)" + DoubleToString(averageProfitOrLossPerTrade, 2) + currency +
      "\n   --------------------------------------------------------" +
      "\n   -> Average Gross Profit = " + DoubleToString(averageGrossProfit, 2) + currency +
      "\n   -> Average Gross Loss   = -" + DoubleToString(averageGrossLoss, 2) + currency +
      "\n   --------------------------------------------------------" +
      "\n-----------------------------------------------------------------------------------------------------";
//--
  }

また、この関数は標準関数のOnTrade関数内に配置することで、すべての取引操作のたびに実行され、プロフィットファクターが再計算されるようにします。

void OnTrade()
  {
//---
   CalcProfitFactor();
  }

最新のデータがチャート上に表示されるようにするために、OnTick標準関数内で毎回新しいティックが到来するたびに、更新されたプロフィットファクターに関するすべての情報を保持するcommentStringComment関数を使って表示します。

void OnTick()
  {
//---
   Comment(commentString);
  }

以下は、MetaTrader5のチャートウィンドウに表示されたGetProfitFactor EAの出力結果です。

HistoryManager.ex5を活用したGetProfitFactor EA

便宜上、GetProfitFactor.mq5ソースファイルをこの記事の最後に添付します。



特定のEAまたは銘柄における当週の粗利益および純利益の計算方法

本例では、今週の財務実績(粗利益、スワップ、手数料、純利益)を包括的に把握できるMQL5スクリプトを作成します。これにより、History Managerライブラリを活用して、MetaTrader 5ターミナル内で口座全体、特定の銘柄、またはEAのマジックナンバー単位で週次のパフォーマンスを素早く評価する方法を示します。

まず、新しいスクリプト「GetNetProfitThisWeek.mq5」を作成し、フォルダ「Scripts\Wanateki\HistoryManager\GetNetProfitThisWeek.mq5」に保存します。スクリプトの先頭では、まずHistoryManager.mqhライブラリをインクルードして、すべてのライブラリ関数を利用可能にします。

#include <Wanateki/Toolkit/HistoryManager/HistoryManager.mqh>

次に、コード全体をOnStart関数内にまとめて、シンプルかつ明確にします。スクリプトの最初の部分では、口座の通貨を格納するための文字列変数を初期化します。これは、財務指標の出力フォーマットに使用します。

string currency = " " + AccountInfoString(ACCOUNT_CURRENCY);

計算を始める前に、まず現在の週開始時刻を取得する必要があります。これはHistoryManager.ex5ライブラリに含まれるユーティリティ関数GetPeriodStart関数を使うことで簡単におこなえます。現在の週の開始日時(datetime型の値)を取得するには、GetPeriodStart関数にTHIS_WEEKTHIS_WEEKパラメータを渡して呼び出すだけです。この日時を使って、今週発生した取引のみをフィルターできます。

datetime thisWeekStartTime = GetPeriodStart(THIS_WEEK);

まず、取引データを格納する配列を宣言し、GetDealsData関数を使って、現在の週の開始時刻から現在時刻(NOW)までの期間に発生した取引データで配列を埋めます。なお、銘柄はすべて、マジックナンバーは0でフィルターしています。

if(
      GetDealsData(
         dealsData,
         thisWeekStartTime, NOW,
         ALL_SYMBOLS, 0
      ) &&
      ArraySize(dealsData) > 0
   )

粗利益、スワップ合計、手数料合計を保存するための変数を初期化します。これらの変数は、取引データからそれぞれの値を累積するために使われます。

double totalGrossProfit = 0.0,
             totalSwap = 0.0,
             totalCommission = 0.0;

dealsData配列内の各取引をループ処理します。各取引について、それが決済取引(DEAL_ENTRY_OUT)かどうかを確認します。もしそうであれば、利益スワップ手数料をそれぞれの合計変数に加算します。

int totalDeals = ArraySize(dealsData);
for(int k = 0; k < totalDeals; k++)
  {
   if(dealsData[k].entry == DEAL_ENTRY_OUT)
     {
      totalGrossProfit += dealsData[k].profit;
      totalSwap += dealsData[k].swap;
      totalCommission += dealsData[k].commission;
     }
  }

スワップ手数料を合計して、総経費を計算します。さらに、総経費粗利益から差し引いて、総純利益の合計を計算します。

double totalExpenses = totalSwap + totalCommission;
double totalNetProfit = totalGrossProfit - MathAbs(totalExpenses);

Print関数を使用して、結果をMetaTrader 5ログに出力します。これには、今週の粗利益、総スワップ、総手数料、純利益の合計が含まれます。さらに、Comment関数を使って、これらの結果をチャートウィンドウに直接表示します。これにより、今週の財務指標の詳細な概要が示されます。

HistoryManager.ex5-今週の純利益合計を取得

こちらが、すべてのコード部分を正しい順序でまとめた、OnStart関数の全体コードです。

void OnStart()
  {
//---
   string currency = " " + AccountInfoString(ACCOUNT_CURRENCY);
   datetime thisWeekStartTime = GetPeriodStart(THIS_WEEK);
   DealData dealsData[];
   if(
      GetDealsData(
         dealsData,
         thisWeekStartTime, NOW,
         ALL_SYMBOLS, 0
      ) &&
      ArraySize(dealsData) > 0
   )
     {
      double totalGrossProfit = 0.0,
             totalSwap = 0.0,
             totalCommission = 0.0;
      int totalDeals = ArraySize(dealsData);
      for(int k = 0; k < totalDeals; k++)
        {
         if(dealsData[k].entry == DEAL_ENTRY_OUT)
           {
            totalGrossProfit += dealsData[k].profit;
            totalSwap += dealsData[k].swap;
            totalCommission += dealsData[k].commission;
           }
        }
      double totalExpenses = totalSwap + totalCommission;
      double totalNetProfit = totalGrossProfit - MathAbs(totalExpenses);

      Print("-------------------------------------------------");
      Print(
         "Account No: ", AccountInfoInteger(ACCOUNT_LOGIN),
         " [ THIS WEEK'S NET PROFIT ]"
      );
      Print(
         "Total Gross Profit This Week: ",
         DoubleToString(totalGrossProfit, 2),
         " ", currency
      );
      Print(
         "Total Swaps This Week: ", DoubleToString(totalSwap, 2),
         " ", currency
      );
      Print(
         "Total Commission This Week: ", DoubleToString(totalCommission, 2),
         " ", currency
      );
      Print(
         "Total Net Profit This Week: ",
         DoubleToString(totalNetProfit, 2), " ",
         currency
      );
      
     //--
     Comment(
         "\n\n-----------------------------------------------------------------------------------------------------" +
         "-------------------------------------------------------------------" +
         "\n  HistoryManager.ex5 --- TOTAL NET PROFIT THIS WEEK ---" +
         "\n-----------------------------------------------------------------------------------------------------" +
         "------------------------------------------------------" +
         "\n DATE = ( From: " + TimeToString(thisWeekStartTime) + ", to: " + TimeToString(NOW) + " )" +
         "\n Account No  = " + IntegerToString(AccountInfoInteger(ACCOUNT_LOGIN)) +
         "\n------------------------------------------------------" +
         "\n   -> Total Gross Profit =  " + DoubleToString(totalGrossProfit, 2) +
         currency +
         "\n   -> Total Swaps        =  " + DoubleToString(totalSwap, 2) +
         currency +
         "\n   -> Total Commission   =  " + DoubleToString(totalCommission, 2) +
         currency +
         "\n-----------------------------------------------------------------------------------------------------" +
         "------------------------------------------------------" +
         "\n   -> TOTAL NET PROFIT   =  " + DoubleToString(totalNetProfit, 2) +
         currency +
         "\n-----------------------------------------------------------------------------------------------------" +
         "------------------------------------------------------" +         
         "\n-----------------------------------------------------------------------------------------------------" +
         "-------------------------------------------------------------------"
      );
     }
  }

完全なスクリプトソースコードについては、この記事の最後に添付されているGetNetProfitThisWeek.mq5ソースファイルをダウンロードしてください。


特定の銘柄またはEAの利益対損失比率(pips換算)の計算方法

この例では、MQL5を使って特定の取引未絵柄やEA全体の利益対損失比率(pips換算)を計算する方法を解説します。この計算は、取引戦略のパフォーマンスを評価するうえで重要な指標であり、得られたpipsベースの損益を比較することで、戦略が利益を出しているのか、損益が均衡しているのか、それとも損失が多いのかを明確に示します。提供されるコードは過去の取引データを分析し、比率を算出して、ユーザーが理解しやすい形式で結果を表示するように設計されています。

EAにGetSymbolPipsProfitToLossRatio.mq5という名前を付け、適切なフォルダに保存します。まずソースファイルの最初の行でHistoryManager.mqhライブラリをインクルードします。次に、銘柄名を格納する列挙型を作成し、銘柄マジックナンバーを入力パラメータとして定義します。これにより、ユーザーは特定の銘柄のすべての決済ポジション、特定銘柄かつ特定マジックナンバーの決済ポジション、または銘柄に関わらず特定のマジックナンバーのすべてのポジションのいずれかを選択してデータをフィルターできます。

OnInit関数で、口座通貨を取得し、ユーザーの選択に基づいて解析対象の銘柄を決定します。CURRENT_CHART_SYMBOLを選択した場合は現在のチャート銘柄を対象にし、ALL_ACCOUNT_SYMBOLSを選択した場合は口座で取引されているすべての銘柄を解析します。

GetAllPositionsData関数を使って、指定された銘柄とマジックナンバーに該当する過去の取引データを取得し、PositionData構造体の配列に格納します。その後、配列をループし、取引を利益のあるものと損失のあるものに分類します。この処理中に、利益のある取引で得たpipsの合計(totalPipsProfit)と損失のある取引で失ったpipsの合計(totalPipsLoss)を計算します。

pips利益対損失比率は、得たpipsの合計を失ったpipsの合計で割ることで計算します。比率は常に正の値となるように絶対値を使用します。負けトレードがない場合(totalPipsLoss==0)は比率は定義できず、その旨を示すメッセージを表示します。EAは比率を次のように解釈します。

  • 比率 > 1.0:この戦略は利益が出ており、失うpipsよりも多くのpipsを獲得しています。
  • 比率 == 1.0:この戦略はpipsの面で損益が均衡しています。
  • 比率 < 1.0:この戦略は損失が多く、獲得pipsよりも多くのpipsを失っています。

最後にComment関数を使って、解析結果をチャート上に直接表示します。表示内容は、解析対象の銘柄や使用したマジックナンバー(あれば)、解析した取引の総数、利益のあった取引数と損失のあった取引数、得たpips合計と失ったpips合計、計算されたpipsの利益対損失比率とその解釈を含みます。

HistoryManager.ex5 Pips Profit to Loss Ratio EA

OnDeinit関数では、EAが削除または終了されたときにチャート上のコメントをクリアして、作業スペースをきれいに保つシンプルなクリーンアップ処理をおこないます。OnTick関数は空のままにしておきます。解析は初期化時に一度だけ実行されるためです。ただし、必要に応じてリアルタイム計算や更新をおこなうためにこの関数を拡張することも可能です。

以下に、すべてのコードセグメントを正しい順序で示します。

//--
#include <Wanateki/Toolkit/HistoryManager/HistoryManager.mqh>
//--
enum symbolName
  {
   CURRENT_CHART_SYMBOL,
   ALL_ACCOUNT_SYMBOLS,
  };
//--- input parameters
input ulong  magicNo = 0;          //Magic Number (0 to disable)
input symbolName getSymbolName = CURRENT_CHART_SYMBOL;
int OnInit()
  {
//---
   string currency = " " + AccountInfoString(ACCOUNT_CURRENCY);
   string symbol, printedSymbol;

   switch(getSymbolName)
     {
      case CURRENT_CHART_SYMBOL:
         symbol = _Symbol;
         break;
      case ALL_ACCOUNT_SYMBOLS:
         symbol = ALL_SYMBOLS;
         break;
      default:
         symbol = ALL_SYMBOLS;
     }
   printedSymbol = symbol;
   if(symbol == "")
      printedSymbol = "ALL_SYMBOLS";
//--
   int totalTrades = 0;
   int totalLossPositions = 0;
   int totalProfitPositions = 0;
   double totalPipsProfit = 0;
   double totalPipsLoss = 0;
   string interpretation;
   double pipsProfitToLossRatio = 0;
//--
   PositionData positionsData[];
   if(GetAllPositionsData(positionsData, symbol, magicNo) && ArraySize(positionsData) > 0)
     {
      totalTrades = ArraySize(positionsData);
      for(int r = 0; r < totalTrades; r++)
        {
         if(positionsData[r].profit > 0) // profitable trade
           {
            ++totalProfitPositions;
            totalPipsProfit += positionsData[r].pipProfit;
           }
         else  // loss trade
           {
            ++totalLossPositions;
            totalPipsLoss += positionsData[r].pipProfit;
           }
        }
      // Calculate the pip profit loss ratioInterpretation
      if(totalPipsLoss == 0)
        {
         interpretation = "Pips Profit-to-Loss Ratio: Undefined (Total pips loss is zero)." +
                          "The strategy has no losing trades.";
        }
      else
        {
         pipsProfitToLossRatio = fabs(totalPipsProfit / totalPipsLoss);

         switch(pipsProfitToLossRatio > 1.0 ? 1 : pipsProfitToLossRatio == 1.0 ? 0 : -1)
           {
            case 1:
               interpretation = "Pips Profit-to-Loss Ratio: " + DoubleToString(pipsProfitToLossRatio, 2) +
                                ". The strategy is profitable as it gains more pips than it loses.";
               break;
            case 0:
               interpretation = "Pips Profit-to-Loss Ratio: " + DoubleToString(pipsProfitToLossRatio, 2) +
                                ". The strategy breaks even in terms of pips.";
               break;
            case -1:
               interpretation = "Pips Profit-to-Loss Ratio: " + DoubleToString(pipsProfitToLossRatio, 2) +
                                ". The strategy is unprofitable as it loses more pips than it gains.";
               break;
           }
        }

      Comment(
         "\n\n-----------------------------------------------------------------------------------------------------" +
         "---------------------------" +
         "\n  HistoryManager.ex5 --- PIPS PROFIT TO LOSS RATIO ---" +
         "\n-----------------------------------------------------------------------------------------------------" +
         "---------------------------" +
         "\n   -> Symbol   = " + printedSymbol +
         "\n   -> Magic No = " + IntegerToString(magicNo) +
         "\n-----------------------------------------------------------------------------------------------------" +
         "---------------------------" +
         "\n-----------------------------------------------------------------------------------------------------" +
         "---------------------------" +
         "\n" + interpretation +
         "\n-----------------------------------------------------------------------------------------------------" +
         "---------------------------" +
         "\n-----------------------------------------------------------------------------------------------------" +
         "---------------------------" +
         "\n   -> Total Trades Analysed     = " + IntegerToString(totalTrades) +
         "\n   -> Total Profitable Trades   = " + IntegerToString(totalProfitPositions) +
         " ( " + DoubleToString(totalPipsProfit, 0) + " Pips )" +
         "\n   -> Total Loss Trades         = " + IntegerToString(totalLossPositions) +
         " ( " + DoubleToString(totalPipsLoss, 0) + " Pips )" +
         "\n   --------------------------------------------------------------------------" +
         "\n   -> PIPS PROFIT TO LOSS RATIO = " + DoubleToString(pipsProfitToLossRatio, 2) +
         "\n   --------------------------------------------------------------------------" +
         "\n-----------------------------------------------------------------------------------------------------" +
         "---------------------------"
      );
     }

//---
   return(INIT_SUCCEEDED);
  }

完全なGetSymbolPipsProfitToLossRatio.mq5ソースファイルは、この記事の下部からダウンロードできます。


口座への入金総額を取得する方法

このセクションでは、GetTotalDeposits.mq5という名前のシンプルなMQL5スクリプトを作成します。このスクリプトは、ライブラリ内のGetAllDealsData関数を活用して、取引履歴データを取得・分析し、口座への資金入金履歴を明確に把握するための手助けをします。アルゴリズム上で口座への入金総額を追跡したいとき、記録管理や税務目的で資金履歴を監査したいとき、あるいは単純に入金取引の正確性を確認したいときに役立つ便利なツールです。

まず、GetAllDealsData関数を使用して口座のすべての過去の取引データを取得します。このデータはDealData構造体の配列に保存されます。次に、合計入金額を格納するための変数を初期化し、配列内の各取引をループ処理します。各取引のタイプDEAL_TYPE_BALANCEであるかどうかを確認することで入金取引を判別し、該当する取引の利益値を加算して合計入金額を算出します。

必要なデータをすべて計算して保存した後は、ターミナルに入金総額を出力し、Comment関数を使用してチャート上にも表示します。これにより、口座の入金履歴がユーザーにとって分かりやすく表示されます。

#include <Wanateki/Toolkit/HistoryManager/HistoryManager.mqh>
void OnStart()
  {
//---
// Find and list total deposited funds in the account
   DealData dealsData[];
   if(GetAllDealsData(dealsData) && ArraySize(dealsData) > 0)
     {
      double totalDeposits = 0.0;
      int totalDeals = ArraySize(dealsData);
      Print("");
      for(int k = 0; k < totalDeals; k++)
        {
         if(dealsData[k].type == DEAL_TYPE_BALANCE)
           {
            totalDeposits += dealsData[k].profit;
            Print(
               dealsData[k].profit, " ", AccountInfoString(ACCOUNT_CURRENCY),
               " --> Cash deposit on: ", dealsData[k].time
            );
           }
        }
      Print("-------------------------------------------------");
      Print(
         "Account No: ", AccountInfoInteger(ACCOUNT_LOGIN),
         " Total Cash Deposits: ", totalDeposits, " ",
         AccountInfoString(ACCOUNT_CURRENCY)
      );

      Comment(
         "\n\n-----------------------------------------------------------------------------------------------------" +
         "---------------------------------------------------------" +
         "\n  HistoryManager.ex5 --- TOTAL ACCOUNT DEPOSITS ---" +
         "\n-----------------------------------------------------------------------------------------------------" +
         "------------------------------------------------------" +
         "\n   -> Account No  = " + IntegerToString(AccountInfoInteger(ACCOUNT_LOGIN)) +
         "\n   -> Total Cash Deposits =  " + DoubleToString(totalDeposits, 2) +
         AccountInfoString(ACCOUNT_CURRENCY) +
         "\n-----------------------------------------------------------------------------------------------------" +
         "------------------------------------------------------"
      );
     }
  }

完全なGetTotalDeposits.mq5ソースファイルはこの記事の下部からダウンロードできます。


History Manager EX5ライブラリを活用した価格データ駆動型EAの作成方法

この記事の最後の例として、PriceTrader_EAというシンプルながら強力な価格データ駆動型のEAを作成します。このEAは、PositionsManager.ex5HistoryManager.ex5の2つのライブラリによって動作します。十分なバックテストと最適化をおこなった上で大口の口座で運用すれば、大きな利益を生み出す可能性を秘めています。PriceTrader_EAのソースコードは非常に簡潔かつ効率的です。これは、あらかじめ開発済みのPositionsManager.ex5HistoryManager.ex5ライブラリを活用しているためであり、コード量を最小限に抑えつつ、信頼性と一貫性を確保しています。

PriceTrader_EAは、価格データと過去のトレード実績に基づいて売買判断をおこないます。主な特徴は以下のとおりです。

  • 動的ロットサイズ設定:過去の取引結果に基づきロットサイズを調整し、負けトレードの後にはロットサイズを倍にして損失を回収しようとします(あらかじめ定義された上限内で動作します)。
  • 価格アクションに基づく取引方向H1(1時間枠)でのプライスアクションに基づいて、現在のトレンド方向に沿った取引を実行します。
  • リスク管理:ストップロス(SL)とテイクプロフィット(TP)の水準は、現在のスプレッドに基づいて動的に計算され、市場状況の変化に柔軟に対応します。

ソースコードのヘッダー部分では、まずHistoryManager.mqhおよびPositionsManager.mqhのライブラリヘッダーファイルをインクルードするところから始めます。

#include <Wanateki/Toolkit/HistoryManager/HistoryManager.mqh>
#include <Wanateki/Toolkit/PositionsManager/PositionsManager.mqh>

次に、PriceTrader_EA入力パラメータを定義します。これらのパラメータを使用して、マジックナンバー、TPSLスプレッド乗数、および最大ロットサイズの増加を設定できます。

input ulong magicNo = 101010;
input int tpSpreadMulti = 70;
input int slSpreadMulti = 90;
input int maxLotIncrease = 1000;

現在のスプレッド、ロットサイズ、オープンポジションの数などの情報を格納するための主要な変数を初期化します。これらの変数は、EAのロジック全体で使用されます。

bool eaJustLoaded = true;
double spread;
int spreadPips;
long minSLTP = SymbolInfoInteger(Symbol(), SYMBOL_TRADE_STOPS_LEVEL);
long freezeLevel = SymbolInfoInteger(Symbol(), SYMBOL_TRADE_FREEZE_LEVEL);
double lotSize;
int sl, tp;
int totalOpenPositions, totalBuyPositionsOpen, totalSellPositionsOpen;
//--
PositionData lastClosedPositionInfo;

OnInit関数では、現在のスプレッドを計算し、スプレッド乗数に基づいてTPレベルとSLレベルを初期化します。PriceTrader_EAが正常に読み込まれたことを示すサウンドも再生します。

int OnInit()
  {
//---
   spread = SymbolInfoDouble(_Symbol, SYMBOL_ASK) - SymbolInfoDouble(_Symbol, SYMBOL_BID);
   spread = NormalizeDouble(spread, _Digits);
   spreadPips = int(spread / _Point);
   tp = spreadPips * tpSpreadMulti;
   sl = spreadPips * slSpreadMulti;
//--
   PlaySound("connect.wav");
//---
   return(INIT_SUCCEEDED);
  }

OnDeinit関数では、チャートのコメントをクリアし、PriceTrader_EAがアンロードされチャートから削除されたことを示すサウンドを再生します。

void OnDeinit(const int reason)
  {
//---
   Comment("");
   PlaySound("disconnect.wav");
  }

OnTick関数にはPriceTrader_EAのコアロジックが含まれています。この関数では次のことをおこないます。

  • 現現在のロットサイズとポジション数を取得する
  • PriceTrader_EAが読み込まれた直後であるかを確認し、H1のプライスアクションに基づいて初回の取引を開始する
  • 直近の決済済み取引の結果に応じて、ロットサイズと取引方向を調整する
  • 利益の出ているトレンドを活かす、または損失を回復するために、連続トレードを実行する

void OnTick()
  {
//---
   lotSize = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
//--
   totalOpenPositions = SymbolPositionsTotal(_Symbol, magicNo);
   totalBuyPositionsOpen = SymbolBuyPositionsTotal(_Symbol, magicNo);
   totalSellPositionsOpen = SymbolSellPositionsTotal(_Symbol, magicNo);

   if(eaJustLoaded && totalOpenPositions == 0)
     {
      //--
      GetLastClosedPositionData(lastClosedPositionInfo, _Symbol, magicNo);
      if(lastClosedPositionInfo.ticket > 0 && lastClosedPositionInfo.profit < 0)
        {
         if(lastClosedPositionInfo.volume * 2 < lotSize * maxLotIncrease)
            lotSize = lastClosedPositionInfo.volume * 2; // double lot size
        }
      //--
      if(iOpen(_Symbol, PERIOD_H1, 0) < iClose(_Symbol, PERIOD_H1, 0))
        {
         OpenBuyPosition(magicNo, _Symbol, lotSize, sl, tp, "Initial_Position");
        }
      else
        {
         OpenSellPosition(magicNo, _Symbol, lotSize, sl, tp, "Initial_Position");
        }
      if(totalOpenPositions > 0)
         eaJustLoaded = false;
     }
   else
     {
      eaJustLoaded = false;
     }

   if(totalOpenPositions == 0 && !eaJustLoaded)
     {
      if(GetLastClosedPositionData(lastClosedPositionInfo, _Symbol, magicNo))
        {
         if(lastClosedPositionInfo.profit > 0) // PROFITABLE TRADE
           {
            if(lastClosedPositionInfo.type == POSITION_TYPE_BUY)
              {
               OpenBuyPosition(magicNo, _Symbol, lotSize, sl, tp, "Consecutive Profit");
              }
            else  // SELL POSITION
              {
               OpenSellPosition(magicNo, _Symbol, lotSize, sl, tp, "Consecutive Profit");
              }
           }
         else   // LOSS TRADE
           {
            if(lastClosedPositionInfo.volume * 2 < lotSize * maxLotIncrease)
               lotSize = lastClosedPositionInfo.volume * 2; // double lot size
            //--
            if(lastClosedPositionInfo.type == POSITION_TYPE_BUY)
              {
               // Reverse trade direction
               OpenSellPosition(magicNo, _Symbol, lotSize, sl, tp, "Loss Recovery");
              }
            else  // SELL POSITION
              {
               OpenBuyPosition(magicNo, _Symbol, lotSize, sl, tp, "Loss Recovery");
              }
           }
        }
     }

PriceTrader_EAは、シンプルでありながら効果的な自動トレンドフォロー戦略を好む、または必要とするトレーダーに最適です。このEAは、動的なリスク管理を備えており、ロットサイズを柔軟に調整することで損失を素早く回復できるよう設計されています。そのため、不利な相場状況でも戦略の堅牢性を維持することが可能です。さらに、PriceTrader_EAは巧妙に実装されており、MetaTrader 5上でのバックテストが非常に簡単かつ効率的におこなえるようになっています。ロットサイズ、ストップロス、テイクプロフィットの各入力パラメータは、読み込まれた銘柄に基づいて自動的に調整されるため、手動で設定を変更する必要がなく、さまざまな銘柄において最適なパフォーマンスを実現できます。

完全なPriceTrader_EA.mq5ソースファイルとPositionsManager.ex5ライブラリは、この記事の下部にあります。


Price Trader EAのバックテスト

MetaTrader 5ストラテジーテスターでバックテストを実行し、この単純な取引戦略が過去14か月間にどのように機能するかを確認しましょう。
ストラテジーテスターで適用する設定は次のとおりです。

  • 証券会社: Deriv

  • サーバー:Deriv-Demo

  • Symbol: Volatility 50 (1s) Index

  • 時間枠:日次

  • テスト期間(日付): 1年2か月(2024年1月から2025年2月)

  • モデリング: 実際のティックに基づいたすべてのティック

  • 入金: 5,000 USD

  • レバレッジ: 1:1000

WanatekiPriceTrader_EAバックテスト設定

入力設定:

WanatekiPriceTrader_EAバックテスト入力

PriceTrader_EAのバックテスト結果は次のとおりです

WanatekiPriceTrader_EAバックテストレポート

WanatekiPriceTrader_EAバックテストレポート


WanatekiPriceTrader_EAバックテストレポート

WanatekiPriceTrader_EAバックテストレポート

WanatekiPriceTrader_EAバックテストレポート

WanatekiPriceTrader_EAバックテストレポート

バックテストの結果を確認すると、PriceTrader_EAはなんと129%以上の利益を記録しながら、わずか29%という低いドローダウンに抑えることに成功しました。このシンプルでありながら効果的な戦略は、大きな可能性を示しており、さらに調整・最適化をおこなうことで、より優れた成果が期待できます。PriceTrader_EAは、取引する銘柄や資産に応じてロットサイズ、ストップロス、テイクプロフィットといった入力パラメータを動的に調整するため、デモ口座で簡単にテストすることができます。チャートにEAを読み込むだけで、1日またはそれ以上稼働させることで、そのパフォーマンスを確認できます。ストラテジーテスターで得られた利益と同様に、リアルタイムでも収益を生み出すかを実際に観察できます。この柔軟性により、PriceTrader_EAはテスト用としてもライブ取引用としても非常に優れたツールとなっています。


結論

本連載の最終記事で紹介したように、HistoryManager.ex5ライブラリは、MetaTrader 5における取引履歴の処理を大幅に簡略化できる、強力かつ効率的なツールです。このライブラリには豊富な機能が備わっており、取引、注文、ポジション、未決注文などのデータに、シンプルな1行の関数呼び出しで簡単にアクセスし、管理することができます。このような洗練されたアプローチにより、時間と労力を節約し、戦略の開発と最適化に集中できるようになります。

本記事では、HistoryManager.ex5ライブラリの可能性を最大限に活用するための実践的なコード例を紹介しました。これらの例と、本連載を通して共有した知識によって、MetaTrader 5上での取引活動から得られるあらゆる種類の履歴データを、MQL5を使ってアルゴリズム的に処理するためのツールとリソースが揃いました。本連載を最後まで読み進めてくださった読者の皆さまへの感謝の気持ちとして、いくつかの概念を実践的に応用した基本的ながら効果的なEA PriceTrader_EAをご提供します。

MQL5開発の旅にご一緒いただき、誠にありがとうございました。こうして熱心に学び、ツールを探求する姿勢は、アルゴリズムトレードの技術を習得しようとする強い意志の現れです。今後も市場の複雑さを解き明かし、成功に近づくためのMQL5開発に取り組んでいかれることを心から願っております。コーディングをお楽しみください。そして、あなたのストラテジーが常に成果を上げ続けますように。


リソースとソースファイル

この記事で参照されているすべてのコードは、便宜上以下に提供されています。ここに含まれる表には、付属のEX5ライブラリとソースコードファイルの概要が示されており、説明されている例に簡単にアクセスし、実装し、調査することができます。

ファイル名 説明
HistoryManager.ex5 取引履歴を処理および管理するために設計されたEX5ライブラリ
PositionsManager.ex5 ポジションと注文を管理および処理するためのEX5ライブラリ
HistoryManager.mqh HistoryManager.ex5ライブラリからソースファイルにデータ構造とプロトタイプ関数をインポートするために使用されるヘッダーファイル
PositionsManager.mqh PositionsManager.ex5ライブラリからソースファイルにプロトタイプ関数をインポートするために使用されるヘッダーファイル
GetProfitFactor.mq5 粗利益、粗損失、利益率などの主要な指標を計算して、取引戦略のパフォーマンスを分析するEA
GetNetProfitThisWeek.mq5 今週の純利益を計算するスクリプト
GetSymbolPipsProfitToLossRatio.mq5 特定の取引銘柄またはEA全体の損益比率をpips単位で計算するEA
GetTotalDeposits.mq5 取引データを取得して分析し、アカウントの資金調達または現金入金履歴の概要を明確に示すスクリプト
PriceTrader_EA.mq5 取引履歴データを使用して価格の方向を検出し、損失から回復する価格データ駆動型のEA(PositionsManager.ex5およびHistoryManager.ex5ライブラリを活用)



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

最後のコメント | ディスカッションに移動 (3)
hini
hini | 5 7月 2025 において 15:31
こんにちは、作者さん。パフォーマンスをテストしましたか?多数の注文が ある場合、どの程度速くなりますか?
Wanateki Solutions LTD
Kelvin Muturi Muigua | 6 7月 2025 において 23:03
hiniさん、こんにちは。大量のヒストリカルオーダーを扱う場合でも、ミリ秒単位で照会結果を返すので高速ですが、お使いのコンピュータの速度にもよります。
hini
hini | 7 7月 2025 において 00:18
Kelvin Muturi Muigua #:
hiniさん、こんにちは。大量のヒストリカルオーダーを扱う場合でも、ミリ秒単位で照会結果を返すので高速ですが、これはお使いのコンピュータの速度によります。
ありがとうございます!
MQL5での取引戦略の自動化(第11回):マルチレベルグリッド取引システムの開発 MQL5での取引戦略の自動化(第11回):マルチレベルグリッド取引システムの開発
本記事では、MQL5を使用してマルチレベルのグリッド取引システムEAを開発し、グリッド取引戦略の背後にあるアーキテクチャとアルゴリズム設計に焦点を当てます。複数層にわたるグリッドロジックの実装と、市場のさまざまな状況に対応するためのリスク管理手法について探ります。最後に、自動売買システムの構築・テスト・改善をおこなうための詳細な説明と実践的なヒントを提供します。
プライスアクション分析ツールキットの開発(第17回):TrendLoom EAツール プライスアクション分析ツールキットの開発(第17回):TrendLoom EAツール
プライスアクションを観察し、取引をおこなう立場から言うと、複数の時間枠でトレンドが確認された場合、その方向にトレンドが継続することがよくあります。ただし、トレンドがどれくらい続くかは一定ではなく、ポジションを長期で保有するのか、それともスキャルピングのような短期取引をおこなうのかといったトレーダーのスタイルによって異なります。トレンド確認に使用する時間枠の選択は非常に重要な役割を果たします。以下の記事では、ワンクリックや定期的な更新によって、複数の時間足にわたる全体的なトレンドを自動で分析できる便利なシステムを紹介しています。ぜひご覧ください。
データサイエンスとML(第34回):時系列分解、株式市場を核心にまで分解 データサイエンスとML(第34回):時系列分解、株式市場を核心にまで分解
ノイズが多く、予測が難しいデータで溢れる世界では、意味のあるパターンを特定するのは困難です。この記事では、データをトレンド、季節パターン、ノイズといった主要な要素に分解する強力な分析手法「季節分解」について解説します。こうしてデータを分解することで、隠れた洞察を見つけ、より明確で解釈しやすい情報を得ることが可能になります。
プライスアクション分析ツールキットの開発(第16回):クォーターズ理論の紹介(II) - Intrusion Detector EA プライスアクション分析ツールキットの開発(第16回):クォーターズ理論の紹介(II) - Intrusion Detector EA
前回の記事では、「Quarters Drawer」というシンプルなスクリプトを紹介しました。このツールを基盤として、今回はさらに一歩進め、これらのクォーターを監視し、市場がどのように反応するかを見極めるためのモニター型エキスパートアドバイザー(EA)を作成します。本記事では、ゾーン検出ツールの開発プロセスについて紹介します。