Sở hữu ngay máy chủ VPS Robot Forex khi giao dịch tại HotForex

Mục lục:

Giới thiệu

Trong khi phân tích một số lượng lớn chiến lược giao dịch, các đơn đặt hàng phát triển ứng dụng cho thiết bị đầu cuối MetaTrader 5 / MetaTrader 4 và các trang web khác nhau liên quan đến tập lệnh, chỉ báo và robot cho MetaTrader, tôi đã đi đến kết luận rằng tất cả sự đa dạng này chủ yếu dựa trên cùng các chức năng cơ bản, hành động và giá trị xuất hiện thường xuyên trong các chương trình khác nhau.

Trong thực tế, logic của bất kỳ chương trình nào cũng có thể được chia thành nhiều hành động giống hệt nhau. Kết quả của những hành động này được sử dụng để xây dựng logic của các ứng dụng. Điều này đã được xác nhận nhiều lần bởi tính đồng nhất của các câu hỏi được hỏi trên các diễn đàn MQL4/MQL5. Những người dùng khác nhau hỏi về cơ bản cùng một câu hỏi về các thuật toán và nhiệm vụ họ giải quyết.

Khái niệm

Bất kỳ loại dữ liệu nào cũng có thể được biểu diễn dưới dạng một tập hợp các đối tượng có cùng thuộc tính.

Ví dụ, một khung thời gian có thể được biểu diễn dưới dạng một danh sách dài, mỗi ô tiếp theo lưu trữ một đối tượng có một tập các thuộc tính cùng loại với tất cả các tập hợp khác thuộc về các đối tượng tương tự trong các mốc thời gian. Dữ liệu của một đối tượng như vậy được biểu thị bằng cấu trúc MqlRates:

Cấu trúc để lưu trữ prices, volumes và spread.

struct MqlRates 
  { 
   datetime time;         // period start time 
   double   open;         // open price 
   double   high;         // highest price per period 
   double   low;          // lowest price per period 
   double   close;        // close price 
   long     tick_volume;  // tick volume 
   int      spread;       // spread 
   long     real_volume;  // exchange volume 
  };

Một tập hợp dữ liệu đánh dấu cũng có thể được mô tả như một danh sách có thứ tự trong đó một đánh dấu được biểu thị bởi cấu trúc MqlTick là một đối tượng với một tập các thuộc tính cố định:

Cấu trúc để lưu trữ giá cuối cùng bằng ký hiệu – symbol. Cấu trúc được thiết kế để có được dữ liệu cần thiết nhất về giá hiện tại một cách kịp thời.

struct MqlTick 
  { 
   datetime     time;          // Last price update time 
   double       bid;           // Current Bid price 
   double       ask;           // Current Ask price 
   double       last;          // Current price of the last deal (Last) 
   ulong        volume;        // Volume for the current Last price 
   long         time_msc;      // Time of the last price update in milliseconds 
   uint         flags;         // Tick flags 
   double       volume_real;   // Volume for the current Last price with increased accuracy 
  };

Bất kỳ dữ liệu nào khác cần thiết để phân tích và chuẩn bị logic chương trình cũng được sắp xếp dưới dạng danh sách đối tượng đơn giản.

Tất cả các đối tượng trong một danh sách sẽ có cùng loại dữ liệu cụ thể cho loại đối tượng này bất kể đó là danh sách các đơn đặt hàng, giao dịch hoặc đơn đặt hàng đang chờ xử lý. Đối với mỗi đối tượng cụ thể, chúng ta sẽ phát triển một lớp có chức năng tối thiểu cần thiết để lưu trữ, sắp xếp và hiển thị dữ liệu.

An toàn & bảo mật vốn đầu tư tại HotForex

Cấu trúc dữ liệu thư viện

Như đã đề cập, thư viện bao gồm danh sách đối tượng và cung cấp khả năng chọn bất kỳ mục nào trong danh sách theo bất kỳ tiêu chí tùy chỉnh hoặc thuộc tính nào được đối tượng đó hỗ trợ. Thư viện sẽ tự thu thập dữ liệu cần thiết để lưu trữ và xử lý. Không cần sự can thiệp của con người. Người dùng sẽ chỉ áp dụng kết quả của các truy vấn thư viện của họ.

Tôi sẽ mô tả tất cả các bước phát triển thư viện bắt đầu với các chủ đề đơn giản nhất và dần dần thêm chức năng và dữ liệu mới vào cái đã có. Thư viện sẽ được phát triển ở chế độ ‘trực tiếp’. Yêu cầu chỉnh sửa và bổ sung sẽ được thực hiện trong mỗi bài viết. Tôi tin rằng, phong cách trình bày này là hữu ích nhất vì nó liên quan đến độc giả vào sự phát triển.
Cấu trúc tối thiểu của dữ liệu thư viện là một tập hợp các đối tượng khác nhau để mô tả các thuộc tính của dữ liệu cần thiết, trong khi các bộ sưu tập dữ liệu là danh sách lưu trữ các đối tượng tương ứng.

Chúng ta sẽ sử dụng lớp của mảng động của con trỏ tới các thể hiện của lớp CObject và các lớp dẫn xuất của nó từ bộ sưu tập dữ liệu thư viện chuẩn để sắp xếp các danh sách. Vì các đối tượng của lớp cơ sở của thư viện chuẩn CObject là bắt buộc để lưu trữ trong danh sách như vậy, nên chúng ta sẽ chỉ kế thừa từng lớp đối tượng của chúng ta từ lớp cơ sở CObject.

Ví dụ đầu tiên với thư viện

Đầu tiên, chúng ta sẽ phát triển thư viện cho các tài khoản phòng hộ – hedge của thiết bị đầu cuối MetaTrader 5. Sau khi chuẩn bị chức năng tối thiểu, chúng ta sẽ điều chỉnh hoạt động của nó thành MetaTrader 4. Tiếp theo, sau khi triển khai lịch sử tài khoản, vị trí thị trường hiện tại và xử lý đơn đặt hàng đang chờ xử lý, chúng ta sẽ thêm khả năng hoạt động với tài khoản lưới MetaTrader 5. Cuối cùng, chúng ta sẽ lấp đầy thư viện với một loạt các chức năng.

Hãy bắt đầu với lịch sử tài khoản. Nhiều chiến lược áp dụng kết quả của các giao dịch trong quá khứ bằng cách này hay cách khác, ví dụ, kết quả của các giao dịch trước đó, phương thức đóng cửa của họ (dừng lỗ, chốt lời), giá cả, v.v. Bên cạnh đó, có thể sử dụng kết quả cho ngày cuối cùng Như một điểm khởi đầu cho công việc hiện tại. Các loại chiến lược giao dịch là vô hạn, và nhiệm vụ của chúng ta là cung cấp quyền truy cập nhanh vào tất cả sự đa dạng.

Trước tiên, hãy xác định thuật ngữ để làm việc với các bộ sưu tập các đơn đặt hàng, giao dịch, lệnh thị trường và vị trí lịch sử. Hệ thống đặt hàng MetaTrader 4 khác với hệ thống MetaTrader 5. Mặc dù MetaTrader 4 có tính năng thị trường và các đơn đặt hàng đang chờ xử lý, nhưng trong MetaTrader 5, một đơn hàng về cơ bản là một yêu cầu giao dịch (lệnh thị trường) tạo ra một giao dịch, trong khi giao dịch lần lượt tạo ra một vị thế. Bên cạnh đó, có những đơn đặt hàng đang chờ xử lý. Nói cách khác, chúng ta có ít nhất ba đối tượng – một mệnh lệnh, một thỏa thuận và một vị trí. Để tránh bị phân tâm bởi các tên và định nghĩa, hãy gọi lớp để lưu trữ dữ liệu theo đơn đặt hàng, giao dịch và vị trí chỉ đơn giản là một lớp thứ tự trừu tượng. Hơn nữa, mọi thứ sẽ được sắp xếp theo loại (đơn đặt hàng, giao dịch, v.v.) trong danh sách của chúng ta (bộ sưu tập các đơn đặt hàng lịch sử được đề cập ở đầu bài viết).

Lớp trừu tượng đơn hàng là để chứa một đơn đặt hàng hoặc vé thỏa thuận, cũng như toàn bộ dữ liệu về các tham số của đơn đặt hàng hoặc giao dịch và trạng thái của đơn hàng. Trạng thái hiển thị chính xác đối tượng là gì – một đơn đặt hàng, giao dịch hoặc vị trí.
Trong thư mục dữ liệu đầu cuối \\MQL5\\ Bao gồm, hãy tạo thư mục Do EAS nơi lưu trữ các tệp thư viện. Ở giai đoạn này, chúng ta sẽ cần thêm hai thư mục trong thư mục Do EAS: thư mục Đối tượng sẽ lưu trữ các lớp đối tượng, trong khi Bộ sưu tập sẽ chứa các bộ sưu tập dữ liệu (danh sách đối tượng).
Để tìm thư mục dữ liệu đầu cuối, hãy chuyển đến Tệp – Thư mục dữ liệu mở (Ctrl + Shift + D).

Bây giờ chúng ta có thể tạo lớp đầu tiên (lớp thứ tự trừu tượng). Tạo một lớp mới trong thư mục Đối tượng và đặt tên là COrder (1). Đảm bảo đặt lớp CObject (2) của thư viện chuẩn làm cơ sở. Trong trường hợp này, lớp đối tượng mới của chúng ta được kế thừa từ lớp CObject và nó có thể được đặt trong danh sách các đối tượng CArrayObj của thư viện chuẩn.

Sau khi nhấp vào Kết thúc, tệp Order.mqh (3) mới xuất hiện trong thư mục Đối tượng của thư mục thư viện. Hiện tại, đây chỉ là một tác phẩm của lớp:

