Sử dụng thư viện – triển khai ứng dụng nền tảng Meta Trader 5: History của Order và Deal

3491

Mục lục

  1. Objects History của Order and Deal
  2. Thu thập các thông tin History của Order và Deal
  3. Tóm tắt phần tiếp theo

Trong bài viết trước, chúng ta đã bắt đầu tạo một thư viện đa nền tảng lớn đơn giản hóa việc phát triển các chương trình cho nền tảng MetaTrader 5 và MetaTrader 4. Và đã tạo ra đối tượng trừu tượng COrder, một đối tượng cơ sở để lưu trữ dữ liệu trên các đơn đặt hàng và giao dịch lịch sử, cũng như các lệnh và vị trí thị trường.

Trong phần này, chúng ta sẽ tiến hành phát triển tất cả các đối tượng cần thiết để lưu trữ dữ liệu lịch sử tài khoản trong các bộ sưu tập, chuẩn bị thu thập các đơn đặt hàng và giao dịch lịch sử, cũng như sửa đổi và cải thiện các đối tượng và bảng liệt kê đã tạo.

Objects History của Order and Deal

Đối tượng cơ sở COrder chứa tất cả dữ liệu trên bất kỳ đối tượng tài khoản nào, có thể là lệnh thị trường (lệnh thực hiện hành động), lệnh chờ xử lý, giao dịch hoặc vị trí. Để chúng tôi tự do vận hành tất cả các đối tượng này tách biệt với nhau, chúng tôi sẽ phát triển một số lớp dựa trên COrder trừu tượng. Các lớp này sẽ chỉ ra chính xác sự liên kết của đối tượng với loại của nó.

Danh sách các đơn đặt hàng và giao dịch lịch sử có thể có một số loại đối tượng như vậy: đã xóa lệnh chờ xử lý, đặt lệnh thị trường và giao dịch (kết quả thực hiện lệnh thị trường). Ngoài ra còn có hai loại đối tượng nữa trong MQL4: số dư và hoạt động tín dụng (trong MQL5, những dữ liệu này được lưu trữ trong các thuộc tính giao dịch).

Tạo lớp CHistoryOrder mới trong thư mục Đối tượng của thư viện. Để thực hiện việc này, bấm chuột phải vào thư mục Objects và chọn mục menu ‘New file’ (Ctrl + N). Trong Trình hướng dẫn MQL5 mới mở, chọn ‘ New Class’ và nhấp vào Tiếp theo. Nhập CHistoryOrder (1) trong trường tên lớp, chỉ định tên của lớp trừu tượng COrder (2) trong trường lớp cơ sở và nhấp vào Kết thúc.

Sau đó, tệp HistoryOrder.mqh (3) được tạo trong thư mục Đối tượng. Mở nó ra:

//+------------------------------------------------------------------+
//|                                                 HistoryOrder.mqh |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property version   "1.00"
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CHistoryOrder : public COrder
  {
private:

public:
                     CHistoryOrder();
                    ~CHistoryOrder();
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CHistoryOrder::CHistoryOrder()
  {
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CHistoryOrder::~CHistoryOrder()
  {
  }
//+------------------------------------------------------------------+

Hiện tại, đây chỉ là một lớp mẫu. Nếu chúng ta cố gắng biên dịch nó, chúng ta sẽ thấy năm lỗi đã quen thuộc – lớp mới xuất phát từ COrder không biết gì về cha mẹ của nó. Thêm bao gồm tệp Order.mqh:

#include "Order.mqh"

Bây giờ tất cả được biên dịch không có vấn đề.

Class sẽ khá nhỏ. Chúng ta cần xác định lại các phương thức lớp cha mẹ COrder, trả về các cờ bảo trì thuộc tính đơn hàng, cũng như đặt truyền vé đơn hàng cho lớp trong hàm tạo:

//+------------------------------------------------------------------+
//|                                                 HistoryOrder.mqh |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property version   "1.00"
//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include "Order.mqh"
//+------------------------------------------------------------------+
//| History market order                                             |
//+------------------------------------------------------------------+
class CHistoryOrder : public COrder
  {
public:
   //--- Constructor
                     CHistoryOrder(const ulong ticket) : COrder(ORDER_STATUS_HISTORY_ORDER,ticket) {}
   //--- Supported integer order properties
   virtual bool      SupportProperty(ENUM_ORDER_PROP_INTEGER property);
  };
//+------------------------------------------------------------------+
//| Return 'true' if the order supports the passed property,         |
//| otherwise, return 'false'                                        |
//+------------------------------------------------------------------+
bool CHistoryOrder::SupportProperty(ENUM_ORDER_PROP_INTEGER property)
  {
   if(property==ORDER_PROP_TIME_EXP       || 
      property==ORDER_PROP_DEAL_ENTRY     || 
      property==ORDER_PROP_TIME_UPDATE    || 
      property==ORDER_PROP_TIME_UPDATE_MSC
     ) return false;
   return true;
  }
//+------------------------------------------------------------------+

Do đó, một vé-ticket của một đơn đặt hàng đã chọn được chuyển đến hàm tạo của lớp, trong khi trạng thái đơn hàng (thứ tự lịch sử) và vé của nó được chuyển đến hàm tạo được bảo vệ của đối tượng cha COrder.

Chúng tôi cũng đã định nghĩa lại phương thức ảo của lớp cha hỗ trợ trả về các thuộc tính thứ tự số nguyên. Các phương thức trả về sự hỗ trợ cho các thuộc tính thực và chuỗi của đơn hàng đã được giữ nguyên – các phương thức lớp cha này luôn trả về ‘true’ và chúng tôi sẽ giả sử rằng thứ tự lịch sử hỗ trợ tất cả các thuộc tính thực và chuỗi, vì vậy chúng tôi sẽ không xác định lại chúng

Kiểm tra thuộc tính trong phương thức hỗ trợ các thuộc tính số nguyên. Nếu đây là thời gian hết hạn, hướng giao dịch hoặc thời gian thay đổi vị trí, hãy trả về ‘false’. Các tính chất như vậy không được hỗ trợ bởi các đơn đặt hàng thị trường. Tất cả các thuộc tính còn lại được hỗ trợ và ‘true’ được trả về.
Theo cách tương tự, tạo lớp CHistoryPending của lệnh đang chờ xử lý (đã xóa) và lớp thỏa thuận lịch sử CHistoryDeal:

//+------------------------------------------------------------------+
//|                                               HistoryPending.mqh |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property version   "1.00"
//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include "Order.mqh"
//+------------------------------------------------------------------+
//| Removed pending order                                            |
//+------------------------------------------------------------------+
class CHistoryPending : public COrder
  {
public:
   //--- Constructor
                     CHistoryPending(const ulong ticket) : COrder(ORDER_STATUS_HISTORY_PENDING,ticket) {}
   //--- Supported order properties (1) real, (2) integer
   virtual bool      SupportProperty(ENUM_ORDER_PROP_DOUBLE property);
   virtual bool      SupportProperty(ENUM_ORDER_PROP_INTEGER property);
  };
//+------------------------------------------------------------------+
//| Return 'true' if the order supports the passed property,         |
//| otherwise, return 'false'                                        |
//+------------------------------------------------------------------+
bool CHistoryPending::SupportProperty(ENUM_ORDER_PROP_INTEGER property)
  {
   if(property==ORDER_PROP_PROFIT_PT         ||
      property==ORDER_PROP_DEAL_ORDER        ||
      property==ORDER_PROP_DEAL_ENTRY        ||
      property==ORDER_PROP_TIME_UPDATE       ||
      property==ORDER_PROP_TIME_UPDATE_MSC   ||
      property==ORDER_PROP_TICKET_FROM       ||
      property==ORDER_PROP_TICKET_TO         ||
      property==ORDER_PROP_CLOSE_BY_SL       ||
      property==ORDER_PROP_CLOSE_BY_TP
     ) return false;
   return true;
  }
//+------------------------------------------------------------------+
//| Return 'true' if the order supports the passed property,         |
//| otherwise, returns 'false'                                       |
//+------------------------------------------------------------------+
bool CHistoryPending::SupportProperty(ENUM_ORDER_PROP_DOUBLE property)
  {
   if(property==ORDER_PROP_COMMISSION  ||
      property==ORDER_PROP_SWAP        ||
      property==ORDER_PROP_PROFIT      ||
      property==ORDER_PROP_PROFIT_FULL ||
      property==ORDER_PROP_PRICE_CLOSE
     ) return false;
   return true;
  }
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//|                                                  HistoryDeal.mqh |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property version   "1.00"
//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include "Order.mqh"
//+------------------------------------------------------------------+
//| Historical deal                                                  |
//+------------------------------------------------------------------+
class CHistoryDeal : public COrder
  {
public:
   //--- Constructor
                     CHistoryDeal(const ulong ticket) : COrder(ORDER_STATUS_DEAL,ticket) {}
   //--- Supported deal properties (1) real, (2) integer
   virtual bool      SupportProperty(ENUM_ORDER_PROP_DOUBLE property);
   virtual bool      SupportProperty(ENUM_ORDER_PROP_INTEGER property);
  };
//+------------------------------------------------------------------+
//| Return 'true' if the order supports the passed property,         |
//| otherwise, return 'false'                                        |
//+------------------------------------------------------------------+
bool CHistoryDeal::SupportProperty(ENUM_ORDER_PROP_INTEGER property)
  {
   if(property==ORDER_PROP_TIME_EXP          || 
      property==ORDER_PROP_PROFIT_PT         ||
      property==ORDER_PROP_POSITION_BY_ID    ||
      property==ORDER_PROP_TIME_UPDATE       ||
      property==ORDER_PROP_TIME_UPDATE_MSC   ||
      property==ORDER_PROP_STATE             ||
      (
       this.OrderType()==DEAL_TYPE_BALANCE &&
       (
        property==ORDER_PROP_POSITION_ID     ||
        property==ORDER_PROP_POSITION_BY_ID  ||
        property==ORDER_PROP_TICKET_FROM     ||
        property==ORDER_PROP_TICKET_TO       ||
        property==ORDER_PROP_DEAL_ORDER      ||
        property==ORDER_PROP_MAGIC           ||
        property==ORDER_PROP_TIME_CLOSE      ||
        property==ORDER_PROP_TIME_CLOSE_MSC  ||
        property==ORDER_PROP_CLOSE_BY_SL     ||
        property==ORDER_PROP_CLOSE_BY_TP
       )
      )
     ) return false;
   return true;
  }
//+------------------------------------------------------------------+
bool CHistoryDeal::SupportProperty(ENUM_ORDER_PROP_DOUBLE property)
  {
   if(property==ORDER_PROP_TP                || 
      property==ORDER_PROP_SL                || 
      property==ORDER_PROP_PRICE_CLOSE       ||
      property==ORDER_PROP_VOLUME_CURRENT    ||
      property==ORDER_PROP_PRICE_STOP_LIMIT  ||
      (
       this.OrderType()==DEAL_TYPE_BALANCE &&
       (
        property==ORDER_PROP_PRICE_OPEN      ||
        property==ORDER_PROP_COMMISSION      ||
        property==ORDER_PROP_SWAP            ||
        property==ORDER_PROP_VOLUME
       )
      )
     ) return false;
   return true;
  }
//+------------------------------------------------------------------+

Chúng tôi đã tạo ra ba đối tượng thứ tự bộ sưu tập các đơn đặt hàng lịch sử sẽ được dựa trên. Tất cả chúng được kế thừa từ lớp cơ sở thứ tự trừu tượng COrder. Chúng có các thuộc tính của nó nhưng chỉ cho phép trả về các thuộc tính được hỗ trợ bởi các loại đơn đặt hàng này. Tất cả chúng đều được đặt trong một danh sách bộ sưu tập (tập hợp các đơn đặt hàng lịch sử), từ đó chúng tôi sẽ nhận được tất cả dữ liệu cần thiết về lịch sử tài khoản theo bất kỳ thành phần và thứ tự nào.

Không phải tất cả các thuộc tính được hỗ trợ hoặc không được hỗ trợ đều được tính đến trong các phương thức SupportProperty() để hiển thị các thuộc tính thứ tự trong tạp chí. Ví dụ: chỉ có ba loại được xem xét cho các giao dịch: mua, bán và cân bằng hoạt động.

Các thuộc tính chưa được xem xét và chưa được chỉ định rõ ràng trong các phương thức trả lại hỗ trợ cho chúng sẽ luôn được in. Sau đó, bạn có thể thêm chúng vào phương thức để không in các thuộc tính luôn trả về giá trị 0 bất kể tình huống (không được hỗ trợ).

Thu thập các thông tin History của Order và Deal

Nó luôn hữu ích để có lịch sử tài khoản trong tầm tay. Thiết bị đầu cuối cung cấp nó và cung cấp cho các công cụ để có được nó trong các chương trình. Tuy nhiên, các tác vụ hiện tại của chúng tôi yêu cầu một danh sách tùy chỉnh, chúng tôi có thể sắp xếp và sắp xếp lại để trả lại dữ liệu cần thiết cho các chương trình của chúng tôi. Điều này có nghĩa là phải thay đổi trạng thái lịch sử tài khoản trước đó tại mỗi lần đánh dấu. Nếu một thay đổi được phát hiện, danh sách các đơn đặt hàng và giao dịch lịch sử sẽ được tính toán lại. Nhưng sắp xếp toàn bộ lịch sử ở mỗi đánh dấu là quá tốn tài nguyên. Do đó, chúng tôi sẽ chỉ bổ sung vào danh sách dữ liệu mới của chúng tôi, trong khi dữ liệu trước đó đã được lưu trữ trong danh sách.

Hãy tạo lớp CHistoryCollection mới trong thư mục Collections:

Nhấp chuột phải vào thư mục Collections, chọn ‘New file’, chọn ‘new class’ trong cửa sổ Trình hướng dẫn MQL và nhấp vào Tiếp theo. Nhập tên lớp CHistoryCollection, để trống trường lớp cơ sở và nhấp vào Kết thúc.

//+------------------------------------------------------------------+
//|                                            HistoryCollection.mqh |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property version   "1.00"
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CHistoryCollection
  {
private:

public:
                     CHistoryCollection();
                    ~CHistoryCollection();
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CHistoryCollection::CHistoryCollection()
  {
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CHistoryCollection::~CHistoryCollection()
  {
  }
//+------------------------------------------------------------------+

Include CArrayObj và define the list

//+------------------------------------------------------------------+
//|                                            HistoryCollection.mqh |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property version   "1.00"
//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include <Arrays\ArrayObj.mqh>
//+------------------------------------------------------------------+
//| Collection of historical orders and deals                        |
//+------------------------------------------------------------------+
class CHistoryCollection
  {
private:
   CArrayObj         m_list_all_orders;      // List of historical orders and deals

public:
                     CHistoryCollection();
                    ~CHistoryCollection();
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CHistoryCollection::CHistoryCollection()
  {
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CHistoryCollection::~CHistoryCollection()
  {
  }
//+------------------------------------------------------------------+

Cần lưu các chỉ số của các đơn đặt hàng và giao dịch cuối cùng được thêm vào bộ sưu tập. Bên cạnh đó, chúng ta cần biết sự khác biệt giữa số lượng đơn đặt hàng và giao dịch trong quá khứ và hiện tại, do đó chúng tôi sẽ tạo các thành viên lớp riêng để lưu trữ chúng:

//+------------------------------------------------------------------+
//|                                            HistoryCollection.mqh |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property version   "1.00"
//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include <Arrays\ArrayObj.mqh>
//+------------------------------------------------------------------+
//| Collection of historical orders and deals                        |
//+------------------------------------------------------------------+
class CHistoryCollection
  {
private:
   CArrayObj         m_list_all_orders;      // List of historical orders and deals
   int               m_index_order;          // Index of the last order added to the collection from the terminal history list (MQL4, MQL5)
   int               m_index_deal;           // Index of the last deal added to the collection from the terminal history list (MQL5)
   int               m_delta_order;          // Difference in the number of orders as compared to the past check
   int               m_delta_deal;           // Difference in the number of deals as compared to the past check
public:
                     CHistoryCollection();
                    ~CHistoryCollection();
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CHistoryCollection::CHistoryCollection()
  {
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CHistoryCollection::~CHistoryCollection()
  {
  }
//+------------------------------------------------------------------+

Trong lần khởi chạy đầu tiên, tất cả các thành viên lớp riêng được đặt lại và lịch sử được tính lại. Để làm điều này, chỉ cần thêm danh sách khởi tạo thành viên lớp trong hàm tạo của lớp và đặt tiêu chí mặc định mà danh sách bộ sưu tập sẽ được sắp xếp theo.

Hiện tại, chúng tôi có các nhà xây dựng mặc định. Trước khi viết triển khai, chúng ta nên tạo một bảng liệt kê chứa tất cả các tiêu chí có thể để sắp xếp các đơn đặt hàng và giao dịch trong danh sách bộ sưu tập.
Nhưng trước tiên, hãy sắp xếp các thuộc tính thứ tự số nguyên, thực và chuỗi để hiển thị logic hơn trong nhật ký. Mở tệp Defines.mqh từ thư mục gốc của thư viện và đặt các thành viên liệt kê theo thứ tự yêu cầu:

//+------------------------------------------------------------------+
//| Order, deal, position integer properties                         |
//+------------------------------------------------------------------+
enum ENUM_ORDER_PROP_INTEGER
  {
   ORDER_PROP_TICKET = 0,                                   // Order ticket
   ORDER_PROP_MAGIC,                                        // Order magic number
   ORDER_PROP_TIME_OPEN,                                    // Open time (MQL5 Deal time)
   ORDER_PROP_TIME_CLOSE,                                   // Close time (MQL5 Execution or removal time - ORDER_TIME_DONE)
   ORDER_PROP_TIME_OPEN_MSC,                                // Open time in milliseconds (MQL5 Deal time in msc)
   ORDER_PROP_TIME_CLOSE_MSC,                               // Close time in milliseconds (MQL5 Execution or removal time - ORDER_TIME_DONE_MSC)
   ORDER_PROP_TIME_EXP,                                     // Order expiration date (for pending orders)
   ORDER_PROP_STATUS,                                       // Order status (from the ENUM_ORDER_STATUS enumeration)
   ORDER_PROP_TYPE,                                         // Order type (MQL5 deal type)
   ORDER_PROP_DIRECTION,                                    // Direction (Buy, Sell)
   ORDER_PROP_REASON,                                       // Deal/order/position reason or source
   ORDER_PROP_POSITION_ID,                                  // Position ID
   ORDER_PROP_POSITION_BY_ID,                               // Opposite position ID
   ORDER_PROP_DEAL_ORDER,                                   // Order a deal is based on
   ORDER_PROP_DEAL_ENTRY,                                   // Deal direction – IN, OUT or IN/OUT
   ORDER_PROP_TIME_UPDATE,                                  // Position change time in seconds
   ORDER_PROP_TIME_UPDATE_MSC,                              // Position change time in milliseconds
   ORDER_PROP_TICKET_FROM,                                  // Parent order ticket
   ORDER_PROP_TICKET_TO,                                    // Derived order ticket
   ORDER_PROP_PROFIT_PT,                                    // Profit in points
   ORDER_PROP_CLOSE_BY_SL,                                  // Flag of closing by StopLoss
   ORDER_PROP_CLOSE_BY_TP,                                  // Flag of closing by TakeProfit
  }; 
#define ORDER_PROP_INTEGER_TOTAL    (22)                    // Total number of integer properties
//+------------------------------------------------------------------+
//| Order, deal, position real properties                            |
//+------------------------------------------------------------------+
enum ENUM_ORDER_PROP_DOUBLE
  {
   ORDER_PROP_PRICE_OPEN = ORDER_PROP_INTEGER_TOTAL,        // Open price (MQL5 deal price)
   ORDER_PROP_PRICE_CLOSE,                                  // Close price
   ORDER_PROP_SL,                                           // StopLoss price
   ORDER_PROP_TP,                                           // TakeProfit price
   ORDER_PROP_PROFIT,                                       // Profit
   ORDER_PROP_COMMISSION,                                   // Commission
   ORDER_PROP_SWAP,                                         // Swap
   ORDER_PROP_VOLUME,                                       // Volume
   ORDER_PROP_VOLUME_CURRENT,                               // Unexecuted volume
   ORDER_PROP_PROFIT_FULL,                                  // Profit+commission+swap
   ORDER_PROP_PRICE_STOP_LIMIT,                             // Limit order price when StopLimit order is activated
  };
#define ORDER_PROP_DOUBLE_TOTAL     (11)                    // Total number of real properties
//+------------------------------------------------------------------+
//| Order, deal, position string properties                          |
//+------------------------------------------------------------------+
enum ENUM_ORDER_PROP_STRING
  {
   ORDER_PROP_SYMBOL = (ORDER_PROP_INTEGER_TOTAL+ORDER_PROP_DOUBLE_TOTAL), // Order symbol
   ORDER_PROP_COMMENT,                                      // Order comment
   ORDER_PROP_EXT_ID                                        // Order ID in an external trading system
  };
#define ORDER_PROP_STRING_TOTAL     (3)                     // Total number of string properties
//+------------------------------------------------------------------+

Bây giờ, hãy thêm phép liệt kê với tất cả các loại thứ tự có thể và sắp xếp thỏa thuận vào cùng một tệp:

//+------------------------------------------------------------------+
//| Possible criteria of orders and deals sorting                    |
//+------------------------------------------------------------------+
enum ENUM_SORT_ORDERS_MODE
  {
   //--- Sort by integer properties
   SORT_BY_ORDER_TICKET          =  0,                      // Sort by order ticket
   SORT_BY_ORDER_MAGIC           =  1,                      // Sort by order magic number
   SORT_BY_ORDER_TIME_OPEN       =  2,                      // Sort by order open time
   SORT_BY_ORDER_TIME_CLOSE      =  3,                      // Sort by order close time
   SORT_BY_ORDER_TIME_OPEN_MSC   =  4,                      // Sort by order open time in milliseconds
   SORT_BY_ORDER_TIME_CLOSE_MSC  =  5,                      // Sort by order close time in milliseconds
   SORT_BY_ORDER_TIME_EXP        =  6,                      // Sort by order expiration date
   SORT_BY_ORDER_STATUS          =  7,                      // Sort by order status (market order/pending order/deal)
   SORT_BY_ORDER_TYPE            =  8,                      // Sort by order type
   SORT_BY_ORDER_REASON          =  10,                     // Sort by deal/order/position reason/source
   SORT_BY_ORDER_POSITION_ID     =  11,                     // Sort by position ID
   SORT_BY_ORDER_POSITION_BY_ID  =  12,                     // Sort by opposite position ID
   SORT_BY_ORDER_DEAL_ORDER      =  13,                     // Sort by order a deal is based on
   SORT_BY_ORDER_DEAL_ENTRY      =  14,                     // Sort by deal direction – IN, OUT or IN/OUT
   SORT_BY_ORDER_TIME_UPDATE     =  15,                     // Sort by position change time in seconds
   SORT_BY_ORDER_TIME_UPDATE_MSC =  16,                     // Sort by position change time in milliseconds
   SORT_BY_ORDER_TICKET_FROM     =  17,                     // Sort by parent order ticket
   SORT_BY_ORDER_TICKET_TO       =  18,                     // Sort by derived order ticket
   SORT_BY_ORDER_PROFIT_PT       =  19,                     // Sort by order profit in points
   SORT_BY_ORDER_CLOSE_BY_SL     =  20,                     // Sort by order closing by StopLoss flag
   SORT_BY_ORDER_CLOSE_BY_TP     =  21,                     // Sort by order closing by TakeProfit flag
   //--- Sort by real properties
   SORT_BY_ORDER_PRICE_OPEN      =  ORDER_PROP_INTEGER_TOTAL,// Sort by open price
   SORT_BY_ORDER_PRICE_CLOSE     =  23,                     // Sort by close price
   SORT_BY_ORDER_SL              =  24,                     // Sort by StopLoss price
   SORT_BY_ORDER_TP              =  25,                     // Sort by TakeProfit price
   SORT_BY_ORDER_PROFIT          =  26,                     // Sort by profit
   SORT_BY_ORDER_COMMISSION      =  27,                     // Sort by commission
   SORT_BY_ORDER_SWAP            =  28,                     // Sort by swap
   SORT_BY_ORDER_VOLUME          =  29,                     // Sort by volume
   SORT_BY_ORDER_VOLUME_CURRENT  =  30,                     // Sort by unexecuted volume
   SORT_BY_ORDER_PROFIT_FULL     =  31,                     // Sort by profit+commission+swap criterion
   SORT_BY_ORDER_PRICE_STOP_LIMIT=  32,                     // Sort by Limit order when StopLimit order is activated
   //--- Sort by string properties
   SORT_BY_ORDER_SYMBOL          =  ORDER_PROP_INTEGER_TOTAL+ORDER_PROP_DOUBLE_TOTAL,// Sort by symbol
   SORT_BY_ORDER_COMMENT         =  34,                     // Sort by comment
   SORT_BY_ORDER_EXT_ID          =  35                      // Sort by order ID in an external trading system
  };
//+------------------------------------------------------------------+
Lưu ý: Các chỉ số của các thành viên liệt kê sắp xếp phải trùng với các chỉ số của các thành viên liệt kê thuộc tính, vì danh sách phải được sắp xếp theo cùng một giá trị được sử dụng để tìm kiếm trong danh sách đó. 

Như chúng ta có thể thấy, thuộc tính sắp xếp ORDER_PROP_DIRMENT đã bị bỏ qua trong danh sách đó vì đây là thuộc tính dịch vụ được sử dụng cho nhu cầu thư viện, giống như các thuộc tính tùy chỉnh khác mà chúng ta đã thêm trước đây. Tuy nhiên, họ có thể cần phân loại. Đây là lý do tại sao họ đã bị bỏ lại.

Bây giờ chúng ta có thể triển khai hàm tạo của lớp CHistoryCollection:

//+------------------------------------------------------------------+
//|                                            HistoryCollection.mqh |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property version   "1.00"
//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include <Arrays\ArrayObj.mqh>
#include "..\DELib.mqh"
//+------------------------------------------------------------------+
//| Collection of historical orders and deals                        |
//+------------------------------------------------------------------+
class CHistoryCollection
  {
private:
   CArrayObj         m_list_all_orders;      // List of historical orders and deals
   int               m_index_order;          // Index of the last order added to the collection from the terminal history list (MQL4, MQL5)
   int               m_index_deal;           // Index of the last deal added to the collection from the terminal history list (MQL5)
   int               m_delta_order;          // Difference in the number of orders as compared to the past check
   int               m_delta_deal;           // Difference in the number of deals as compared to the past check
public:
                     CHistoryCollection();
                    ~CHistoryCollection();
  };
//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CHistoryCollection::CHistoryCollection(void) : m_index_deal(0), 
                                               m_delta_deal(0), 
                                               m_index_order(0),
                                               m_delta_order(0) 
  {
   m_list_all_orders.Sort(SORT_BY_ORDER_TIME_CLOSE);
  }
//+------------------------------------------------------------------+

Hãy phân tích danh sách. Vì hàm tạo của lớp chỉ sử dụng giá trị của một phép liệt kê mới được thêm vào, nên chúng ta nên đưa tệp Defines.mqh vào tệp lớp. Trong khi chuẩn bị lớp cơ sở của thứ tự trừu tượng trong bài viết đầu tiên, chúng tôi đã phát triển thư viện các hàm dịch vụ DELib.mqh và bao gồm tệp Defines.mqh với tất cả các liệt kê cần thiết và thay thế macro cho nó. Do đó, chúng tôi sẽ bao gồm thư viện các chức năng dịch vụ.
Trong danh sách khởi tạo của hàm tạo, tất cả các chỉ số và giá trị của sự khác biệt giữa các số hiện tại và các số trước đó được đặt lại và sắp xếp mặc định theo thời gian đóng được chỉ định trong phần thân của hàm tạo.

Bây giờ là lúc để bắt đầu thu thập thông tin từ tài khoản và lưu nó trong danh sách thu thập. Để làm điều này, đi qua lịch sử tài khoản trong các vòng lặp và chỉ định từng đơn hàng trong danh sách. Nếu số lượng đơn đặt hàng hoặc giao dịch đã thay đổi so với kiểm tra trước đó, thì hãy đặt cờ của sự kiện giao dịch xảy ra. Cần gửi tin nhắn về sự kiện mới xảy ra trong lịch sử tài khoản tới một chương trình bên ngoài.

Khai báo cờ sự kiện giao dịch trong phần lớp riêng và phương thức Refresh() để cập nhật bộ sưu tập lịch sử trong công khai:

//+------------------------------------------------------------------+
//| Collection of historical orders and deals                        |
//+------------------------------------------------------------------+
class CHistoryCollection
  {
private:
   CArrayObj         m_list_all_orders;      // List of all historical orders and deals
   bool              m_is_trade_event;       // Trading event flag
   int               m_index_order;          // Index of the last order added to the collection from the terminal history list (MQL4, MQL5)
   int               m_index_deal;           // Index of the last deal added to the collection from the terminal history list (MQL5)
   int               m_delta_order;          // Difference in the number of orders as compared to the past check
   int               m_delta_deal;           // Difference in the number of deals as compared to the past check
public:
                     CHistoryCollection();
   //--- Update the list of orders, fill data on the number of new ones and set the trading event flag
   void              Refresh(void);
  };
//+------------------------------------------------------------------+

Để thực hiện cập nhật danh sách các đơn đặt hàng bộ sưu tập, cần thêm một thay thế macro để yêu cầu dữ liệu lịch sử đầy đủ. Hàm HistorySelect() được sử dụng cho điều đó. Ngày bắt đầu và kết thúc của dữ liệu cần thiết được truyền vào các tham số của nó. Để có được danh sách đầy đủ về lịch sử tài khoản, ngày đầu tiên phải được thông qua là 0, trong khi ngày kết thúc phải được thông qua là TimeCurrent(). Tuy nhiên, trong trường hợp đó, dữ liệu lịch sử trả về đôi khi có thể không đầy đủ. Để tránh điều đó, hãy nhập một ngày vượt quá thời gian máy chủ hiện tại thay vì TimeCurrent(). Tôi sẽ nhập ngày tối đa có thể: 31.12.3000 23:59:59. Một lợi thế khác ở đây là các biểu tượng tùy chỉnh có thể chứa một ngày như vậy và việc lấy lịch sử vẫn sẽ hoạt động.

Hãy chèn một thay thế macro mới vào tệp Defines.mqh:

//+------------------------------------------------------------------+
//|                                                      Defines.mqh |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
//+------------------------------------------------------------------+
//| Macro substitutions                                              |
//+------------------------------------------------------------------+
#define COUNTRY_LANG   ("Russian")              // Country language
#define DFUN           (__FUNCTION__+": ")      // "Function description"
#define END_TIME       (D'31.12.3000 23:59:59') // End time to request account history data
//+------------------------------------------------------------------+

Bây giờ, thay vì nhập TimeCurent() làm thời gian kết thúc, chúng tôi sẽ nhập macro END_TIME.
Thực hiện cập nhật danh sách thứ tự bộ sưu tập:

//+------------------------------------------------------------------+
//| Update the order list                                            |
//+------------------------------------------------------------------+
void CHistoryCollection::Refresh(void)
  {
#ifdef __MQL4__
   int total=::OrdersHistoryTotal(),i=m_index_order;
   for(; i<total; i++)
     {
      if(!::OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)) continue;
      ENUM_ORDER_TYPE order_type=(ENUM_ORDER_TYPE)::OrderType();
      //--- Closed positions and balance/credit operations
      if(order_type<ORDER_TYPE_BUY_LIMIT || order_type>ORDER_TYPE_SELL_STOP)
        {
         CHistoryOrder *order=new CHistoryOrder(::OrderTicket());
         if(order==NULL) continue;
         m_list_all_orders.InsertSort(order);
        }
      else
        {
         //--- Removed pending orders
         CHistoryPending *order=new CHistoryPending(::OrderTicket());
         if(order==NULL) continue;
         m_list_all_orders.InsertSort(order);
        }
     }
//---
   int delta_order=i-m_index_order;
   this.m_index_order=i;
   this.m_delta_order=delta_order;
   this.m_is_trade_event=(this.m_delta_order!=0 ? true : false);
//--- __MQL5__
#else 
   if(!::HistorySelect(0,END_TIME)) return;
//--- Orders
   int total_orders=::HistoryOrdersTotal(),i=m_index_order;
   for(; i<total_orders; i++)
     {
      ulong order_ticket=::HistoryOrderGetTicket(i);
      if(order_ticket==0) continue;
      ENUM_ORDER_TYPE type=(ENUM_ORDER_TYPE)::HistoryOrderGetInteger(order_ticket,ORDER_TYPE);
      if(type==ORDER_TYPE_BUY || type==ORDER_TYPE_SELL)
        {
         CHistoryOrder *order=new CHistoryOrder(order_ticket);
         if(order==NULL) continue;
         m_list_all_orders.InsertSort(order);
        }
      else
        {
         CHistoryPending *order=new CHistoryPending(order_ticket);
         if(order==NULL) continue;
         m_list_all_orders.InsertSort(order);
        }
     }
//--- save the index of the last added order and the difference as compared to the previous check
   int delta_order=i-this.m_index_order;
   this.m_index_order=i;
   this.m_delta_order=delta_order;
   
//--- Deals
   int total_deals=::HistoryDealsTotal(),j=m_index_deal;
   for(; j<total_deals; j++)
     {
      ulong deal_ticket=::HistoryDealGetTicket(j);
      if(deal_ticket==0) continue;
      CHistoryDeal *deal=new CHistoryDeal(deal_ticket);
      if(deal==NULL) continue;
      m_list_all_orders.InsertSort(deal);
     }
//--- save the index of the last added deal and the difference as compared to the previous check
   int delta_deal=j-this.m_index_deal;
   this.m_index_deal=j;
   this.m_delta_deal=delta_deal;
//--- Set the new event flag in history
   this.m_is_trade_event=(this.m_delta_order+this.m_delta_deal);
#endif 
  }
//+------------------------------------------------------------------+

Còn tiếp…