//+------------------------------------------------------------------+
//|                                                        Order.mqh |
//|                                  Copyright 2019, Forex 365 Crop. |
//|                                              https://forex365.vn |
//+------------------------------------------------------------------+
#property copyright "Copyright 2019, Forex 365 Corp."
#property link      "https://forex365.vn"
#property version   "1.00"
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class COrder : public CObject
  {
private:

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

Khi cố gắng biên dịch mã, chúng ta nhận được năm lỗi. Chúng chỉ ra sự vắng mặt của lớp CObject, lớp COrder có nguồn gốc từ. Bao gồm tệp lớp CObject vào danh sách và biên dịch lại một lần nữa. Bây giờ mọi thứ đều ổn.

//+------------------------------------------------------------------+
//|                                                        Order.mqh |
//|                                  Copyright 2019, Forex 365 Crop. |
//|                                              https://forex365.vn |
//+------------------------------------------------------------------+
#property copyright "Copyright 2019, Forex 365 Corp."
#property link      "https://forex365.vn"
#property version   "1.00"
#include <Object.mqh>
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class COrder : public CObject
  {
private:

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

Đối tượng của lớp được tạo trong một vòng lặp theo đơn đặt hàng, giao dịch hoặc vị trí khi thứ tự, giao dịch hoặc vị trí tiếp theo được chọn. Để khởi tạo các trường của đối tượng ngay lập tức, chúng ta sẽ tạo một hàm tạo riêng, loại đối tượng (trạng thái) và vé được chuyển đến để nhận dạng tiếp theo. Nhưng trước tiên, hãy đặt Defines.mqh mới bao gồm tệp vào thư mục gốc của dự án, nơi lưu trữ tất cả các liệt kê cần thiết cho thư viện, cũng như thay thế macro, hằng và cấu trúc.

//+------------------------------------------------------------------+
//|                                                      Defines.mqh |
//|                                  Copyright 2019, Forex 365 Crop. |
//|                                              https://forex365.vn |
//+------------------------------------------------------------------+
#property copyright "Copyright 2019, Forex 365 Corp."
#property link      "https://forex365.vn"
//+------------------------------------------------------------------+
//| Abstract order type (status)                                     |
//+------------------------------------------------------------------+
enum ENUM_ORDER_STATUS
  {
   ORDER_STATUS_MARKET_PENDING,                             // Current pending order
   ORDER_STATUS_MARKET_ACTIVE,                              // Active market order
   ORDER_STATUS_HISTORY_ORDER,                              // History market order
   ORDER_STATUS_HISTORY_PENDING,                            // Removed pending order
   ORDER_STATUS_BALANCE,                                    // Balance operation
   ORDER_STATUS_CREDIT,                                     // Credit operation
   ORDER_STATUS_DEAL,                                       // Deal
   ORDER_STATUS_UNKNOWN                                     // Unknown status
  };
//+------------------------------------------------------------------+
//| Order, deal, position integer properties                         |
//+------------------------------------------------------------------+
enum ENUM_ORDER_PROP_INTEGER
  {
   ORDER_PROP_TICKET = 0,                                   // Order ticket
   ORDER_PROP_MAGIC,                                        // Order magic
   ORDER_PROP_TIME_OPEN,                                    // Open time
   ORDER_PROP_TIME_CLOSE,                                   // Close time
   ORDER_PROP_TIME_EXP,                                     // Order expiration date (for pending orders)
   ORDER_PROP_TYPE,                                         // Order and deal type
   ORDER_PROP_STATUS,                                       // Order status (from the ENUM_ORDER_STATUS enumeration)
   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, based on which a deal is executed
   ORDER_PROP_DEAL_ENTRY,                                   // Deal direction – IN, OUT or IN/OUT
   ORDER_PROP_TIME_OPEN_MSC,                                // Open time in milliseconds
   ORDER_PROP_TIME_CLOSE_MSC,                               // Close time in milliseconds (execution or removal time - ORDER_TIME_DONE_MSC)
   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
   ORDER_PROP_DIRECTION,                                    // Direction (Buy, Sell)
  }; 
#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_PROFIT,                                       // Profit
   ORDER_PROP_COMMISSION,                                   // Commission
   ORDER_PROP_SWAP,                                         // Swap
   ORDER_PROP_VOLUME,                                       // Volume
   ORDER_PROP_VOLUME_CURRENT,                               // Unexecuted volume
   ORDER_PROP_SL,                                           // StopLoss price
   ORDER_PROP_TP,                                           // TakeProfit price
   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
//+------------------------------------------------------------------+

Một số tài sản cũng được đặt vào bảng liệt kê: vé đặt hàng mẹ, vé đặt hàng xuất phát, lợi nhuận theo điểm, tài sản đóng cửa bằng cách dừng lỗ hoặc chốt lãi, định hướng và lợi nhuận đầy đủ – xem xét hoa hồng và hoán đổi. Những dữ liệu này thường được sử dụng trong logic chiến lược giao dịch, vì vậy chúng nên được lưu trữ trong các trường thứ tự trừu tượng, cũng như được cập nhật và nhận trong các chương trình tùy chỉnh ngay lập tức.
Để kết hợp tất cả các thuộc tính thứ tự (số nguyên, số thực và chuỗi), tạo các thay thế macro chứa số lượng tham số trong mỗi ba kiểu liệt kê cho mỗi loại thuộc tính.
Việc đánh số liệt kê các thuộc tính số nguyên bắt đầu từ 0, trong khi việc đánh số các liệt kê của các thuộc tính khác bắt đầu bằng tổng số thuộc tính trước đó. Do đó, chúng ta luôn có thể lấy chỉ số của tài sản mà chúng ta cần là sự khác biệt giữa số lượng tài sản được yêu cầu và số tài sản ban đầu của bảng liệt kê này.
Sau khi tạo tệp Defines.mqh, hãy kết nối nó với tệp hiện tại của lớp COrder và tạo trong phần riêng tư biến thành viên lớp để lưu trữ phiếu đặt hàng và ba mảng để lưu trữ các thuộc tính thứ tự số nguyên, thực và chuỗi:

//+------------------------------------------------------------------+
//|                                                        Order.mqh |
//|                                  Copyright 2019, Forex 365 Crop. |
//|                                              https://forex365.vn |
//+------------------------------------------------------------------+
#property copyright "Copyright 2019, Forex 365 Corp."
#property link      "https://forex365.vn"
#property version   "1.00"
#include <Object.mqh>
#include "..\Defines.mqh"
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class COrder : public CObject
  {
private:
   ulong             m_ticket;                                 // Selected order/deal ticket (MQL5)
   long              m_long_prop[ORDER_PROP_INTEGER_TOTAL];    // Integer properties
   double            m_double_prop[ORDER_PROP_DOUBLE_TOTAL];   // Real properties
   string            m_string_prop[ORDER_PROP_STRING_TOTAL];   // String properties
public:
                     COrder();
                    ~COrder();
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
COrder::COrder()
  {
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
COrder::~COrder()
  {
  }
//+------------------------------------------------------------------+

Để bao gồm tệp Defines.mqh, chúng ta đặt đường dẫn tương đối đến tệp trong dấu ngoặc kép thay vì áp dụng dấu ngoặc nhọn mà chúng ta đã sử dụng khi bao gồm CObject. Điều này được thực hiện để khi chuyển thư viện sang bất kỳ thư mục nào khác, kết nối giữa các tệp không bị mất và luôn đề cập đến vị trí của tệp Defines.mqh so với thư mục hiện tại.

Bây giờ, hãy tạo hai phương thức trong cùng một phần riêng tư. Cái đầu tiên là trả về một vị trí chính xác của thuộc tính cần thiết trong mảng thuộc tính, trong khi cái thứ hai là trả về một hàm tạo được bảo vệ trong phần được bảo vệ tương ứng. Để lại hàm tạo mặc định để tạo một đối tượng thứ tự trống mà không khởi tạo các thuộc tính của nó và loại bỏ hàm hủy (chúng ta không cần nó và nó sẽ được tạo tự động trong quá trình biên dịch):

//+------------------------------------------------------------------+
//|                                                        Order.mqh |
//|                                  Copyright 2019, Forex 365 Crop. |
//|                                              https://forex365.vn |
//+------------------------------------------------------------------+
#property copyright "Copyright 2019, Forex 365 Corp."
#property link      "https://forex365.vn"
#property version   "1.00"
#include <Object.mqh>
#include "..\Defines.mqh"
//+------------------------------------------------------------------+
//| Abstract order class                                             |
//+------------------------------------------------------------------+
class COrder : public CObject
  {
private:
   ulong             m_ticket;                                    // Selected order/deal ticket (MQL5)
   long              m_long_prop[ORDER_PROP_INTEGER_TOTAL];       // Integer properties
   double            m_double_prop[ORDER_PROP_DOUBLE_TOTAL];      // Real properties
   string            m_string_prop[ORDER_PROP_STRING_TOTAL];      // String properties
   
   //--- Return the array index the double property is actually located at
   int               IndexProp(ENUM_ORDER_PROP_DOUBLE property)   const { return (int)property-ORDER_PROP_INTEGER_TOTAL;                  }
   //--- Return the array index the string property is actually located at
   int               IndexProp(ENUM_ORDER_PROP_STRING property)   const { return (int)property-ORDER_PROP_INTEGER_TOTAL-ORDER_PROP_DOUBLE_TOTAL;}
public:
   //--- Default constructor
                     COrder(void){;}
protected:                                                                     
   //--- Protected parametric constructor                                
                     COrder(ENUM_ORDER_STATUS order_status,const ulong ticket);
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
COrder::COrder(ENUM_ORDER_STATUS order_status,const ulong ticket)
  {
  }
//+------------------------------------------------------------------+

Cho đến nay, các nhà xây dựng được bảo vệ không làm gì. Nó sẽ được sử dụng để khởi tạo ngay lập tức tất cả các thuộc tính của đơn hàng, vé được chuyển đến hàm tạo của lớp, khi tạo một đối tượng. Vì thứ tự đã được chọn, chúng ta có thể có được các thuộc tính cần thiết của một thứ tự đã chọn và ghi chúng vào các mảng của các thuộc tính đối tượng. Chúng ta sẽ thực hiện việc này muộn hơn một chút sau khi tạo phương thức nhận và trả lại dữ liệu đơn hàng.

Vì đây là một thư viện đa nền tảng, sẽ thuận tiện hơn để tạo các phương thức riêng biệt để có được các thuộc tính đơn hàng.
Trong phần được bảo vệ, thêm mô tả về các phương thức để nhận các thuộc tính số nguyên, thực và chuỗi của một đơn hàng đã chọn.

//+------------------------------------------------------------------+
//|                                                        Order.mqh |
//|                                  Copyright 2019, Forex 365 Crop. |
//|                                              https://forex365.vn |
//+------------------------------------------------------------------+
#property copyright "Copyright 2019, Forex 365 Corp."
#property link      "https://forex365.vn"
#property version   "1.00"
#include <Object.mqh>
#include "..\Defines.mqh"
//+------------------------------------------------------------------+
//| Abstract order class                                             |
//+------------------------------------------------------------------+
class COrder : public CObject
  {
private:
   ulong             m_ticket;                                    // Selected order/deal ticket (MQL5)
   long              m_long_prop[ORDER_PROP_INTEGER_TOTAL];       // Integer properties
   double            m_double_prop[ORDER_PROP_DOUBLE_TOTAL];      // Real properties
   string            m_string_prop[ORDER_PROP_STRING_TOTAL];      // String properties
   
   //--- Return the index of the array the double property is actually located at
   int               IndexProp(ENUM_ORDER_PROP_DOUBLE property)   const { return (int)property-ORDER_PROP_INTEGER_TOTAL;                        }
   //--- Return the index of the array the string property is actually located at
   int               IndexProp(ENUM_ORDER_PROP_STRING property)   const { return (int)property-ORDER_PROP_INTEGER_TOTAL-ORDER_PROP_DOUBLE_TOTAL;}
public:
   //--- Default constructor
                     COrder(void){;}
protected:
   //--- Protected parametric constructor
                     COrder(ENUM_ORDER_STATUS order_status,const ulong ticket);
                     
   //--- Get and return integer properties of a selected order from its parameters
   long              OrderMagicNumber(void)        const;
   long              OrderTicket(void)             const;
   long              OrderTicketFrom(void)         const;
   long              OrderTicketTo(void)           const;
   long              OrderPositionID(void)         const;
   long              OrderPositionByID(void)       const;
   long              OrderOpenTimeMSC(void)        const;
   long              OrderCloseTimeMSC(void)       const;
   long              OrderType(void)               const;
   long              OrderTypeByDirection(void)    const;
   long              OrderTypeFilling(void)        const;
   long              OrderTypeTime(void)           const;
   long              OrderReason(void)             const;
   long              DealOrder(void)               const;
   long              DealEntry(void)               const;
   bool              OrderCloseByStopLoss(void)    const;
   bool              OrderCloseByTakeProfit(void)  const;
   datetime          OrderOpenTime(void)           const;
   datetime          OrderCloseTime(void)          const;
   datetime          OrderExpiration(void)         const;
   datetime          PositionTimeUpdate(void)      const;
   datetime          PositionTimeUpdateMSC(void)   const;
   
   //--- Get and return real properties of a selected order from its parameters: (1) open price, (2) close price, (3) profit,
   //---  (4) commission, (5) swap, (6) volume, (7) unexecuted volume (8) StopLoss price, (9) TakeProfit price (10) StopLimit order price
   double            OrderOpenPrice(void)          const;
   double            OrderClosePrice(void)         const;
   double            OrderProfit(void)             const;
   double            OrderCommission(void)         const;
   double            OrderSwap(void)               const;
   double            OrderVolume(void)             const;
   double            OrderVolumeCurrent(void)      const;
   double            OrderStopLoss(void)           const;
   double            OrderTakeProfit(void)         const;
   double            OrderPriceStopLimit(void)     const;
   
   //--- Get and return string properties of a selected order from its parameters: (1) symbol, (2) comment, (3) ID at an exchange
   string            OrderSymbol(void)             const;
   string            OrderComment(void)            const;
   string            OrderExternalID(void)         const;
   
//---
  };
//+------------------------------------------------------------------+
//| Closed parametric constructor                                    |
//+------------------------------------------------------------------+
COrder::COrder(ENUM_ORDER_STATUS order_status,const ulong ticket)
  {
  }
//+------------------------------------------------------------------+

Hiện tại, chỉ có các phương thức nhận tài sản đã được khai báo. Chúng chưa được thực hiện, mặc dù lớp được biên dịch không có lỗi. Mảng thuộc tính thứ tự sẽ được điền vào hàm tạo của lớp bằng các phương thức chúng ta vừa thêm. Khi tất cả đã sẵn sàng, các mảng này sẽ cho phép chúng ta có được trong chương trình bất kỳ tài sản nào theo yêu cầu.

Phương thức ảo so sánh các đối tượng theo các thuộc tính được chỉ định được khai báo trong lớp CObject của thư viện chuẩn. Tuy nhiên, phương thức nên được thực hiện trong các lớp con. Do đó, hãy thêm vào lớp thứ tự trừu tượng phương thức để so sánh các đối tượng COrder theo bất kỳ thuộc tính nào của nó, cũng như một số phương thức công khai để truy cập các thuộc tính đơn hàng và các phương thức ảo trả về các cờ để hỗ trợ thuộc tính cụ thể của đối tượng đơn hàng. Các phương thức này sẽ được thực hiện trong các đối tượng hậu duệ của lớp COrder. Điều này sẽ được yêu cầu sau này để chọn các đơn đặt hàng từ danh sách bộ sưu tập bởi bất kỳ thuộc tính nào của chúng. Theo mặc định, nếu bất kỳ phương thức nào trong số các phương thức này không được triển khai trong lớp con cháu, cờ cho biết sự hỗ trợ của đơn hàng cho thuộc tính đó được trả về.

//+------------------------------------------------------------------+
//|                                                        Order.mqh |
//|                                  Copyright 2019, Forex 365 Crop. |
//|                                              https://forex365.vn |
//+------------------------------------------------------------------+
#property copyright "Copyright 2019, Forex 365 Corp."
#property link      "https://forex365.vn"
#property version   "1.00"
#include <Object.mqh>
#include "..\Defines.mqh"
//+------------------------------------------------------------------+
//| Abstract order class                                             |
//+------------------------------------------------------------------+
class COrder : public CObject
  {
private:
   ulong             m_ticket;                                    // Selected order/deal ticket (MQL5)
   long              m_long_prop[ORDER_PROP_INTEGER_TOTAL];       // Integer properties
   double            m_double_prop[ORDER_PROP_DOUBLE_TOTAL];      // Real properties
   string            m_string_prop[ORDER_PROP_STRING_TOTAL];      // String properties
   
   //--- Return the index of the array the double property is actually located at
   int               IndexProp(ENUM_ORDER_PROP_DOUBLE property)   const { return (int)property-ORDER_PROP_INTEGER_TOTAL;                        }
   //--- Return the index of the array the string property is actually located at
   int               IndexProp(ENUM_ORDER_PROP_STRING property)   const { return (int)property-ORDER_PROP_INTEGER_TOTAL-ORDER_PROP_DOUBLE_TOTAL;}
public:
   //--- Default constructor
                     COrder(void){;}
protected:
   //--- Protected parametric constructor
                     COrder(ENUM_ORDER_STATUS order_status,const ulong ticket);
                     
   //--- Get and return integer properties of a selected order from its parameters
   long              OrderMagicNumber(void)        const;
   long              OrderTicket(void)             const;
   long              OrderTicketFrom(void)         const;
   long              OrderTicketTo(void)           const;
   long              OrderPositionID(void)         const;
   long              OrderPositionByID(void)       const;
   long              OrderOpenTimeMSC(void)        const;
   long              OrderCloseTimeMSC(void)       const;
   long              OrderType(void)               const;
   long              OrderTypeByDirection(void)    const;
   long              OrderTypeFilling(void)        const;
   long              OrderTypeTime(void)           const;
   long              OrderReason(void)             const;
   long              DealOrder(void)               const;
   long              DealEntry(void)               const;
   bool              OrderCloseByStopLoss(void)    const;
   bool              OrderCloseByTakeProfit(void)  const;
   datetime          OrderOpenTime(void)           const;
   datetime          OrderCloseTime(void)          const;
   datetime          OrderExpiration(void)         const;
   datetime          PositionTimeUpdate(void)      const;
   datetime          PositionTimeUpdateMSC(void)   const;
   
   //--- Get and return real properties of a selected order from its parameters: (1) open price, (2) close price, (3) profit,
   //---  (4) commission, (5) swap, (6) volume, (7) unexecuted volume (8) StopLoss price, (9) TakeProfit price (10) StopLimit order price
   double            OrderOpenPrice(void)          const;
   double            OrderClosePrice(void)         const;
   double            OrderProfit(void)             const;
   double            OrderCommission(void)         const;
   double            OrderSwap(void)               const;
   double            OrderVolume(void)             const;
   double            OrderVolumeCurrent(void)      const;
   double            OrderStopLoss(void)           const;
   double            OrderTakeProfit(void)         const;
   double            OrderPriceStopLimit(void)     const;
   
   //--- Get and return string properties of a selected order from its parameters: (1) symbol, (2) comment, (3) ID at an exchange
   string            OrderSymbol(void)             const;
   string            OrderComment(void)            const;
   string            OrderExternalID(void)         const;
   
public:
   //--- Return (1) integer, (2) real and (3) string order properties from the property array
   long              GetProperty(ENUM_ORDER_PROP_INTEGER property)      const { return m_long_prop[property];                    }
   double            GetProperty(ENUM_ORDER_PROP_DOUBLE property)       const { return m_double_prop[this.IndexProp(property)];  }
   string            GetProperty(ENUM_ORDER_PROP_STRING property)       const { return m_string_prop[this.IndexProp(property)];  }
   
   //--- Return the flag of the order supporting the property
   virtual bool      SupportProperty(ENUM_ORDER_PROP_INTEGER property)        { return true; }
   virtual bool      SupportProperty(ENUM_ORDER_PROP_DOUBLE property)         { return true; }
   virtual bool      SupportProperty(ENUM_ORDER_PROP_STRING property)         { return true; }
   
   //--- Compare COrder objects by all possible properties
   virtual int       Compare(const CObject *node,const int mode=0) const;
   
//---
  };
//+------------------------------------------------------------------+
//| Closed parametric constructor                                    |
//+------------------------------------------------------------------+
COrder::COrder(ENUM_ORDER_STATUS order_status,const ulong ticket)
  {
  }
//+------------------------------------------------------------------+

Thực hiện phương pháp so sánh hai đơn hàng theo một thuộc tính được chỉ định:

//+------------------------------------------------------------------+
//| Compare COrder objects by all possible properties                |
//+------------------------------------------------------------------+
int COrder::Compare(const CObject *node,const int mode=0) const
  {
   const COrder *order_compared=node;
//--- compare integer properties of two orders
   if(mode<ORDER_PROP_INTEGER_TOTAL)
     {
      long value_compared=order_compared.GetProperty((ENUM_ORDER_PROP_INTEGER)mode);
      long value_current=this.GetProperty((ENUM_ORDER_PROP_INTEGER)mode);
      return(value_current>value_compared ? 1 : value_current<value_compared ? -1 : 0);
     }
//--- compare real properties of two orders
   else if(mode<ORDER_PROP_DOUBLE_TOTAL+ORDER_PROP_INTEGER_TOTAL)
     {
      double value_compared=order_compared.GetProperty((ENUM_ORDER_PROP_DOUBLE)mode);
      double value_current=this.GetProperty((ENUM_ORDER_PROP_DOUBLE)mode);
      return(value_current>value_compared ? 1 : value_current<value_compared ? -1 : 0);
     }
//--- compare string properties of two orders
   else if(mode<ORDER_PROP_DOUBLE_TOTAL+ORDER_PROP_INTEGER_TOTAL+ORDER_PROP_STRING_TOTAL)
     {
      string value_compared=order_compared.GetProperty((ENUM_ORDER_PROP_STRING)mode);
      string value_current=this.GetProperty((ENUM_ORDER_PROP_STRING)mode);
      return(value_current>value_compared ? 1 : value_current<value_compared ? -1 : 0);
     }
   return 0;
  }
//+------------------------------------------------------------------+

Phương thức nhận con trỏ tới đối tượng thứ tự có thuộc tính nên được so sánh với một giá trị nhất định, cũng như chính giá trị từ phép liệt kê thuộc tính thứ tự.
Nếu giá trị đơn hàng vượt quá giá trị so sánh, hệ thống trả về 1, nếu nó nhỏ hơn giá trị so sánh, hệ thống trả về -1, nếu không – 0. Danh sách các đơn hàng được thực hiện so sánh được sắp xếp sơ bộ theo thuộc tính so sánh.

Bây giờ, hãy thực hiện các phương thức để nhận các thuộc tính đơn hàng và ghi chúng vào các mảng thuộc tính. Đây là những phương pháp đã được khai báo trước đó trong phần riêng tư. Vì các phương thức nhận thuộc tính đơn hàng là đa nền tảng, hãy phân tích chúng bằng cách sử dụng số ma thuật EA làm ví dụ:

//+------------------------------------------------------------------+
//| Return magic number                                              |
//+------------------------------------------------------------------+
long COrder::OrderMagicNumber() const
  {
#ifdef __MQL4__
   return ::OrderMagicNumber();
#else
   long res=0;
   switch((ENUM_ORDER_STATUS)this.GetProperty(ORDER_PROP_STATUS))
     {
      case ORDER_STATUS_MARKET_ACTIVE     : res=::PositionGetInteger(POSITION_MAGIC);           break;
      case ORDER_STATUS_MARKET_PENDING    : res=::OrderGetInteger(ORDER_MAGIC);                 break;
      case ORDER_STATUS_DEAL              : res=::HistoryDealGetInteger(m_ticket,DEAL_MAGIC);   break;
      case ORDER_STATUS_HISTORY_PENDING   :
      case ORDER_STATUS_HISTORY_ORDER     : res=::HistoryOrderGetInteger(m_ticket,ORDER_MAGIC); break;
      default                             : res=0;                                              break;
     }
   return res;
#endif
  }
//+------------------------------------------------------------------+

Nếu đây là mã cho MQL4, số ma thuật được trả về bởi hàm MQL5 OrderMagicNumber(). Nếu không, hãy kiểm tra trạng thái đơn hàng. Tùy thuộc vào những gì chúng ta đang giải quyết, trả lại một vị trí, một đơn đặt hàng hoặc một số ma thuật thỏa thuận.

Các phương pháp còn lại để đọc và viết các thuộc tính của một thứ tự/thỏa thuận/vị trí được tô sáng được thực hiện theo cùng một cách. Bạn có thể tự mình phân tích chúng.

Các phương thức để có được các thuộc tính số thứ tự/giao dịch/vị trí:

//+------------------------------------------------------------------+
//| Return the ticket                                                |
//+------------------------------------------------------------------+
long COrder::OrderTicket(void) const
  {
#ifdef __MQL4__
   return ::OrderTicket();
#else
   long res=0;
   switch((ENUM_ORDER_STATUS)this.GetProperty(ORDER_PROP_STATUS))
     {
      case ORDER_STATUS_MARKET_ACTIVE     :
      case ORDER_STATUS_MARKET_PENDING    :
      case ORDER_STATUS_HISTORY_PENDING   :
      case ORDER_STATUS_HISTORY_ORDER     :
      case ORDER_STATUS_DEAL              : res=(long)m_ticket;                                 break;
      default                             : res=0;                                              break;
     }
   return res;
#endif
  }
//+------------------------------------------------------------------+
//| Return the parent order ticket                                   |
//+------------------------------------------------------------------+
long COrder::OrderTicketFrom(void) const
  {
   long ticket=0;
#ifdef __MQL4__
   string order_comment=::OrderComment();
   if(::StringFind(order_comment,"from #")>WRONG_VALUE) ticket=::StringToInteger(::StringSubstr(order_comment,6));
#endif
   return ticket;
  }
//+------------------------------------------------------------------+
//| Return the child order ticket                                    |
//+------------------------------------------------------------------+
long COrder::OrderTicketTo(void) const
  {
   long ticket=0;
#ifdef __MQL4__
   string order_comment=::OrderComment();
   if(::StringFind(order_comment,"to #")>WRONG_VALUE) ticket=::StringToInteger(::StringSubstr(order_comment,4));
#endif
   return ticket;
  }
//+------------------------------------------------------------------+
//| Return position ID                                               |
//+------------------------------------------------------------------+
long COrder::OrderPositionID(void) const
  {
#ifdef __MQL4__
   return ::OrderMagicNumber();
#else
   long res=0;
   switch((ENUM_ORDER_STATUS)this.GetProperty(ORDER_PROP_STATUS))
     {
      case ORDER_STATUS_MARKET_ACTIVE     : res=::PositionGetInteger(POSITION_IDENTIFIER);            break;
      case ORDER_STATUS_MARKET_PENDING    : res=::OrderGetInteger(ORDER_POSITION_ID);                 break;
      case ORDER_STATUS_HISTORY_PENDING   :
      case ORDER_STATUS_HISTORY_ORDER     : res=::HistoryOrderGetInteger(m_ticket,ORDER_POSITION_ID); break;
      case ORDER_STATUS_DEAL              : res=::HistoryDealGetInteger(m_ticket,DEAL_POSITION_ID);   break;
      default                             : res=0;                                                    break;
     }
   return res;
#endif
  }
//+------------------------------------------------------------------+
//| Return the opposite position ID                                  |
//+------------------------------------------------------------------+
long COrder::OrderPositionByID(void) const
  {
#ifdef __MQL4__
   return 0;
#else
   long res=0;
   switch((ENUM_ORDER_STATUS)this.GetProperty(ORDER_PROP_STATUS))
     {
      case ORDER_STATUS_MARKET_PENDING    : res=::OrderGetInteger(ORDER_POSITION_BY_ID);                 break;
      case ORDER_STATUS_HISTORY_PENDING   :
      case ORDER_STATUS_HISTORY_ORDER     : res=::HistoryOrderGetInteger(m_ticket,ORDER_POSITION_BY_ID); break;
      default                             : res=0;                                                       break;
     }
   return res;
#endif
  }
//+------------------------------------------------------------------+
//| Return open time in milliseconds                                 |
//+------------------------------------------------------------------+
long COrder::OrderOpenTimeMSC(void) const
  {
#ifdef __MQL4__
   return (long)::OrderOpenTime();
#else
   long res=0;
   switch((ENUM_ORDER_STATUS)this.GetProperty(ORDER_PROP_STATUS))
     {
      case ORDER_STATUS_MARKET_ACTIVE     : res=::PositionGetInteger(POSITION_TIME_MSC);                 break;
      case ORDER_STATUS_MARKET_PENDING    : res=::OrderGetInteger(ORDER_TIME_SETUP_MSC);                 break;
      case ORDER_STATUS_HISTORY_PENDING   :
      case ORDER_STATUS_HISTORY_ORDER     : res=::HistoryOrderGetInteger(m_ticket,ORDER_TIME_SETUP_MSC); break;
      case ORDER_STATUS_DEAL              : res=::HistoryDealGetInteger(m_ticket,DEAL_TIME_MSC);         break;
      default                             : res=0;                                                       break;
     }
   return res;
#endif
  }
//+------------------------------------------------------------------+
//| Return close time in milliseconds                                |
//+------------------------------------------------------------------+
long COrder::OrderCloseTimeMSC(void) const
  {
#ifdef __MQL4__
   return (long)::OrderCloseTime();
#else
   long res=0;
   switch((ENUM_ORDER_STATUS)this.GetProperty(ORDER_PROP_STATUS))
     {
      case ORDER_STATUS_HISTORY_PENDING   :
      case ORDER_STATUS_HISTORY_ORDER     : res=::HistoryOrderGetInteger(m_ticket,ORDER_TIME_DONE_MSC);     break;
      case ORDER_STATUS_DEAL              : res=(datetime)::HistoryDealGetInteger(m_ticket,DEAL_TIME_MSC);  break;
      default                             : res=0;                                                          break;
     }
   return res;
#endif
  }
//+------------------------------------------------------------------+
//| Return the type                                                  |
//+------------------------------------------------------------------+
long COrder::OrderType(void) const
  {
#ifdef __MQL4__
   return (long)::OrderType();
#else
   long res=0;
   switch((ENUM_ORDER_STATUS)this.GetProperty(ORDER_PROP_STATUS))
     {
      case ORDER_STATUS_MARKET_ACTIVE     : res=::PositionGetInteger(POSITION_TYPE);            break;
      case ORDER_STATUS_MARKET_PENDING    : res=::OrderGetInteger(ORDER_TYPE);                  break;
      case ORDER_STATUS_HISTORY_PENDING   :
      case ORDER_STATUS_HISTORY_ORDER     : res=::HistoryOrderGetInteger(m_ticket,ORDER_TYPE);  break;
      case ORDER_STATUS_DEAL              : res=::HistoryDealGetInteger(m_ticket,DEAL_TYPE);    break;
      default                             : res=0;                                              break;
     }
   return res;
#endif
  }
//+------------------------------------------------------------------+
//| Return the type by direction                                     |
//+------------------------------------------------------------------+
long COrder::OrderTypeByDirection(void) const
  {
   ENUM_ORDER_STATUS status=(ENUM_ORDER_STATUS)this.GetProperty(ORDER_PROP_STATUS);
   if(status==ORDER_STATUS_MARKET_ACTIVE)
     {
      return(this.OrderType()==POSITION_TYPE_BUY ? ORDER_TYPE_BUY : ORDER_TYPE_SELL);
     }
   if(status==ORDER_STATUS_MARKET_PENDING || status==ORDER_STATUS_HISTORY_PENDING)
     {
      return
        (
         this.OrderType()==ORDER_TYPE_BUY_LIMIT || 
         this.OrderType()==ORDER_TYPE_BUY_STOP 
         #ifdef __MQL5__                        ||
         this.OrderType()==ORDER_TYPE_BUY_STOP_LIMIT 
         #endif ? 
         ORDER_TYPE_BUY : 
         ORDER_TYPE_SELL
        );
     }
   if(status==ORDER_STATUS_HISTORY_ORDER)
     {
      return this.OrderType();
     }
   return WRONG_VALUE;
  }
//+------------------------------------------------------------------+
//| Return execution type by residue                                 |
//+------------------------------------------------------------------+
long COrder::OrderTypeFilling(void) const
  {
#ifdef __MQL4__
   return (long)ORDER_FILLING_RETURN;
#else 
   long res=0;
   switch((ENUM_ORDER_STATUS)this.GetProperty(ORDER_PROP_STATUS))
     {
      case ORDER_STATUS_MARKET_PENDING    : res=::OrderGetInteger(ORDER_TYPE_FILLING);                break;
      case ORDER_STATUS_HISTORY_PENDING   :
      case ORDER_STATUS_HISTORY_ORDER     : res=::HistoryOrderGetInteger(m_ticket,ORDER_TYPE_FILLING);break;
      default                             : res=0;                                                    break;
     }
   return res;
#endif 
  }
//+------------------------------------------------------------------+
//| Return order lifetime                                            |
//+------------------------------------------------------------------+
long COrder::OrderTypeTime(void) const
  {
#ifdef __MQL4__
   return (long)ORDER_TIME_GTC;
#else 
   long res=0;
   switch((ENUM_ORDER_STATUS)this.GetProperty(ORDER_PROP_STATUS))
     {
      case ORDER_STATUS_MARKET_PENDING    : res=::OrderGetInteger(ORDER_TYPE_TIME);                break;
      case ORDER_STATUS_HISTORY_PENDING   :
      case ORDER_STATUS_HISTORY_ORDER     : res=::HistoryOrderGetInteger(m_ticket,ORDER_TYPE_TIME);break;
      default                             : res=0;                                                 break;
     }
   return res;
#endif 
  }
//+------------------------------------------------------------------+
//| Order reason or source                                           |
//+------------------------------------------------------------------+
long COrder::OrderReason(void) const
  {
#ifdef __MQL4__
   return
     (
      this.OrderCloseByStopLoss()   ?  ORDER_REASON_SL      :
      this.OrderCloseByTakeProfit() ?  ORDER_REASON_TP      :  
      this.OrderMagicNumber()!=0    ?  ORDER_REASON_EXPERT  : WRONG_VALUE
     );
#else 
   long res=WRONG_VALUE;
   switch((ENUM_ORDER_STATUS)this.GetProperty(ORDER_PROP_STATUS))
     {
      case ORDER_STATUS_MARKET_ACTIVE     : res=::PositionGetInteger(POSITION_REASON);          break;
      case ORDER_STATUS_MARKET_PENDING    : res=::OrderGetInteger(ORDER_REASON);                break;
      case ORDER_STATUS_HISTORY_PENDING   :
      case ORDER_STATUS_HISTORY_ORDER     : res=::HistoryOrderGetInteger(m_ticket,ORDER_REASON);break;
      case ORDER_STATUS_DEAL              : res=::HistoryDealGetInteger(m_ticket,DEAL_REASON);  break;
      default                             : res=WRONG_VALUE;                                    break;
     }
   return res;
#endif 
  }
//+------------------------------------------------------------------+
//| Order, based on which a deal is performed                        |
//+------------------------------------------------------------------+
long COrder::DealOrder(void) const
  {
#ifdef __MQL4__
   return ::OrderTicket();
#else 
   long res=0;
   switch((ENUM_ORDER_STATUS)this.GetProperty(ORDER_PROP_STATUS))
     {
      case ORDER_STATUS_MARKET_ACTIVE     : res=::PositionGetInteger(POSITION_IDENTIFIER);            break;
      case ORDER_STATUS_MARKET_PENDING    : res=::OrderGetInteger(ORDER_POSITION_ID);                 break;
      case ORDER_STATUS_HISTORY_PENDING   :
      case ORDER_STATUS_HISTORY_ORDER     : res=::HistoryOrderGetInteger(m_ticket,ORDER_POSITION_ID); break;
      case ORDER_STATUS_DEAL              : res=::HistoryDealGetInteger(m_ticket,DEAL_ORDER);         break;
      default                             : res=0;                                                    break;
     }
   return res;
#endif 
  }
//+------------------------------------------------------------------+
//| Deal direction IN, OUT, IN/OUT                                   |
//+------------------------------------------------------------------+
long COrder::DealEntry(void) const
  {
#ifdef __MQL4__
   return ::OrderType();
#else 
   long res=WRONG_VALUE;
   switch((ENUM_ORDER_STATUS)this.GetProperty(ORDER_PROP_STATUS))
     {
      case ORDER_STATUS_DEAL  : res=::HistoryDealGetInteger(m_ticket,DEAL_ENTRY);break;
      default                 : res=WRONG_VALUE;                                 break;
     }
   return res;
#endif 
  }
//+------------------------------------------------------------------+
//| Return the flag of closing a position by StopLoss                |
//+------------------------------------------------------------------+
bool COrder::OrderCloseByStopLoss(void) const
  {
#ifdef __MQL4__
   return(::StringFind(::OrderComment(),"[sl")>WRONG_VALUE);
#else 
   return
     (
      this.Status()==ORDER_STATUS_HISTORY_ORDER ? this.OrderReason()==ORDER_REASON_SL : 
      this.Status()==ORDER_STATUS_DEAL ? this.OrderReason()==DEAL_REASON_SL : false
     );
#endif 
  }
//+------------------------------------------------------------------+
//| Return the flag of closing position by TakeProfit                |
//+------------------------------------------------------------------+
bool COrder::OrderCloseByTakeProfit(void) const
  {
#ifdef __MQL4__
   return(::StringFind(::OrderComment(),"[tp")>WRONG_VALUE);
#else 
   return
     (
      this.Status()==ORDER_STATUS_HISTORY_ORDER ? this.OrderReason()==ORDER_REASON_TP : 
      this.Status()==ORDER_STATUS_DEAL ? this.OrderReason()==DEAL_REASON_TP : false
     );
#endif 
  }
//+------------------------------------------------------------------+
//| Return open time                                                 |
//+------------------------------------------------------------------+
datetime COrder::OrderOpenTime(void) const
  {
#ifdef __MQL4__
   return ::OrderOpenTime();
#else 
   datetime res=0;
   switch((ENUM_ORDER_STATUS)this.GetProperty(ORDER_PROP_STATUS))
     {
      case ORDER_STATUS_MARKET_ACTIVE     : res=(datetime)::PositionGetInteger(POSITION_TIME);                 break;
      case ORDER_STATUS_MARKET_PENDING    : res=(datetime)::OrderGetInteger(ORDER_TIME_SETUP);                 break;
      case ORDER_STATUS_HISTORY_PENDING   :
      case ORDER_STATUS_HISTORY_ORDER     : res=(datetime)::HistoryOrderGetInteger(m_ticket,ORDER_TIME_SETUP); break;
      case ORDER_STATUS_DEAL              : res=(datetime)::HistoryDealGetInteger(m_ticket,DEAL_TIME);         break;
      default                             : res=0;                                                             break;
     }
   return res;
#endif 
  }
//+------------------------------------------------------------------+
//| Return close time                                                |
//+------------------------------------------------------------------+
datetime COrder::OrderCloseTime(void) const
  {
#ifdef __MQL4__
   return ::OrderCloseTime();
#else 
   datetime res=0;
   switch((ENUM_ORDER_STATUS)this.GetProperty(ORDER_PROP_STATUS))
     {
      case ORDER_STATUS_HISTORY_PENDING   :
      case ORDER_STATUS_HISTORY_ORDER     : res=(datetime)::HistoryOrderGetInteger(m_ticket,ORDER_TIME_DONE);  break;
      case ORDER_STATUS_DEAL              : res=(datetime)::HistoryDealGetInteger(m_ticket,DEAL_TIME);         break;
      default                             : res=0;                                                             break;
     }
   return res;
#endif 
  }
//+------------------------------------------------------------------+
//| Return expiration time                                           |
//+------------------------------------------------------------------+
datetime COrder::OrderExpiration(void) const
  {
#ifdef __MQL4__
   return ::OrderExpiration();
#else 
   datetime res=0;
   switch((ENUM_ORDER_STATUS)this.GetProperty(ORDER_PROP_STATUS))
     {
      case ORDER_STATUS_MARKET_PENDING    : res=(datetime)::OrderGetInteger(ORDER_TIME_EXPIRATION);                  break;
      case ORDER_STATUS_HISTORY_PENDING   : res=(datetime)::HistoryOrderGetInteger(m_ticket,ORDER_TIME_EXPIRATION);  break;
      default                             : res=0;                                                                   break;
     }
   return res;
#endif 
  }
//+------------------------------------------------------------------+
//| Position change time in seconds                                  |
//+------------------------------------------------------------------+
datetime COrder::PositionTimeUpdate(void) const
  {
#ifdef __MQL4__
   return 0;
#else 
   datetime res=0;
   switch((ENUM_ORDER_STATUS)this.GetProperty(ORDER_PROP_STATUS))
     {
      case ORDER_STATUS_MARKET_ACTIVE  : res=(datetime)::PositionGetInteger(POSITION_TIME_UPDATE); break;
      default                          : res=0;                                                    break;
     }
   return res;
#endif 
  }
//+------------------------------------------------------------------+
//| Position change time in milliseconds                             |
//+------------------------------------------------------------------+
datetime COrder::PositionTimeUpdateMSC(void) const
  {
#ifdef __MQL4__
   return 0;
#else 
   datetime res=0;
   switch((ENUM_ORDER_STATUS)this.GetProperty(ORDER_PROP_STATUS))
     {
      case ORDER_STATUS_MARKET_ACTIVE  : res=(datetime)::PositionGetInteger(POSITION_TIME_UPDATE_MSC);break;
      default                          : res=0;                                                       break;
     }
   return res;
#endif 
  }
//+------------------------------------------------------------------+

Các phương thức để có được các đặc tính thực của đơn hàng/giao dịch/vị trí:

//+------------------------------------------------------------------+
//| Return open price                                                |
//+------------------------------------------------------------------+
double COrder::OrderOpenPrice(void) const
  {
#ifdef __MQL4__
   return ::OrderOpenPrice();
#else 
   double res=0;
   switch((ENUM_ORDER_STATUS)this.GetProperty(ORDER_PROP_STATUS))
     {
      case ORDER_STATUS_MARKET_ACTIVE     : res=::PositionGetDouble(POSITION_PRICE_OPEN);          break;
      case ORDER_STATUS_MARKET_PENDING    : res=::OrderGetDouble(ORDER_PRICE_OPEN);                break;
      case ORDER_STATUS_HISTORY_PENDING   :
      case ORDER_STATUS_HISTORY_ORDER     : res=::HistoryOrderGetDouble(m_ticket,ORDER_PRICE_OPEN);break;
      case ORDER_STATUS_DEAL              : res=::HistoryDealGetDouble(m_ticket,DEAL_PRICE);       break;
      default                             : res=0;                                                 break;
     }
   return res;
#endif 
  }
//+------------------------------------------------------------------+
//| Return close price                                               |
//+------------------------------------------------------------------+
double COrder::OrderClosePrice(void) const
  {
#ifdef __MQL4__
   return ::OrderClosePrice();
#else 
   double res=0;
   switch((ENUM_ORDER_STATUS)this.GetProperty(ORDER_PROP_STATUS))
     {
      case ORDER_STATUS_HISTORY_PENDING   :
      case ORDER_STATUS_HISTORY_ORDER     : res=::HistoryOrderGetDouble(m_ticket,ORDER_PRICE_OPEN);break;
      case ORDER_STATUS_DEAL              : res=::HistoryDealGetDouble(m_ticket,DEAL_PRICE);       break;
      default                             : res=0;                                                 break;
     }
   return res;
#endif 
  }
//+------------------------------------------------------------------+
//| Return profit                                                    |
//+------------------------------------------------------------------+
double COrder::OrderProfit(void) const
  {
#ifdef __MQL4__
   return ::OrderProfit();
#else 
   double res=0;
   switch((ENUM_ORDER_STATUS)this.GetProperty(ORDER_PROP_STATUS))
     {
      case ORDER_STATUS_MARKET_ACTIVE  : res=::PositionGetDouble(POSITION_PROFIT);        break;
      case ORDER_STATUS_DEAL           : res=::HistoryDealGetDouble(m_ticket,DEAL_PROFIT);break;
      default                          : res=0;                                           break;
     }
   return res;
#endif 
  }
//+------------------------------------------------------------------+
//| Return commission                                                |
//+------------------------------------------------------------------+
double COrder::OrderCommission(void) const
  {
#ifdef __MQL4__
   return ::OrderCommission();
#else 
   double res=0;
   switch((ENUM_ORDER_STATUS)this.GetProperty(ORDER_PROP_STATUS))
     {
      case ORDER_STATUS_DEAL  : res=::HistoryDealGetDouble(m_ticket,DEAL_COMMISSION);  break;
      default                 : res=0;                                                 break;
     }
   return res;
#endif 
  }
//+------------------------------------------------------------------+
//| Return swap                                                      |
//+------------------------------------------------------------------+
double COrder::OrderSwap(void) const
  {
#ifdef __MQL4__
   return ::OrderSwap();
#else 
   double res=0;
   switch((ENUM_ORDER_STATUS)this.GetProperty(ORDER_PROP_STATUS))
     {
      case ORDER_STATUS_MARKET_ACTIVE  : res=::PositionGetDouble(POSITION_SWAP);          break;
      case ORDER_STATUS_DEAL           : res=::HistoryDealGetDouble(m_ticket,DEAL_SWAP);  break;
      default                          : res=0;                                           break;
     }
   return res;
#endif 
  }
//+------------------------------------------------------------------+
//| Return volume                                                    |
//+------------------------------------------------------------------+
double COrder::OrderVolume(void) const
  {
#ifdef __MQL4__
   return ::OrderLots();
#else 
   double res=0;
   switch((ENUM_ORDER_STATUS)this.GetProperty(ORDER_PROP_STATUS))
     {
      case ORDER_STATUS_MARKET_ACTIVE     : res=::PositionGetDouble(POSITION_VOLUME);                    break;
      case ORDER_STATUS_MARKET_PENDING    : res=::OrderGetDouble(ORDER_VOLUME_INITIAL);                  break;
      case ORDER_STATUS_HISTORY_PENDING   :
      case ORDER_STATUS_HISTORY_ORDER     : res=::HistoryOrderGetDouble(m_ticket,ORDER_VOLUME_INITIAL);  break;
      case ORDER_STATUS_DEAL              : res=::HistoryDealGetDouble(m_ticket,DEAL_VOLUME);            break;
      default                             : res=0;                                                       break;
     }
   return res;
#endif 
  }
//+------------------------------------------------------------------+
//| Return unexecuted volume                                         |
//+------------------------------------------------------------------+
double COrder::OrderVolumeCurrent(void) const
  {
#ifdef __MQL4__
   return ::OrderLots();
#else 
   double res=0;
   switch((ENUM_ORDER_STATUS)this.GetProperty(ORDER_PROP_STATUS))
     {
      case ORDER_STATUS_MARKET_PENDING    : res=::OrderGetDouble(ORDER_VOLUME_CURRENT);                  break;
      case ORDER_STATUS_HISTORY_PENDING   :
      case ORDER_STATUS_HISTORY_ORDER     : res=::HistoryOrderGetDouble(m_ticket,ORDER_VOLUME_CURRENT);  break;
      default                             : res=0;                                                       break;
     }
   return res;
#endif 
  }
//+------------------------------------------------------------------+
//| Return StopLoss price                                            |
//+------------------------------------------------------------------+
double COrder::OrderStopLoss(void) const
  {
#ifdef __MQL4__
   return ::OrderStopLoss();
#else 
   double res=0;
   switch((ENUM_ORDER_STATUS)this.GetProperty(ORDER_PROP_STATUS))
     {
      case ORDER_STATUS_MARKET_ACTIVE     : res=::PositionGetDouble(POSITION_SL);            break;
      case ORDER_STATUS_MARKET_PENDING    : res=::OrderGetDouble(ORDER_SL);                  break;
      case ORDER_STATUS_HISTORY_PENDING   :
      case ORDER_STATUS_HISTORY_ORDER     : res=::HistoryOrderGetDouble(m_ticket,ORDER_SL);  break;
      default                             : res=0;                                           break;
     }
   return res;
#endif 
  }
//+------------------------------------------------------------------+
//| Return TakeProfit price                                          |
//+------------------------------------------------------------------+
double COrder::OrderTakeProfit(void) const
  {
#ifdef __MQL4__
   return ::OrderTakeProfit();
#else 
   double res=0;
   switch((ENUM_ORDER_STATUS)this.GetProperty(ORDER_PROP_STATUS))
     {
      case ORDER_STATUS_MARKET_ACTIVE     : res=::PositionGetDouble(POSITION_TP);            break;
      case ORDER_STATUS_MARKET_PENDING    : res=::OrderGetDouble(ORDER_TP);                  break;
      case ORDER_STATUS_HISTORY_PENDING   :
      case ORDER_STATUS_HISTORY_ORDER     : res=::HistoryOrderGetDouble(m_ticket,ORDER_TP);  break;
      default                             : res=0;                                           break;
     }
   return res;
#endif 
  }
//+------------------------------------------------------------------+
//| Return Limit order price                                         |
//| when StopLimit order is activated                                |
//+------------------------------------------------------------------+
double COrder::OrderPriceStopLimit(void) const
  {
#ifdef __MQL4__
   return 0;
#else 
   double res=0;
   switch((ENUM_ORDER_STATUS)this.GetProperty(ORDER_PROP_STATUS))
     {
      case ORDER_STATUS_MARKET_PENDING    : res=::OrderGetDouble(ORDER_PRICE_STOPLIMIT);                 break;
      case ORDER_STATUS_HISTORY_PENDING   :
      case ORDER_STATUS_HISTORY_ORDER     : res=::HistoryOrderGetDouble(m_ticket,ORDER_PRICE_STOPLIMIT); break;
      default                             : res=0;                                                       break;
     }
   return res;
#endif 
  }
//+------------------------------------------------------------------+

Các phương thức để có được các thuộc tính chuỗi thứ tự/thỏa thuận/vị trí:

//+------------------------------------------------------------------+
//| Return symbol                                                    |
//+------------------------------------------------------------------+
string COrder::OrderSymbol(void) const
  {
#ifdef __MQL4__
   return ::OrderSymbol();
#else 
   string res="";
   switch((ENUM_ORDER_STATUS)this.GetProperty(ORDER_PROP_STATUS))
     {
      case ORDER_STATUS_MARKET_ACTIVE     : res=::PositionGetString(POSITION_SYMBOL);           break;
      case ORDER_STATUS_MARKET_PENDING    : res=::OrderGetString(ORDER_SYMBOL);                 break;
      case ORDER_STATUS_HISTORY_PENDING   :
      case ORDER_STATUS_HISTORY_ORDER     : res=::HistoryOrderGetString(m_ticket,ORDER_SYMBOL); break;
      case ORDER_STATUS_DEAL              : res=::HistoryDealGetString(m_ticket,DEAL_SYMBOL);   break;
      default                             : res="";                                             break;
     }
   return res;
#endif 
  }
//+------------------------------------------------------------------+
//| Return comment                                                   |
//+------------------------------------------------------------------+
string COrder::OrderComment(void) const
  {
#ifdef __MQL4__
   return ::OrderComment();
#else 
   string res="";
   switch((ENUM_ORDER_STATUS)this.GetProperty(ORDER_PROP_STATUS))
     {
      case ORDER_STATUS_MARKET_ACTIVE     : res=::PositionGetString(POSITION_COMMENT);          break;
      case ORDER_STATUS_MARKET_PENDING    : res=::OrderGetString(ORDER_COMMENT);                break;
      case ORDER_STATUS_HISTORY_PENDING   :
      case ORDER_STATUS_HISTORY_ORDER     : res=::HistoryOrderGetString(m_ticket,ORDER_COMMENT);break;
      case ORDER_STATUS_DEAL              : res=::HistoryDealGetString(m_ticket,DEAL_COMMENT);  break;
      default                             : res="";                                             break;
     }
   return res;
#endif 
  }
//+------------------------------------------------------------------+
//| Return ID used by an exchange                                    |
//+------------------------------------------------------------------+
string COrder::OrderExternalID(void) const
  {
#ifdef __MQL4__
   return "";
#else 
   string res="";
   switch((ENUM_ORDER_STATUS)this.GetProperty(ORDER_PROP_STATUS))
     {
      case ORDER_STATUS_MARKET_PENDING    : res=::OrderGetString(ORDER_EXTERNAL_ID);                  break;
      case ORDER_STATUS_HISTORY_PENDING   :
      case ORDER_STATUS_HISTORY_ORDER     : res=::HistoryOrderGetString(m_ticket,ORDER_EXTERNAL_ID);  break;
      case ORDER_STATUS_DEAL              : res=::HistoryDealGetString(m_ticket,DEAL_EXTERNAL_ID);    break;
      default                             : res="";                                                   break;
     }
   return res;
#endif 
  }
//+------------------------------------------------------------------+

Chúng ta đã khai báo và thực hiện các phương thức riêng để nhận các thuộc tính từ dữ liệu đặt hàng.

Bây giờ là lúc triển khai hàm tạo của lớp được bảo vệ bằng cách viết cho nó các phương thức lưu tất cả các thuộc tính của đơn hàng có vé đã được chuyển cho hàm tạo.

Thực hiện trình xây dựng lớp được bảo vệ:

//+------------------------------------------------------------------+
//| Closed parametric constructor                                    |
//+------------------------------------------------------------------+
COrder::COrder(ENUM_ORDER_STATUS order_status,const ulong ticket)
  {
//--- Save integer properties
   m_ticket=ticket;
   m_long_prop[ORDER_PROP_STATUS]                              = order_status;
   m_long_prop[ORDER_PROP_MAGIC]                               = this.OrderMagicNumber();
   m_long_prop[ORDER_PROP_TICKET]                              = this.OrderTicket();
   m_long_prop[ORDER_PROP_TIME_OPEN]                           = (long)(ulong)this.OrderOpenTime();
   m_long_prop[ORDER_PROP_TIME_CLOSE]                          = (long)(ulong)this.OrderCloseTime();
   m_long_prop[ORDER_PROP_TIME_EXP]                            = (long)(ulong)this.OrderExpiration();
   m_long_prop[ORDER_PROP_TYPE]                                = this.OrderType();
   m_long_prop[ORDER_PROP_DIRECTION]                           = this.OrderTypeByDirection();
   m_long_prop[ORDER_PROP_POSITION_ID]                         = this.OrderPositionID();
   m_long_prop[ORDER_PROP_REASON]                              = this.OrderReason();
   m_long_prop[ORDER_PROP_DEAL_ORDER]                          = this.DealOrder();
   m_long_prop[ORDER_PROP_DEAL_ENTRY]                          = this.DealEntry();
   m_long_prop[ORDER_PROP_POSITION_BY_ID]                      = this.OrderPositionByID();
   m_long_prop[ORDER_PROP_TIME_OPEN_MSC]                       = this.OrderOpenTimeMSC();
   m_long_prop[ORDER_PROP_TIME_CLOSE_MSC]                      = this.OrderCloseTimeMSC();
   m_long_prop[ORDER_PROP_TIME_UPDATE]                         = (long)(ulong)this.PositionTimeUpdate();
   m_long_prop[ORDER_PROP_TIME_UPDATE_MSC]                     = (long)(ulong)this.PositionTimeUpdateMSC();
   
//--- Save real properties
   m_double_prop[this.IndexProp(ORDER_PROP_PRICE_OPEN)]        = this.OrderOpenPrice();
   m_double_prop[this.IndexProp(ORDER_PROP_PRICE_CLOSE)]       = this.OrderClosePrice();
   m_double_prop[this.IndexProp(ORDER_PROP_PROFIT)]            = this.OrderProfit();
   m_double_prop[this.IndexProp(ORDER_PROP_COMMISSION)]        = this.OrderCommission();
   m_double_prop[this.IndexProp(ORDER_PROP_SWAP)]              = this.OrderSwap();
   m_double_prop[this.IndexProp(ORDER_PROP_VOLUME)]            = this.OrderVolume();
   m_double_prop[this.IndexProp(ORDER_PROP_SL)]                = this.OrderStopLoss();
   m_double_prop[this.IndexProp(ORDER_PROP_TP)]                = this.OrderTakeProfit();
   m_double_prop[this.IndexProp(ORDER_PROP_VOLUME_CURRENT)]    = this.OrderVolumeCurrent();
   m_double_prop[this.IndexProp(ORDER_PROP_PRICE_STOP_LIMIT)]  = this.OrderPriceStopLimit();
   
//--- Save string properties
   m_string_prop[this.IndexProp(ORDER_PROP_SYMBOL)]            = this.OrderSymbol();
   m_string_prop[this.IndexProp(ORDER_PROP_COMMENT)]           = this.OrderComment();
   m_string_prop[this.IndexProp(ORDER_PROP_EXT_ID)]            = this.OrderExternalID();
   
//--- Save additional integer properties
   m_long_prop[ORDER_PROP_PROFIT_PT]                           = this.ProfitInPoints();
   m_long_prop[ORDER_PROP_TICKET_FROM]                         = this.OrderTicketFrom();
   m_long_prop[ORDER_PROP_TICKET_TO]                           = this.OrderTicketTo();
   m_long_prop[ORDER_PROP_CLOSE_BY_SL]                         = this.OrderCloseByStopLoss();
   m_long_prop[ORDER_PROP_CLOSE_BY_TP]                         = this.OrderCloseByTakeProfit();
   
//--- Save additional real properties
   m_double_prop[this.IndexProp(ORDER_PROP_PROFIT_FULL)]       = this.ProfitFull();
  }
//+------------------------------------------------------------------+

Khi chúng ta chuyển qua lịch sử hoặc các lệnh / giao dịch / vị trí thị trường trong một vòng lặp hoặc chọn một đơn hàng / giao dịch / vị trí mới, một đối tượng mới xuất phát từ lớp COrder được tạo ra. Trình xây dựng lớp có trạng thái đơn hàng và vé được gọi trong trình tạo lớp chỉ nhận được vé đặt hàng. Tiếp theo, các mảng thuộc tính thứ tự được điền đơn giản vào hàm tạo của lớp COrder bằng các phương thức được mô tả ở trên.

Vì vậy, mỗi đơn hàng / giao dịch / vị trí mới là có tài sản duy nhất của nó. Tất cả chúng sẽ được lưu trữ trong danh sách, trong khi làm việc với các danh sách đó là hoạt động chính của thư viện. Các danh sách có thể được sắp xếp theo bất kỳ thuộc tính thứ tự / thỏa thuận / vị trí. Bên cạnh đó, có thể tạo danh sách mới trong số những danh sách đã chọn.
Ở giai đoạn này, chức năng cơ bản của lớp thứ tự trừu tượng COrder đã được triển khai. Đây là một lớp cơ bản để lưu trữ các loại đơn đặt hàng, giao dịch và vị trí. Tất cả những thứ khác sẽ được bắt nguồn từ nó để tạo các đối tượng chia cho các loại đơn đặt hàng, giao dịch và vị trí.
Thư viện được tạo để truy cập đơn giản vào dữ liệu và phát triển chương trình dễ dàng.
Ở trạng thái hiện tại, chúng ta có ba phương thức công khai để truy cập các thuộc tính của thứ tự trừu tượng GetProperty (XXX). Bạn có thể sử dụng chúng, nhưng điều này không thuận tiện lắm vì bạn cần nhớ tên thành viên của bảng liệt kê mô tả một thuộc tính đơn hàng cụ thể. Do đó, chúng ta sẽ thêm một số phương thức công khai để có được dữ liệu cần thiết. Các phương thức này sẽ có tên hợp lý để ngay lập tức rõ ràng thuộc tính nào có thể thu được bằng cách sử dụng một phương thức cụ thể.

Các phương thức này có thể được sử dụng trong các chương trình tùy chỉnh để đọc các thuộc tính của đơn hàng, thỏa thuận hoặc vị trí đã chọn:

//--- Return (1) ticket, (2) parent order ticket, (3) derived order ticket, (4) magic number, (5) order reason (6) position ID
   //--- (7) opposite position ID, (8) flag of closing by StopLoss, (9) flag of closing by TakeProfit (10) open time, (11) close time,
   //--- (12) open time in milliseconds, (13) close time in milliseconds (14) expiration date, (15) type, (16) status, (17) direction
   long              Ticket(void)                                       const { return this.GetProperty(ORDER_PROP_TICKET);                     }
   long              TicketFrom(void)                                   const { return this.GetProperty(ORDER_PROP_TICKET_FROM);                }
   long              TicketTo(void)                                     const { return this.GetProperty(ORDER_PROP_TICKET_TO);                  }
   long              Magic(void)                                        const { return this.GetProperty(ORDER_PROP_MAGIC);                      }
   long              Reason(void)                                       const { return this.GetProperty(ORDER_PROP_REASON);                     }
   long              PositionID(void)                                   const { return this.GetProperty(ORDER_PROP_POSITION_ID);                }
   long              PositionByID(void)                                 const { return this.GetProperty(ORDER_PROP_POSITION_BY_ID);             }
   bool              IsCloseByStopLoss(void)                            const { return (bool)this.GetProperty(ORDER_PROP_CLOSE_BY_SL);          }
   bool              IsCloseByTakeProfit(void)                          const { return (bool)this.GetProperty(ORDER_PROP_CLOSE_BY_TP);          }
   datetime          TimeOpen(void)                                     const { return (datetime)this.GetProperty(ORDER_PROP_TIME_OPEN);        }
   datetime          TimeClose(void)                                    const { return (datetime)this.GetProperty(ORDER_PROP_TIME_CLOSE);       }
   datetime          TimeOpenMSC(void)                                  const { return (datetime)this.GetProperty(ORDER_PROP_TIME_OPEN_MSC);    }
   datetime          TimeCloseMSC(void)                                 const { return (datetime)this.GetProperty(ORDER_PROP_TIME_CLOSE_MSC);   }
   datetime          TimeExpiration(void)                               const { return (datetime)this.GetProperty(ORDER_PROP_TIME_EXP);         }
   ENUM_ORDER_TYPE   TypeOrder(void)                                    const { return (ENUM_ORDER_TYPE)this.GetProperty(ORDER_PROP_TYPE);      }
   ENUM_ORDER_STATUS Status(void)                                       const { return (ENUM_ORDER_STATUS)this.GetProperty(ORDER_PROP_STATUS);  }
   ENUM_ORDER_TYPE   TypeByDirection(void)                              const { return (ENUM_ORDER_TYPE)this.GetProperty(ORDER_PROP_DIRECTION); }
   
   //--- Return (1) open price, (2) close price, (3) profit, (4) commission, (5) swap, (6) volume, 
   //--- (7) unexecuted volume (8) StopLoss and (9) TakeProfit (10) StopLimit order price
   double            PriceOpen(void)                                    const { return this.GetProperty(ORDER_PROP_PRICE_OPEN);                 }
   double            PriceClose(void)                                   const { return this.GetProperty(ORDER_PROP_PRICE_CLOSE);                }
   double            Profit(void)                                       const { return this.GetProperty(ORDER_PROP_PROFIT);                     }
   double            Comission(void)                                    const { return this.GetProperty(ORDER_PROP_COMMISSION);                 }
   double            Swap(void)                                         const { return this.GetProperty(ORDER_PROP_SWAP);                       }
   double            Volume(void)                                       const { return this.GetProperty(ORDER_PROP_VOLUME);                     }
   double            VolumeCurrent(void)                                const { return this.GetProperty(ORDER_PROP_VOLUME_CURRENT);             }
   double            StopLoss(void)                                     const { return this.GetProperty(ORDER_PROP_SL);                         }
   double            TakeProfit(void)                                   const { return this.GetProperty(ORDER_PROP_TP);                         }
   double            PriceStopLimit(void)                               const { return this.GetProperty(ORDER_PROP_PRICE_STOP_LIMIT);           }
   
   //--- Return (1) symbol, (2) comment, (3) ID at an exchange
   string            Symbol(void)                                       const { return this.GetProperty(ORDER_PROP_SYMBOL);                     }
   string            Comment(void)                                      const { return this.GetProperty(ORDER_PROP_COMMENT);                    }
   string            ExternalID(void)                                   const { return this.GetProperty(ORDER_PROP_EXT_ID);                     }

   //--- Get the full order profit
   double            ProfitFull(void)                                   const { return this.Profit()+this.Comission()+this.Swap();              }
   //--- Get order profit in points
   int               ProfitInPoints(void) const;

Thực hiện phương thức nhận lợi nhuận theo điểm:

//+------------------------------------------------------------------+
//| Return order profit in points                                    |
//+------------------------------------------------------------------+
int COrder::ProfitInPoints(void) const
  {
   ENUM_ORDER_TYPE type=this.TypeOrder();
   string symbol=this.Symbol();
   double point=::SymbolInfoDouble(symbol,SYMBOL_POINT);
   if(type>ORDER_TYPE_SELL || point==0) return 0;
   if(this.Status()==ORDER_STATUS_HISTORY_ORDER)
      return int(type==ORDER_TYPE_BUY ? (this.PriceClose()-this.PriceOpen())/point : type==ORDER_TYPE_SELL ? (this.PriceOpen()-this.PriceClose())/point : 0);
   else if(this.Status()==ORDER_STATUS_MARKET_ACTIVE)
     {
      if(type==ORDER_TYPE_BUY)
         return int((::SymbolInfoDouble(symbol,SYMBOL_BID)-this.PriceOpen())/point);
      else if(type==ORDER_TYPE_SELL)
         return int((this.PriceOpen()-::SymbolInfoDouble(symbol,SYMBOL_ASK))/point);
     }
   return 0;
  }
//+------------------------------------------------------------------+

Và hãy thêm các phương thức công khai để mô tả một số thuộc tính của đối tượng đặt hàng để bạn có thể hiển thị chúng theo yêu cầu một cách thuận tiện:

 //--- Get description of an order's (1) integer, (2) real and (3) string property
   string            GetPropertyDescription(ENUM_ORDER_PROP_INTEGER property);
   string            GetPropertyDescription(ENUM_ORDER_PROP_DOUBLE property);
   string            GetPropertyDescription(ENUM_ORDER_PROP_STRING property);
   //--- Return order status name
   string            StatusDescription(void) const;
   //--- Return order or position name
   string            TypeDescription(void) const;
   //--- Return the deal direction name
   string            DealEntryDescription(void) const;
   //--- Return order/position direction
   string            DirectionDescription(void) const;
   //--- Send description of order properties to journal (full_prop=true - all properties, false - only supported ones)
   void              Print(const bool full_prop=false);

Trước khi chúng ta thực hiện các phương pháp này, chúng ta hãy giải quyết một vấn đề khác: thư viện và các chương trình dựa trên nó yêu cầu các chức năng dịch vụ khác nhau. Ví dụ, trong trường hợp này, chúng ta cần chức năng hiển thị thời gian với mili giây và chức năng nhận tin nhắn bằng một trong hai ngôn ngữ. Ngôn ngữ của tin nhắn là phụ thuộc vào ngôn ngữ đầu cuối.

Tạo một tệp bao gồm mới trong thư mục gốc của thư viện:

Và gọi nó là DELib. Đây sẽ là tệp thư viện của các chức năng dịch vụ có sẵn để sử dụng cho cả các lớp thư viện và các chương trình dựa trên thư viện.

Nhấp vào Kết thúc để tạo tệp mẫu:

//+------------------------------------------------------------------+
//|                                                        DELib.mqh |
//|                                  Copyright 2019, Forex 365 Crop. |
//|                                              https://forex365.vn |
//+------------------------------------------------------------------+
#property copyright "Copyright 2019, Forex 365 Corp."
#property link      "https://forex365.vn"
//+------------------------------------------------------------------+
//| defines                                                          |
//+------------------------------------------------------------------+
// #define MacrosHello   "Hello, world!"
// #define MacrosYear    2010
//+------------------------------------------------------------------+
//| DLL imports                                                      |
//+------------------------------------------------------------------+
// #import "user32.dll"
//   int      SendMessageA(int hWnd,int Msg,int wParam,int lParam);
// #import "my_expert.dll"
//   int      ExpertRecalculate(int wParam,int lParam);
// #import
//+------------------------------------------------------------------+
//| EX5 imports                                                      |
//+------------------------------------------------------------------+
// #import "stdlib.ex5"
//   string ErrorDescription(int error_code);
// #import
//+------------------------------------------------------------------+

Bao gồm tệp Defines.mqh cho nó và sửa đổi mẫu theo nhu cầu của chúng ta:

//+------------------------------------------------------------------+
//|                                                        DELib.mqh |
//|                                  Copyright 2019, Forex 365 Crop. |
//|                                              https://forex365.vn |
//+------------------------------------------------------------------+
#property copyright "Copyright 2019, Forex 365 Corp."
#property link      "https://forex365.vn"
#property strict  // Necessary for mql4
//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include "Defines.mqh"
//+------------------------------------------------------------------+
//| Service functions                                                |
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+

Vì chúng ta đã đưa Defines.mqh vào tệp này, chúng ta có thể đưa tệp mới này (chứ không phải Defines.mqh) vào tệp lớp COrder, để cả hai đều có sẵn trong thư viện. Bên cạnh đó, chúng ta sẽ làm điều đó trong một chuỗi chứ không phải hai.
Thay thế lệnh bao gồm trong tệp Order.mqh:

//+------------------------------------------------------------------+
//|                                                        Order.mqh |
//|                                  Copyright 2019, Forex 365 Crop. |
//|                                              https://forex365.vn |
//+------------------------------------------------------------------+
#property copyright "Copyright 2019, Forex 365 Corp."
#property link      "https://forex365.vn"
#property version   "1.00"
#include <Object.mqh>
#include "..\DELib.mqh"
//+------------------------------------------------------------------+
//| Abstract order class                                             |
//+------------------------------------------------------------------+

Chúng ta cũng hãy thêm định nghĩa ngôn ngữ quốc gia của người dùng dưới dạng thay thế macro trong tệp Defines.mqh:

//+------------------------------------------------------------------+
//|                                                      Defines.mqh |
//|                                  Copyright 2019, Forex 365 Crop. |
//|                                              https://forex365.vn |
//+------------------------------------------------------------------+
#property copyright "Copyright 2019, Forex 365 Corp."
#property link      "https://forex365.vn"
//+------------------------------------------------------------------+
//| Macro substitutions                                              |
//+------------------------------------------------------------------+
#define COUNTRY_LANG    "Russian"
//+------------------------------------------------------------------+

Do đó, người dùng sẽ có thể đặt ngôn ngữ gốc của họ cho các tin nhắn được hiển thị nếu ngôn ngữ đầu cuối không phải là tiếng Anh. Tuy nhiên, để đạt được điều này, chúng ta sẽ phải thay thế tất cả các tin nhắn trong tương lai bằng tiếng Nga, chúng ta phải nhập vào đây bằng những tin nhắn theo ngôn ngữ mà người dùng yêu cầu.

Thêm chức năng trả lại tin nhắn bằng một trong hai ngôn ngữ trong tệp DELib.mqh:

//+------------------------------------------------------------------+
//|                                                        DELib.mqh |
//|                                  Copyright 2019, Forex 365 Crop. |
//|                                              https://forex365.vn |
//+------------------------------------------------------------------+
#property copyright "Copyright 2019, Forex 365 Corp."
#property link      "https://forex365.vn"
#property strict  // Necessary for mql4
//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include "Defines.mqh"
//+------------------------------------------------------------------+
//| Service functions                                                |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Return the text in one of two languages                          |
//+------------------------------------------------------------------+
string TextByLanguage(const string text_country_lang,const string text_en)
  {
   return(TerminalInfoString(TERMINAL_LANGUAGE)==COUNTRY_LANG ? text_country_lang : text_en);
  }
//+------------------------------------------------------------------+

Hàm kiểm tra ngôn ngữ đầu cuối và nếu nó phù hợp với các ngôn ngữ được chỉ định trong thay thế macro COUNTRY_LANG, văn bản được truyền trong tham số chức năng đầu tiên được hiển thị. Mặt khác, văn bản chứa trong tham số chức năng thứ hai (tiếng Anh) được hiển thị.

Chúng ta cũng hãy thêm chức năng hiển thị thời gian với mili giây:

//+------------------------------------------------------------------+
//| Return the number of decimal places in a symbol lot              |
//+------------------------------------------------------------------+
uint DigitsLots(const string symbol_name) 
  { 
   return (int)ceil(fabs(log(SymbolInfoDouble(symbol_name,SYMBOL_VOLUME_STEP))/log(10)));
  }
//+------------------------------------------------------------------+

Ngoài các chức năng dịch vụ, chúng ta sẽ cần ba phương thức trả về lý do đặt hàng, hướng và loại giao dịch để hiển thị thông báo trong tạp chí. Thêm ba phương thức vào phần được bảo vệ của lớp COrder:

//--- Return (1) reason, (2) direction, (3) deal type
   string            GetReasonDescription(const long reason)            const;
   string            GetEntryDescription(const long deal_entry)         const;
   string            GetTypeDealDescription(const long type_deal)       const;
//+------------------------------------------------------------------+
//| Reason                                                           |
//+------------------------------------------------------------------+
string COrder::GetReasonDescription(const long reason) const
  {
#ifdef __MQL4__
   return
     (
      this.IsCloseByStopLoss()            ?  TextByLanguage("Срабатывание StopLoss","Due to StopLoss")                  :
      this.IsCloseByTakeProfit()          ?  TextByLanguage("Срабатывание TakeProfit","Due to TakeProfit")              :
      this.Reason()==ORDER_REASON_EXPERT  ?  TextByLanguage("Выставлен из mql4-программы","Placed from mql4 program")   :
      TextByLanguage("Свойство не поддерживается в MQL4","Property not supported in MQL4")
     );
#else 
   string res="";
   switch(this.Status())
     {
      case ORDER_STATUS_MARKET_ACTIVE        : 
         res=
           (
            reason==POSITION_REASON_CLIENT   ?  TextByLanguage("Позиция открыта из десктопного терминала","Position opened from desktop terminal") :
            reason==POSITION_REASON_MOBILE   ?  TextByLanguage("Позиция открыта из мобильного приложения","Position opened from mobile app") :
            reason==POSITION_REASON_WEB      ?  TextByLanguage("Позиция открыта из веб-платформы","Position opened from web platform") :
            reason==POSITION_REASON_EXPERT   ?  TextByLanguage("Позиция открыта из советника или скрипта","Position opened from EA or script") : ""
           );
         break;
      case ORDER_STATUS_MARKET_PENDING       :
      case ORDER_STATUS_HISTORY_PENDING      : 
      case ORDER_STATUS_HISTORY_ORDER        : 
         res=
           (
            reason==ORDER_REASON_CLIENT      ?  TextByLanguage("Ордер выставлен из десктопного терминала","Order set from desktop terminal") :
            reason==ORDER_REASON_MOBILE      ?  TextByLanguage("Ордер выставлен из мобильного приложения","Order set from mobile app") :
            reason==ORDER_REASON_WEB         ?  TextByLanguage("Ордер выставлен из веб-платформы","Oder set from web platform") :
            reason==ORDER_REASON_EXPERT      ?  TextByLanguage("Ордер выставлен советником или скриптом","Order set from EA or script") :
            reason==ORDER_REASON_SL          ?  TextByLanguage("Срабатывание StopLoss","Due to StopLoss") :
            reason==ORDER_REASON_TP          ?  TextByLanguage("Срабатывание TakeProfit","Due to TakeProfit") :
            reason==ORDER_REASON_SO          ?  TextByLanguage("Ордер выставлен в результате наступления Stop Out","Due to Stop Out") : ""
           );
         break;
      case ORDER_STATUS_DEAL                 : 
         res=
           (
            reason==DEAL_REASON_CLIENT       ?  TextByLanguage("Сделка проведена из десктопного терминала","Deal carried out from desktop terminal") :
            reason==DEAL_REASON_MOBILE       ?  TextByLanguage("Сделка проведена из мобильного приложения","Deal carried out from mobile app") :
            reason==DEAL_REASON_WEB          ?  TextByLanguage("Сделка проведена из веб-платформы","Deal carried out from web platform") :
            reason==DEAL_REASON_EXPERT       ?  TextByLanguage("Сделка проведена из советника или скрипта","Deal carried out from EA or script") :
            reason==DEAL_REASON_SL           ?  TextByLanguage("Срабатывание StopLoss","Due to StopLoss") :
            reason==DEAL_REASON_TP           ?  TextByLanguage("Срабатывание TakeProfit","Due to TakeProfit") :
            reason==DEAL_REASON_SO           ?  TextByLanguage("Сделка проведена в результате наступления Stop Out","Due to Stop Out") :
            reason==DEAL_REASON_ROLLOVER     ?  TextByLanguage("Сделка проведена по причине переноса позиции","Due to position rollover") :
            reason==DEAL_REASON_VMARGIN      ?  TextByLanguage("Сделка проведена по причине начисления/списания вариационной маржи","Due to variation margin") :
            reason==DEAL_REASON_SPLIT        ?  TextByLanguage("Сделка проведена по причине сплита (понижения цены) инструмента","Due to split") : ""
           );
         break;
      default                                : res="";   break;
     }
   return res;
#endif 
  }
//+------------------------------------------------------------------+

Liên kết với MQL4 hoặc MQL5 được kiểm tra, lý do đơn hàng được chuyển trong các đầu vào được xác minh theo trạng thái đơn hàng và mô tả của nó được trả về.

//+------------------------------------------------------------------+
//| Deal direction description                                       |
//+------------------------------------------------------------------+
string COrder::GetEntryDescription(const long deal_entry) const
  {
#ifdef __MQL4__
   return TextByLanguage("Свойство не поддерживается в MQL4","Property not supported in MQL4");
#else 
   string res="";
   switch(this.Status())
     {
      case ORDER_STATUS_MARKET_ACTIVE     : 
         res=TextByLanguage("Свойство не поддерживается у позиции","Property not supported for position"); 
         break;
      case ORDER_STATUS_MARKET_PENDING    :
      case ORDER_STATUS_HISTORY_PENDING   : 
         res=TextByLanguage("Свойство не поддерживается у отложенного ордера","Property not supported for pending order"); 
         break;
      case ORDER_STATUS_HISTORY_ORDER     : 
         res=TextByLanguage("Свойство не поддерживается у исторического ордера","Property not supported for history order"); 
         break;
      case ORDER_STATUS_DEAL              : 
         res=
           (
            deal_entry==DEAL_ENTRY_IN     ?  TextByLanguage("Вход в рынок","Entry to the market") :
            deal_entry==DEAL_ENTRY_OUT    ?  TextByLanguage("Выход из рынка","Out from the market") :
            deal_entry==DEAL_ENTRY_INOUT  ?  TextByLanguage("Разворот","Reversal") :
            deal_entry==DEAL_ENTRY_OUT_BY ?  TextByLanguage("Закрытие встречной позицией","Closing by opposite position") : ""
           );
         break;
      default                             : res=""; break;
     }
   return res;
#endif 
  }
//+------------------------------------------------------------------+

Liên kết với MQL4 hoặc MQL5 được kiểm tra, hướng giao dịch được chuyển trong các đầu vào được xác minh theo trạng thái đơn hàng và mô tả của nó được trả về.

//+------------------------------------------------------------------+
//| Return deal type name                                            |
//+------------------------------------------------------------------+
string COrder::GetTypeDealDescription(const long deal_type) const
  {
#ifdef __MQL4__
   return TextByLanguage("Свойство не поддерживается в MQL4","Property not supported in MQL4");
#else 
   string res="";
   switch(this.Status())
     {
      case ORDER_STATUS_MARKET_ACTIVE     : 
         res=TextByLanguage("Свойство не поддерживается у позиции","Property not supported for position"); 
         break;
      case ORDER_STATUS_MARKET_PENDING    :
      case ORDER_STATUS_HISTORY_PENDING   : 
         res=TextByLanguage("Свойство не поддерживается у отложенного ордера","Property not supported for pending order"); 
         break;
      case ORDER_STATUS_HISTORY_ORDER     : 
         res=TextByLanguage("Свойство не поддерживается у исторического ордера","Property not supported for history order"); 
         break;
      case ORDER_STATUS_DEAL              : 
         res=
           (
            deal_type==DEAL_TYPE_BUY                      ?  TextByLanguage("Сделка на покупку","Buy deal") :
            deal_type==DEAL_TYPE_SELL                     ?  TextByLanguage("Сделка на продажу","Sell deal") :
            deal_type==DEAL_TYPE_BALANCE                  ?  TextByLanguage("Начисление баланса","Balance accrual") :
            deal_type==DEAL_TYPE_CREDIT                   ?  TextByLanguage("Начисление кредита","Credit accrual") :
            deal_type==DEAL_TYPE_CHARGE                   ?  TextByLanguage("Дополнительные сборы","Extra charges") :
            deal_type==DEAL_TYPE_CORRECTION               ?  TextByLanguage("Корректирующая запись","Corrective entry") :
            deal_type==DEAL_TYPE_BONUS                    ?  TextByLanguage("Перечисление бонусов","Bonuses") :
            deal_type==DEAL_TYPE_COMMISSION               ?  TextByLanguage("Дополнительные комиссии","Additional comissions") :
            deal_type==DEAL_TYPE_COMMISSION_DAILY         ?  TextByLanguage("Комиссия, начисляемая в конце торгового дня","Commission accrued at the end of a trading day") :
            deal_type==DEAL_TYPE_COMMISSION_MONTHLY       ?  TextByLanguage("Комиссия, начисляемая в конце месяца","Commission accrued at the end of a month") :
            deal_type==DEAL_TYPE_COMMISSION_AGENT_DAILY   ?  TextByLanguage("Агентская комиссия, начисляемая в конце торгового дня","Agency commission charged at the end of a trading day") :
            deal_type==DEAL_TYPE_COMMISSION_AGENT_MONTHLY ?  TextByLanguage("Агентская комиссия, начисляемая в конце месяца","Agency commission charged at the end of a month") :
            deal_type==DEAL_TYPE_INTEREST                 ?  TextByLanguage("Начисления процентов на свободные средства","Accrued interest on free funds") :
            deal_type==DEAL_TYPE_BUY_CANCELED             ?  TextByLanguage("Отмененная сделка покупки","Canceled buy transaction") :
            deal_type==DEAL_TYPE_SELL_CANCELED            ?  TextByLanguage("Отмененная сделка продажи","Canceled sell transaction") :
            deal_type==DEAL_DIVIDEND                      ?  TextByLanguage("Начисление дивиденда","Accrued dividends") :
            deal_type==DEAL_DIVIDEND_FRANKED              ?  TextByLanguage("Начисление франкированного дивиденда","Accrual of franked dividend") :
            deal_type==DEAL_TAX                           ?  TextByLanguage("Начисление налога","Tax accrual") : ""
           );
         break;
      default                             : res=""; break;
     }
   return res;
#endif 
  }

Liên kết với MQL4 hoặc MQL5 được kiểm tra, loại giao dịch được chuyển trong các đầu vào được xác minh theo trạng thái đơn hàng và mô tả của nó được trả về.

Thực hiện các phương pháp mô tả các thuộc tính thứ tự:

//+------------------------------------------------------------------+
//| Return description of an order's integer property                |
//+------------------------------------------------------------------+
string COrder::GetPropertyDescription(ENUM_ORDER_PROP_INTEGER property)
  {
   return
     (
   //--- General properties
      property==ORDER_PROP_MAGIC             ?  TextByLanguage("Магик","Magic")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+(string)this.GetProperty(property)
         )  :
      property==ORDER_PROP_TICKET            ?  TextByLanguage("Тикет","Ticket")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          " #"+(string)this.GetProperty(property)
         )  :
      property==ORDER_PROP_TICKET_FROM       ?  TextByLanguage("Тикет родительского ордера","Ticket of parent order")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          " #"+(string)this.GetProperty(property)
         )  :
      property==ORDER_PROP_TICKET_TO         ?  TextByLanguage("Тикет наследуемого ордера","Inherited order ticket")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          " #"+(string)this.GetProperty(property)
         )  :
      property==ORDER_PROP_TIME_OPEN         ?  TextByLanguage("Время открытия","Open time")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+::TimeToString(this.GetProperty(property),TIME_DATE|TIME_MINUTES|TIME_SECONDS)
         )  :
      property==ORDER_PROP_TIME_CLOSE        ?  TextByLanguage("Время закрытия","Close time")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+::TimeToString(this.GetProperty(property),TIME_DATE|TIME_MINUTES|TIME_SECONDS)
         )  :
      property==ORDER_PROP_TIME_EXP          ?  TextByLanguage("Дата экспирации","Expiration date")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          (this.GetProperty(property)==0     ?  TextByLanguage(": Не задана",": Not set") :
          ": "+::TimeToString(this.GetProperty(property),TIME_DATE|TIME_MINUTES|TIME_SECONDS))
         )  :
      property==ORDER_PROP_TYPE              ?  TextByLanguage("Тип","Type")+": "+this.TypeDescription()                   :
      property==ORDER_PROP_DIRECTION         ?  TextByLanguage("Тип по направлению","Type by direction")+": "+this.DirectionDescription() :
      
      property==ORDER_PROP_REASON            ?  TextByLanguage("Причина","Reason")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+this.GetReasonDescription(this.GetProperty(property))
         )  :
      property==ORDER_PROP_POSITION_ID       ?  TextByLanguage("Идентификатор позиции","Position ID")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": #"+(string)this.GetProperty(property)
         )  :
      property==ORDER_PROP_DEAL_ORDER        ?  TextByLanguage("Сделка на основании ордера","Deal by order")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": #"+(string)this.GetProperty(property)
         )  :
      property==ORDER_PROP_DEAL_ENTRY        ?  TextByLanguage("Направление сделки","Deal direction")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+this.GetEntryDescription(this.GetProperty(property))
         )  :
      property==ORDER_PROP_POSITION_BY_ID    ?  TextByLanguage("Идентификатор встречной позиции","Opposite position ID")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+(string)this.GetProperty(property)
         )  :
      property==ORDER_PROP_TIME_OPEN_MSC     ?  TextByLanguage("Время открытия в милисекундах","Open time in milliseconds")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+(string)this.GetProperty(property)+" > "+TimeMSCtoString(this.GetProperty(property))
         )  :
      property==ORDER_PROP_TIME_CLOSE_MSC    ?  TextByLanguage("Время закрытия в милисекундах","Close time in milliseconds")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+(string)this.GetProperty(property)+" > "+TimeMSCtoString(this.GetProperty(property))
         )  :
      property==ORDER_PROP_TIME_UPDATE       ?  TextByLanguage("Время изменения позиции","Position change time")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+(this.GetProperty(property)!=0 ? ::TimeToString(this.GetProperty(property),TIME_DATE|TIME_MINUTES|TIME_SECONDS) : "0")
         )  :
      property==ORDER_PROP_TIME_UPDATE_MSC   ?  TextByLanguage("Время изменения позиции в милисекундах","Position change time in milliseconds")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+(this.GetProperty(property)!=0 ? (string)this.GetProperty(property)+" > "+TimeMSCtoString(this.GetProperty(property)) : "0")
         )  :
   //--- Additional property
      property==ORDER_PROP_STATUS            ?  TextByLanguage("Статус","Status")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": \""+this.StatusDescription()+"\""
         )  :
      property==ORDER_PROP_PROFIT_PT         ?  TextByLanguage("Прибыль в пунктах","Profit in points")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+(string)this.GetProperty(property)
         )  :
      property==ORDER_PROP_CLOSE_BY_SL       ?  TextByLanguage("Закрытие по StopLoss","Close by StopLoss")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+(this.GetProperty(property) ? TextByLanguage("Да","Yes") : TextByLanguage("Нет","No"))
         )  :
      property==ORDER_PROP_CLOSE_BY_TP       ?  TextByLanguage("Закрытие по TakeProfit","Close by TakeProfit")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+(this.GetProperty(property) ? TextByLanguage("Да","Yes") : TextByLanguage("Нет","No"))
         )  :
      ""
     );
  }
//+------------------------------------------------------------------+
//| Return description of order's real property                      |
//+------------------------------------------------------------------+
string COrder::GetPropertyDescription(ENUM_ORDER_PROP_DOUBLE property)
  {
   int dg=(int)::SymbolInfoInteger(this.GetProperty(ORDER_PROP_SYMBOL),SYMBOL_DIGITS);
   int dgl=(int)DigitsLots(this.GetProperty(ORDER_PROP_SYMBOL));
   return
     (
      //--- General properties
      property==ORDER_PROP_PRICE_CLOSE       ?  TextByLanguage("Цена закрытия","Close price")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+::DoubleToString(this.GetProperty(property),dg)
         )  :
      property==ORDER_PROP_PRICE_OPEN        ?  TextByLanguage("Цена открытия","Open price")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+::DoubleToString(this.GetProperty(property),dg)
         )  :
      property==ORDER_PROP_SL                ?  TextByLanguage("Цена StopLoss","StopLoss price")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          (this.GetProperty(property)==0     ?  TextByLanguage(": Отсутствует",": Not set"):": "+::DoubleToString(this.GetProperty(property),dg))
         )  :
      property==ORDER_PROP_TP                ?  TextByLanguage("Цена TakeProfit","TakeProfit price")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          (this.GetProperty(property)==0     ?  TextByLanguage(": Отсутствует",": Not set"):": "+::DoubleToString(this.GetProperty(property),dg))
         )  :
      property==ORDER_PROP_PROFIT            ?  TextByLanguage("Прибыль","Profit")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+::DoubleToString(this.GetProperty(property),2)
         )  :
      property==ORDER_PROP_COMMISSION        ?  TextByLanguage("Комиссия","Comission")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+::DoubleToString(this.GetProperty(property),2)
         )  :
      property==ORDER_PROP_SWAP              ?  TextByLanguage("Своп","Swap")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+::DoubleToString(this.GetProperty(property),2)
         )  :
      property==ORDER_PROP_VOLUME            ?  TextByLanguage("Объём","Volume")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+::DoubleToString(this.GetProperty(property),dgl)
          ) :
      property==ORDER_PROP_VOLUME_CURRENT    ?  TextByLanguage("Невыполненный объём","Unfulfilled volume")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+::DoubleToString(this.GetProperty(property),dgl)
          ) :
      property==ORDER_PROP_PRICE_STOP_LIMIT  ? 
         TextByLanguage("Цена постановки Limit ордера при активации StopLimit ордера","Price of placing Limit order when StopLimit order activated")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+::DoubleToString(this.GetProperty(property),dg)
          ) :
      //--- Additional property
      property==ORDER_PROP_PROFIT_FULL       ?  TextByLanguage("Прибыль+комиссия+своп","Profit+Comission+Swap")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+::DoubleToString(this.GetProperty(property),2)
          ) :
      ""
     );
  }
//+------------------------------------------------------------------+
//| Return description of the order's string property                |
//+------------------------------------------------------------------+
string COrder::GetPropertyDescription(ENUM_ORDER_PROP_STRING property)
  {
   return
     (
      property==ORDER_PROP_SYMBOL         ?  TextByLanguage("Символ","Symbol")+": \""+this.GetProperty(property)+"\""            :
      property==ORDER_PROP_COMMENT        ?  TextByLanguage("Комментарий","Comment")+
         (this.GetProperty(property)==""  ?  TextByLanguage(": Отсутствует",": Not set"):": \""+this.GetProperty(property)+"\"") :
      property==ORDER_PROP_EXT_ID         ?  TextByLanguage("Идентификатор на бирже","ID on exchange")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
         (this.GetProperty(property)==""  ?  TextByLanguage(": Отсутствует",": Not set"):": \""+this.GetProperty(property)+"\"")):
      ""
     );
  }
//+------------------------------------------------------------------+

Thực hiện các phương thức trả về tên của trạng thái đơn hàng, tên của đơn hàng hoặc vị trí, tên của hướng giao dịch, mô tả loại hướng lệnh / vị trí và phương thức hiển thị thuận tiện các thuộc tính đơn hàng trong tạp chí .

Đầu tiên, thêm một thay thế macro khác vào tệp Defines.mqh để hiển thị thuận tiện tên hàm / phương thức trong tạp chí:

//+------------------------------------------------------------------+
//| Macro substitutions                                              |
//+------------------------------------------------------------------+
#define COUNTRY_LANG    "Russian"            // Country language
#define DFUN           (__FUNCTION__+": ")   // "Function description"
//+------------------------------------------------------------------+

Bây giờ, thay vì viết các chuỗi đầy đủ, chúng ta chỉ cần viết DFUN và trình biên dịch thay đổi mô tả thành các chuỗi được đặt trong macro.

//+------------------------------------------------------------------+
//| Return the order status name                                     |
//+------------------------------------------------------------------+
string COrder::StatusDescription(void) const
  {
   ENUM_ORDER_STATUS status=this.Status();
   ENUM_ORDER_TYPE   type=(ENUM_ORDER_TYPE)this.TypeOrder();
   return
     (
      status==ORDER_STATUS_BALANCE        ?  TextByLanguage("Балансная операция","Balance operation") :
      status==ORDER_STATUS_CREDIT         ?  TextByLanguage("Кредитная операция","Credits operation") :
      status==ORDER_STATUS_HISTORY_ORDER  || status==ORDER_STATUS_HISTORY_PENDING                     ?  
      (
       type>ORDER_TYPE_SELL ? TextByLanguage("Отложенный ордер","Pending order")                      :
       TextByLanguage("Ордер на ","The order to ")+(type==ORDER_TYPE_BUY ? TextByLanguage("покупку","buy") : TextByLanguage("продажу","sell"))
      )                                                                                               :
      status==ORDER_STATUS_DEAL           ?  TextByLanguage("Сделка","Deal")                          :
      status==ORDER_STATUS_MARKET_ACTIVE  ?  TextByLanguage("Позиция","Active position")              :
      status==ORDER_STATUS_MARKET_PENDING ?  TextByLanguage("Установленный отложенный ордер","Active pending order") :
      ""
     );
  }
//+------------------------------------------------------------------+
//| Return order or position name                                    |
//+------------------------------------------------------------------+
string COrder::TypeDescription(void) const
  {
   if(this.Status()==ORDER_STATUS_DEAL)
      return this.GetTypeDealDescription(this.TypeOrder());
   else switch(this.TypeOrder())
     {
      case ORDER_TYPE_BUY              :  return "Buy";
      case ORDER_TYPE_BUY_LIMIT        :  return "Buy Limit";
      case ORDER_TYPE_BUY_STOP         :  return "Buy Stop";
      case ORDER_TYPE_SELL             :  return "Sell";
      case ORDER_TYPE_SELL_LIMIT       :  return "Sell Limit";
      case ORDER_TYPE_SELL_STOP        :  return "Sell Stop";
      #ifdef __MQL4__
      case ORDER_TYPE_BALANCE          :  return TextByLanguage("Балансовая операция","Balance operation");
      case ORDER_TYPE_CREDIT           :  return TextByLanguage("Кредитная операция","Credit operation");
      #else 
      case ORDER_TYPE_BUY_STOP_LIMIT   :  return "Buy Stop Limit";
      case ORDER_TYPE_SELL_STOP_LIMIT  :  return "Sell Stop Limit";
      #endif 
      default                          :  return TextByLanguage("Неизвестный тип","Unknown type");
     }
  }
//+------------------------------------------------------------------+
//| Return deal direction name                                       |
//+------------------------------------------------------------------+
string COrder::DealEntryDescription(void) const
  {
   return(this.Status()==ORDER_STATUS_DEAL ? this.GetEntryDescription(this.GetProperty(ORDER_PROP_DEAL_ENTRY)) : "");
  }
//+------------------------------------------------------------------+
//| Return order/position direction type                             |
//+------------------------------------------------------------------+
string COrder::DirectionDescription(void) const
  {
   if(this.Status()==ORDER_STATUS_DEAL)
      return this.TypeDescription();
   switch(this.TypeByDirection())
     {
      case ORDER_TYPE_BUY  :  return "Buy";
      case ORDER_TYPE_SELL :  return "Sell";
      default              :  return TextByLanguage("Неизвестный тип","Unknown type");
     }
  }
//+------------------------------------------------------------------+
//| Send order properties to the journal                             |
//+------------------------------------------------------------------+
void COrder::Print(const bool full_prop=false)
  {
   ::Print("============= ",TextByLanguage("Начало списка параметров: \"","Beginning of the parameter list: \""),this.StatusDescription(),"\" =============");
   int beg=0, end=ORDER_PROP_INTEGER_TOTAL;
   for(int i=beg; i<end; i++)
     {
      ENUM_ORDER_PROP_INTEGER prop=(ENUM_ORDER_PROP_INTEGER)i;
      if(!full_prop && !this.SupportProperty(prop)) continue;
      ::Print(this.GetPropertyDescription(prop));
     }
   ::Print("------");
   beg=end; end+=ORDER_PROP_DOUBLE_TOTAL;
   for(int i=beg; i<end; i++)
     {
      ENUM_ORDER_PROP_DOUBLE prop=(ENUM_ORDER_PROP_DOUBLE)i;
      if(!full_prop && !this.SupportProperty(prop)) continue;
      ::Print(this.GetPropertyDescription(prop));
     }
   ::Print("------");
   beg=end; end+=ORDER_PROP_STRING_TOTAL;
   for(int i=beg; i<end; i++)
     {
      ENUM_ORDER_PROP_STRING prop=(ENUM_ORDER_PROP_STRING)i;
      if(!full_prop && !this.SupportProperty(prop)) continue;
      ::Print(this.GetPropertyDescription(prop));
     }
   ::Print("================== ",TextByLanguage("Конец списка параметров: \"","End of the parameter list: \""),this.StatusDescription(),"\" ==================\n");
  }
//+------------------------------------------------------------------+

Bây giờ tất cả các phương thức của lớp thứ tự trừu tượng COrder đã được thực hiện, chúng ta có thể thấy những gì chúng ta đã thực sự có được ở giai đoạn này.

Kiểm tra COrder

Hãy thử và xem các đối tượng cơ sở COrder được tạo và chứa đầy dữ liệu như thế nào. Hơn nữa, chúng ta sẽ phát triển các đối tượng theo các loại dựa trên nó và lưu trữ chúng trong các bộ sưu tập.
Trong thư mục Experts hoặc thư mục con, hãy tạo một thư mục mới và gọi nó là TestDo EAS. Tiếp theo, tạo một thư mục khác bên trong thư mục mới được tạo: Part01. Tập tin EA thử nghiệm được đặt trong đó.

//+------------------------------------------------------------------+
//|                                             TestDoEasyPart01.mq5 |
//|                                  Copyright 2019, Forex 365 Crop. |
//|                                              https://forex365.vn |
//+------------------------------------------------------------------+
#property copyright "Copyright 2019, Forex 365 Corp."
#property link      "https://forex365.vn"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
   
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   
  }
//+------------------------------------------------------------------+

Bài kiểm tra càng đơn giản càng tốt, vì vậy không cần phải phát minh lại bánh xe. Vì vậy, chúng ta chỉ đơn giản bao gồm lớp của thứ tự trừu tượng COrder và lớp CArrayObj từ thư viện chuẩn và tạo danh sách đối tượng:

//+------------------------------------------------------------------+
//|                                             TestDoEasyPart01.mq5 |
//|                                  Copyright 2019, Forex 365 Crop. |
//|                                              https://forex365.vn |
//+------------------------------------------------------------------+
#property copyright "Copyright 2019, Forex 365 Corp."
#property link      "https://forex365.vn"
#property version   "1.00"
//--- includes
#include <DoEasy\Objects\Order.mqh>
#include <Arrays\ArrayObj.mqh>
//--- global variables
CArrayObj      list_all_orders;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+

Tiếp theo, đặt cờ danh sách đã sắp xếp vào danh sách đối tượng trong OnInit () và điền vào đó với tất cả các giao dịch và đơn hàng lịch sử trong hai vòng.

Sau đó hiển thị dữ liệu trên từng đối tượng của danh sách đã điền trong nhật ký Chuyên gia của thiết bị đầu cuối trong vòng lặp:

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   list_all_orders.Sort();
   list_all_orders.Clear();
   if(!HistorySelect(0,TimeCurrent()))
     {
      Print(DFUN,TextByLanguage(": Не удалось получить историю сделок и ордеров",": Failed to get history of deals and orders"));
      return INIT_FAILED;
     }
//--- Deals
   int total_deals=HistoryDealsTotal();
   for(int i=0; i<total_deals; i++)
     {
      ulong deal_ticket=::HistoryDealGetTicket(i);
      if(deal_ticket==0) continue;
      COrder *deal=new COrder(ORDER_STATUS_DEAL,deal_ticket);
      if(deal==NULL) continue;
      list_all_orders.InsertSort(deal);
     }
//--- Orders
   int total_orders=HistoryOrdersTotal();
   for(int i=0; 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)
        {
         COrder *order=new COrder(ORDER_STATUS_HISTORY_ORDER,order_ticket);
         if(order==NULL) continue;
         list_all_orders.InsertSort(order);
        }
      else
        {
         COrder *order=new COrder(ORDER_STATUS_HISTORY_PENDING,order_ticket);
         if(order==NULL) continue;
         list_all_orders.InsertSort(order);
        }
     }
//--- Display in the journal
   int total=list_all_orders.Total();
   for(int i=0;i<total;i++)
     {
      COrder *order=list_all_orders.At(i);
      if(order==NULL)
         continue;
      order.Print();
     }
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+

Nếu bây giờ chúng ta cố gắng biên dịch EA, chúng ta sẽ gặp ba lỗi:

Các lỗi chỉ ra rằng chúng ta không thể truy cập các phương thức được bảo vệ của lớp từ bên ngoài. Rốt cuộc, chúng ta đã tạo ra hàm tạo COrder trong phần được bảo vệ của lớp. Khi chúng ta sử dụng lớp làm cơ sở để phát triển các đối tượng theo loại, mọi thứ sẽ ổn vì chúng sẽ có các hàm tạo mở. Bây giờ, để thực hiện kiểm tra, chúng ta chỉ cần di chuyển hàm tạo đến phần chung của lớp COrder:

Bây giờ tất cả được biên dịch không có lỗi và dữ liệu về tất cả các đơn đặt hàng và giao dịch trong lịch sử tài khoản giao dịch được hiển thị trên tạp chí thiết bị đầu cuối.

Tất cả các thuộc tính của mỗi đơn hàng / giao dịch, bao gồm cả những thứ không được hỗ trợ, được hiển thị.

Thực tế là chúng ta đã phát triển các phương thức trả về các cờ để hỗ trợ các thuộc tính cụ thể theo thứ tự này là ảo, để chúng được định nghĩa lại trong các lớp dẫn xuất. Các lớp dẫn xuất này sau đó được sử dụng để hiển thị dữ liệu trong tạp chí. Trong trường hợp đó, tất cả nên được hiển thị chính xác. Nếu có một thuộc tính không được hỗ trợ theo thứ tự, nó sẽ không được hiển thị trong tạp chí, vì phương thức Print (const bool full_prop \u003d false) của lớp COrder có cờ mặc định để vô hiệu hóa hiển thị các thuộc tính không được hỗ trợ trong tạp chí, trong khi Các phương thức ảo SupportProperty () của lớp chỉ cần trả về ‘true’ cho bất kỳ thuộc tính nào.

Phần tiếp theo có gì?

Phần đầu tiên (và nhỏ nhất) đã sẵn sàng. Chúng ta đã phát triển một đối tượng cơ bản cho việc thu thập các đơn đặt hàng và giao dịch lịch sử cũng như cho việc thu thập các đơn đặt hàng và vị trí thị trường. Cho đến nay không có giá trị thực tế nhưng đây chỉ là khởi đầu. Đối tượng cơ bản duy nhất này sẽ trở thành chìa khóa cho hệ thống lưu trữ và hiển thị dữ liệu trên hệ thống đặt hàng. Bước tiếp theo của chúng ta là phát triển các đối tượng và bộ sưu tập cần thiết khác bằng cách sử dụng các nguyên tắc tương tự. Tôi cũng sẽ tự động thu thập dữ liệu liên tục yêu cầu.

Trong phần tiếp theo, tôi sẽ phát triển một số lớp dựa trên thứ tự trừu tượng này. Các lớp sẽ mô tả thứ tự cụ thể, thỏa thuận và các loại vị trí. Tôi sẽ phát triển bộ sưu tập đầu tiên (bộ sưu tập các đơn đặt hàng và giao dịch lịch sử), cũng như cơ sở và đối tượng chính của thư viện – Engine. Tôi cũng sẽ thoát khỏi các lỗi trong khi cố gắng biên dịch thư viện trong MQL4 trong các phần tiếp theo của mô tả phát triển thư viện.

HotForex tặng thưởng 100% và miễn phí nạp rút tiền

BÌNH LUẬN

Vui lòng nhập bình luận của bạn
Vui lòng nhập tên của bạn ở đây

Website này sử dụng Akismet để hạn chế spam. Tìm hiểu bình luận của bạn được duyệt như thế nào.