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

Khái niệm:

Trong các phần trước dành cho thư viện đa nền tảng cho MetaTrader 5 và MetaTrader 4, chúng ta đã phát triển các công cụ để tạo các hàm trường hợp người dùng cho phép truy cập nhanh từ các chương trình vào bất kỳ dữ liệu nào trên bất kỳ đơn hàng và vị trí nào trên tài khoản hedging và netting. Đây là các chức năng để theo dõi các sự kiện xảy ra đối với các đơn hàng và vị trí – đặt, xóa và kích hoạt các đơn đặt hàng đang chờ xử lý, cũng như các vị trí mở và đóng.

Tuy nhiên, chức năng theo dõi việc kích hoạt các đơn đặt hàng StopLimit đã đặt và sửa đổi các lệnh và vị trí thị trường chưa được triển khai.

Trong bài viết này, chúng ta sẽ triển khai theo dõi sự kiện kích hoạt đơn hàng StopLimit dẫn đến việc đặt lệnh Limit.

Thư viện sẽ theo dõi các sự kiện như vậy và gửi các thông điệp cần thiết đến chương trình, để các sự kiện có thể được sử dụng hơn nữa.

Thực hiện

Khi kiểm tra kích hoạt các đơn đặt hàng StopLimit, ta nhận thấy rằng sự kiện này không được phản ánh trong lịch sử tài khoản, điều đó có nghĩa là không thể lấy được đơn giản từ lịch sử tài khoản ‘như hiện tại’. Do đó, chúng ta cần theo dõi trạng thái của các đơn đặt hàng hiện tại cho đến thời điểm nó thay đổi (trong trường hợp của chúng tôi, điều này có nghĩa là thay đổi loại đơn đặt hàng được đặt với cùng một vé).

ta sẽ giải quyết việc triển khai theo dõi kích hoạt đơn hàng StopLimit từ góc độ thực tế. Ngoài việc phát triển chức năng cần thiết, ta sẽ cho phép nó theo dõi các sự kiện khác bằng cách thay đổi các đơn đặt hàng và vị trí hiện tại (thay đổi giá của các đơn đặt hàng đang chờ xử lý, các mức StopLoss và TakeProfit của chúng, cũng như các cấp tương tự thuộc các vị trí mở).

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

Logic của chức năng chuẩn bị là như sau:

Chúng ta có quyền truy cập vào danh sách đầy đủ của tất cả các đơn đặt hàng và vị trí hoạt động trên tài khoản. Danh sách này cũng cho phép chúng ta có được trạng thái hiện tại của từng thuộc tính đối tượng. Để theo dõi sự thay đổi của các thuộc tính được giám sát, chúng ta cần có một danh sách bổ sung có chứa trạng thái “quá khứ” của các thuộc tính ban đầu sẽ bằng với thuộc tính hiện tại.

Khi so sánh các thuộc tính đối tượng từ hai danh sách này, một thuộc tính được coi là thay đổi ngay khi phát hiện sự khác biệt trong bất kỳ thuộc tính được giám sát nào. Trong trường hợp này, một đối tượng “đã thay đổi” ngay lập tức được tạo. Cả quá khứ và thuộc tính thay đổi đều được ghi vào đó và đối tượng được đặt vào danh sách mới – “danh sách các đối tượng đã thay đổi”.

Danh sách này sau đó sẽ được xử lý trong lớp theo dõi các sự kiện tài khoản.

Tất nhiên, chúng ta có thể gửi một sự kiện ngay lập tức sau khi phát hiện các thay đổi trong thuộc tính đối tượng, nhưng chúng ta có thể gặp tình huống khi một số đối tượng bị thay đổi trong một tích tắc. Nếu chúng ta xử lý các thay đổi ngay lập tức, chúng ta có thể xử lý thay đổi chỉ đối tượng cuối cùng từ gói, điều này không thể chấp nhận được. Điều này có nghĩa là chúng ta nên tạo danh sách tất cả các đối tượng đã thay đổi và kiểm tra kích thước của danh sách trong lớp xử lý sự kiện. Mỗi đối tượng thay đổi từ danh sách các đối tượng thay đổi được xử lý trong nó trong một vòng lặp. Điều này ngăn chúng ta mất một số thay đổi xảy ra đồng thời theo thứ tự và thuộc tính vị trí.

Khi tạo tập hợp các lệnh và vị trí thị trường trong phần thứ ba của mô tả thư viện, chúng ta đã quyết định cập nhật danh sách và lưu trữ tổng số băm hiện tại và trước đó được tính dưới dạng vé + thời gian thay đổi vị trí tính bằng mili giây và khối lượng. Điều này cho phép chúng ta liên tục theo dõi tình trạng hiện tại của các đơn đặt hàng và vị trí. Tuy nhiên, để theo dõi các thay đổi về thuộc tính thứ tự và vị trí, những dữ liệu này không đủ để tính toán tổng băm.

  • Chúng ta cần xem xét giá này để thay đổi giá đặt hàng
  • Chúng ta cũng cần xem xét các mức giá này để tính đến các thay đổi giá của StopLoss và TakeProfit.

Điều này có nghĩa là, chúng ta thêm ba giá này vào tổng băm nhưng mỗi giá được chuyển đổi thành số ulong bảy chữ số bằng cách xóa một dấu thập phân và tăng dung lượng số bằng một đơn hàng (để xem xét báo giá sáu chữ số). Ví dụ: nếu giá là 1.12345, giá trị tổng băm là 1123450.

Hãy bắt đầu thực hiện.

Thêm bảng liệt kê với các cờ của vị trí có thể và các tùy chọn thay đổi thứ tự cùng với các tùy chọn sẽ được theo dõi vào tệp Defines.mqh:

//+------------------------------------------------------------------+
//| List of flags of possible order and position change options      |
//+------------------------------------------------------------------+
enum ENUM_CHANGE_TYPE_FLAGS
  {
   CHANGE_TYPE_FLAG_NO_CHANGE    =  0,                      // No changes
   CHANGE_TYPE_FLAG_TYPE         =  1,                      // Order type change
   CHANGE_TYPE_FLAG_PRICE        =  2,                      // Price change
   CHANGE_TYPE_FLAG_STOP         =  4,                      // StopLoss change
   CHANGE_TYPE_FLAG_TAKE         =  8,                      // TakeProfit change
   CHANGE_TYPE_FLAG_ORDER        =  16                      // Order properties change flag
  };
//+------------------------------------------------------------------+
//| Possible order and position change options                       |
//+------------------------------------------------------------------+
enum ENUM_CHANGE_TYPE
  {
   CHANGE_TYPE_NO_CHANGE,                                   // No changes
   CHANGE_TYPE_ORDER_TYPE,                                  // Order type change
   CHANGE_TYPE_ORDER_PRICE,                                 // Order price change
   CHANGE_TYPE_ORDER_PRICE_STOP_LOSS,                       // Order and StopLoss price change 
   CHANGE_TYPE_ORDER_PRICE_TAKE_PROFIT,                     // Order and TakeProfit price change
   CHANGE_TYPE_ORDER_PRICE_STOP_LOSS_TAKE_PROFIT,           // Order, StopLoss and TakeProfit price change
   CHANGE_TYPE_ORDER_STOP_LOSS_TAKE_PROFIT,                 // StopLoss and TakeProfit change
   CHANGE_TYPE_ORDER_STOP_LOSS,                             // Order's StopLoss change
   CHANGE_TYPE_ORDER_TAKE_PROFIT,                           // Order's TakeProfit change
   CHANGE_TYPE_POSITION_STOP_LOSS_TAKE_PROFIT,              // Change position's StopLoss and TakeProfit
   CHANGE_TYPE_POSITION_STOP_LOSS,                          // Change position's StopLoss
   CHANGE_TYPE_POSITION_TAKE_PROFIT,                        // Change position's TakeProfit
  };
//+------------------------------------------------------------------+

Đối với các cờ của các tùy chọn thay đổi thuộc tính thứ tự và vị trí có thể:

  • Cờ thay đổi loại đơn đặt hàng được đặt khi kích hoạt lệnh StopLimit
  • Cờ thay đổi giá được đặt khi sửa đổi giá đặt hàng đang chờ xử lý
  • Dừng lỗ và lấy cờ thay đổi lợi nhuận là tự giải thích
  • Cờ lệnh được sử dụng để xác định thay đổi thuộc tính đơn hàng (không phải vị trí)

ta tin rằng, cờ đặt hàng yêu cầu làm rõ: loại đơn đặt hàng và giá có thể chỉ thay đổi rõ ràng cho các đơn đặt hàng đang chờ xử lý (thay đổi loại vị trí (đảo ngược) trên tài khoản lưới không được xem xét, vì chúng ta đã triển khai theo dõi trong phần thứ sáu của mô tả thư viện), trong khi giá StopLoss và TakeProfit có thể được điều chỉnh cho cả đơn hàng và vị trí. Đây là lý do tại sao chúng ta cần cờ thứ tự. Nó cho phép chúng ta xác định chính xác một sự kiện và gửi loại sự kiện đến lớp theo dõi sự kiện.

Việc liệt kê tất cả các tùy chọn sửa đổi thứ tự và vị trí có thể có tất cả các tùy chọn chúng ta sẽ theo dõi trong tương lai. Trong bài viết này, chúng ta sẽ triển khai theo dõi chỉ một sự kiện kích hoạt đơn hàng StopLimit (CHANGE_TYPE_ORDER_TYPE).

Thêm tám sự kiện mới (sẽ được gửi đến chương trình trong quá trình nhận dạng của chúng) vào bảng liệt kê ENUM_TRADE_EVENT của danh sách các sự kiện giao dịch tài khoản có thể:

//+------------------------------------------------------------------+
//| List of possible trading events on the account                   |
//+------------------------------------------------------------------+
enum ENUM_TRADE_EVENT
  {
   TRADE_EVENT_NO_EVENT = 0,                                // No trading event
   TRADE_EVENT_PENDING_ORDER_PLASED,                        // Pending order placed
   TRADE_EVENT_PENDING_ORDER_REMOVED,                       // Pending order removed
//--- enumeration members matching the ENUM_DEAL_TYPE enumeration members
//--- (constant order below should not be changed, no constants should be added/deleted)
   TRADE_EVENT_ACCOUNT_CREDIT = DEAL_TYPE_CREDIT,           // Accruing credit (3)
   TRADE_EVENT_ACCOUNT_CHARGE,                              // Additional charges
   TRADE_EVENT_ACCOUNT_CORRECTION,                          // Correcting entry
   TRADE_EVENT_ACCOUNT_BONUS,                               // Accruing bonuses
   TRADE_EVENT_ACCOUNT_COMISSION,                           // Additional commissions
   TRADE_EVENT_ACCOUNT_COMISSION_DAILY,                     // Commission charged at the end of a trading day
   TRADE_EVENT_ACCOUNT_COMISSION_MONTHLY,                   // Commission charged at the end of a trading month
   TRADE_EVENT_ACCOUNT_COMISSION_AGENT_DAILY,               // Agent commission charged at the end of a trading day
   TRADE_EVENT_ACCOUNT_COMISSION_AGENT_MONTHLY,             // Agent commission charged at the end of a month
   TRADE_EVENT_ACCOUNT_INTEREST,                            // Accrued interest on free funds
   TRADE_EVENT_BUY_CANCELLED,                               // Canceled buy deal
   TRADE_EVENT_SELL_CANCELLED,                              // Canceled sell deal
   TRADE_EVENT_DIVIDENT,                                    // Accruing dividends
   TRADE_EVENT_DIVIDENT_FRANKED,                            // Accruing franked dividends
   TRADE_EVENT_TAX                        = DEAL_TAX,       // Tax
//--- constants related to the DEAL_TYPE_BALANCE deal type from the DEAL_TYPE_BALANCE enumeration
   TRADE_EVENT_ACCOUNT_BALANCE_REFILL     = DEAL_TAX+1,     // Replenishing account balance
   TRADE_EVENT_ACCOUNT_BALANCE_WITHDRAWAL = DEAL_TAX+2,     // Withdrawing funds from an account
//--- Remaining possible trading events
//--- (constant order below can be changed, constants can be added/deleted)
   TRADE_EVENT_PENDING_ORDER_ACTIVATED    = DEAL_TAX+3,     // Pending order activated by price
   TRADE_EVENT_PENDING_ORDER_ACTIVATED_PARTIAL,             // Pending order partially activated by price
   TRADE_EVENT_POSITION_OPENED,                             // Position opened
   TRADE_EVENT_POSITION_OPENED_PARTIAL,                     // Position opened partially
   TRADE_EVENT_POSITION_CLOSED,                             // Position closed
   TRADE_EVENT_POSITION_CLOSED_BY_POS,                      // Position closed partially
   TRADE_EVENT_POSITION_CLOSED_BY_SL,                       // Position closed by StopLoss
   TRADE_EVENT_POSITION_CLOSED_BY_TP,                       // Position closed by TakeProfit
   TRADE_EVENT_POSITION_REVERSED_BY_MARKET,                 // Position reversal by a new deal (netting)
   TRADE_EVENT_POSITION_REVERSED_BY_PENDING,                // Position reversal by activating a pending order (netting)
   TRADE_EVENT_POSITION_REVERSED_BY_MARKET_PARTIAL,         // Position reversal by partial market order execution (netting)
   TRADE_EVENT_POSITION_REVERSED_BY_PENDING_PARTIAL,        // Position reversal by partial pending order activation (netting)
   TRADE_EVENT_POSITION_VOLUME_ADD_BY_MARKET,               // Added volume to a position by a new deal (netting)
   TRADE_EVENT_POSITION_VOLUME_ADD_BY_MARKET_PARTIAL,       // Added volume to a position by partial activation of an order (netting)
   TRADE_EVENT_POSITION_VOLUME_ADD_BY_PENDING,              // Added volume to a position by activating a pending order (netting)
   TRADE_EVENT_POSITION_VOLUME_ADD_BY_PENDING_PARTIAL,      // Added volume to a position by partial activation of a pending order (netting)
   TRADE_EVENT_POSITION_CLOSED_PARTIAL,                     // Position closed partially
   TRADE_EVENT_POSITION_CLOSED_PARTIAL_BY_POS,              // Position closed partially by an opposite one
   TRADE_EVENT_POSITION_CLOSED_PARTIAL_BY_SL,               // Position closed partially by StopLoss
   TRADE_EVENT_POSITION_CLOSED_PARTIAL_BY_TP,               // Position closed partially by TakeProfit
   TRADE_EVENT_TRIGGERED_STOP_LIMIT_ORDER,                  // StopLimit order activation
   TRADE_EVENT_MODIFY_ORDER_PRICE,                          // Changing order price
   TRADE_EVENT_MODIFY_ORDER_PRICE_STOP_LOSS,                // Changing order and StopLoss price 
   TRADE_EVENT_MODIFY_ORDER_PRICE_TAKE_PROFIT,              // Changing order and TakeProfit price
   TRADE_EVENT_MODIFY_ORDER_PRICE_STOP_LOSS_TAKE_PROFIT,    // Changing order, StopLoss and TakeProfit price
   TRADE_EVENT_MODIFY_ORDER_STOP_LOSS_TAKE_PROFIT,          // Changing order's StopLoss and TakeProfit price
   TRADE_EVENT_MODIFY_POSITION_STOP_LOSS,                   // Changing position StopLoss
   TRADE_EVENT_MODIFY_POSITION_TAKE_PROFIT,                 // Changing position TakeProfit
  };

Cuối cùng, thêm hằng số mới mô tả kích hoạt thứ tự StopLimit vào danh sách ENUM_EVENT_REASON của danh sách lý do sự kiện:

//+------------------------------------------------------------------+
//| Event reason                                                     |
//+------------------------------------------------------------------+
enum ENUM_EVENT_REASON
  {
   EVENT_REASON_REVERSE,                                    // Position reversal (netting)
   EVENT_REASON_REVERSE_PARTIALLY,                          // Position reversal by partial request execution (netting)
   EVENT_REASON_REVERSE_BY_PENDING,                         // Position reversal by pending order activation (netting)
   EVENT_REASON_REVERSE_BY_PENDING_PARTIALLY,               // Position reversal in case of a pending order partial execution (netting)
   //--- All constants related to a position reversal should be located in the above list
   EVENT_REASON_ACTIVATED_PENDING,                          // Pending order activation
   EVENT_REASON_ACTIVATED_PENDING_PARTIALLY,                // Pending order partial activation
   EVENT_REASON_STOPLIMIT_TRIGGERED,                        // StopLimit order activation
   EVENT_REASON_CANCEL,                                     // Cancelation
   EVENT_REASON_EXPIRED,                                    // Order expiration
   EVENT_REASON_DONE,                                       // Request executed in full
   EVENT_REASON_DONE_PARTIALLY,                             // Request executed partially
   EVENT_REASON_VOLUME_ADD,                                 // Add volume to a position (netting)
   EVENT_REASON_VOLUME_ADD_PARTIALLY,                       // Add volume to a position by a partial request execution (netting)
   EVENT_REASON_VOLUME_ADD_BY_PENDING,                      // Add volume to a position when a pending order is activated (netting)
   EVENT_REASON_VOLUME_ADD_BY_PENDING_PARTIALLY,            // Add volume to a position when a pending order is partially executed (netting)
   EVENT_REASON_DONE_SL,                                    // Closing by StopLoss
   EVENT_REASON_DONE_SL_PARTIALLY,                          // Partial closing by StopLoss
   EVENT_REASON_DONE_TP,                                    // Closing by TakeProfit
   EVENT_REASON_DONE_TP_PARTIALLY,                          // Partial closing by TakeProfit
   EVENT_REASON_DONE_BY_POS,                                // Closing by an opposite position
   EVENT_REASON_DONE_PARTIALLY_BY_POS,                      // Partial closing by an opposite position
   EVENT_REASON_DONE_BY_POS_PARTIALLY,                      // Closing an opposite position by a partial volume
   EVENT_REASON_DONE_PARTIALLY_BY_POS_PARTIALLY,            // Partial closing of an opposite position by a partial volume
   //--- Constants related to DEAL_TYPE_BALANCE deal type from the ENUM_DEAL_TYPE enumeration
   EVENT_REASON_BALANCE_REFILL,                             // Refilling the balance
   EVENT_REASON_BALANCE_WITHDRAWAL,                         // Withdrawing funds from the account
   //--- List of constants is relevant to TRADE_EVENT_ACCOUNT_CREDIT from the ENUM_TRADE_EVENT enumeration and shifted to +13 relative to ENUM_DEAL_TYPE (EVENT_REASON_ACCOUNT_CREDIT-3)
   EVENT_REASON_ACCOUNT_CREDIT,                             // Accruing credit
   EVENT_REASON_ACCOUNT_CHARGE,                             // Additional charges
   EVENT_REASON_ACCOUNT_CORRECTION,                         // Correcting entry
   EVENT_REASON_ACCOUNT_BONUS,                              // Accruing bonuses
   EVENT_REASON_ACCOUNT_COMISSION,                          // Additional commissions
   EVENT_REASON_ACCOUNT_COMISSION_DAILY,                    // Commission charged at the end of a trading day
   EVENT_REASON_ACCOUNT_COMISSION_MONTHLY,                  // Commission charged at the end of a trading month
   EVENT_REASON_ACCOUNT_COMISSION_AGENT_DAILY,              // Agent commission charged at the end of a trading day
   EVENT_REASON_ACCOUNT_COMISSION_AGENT_MONTHLY,            // Agent commission charged at the end of a month
   EVENT_REASON_ACCOUNT_INTEREST,                           // Accruing interest on free funds
   EVENT_REASON_BUY_CANCELLED,                              // Canceled buy deal
   EVENT_REASON_SELL_CANCELLED,                             // Canceled sell deal
   EVENT_REASON_DIVIDENT,                                   // Accruing dividends
   EVENT_REASON_DIVIDENT_FRANKED,                           // Accruing franked dividends
   EVENT_REASON_TAX                                         // Tax
  };
#define REASON_EVENT_SHIFT    (EVENT_REASON_ACCOUNT_CREDIT-3)

Chúng ta đã thực hiện tất cả các thay đổi trong tệp Defines.mqh.

Vì chúng ta đã quyết định tạo và lưu trữ danh sách các lệnh điều khiển, danh sách này sẽ lưu trữ các đối tượng với một tập các thuộc tính đủ tối thiểu để xác định thời điểm một trong số chúng thay đổi theo thứ tự thị trường và các đối tượng vị trí.

Hãy tạo lớp đối tượng thứ tự điều khiển.

Tạo lớp OrderControl.mqh mới trong thư mục Bộ sưu tập. Đặt lớp thư viện chuẩn CObject làm lớp cơ bản và bao gồm các tệp cần thiết cho hoạt động của lớp:

//+------------------------------------------------------------------+
//|                                                 OrderControl.mqh |
//|                                   Copyright 2020, Forex365 Corp. |
//|                                              https://forex365.vn |
//+------------------------------------------------------------------+
#property copyright "Copyright 2020, Forex365 Corp."
#property link      "https://forex365.vn"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include "..\Defines.mqh"             
#include "..\Objects\Orders\Order.mqh"
#include <Object.mqh>                 
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class COrderControl : public CObject
  {
private:

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

Khai báo tất cả các biến và phương thức cần thiết trong phần riêng của lớp ngay lập tức:

private:
   ENUM_CHANGE_TYPE  m_changed_type;                                    // Order change type
   MqlTick           m_tick;                                            // Tick structure
   string            m_symbol;                                          // Symbol
   ulong             m_position_id;                                     // Position ID
   ulong             m_ticket;                                          // Order ticket
   long              m_magic;                                           // Magic number
   ulong             m_type_order;                                      // Order type
   ulong             m_type_order_prev;                                 // Previous order type
   double            m_price;                                           // Order price
   double            m_price_prev;                                      // Previous order price
   double            m_stop;                                            // StopLoss price
   double            m_stop_prev;                                       // Previous StopLoss price
   double            m_take;                                            // TakeProfit price
   double            m_take_prev;                                       // Previous TakeProfit price
   double            m_volume;                                          // Order volume
   datetime          m_time;                                            // Order placement time
   datetime          m_time_prev;                                       // Order previous placement time
   int               m_change_code;                                     // Order change code
//--- return the presence of the property change flag
   bool              IsPresentChangeFlag(const int change_flag)   const { return (this.m_change_code & change_flag)==change_flag;   }
//--- Return the order parameters change type
   void              CalculateChangedType(void);

Tất cả các biến thành viên lớp có mô tả rõ ràng. ta nên làm rõ về biến lưu trữ cấu trúc đánh dấu: khi lệnh StopLimit được kích hoạt, chúng ta cần tiết kiệm thời gian kích hoạt. Thời gian nên được đặt theo mili giây, trong khi TimeCản() trả về thời gian không có mili giây. Để có được thời gian của lần đánh dấu cuối cùng, một đơn hàng đã được kích hoạt bằng mili giây, chúng ta sẽ sử dụng hàm chuẩn SymbolInfoTick() điền vào cấu trúc đánh dấu với dữ liệu, bao gồm thời gian đánh dấu tính bằng mili giây.

Mã thay đổi thứ tự bao gồm các cờ mà chúng ta đã mô tả trong bảng liệt kê ENUM_CHANGE_TYPE_FLAGS và phụ thuộc vào các thay đổi thuộc tính đơn hàng đã xảy ra. Phương thức riêng tính toán CompateChangedType() được mô tả bên dưới kiểm tra các cờ và tạo mã sửa đổi thứ tự.

Trong phần lớp công khai, sắp xếp các phương thức nhận và ghi dữ liệu về trạng thái trước và hiện tại của các thuộc tính thứ tự điều khiển, phương thức đặt loại sửa đổi thuộc tính thứ tự xảy ra, phương thức đặt trạng thái mới của một thứ tự đã sửa đổi, Phương thức trả về loại thay đổi đã xảy ra và phương thức kiểm tra sự thay đổi của các thuộc tính thứ tự, cũng như cài đặt và trả về loại thay đổi đã xảy ra. Phương thức này được gọi từ lớp thu thập lệnh thị trường và vị trí để phát hiện sửa đổi các lệnh và vị trí hoạt động.

//+------------------------------------------------------------------+
//|                                                 OrderControl.mqh |
//|                                   Copyright 2020, Forex365 Corp. |
//|                                              https://forex365.vn |
//+------------------------------------------------------------------+
#property copyright "Copyright 2020, Forex365 Corp."
#property link      "https://forex365.vn"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include "..\Defines.mqh"
#include "..\Objects\Orders\Order.mqh"
#include <Object.mqh>
//+------------------------------------------------------------------+
//| Order and position control class                                 |
//+------------------------------------------------------------------+
class COrderControl : public CObject
  {
private:
   ENUM_CHANGE_TYPE  m_changed_type;                                    // Order change type
   MqlTick           m_tick;                                            // Tick structure
   string            m_symbol;                                          // Symbol
   ulong             m_position_id;                                     // Position ID
   ulong             m_ticket;                                          // Order ticket
   long              m_magic;                                           // Magic number
   ulong             m_type_order;                                      // Order type
   ulong             m_type_order_prev;                                 // Previous order type
   double            m_price;                                           // Order price
   double            m_price_prev;                                      // Previous order price
   double            m_stop;                                            // StopLoss price
   double            m_stop_prev;                                       // Previous StopLoss price
   double            m_take;                                            // TakeProfit price
   double            m_take_prev;                                       // Previous TakeProfit price
   double            m_volume;                                          // Order volume
   datetime          m_time;                                            // Order placement time
   datetime          m_time_prev;                                       // Order previous placement time
   int               m_change_code;                                     // Order change code
//--- return the presence of the property change flag
   bool              IsPresentChangeFlag(const int change_flag)   const { return (this.m_change_code & change_flag)==change_flag;   }
//--- Calculate the order parameters change type
   void              CalculateChangedType(void);
public:
//--- Set the (1,2) current and previous type (2,3) current and previous price, (4,5) current and previous StopLoss,
//--- (6,7) current and previous TakeProfit, (8,9) current and previous placement time, (10) volume
   void              SetTypeOrder(const ulong type)                     { this.m_type_order=type;        }
   void              SetTypeOrderPrev(const ulong type)                 { this.m_type_order_prev=type;   }
   void              SetPrice(const double price)                       { this.m_price=price;            }
   void              SetPricePrev(const double price)                   { this.m_price_prev=price;       }
   void              SetStopLoss(const double stop_loss)                { this.m_stop=stop_loss;         }
   void              SetStopLossPrev(const double stop_loss)            { this.m_stop_prev=stop_loss;    }
   void              SetTakeProfit(const double take_profit)            { this.m_take=take_profit;       }
   void              SetTakeProfitPrev(const double take_profit)        { this.m_take_prev=take_profit;  }
   void              SetTime(const datetime time)                       { this.m_time=time;              }
   void              SetTimePrev(const datetime time)                   { this.m_time_prev=time;         }
   void              SetVolume(const double volume)                     { this.m_volume=volume;          }
//--- Set (1) change type, (2) new current status
   void              SetChangedType(const ENUM_CHANGE_TYPE type)        { this.m_changed_type=type;      }
   void              SetNewState(COrder* order);
//--- Check and set order parameters change flags and return the change type
   ENUM_CHANGE_TYPE  ChangeControl(COrder* compared_order);

//--- Return (1,2,3,4) position ID, ticket, magic and symbol, (5,6) current and previous type (7,8) current and previous price,
//--- (9,10) current and previous StopLoss, (11,12) current and previous TakeProfit, (13,14) current and previous placement time, (15) volume
   ulong             PositionID(void)                             const { return this.m_position_id;     }
   ulong             Ticket(void)                                 const { return this.m_ticket;          }
   long              Magic(void)                                  const { return this.m_magic;           }
   string            Symbol(void)                                 const { return this.m_symbol;          }
   ulong             TypeOrder(void)                              const { return this.m_type_order;      }
   ulong             TypeOrderPrev(void)                          const { return this.m_type_order_prev; }
   double            Price(void)                                  const { return this.m_price;           }
   double            PricePrev(void)                              const { return this.m_price_prev;      }
   double            StopLoss(void)                               const { return this.m_stop;            }
   double            StopLossPrev(void)                           const { return this.m_stop_prev;       }
   double            TakeProfit(void)                             const { return this.m_take;            }
   double            TakeProfitPrev(void)                         const { return this.m_take_prev;       }
   ulong             Time(void)                                   const { return this.m_time;            }
   ulong             TimePrev(void)                               const { return this.m_time_prev;       }
   double            Volume(void)                                 const { return this.m_volume;          }
//--- Return the change type
   ENUM_CHANGE_TYPE  GetChangeType(void)                          const { return this.m_changed_type;    }

//--- Constructor
                     COrderControl(const ulong position_id,const ulong ticket,const long magic,const string symbol) :
                                                                        m_change_code(CHANGE_TYPE_FLAG_NO_CHANGE),
                                                                        m_changed_type(CHANGE_TYPE_NO_CHANGE),
                                                                        m_position_id(position_id),m_symbol(symbol),m_ticket(ticket),m_magic(magic) {;}
  };
//+------------------------------------------------------------------+

Trình xây dựng lớp nhận được ID vị trí, vé, số ma thuật và ký hiệu thứ tự / vị trí. Trong danh sách khởi tạo của nó, đặt lại cờ thay đổi thứ tự và loại thay đổi đã xảy ra, cũng như ghi dữ liệu thứ tự / vị trí thu được trong các tham số đã truyền vào các biến thành viên lớp tương ứng ngay lập tức.

Thực hiện các phương thức khai báo bên ngoài lớp cơ thể.

Phương thức riêng tính toán loại thay đổi tham số thứ tự/vị trí:

//+------------------------------------------------------------------+
//| Calculate order parameters change type                           |
//+------------------------------------------------------------------+
void COrderControl::CalculateChangedType(void)
  {
   this.m_changed_type=
     (
      //--- If the order flag is set
      this.IsPresentChangeFlag(CHANGE_TYPE_FLAG_ORDER) ? 
        (
         //--- If StopLimit order is activated
         this.IsPresentChangeFlag(CHANGE_TYPE_FLAG_TYPE)    ?  CHANGE_TYPE_ORDER_TYPE :
         //--- If an order price is modified
         this.IsPresentChangeFlag(CHANGE_TYPE_FLAG_PRICE)   ? 
           (
            //--- If StopLoss and TakeProfit are modified together with the price
            this.IsPresentChangeFlag(CHANGE_TYPE_FLAG_TAKE) && this.IsPresentChangeFlag(CHANGE_TYPE_FLAG_STOP) ? CHANGE_TYPE_ORDER_PRICE_STOP_LOSS_TAKE_PROFIT :
            //--- If TakeProfit modified together with the price
            this.IsPresentChangeFlag(CHANGE_TYPE_FLAG_TAKE) ? CHANGE_TYPE_ORDER_PRICE_TAKE_PROFIT : 
            //--- If StopLoss modified together with the price
            this.IsPresentChangeFlag(CHANGE_TYPE_FLAG_STOP) ? CHANGE_TYPE_ORDER_PRICE_STOP_LOSS   :
            //--- Only order price is modified
            CHANGE_TYPE_ORDER_PRICE
           ) : 
         //--- Price is not modified
         //--- If StopLoss and TakeProfit are modified
         this.IsPresentChangeFlag(CHANGE_TYPE_FLAG_TAKE) && this.IsPresentChangeFlag(CHANGE_TYPE_FLAG_STOP) ? CHANGE_TYPE_ORDER_STOP_LOSS_TAKE_PROFIT :
         //--- If TakeProfit is modified
         this.IsPresentChangeFlag(CHANGE_TYPE_FLAG_TAKE) ? CHANGE_TYPE_ORDER_TAKE_PROFIT : 
         //--- If StopLoss is modified
         this.IsPresentChangeFlag(CHANGE_TYPE_FLAG_STOP) ? CHANGE_TYPE_ORDER_STOP_LOSS   :
         //--- No changes
         CHANGE_TYPE_NO_CHANGE
        ) : 
      //--- Position
      //--- If position's StopLoss and TakeProfit are modified
      this.IsPresentChangeFlag(CHANGE_TYPE_FLAG_TAKE) && this.IsPresentChangeFlag(CHANGE_TYPE_FLAG_STOP) ? CHANGE_TYPE_POSITION_STOP_LOSS_TAKE_PROFIT :
      //--- If position's TakeProfit is modified
      this.IsPresentChangeFlag(CHANGE_TYPE_FLAG_TAKE) ? CHANGE_TYPE_POSITION_TAKE_PROFIT : 
      //--- If position's StopLoss is modified
      this.IsPresentChangeFlag(CHANGE_TYPE_FLAG_STOP) ? CHANGE_TYPE_POSITION_STOP_LOSS   :
      //--- No changes
      CHANGE_TYPE_NO_CHANGE
     );
  }
//+------------------------------------------------------------------+

Phương thức ghi loại thay đổi xảy ra từ phép liệt kê ENUM_CHANGE_TYPE được khai báo trước đó sang biến thành viên lớp m_changed_type tùy thuộc vào sự hiện diện của các cờ trong biến m_change_code.

Tất cả các hành động liên quan đến kiểm tra cờ được mô tả trong các nhận xét cho chuỗi liệt kê phương thức và phải dễ hiểu.

Phương thức riêng tư kiểm tra sự hiện diện của cờ trong biến m_change_code

bool IsPresentChangeFlag(const int change_flag const { return (this.m_change_code & change_flag)==change_flag }

Phương thức nhận cờ kiểm tra. Sự hiện diện của nó trong m_change_code được kiểm tra bằng thao tác AND từng bit và kết quả boolean của phép so sánh (hoạt động từng bit giữa mã và giá trị cờ) với giá trị cờ được kiểm tra được trả về.

Phương thức trả về một trạng thái có liên quan mới của các thuộc tính thứ tự / vị trí:

//+------------------------------------------------------------------+
//| Set the new relevant status                                      |
//+------------------------------------------------------------------+
void COrderControl::SetNewState(COrder* order)
  {
   if(order==NULL || !::SymbolInfoTick(this.Symbol(),this.m_tick))
      return;
   //--- New type
   this.SetTypeOrderPrev(this.TypeOrder());
   this.SetTypeOrder(order.TypeOrder());
   //--- New price
   this.SetPricePrev(this.Price());
   this.SetPrice(order.PriceOpen());
   //--- New StopLoss
   this.SetStopLossPrev(this.StopLoss());
   this.SetStopLoss(order.StopLoss());
   //--- New TakeProfit
   this.SetTakeProfitPrev(this.TakeProfit());
   this.SetTakeProfit(order.TakeProfit());
   //--- New time
   this.SetTimePrev(this.Time());
   this.SetTime(this.m_tick.time_msc);
  }
//+------------------------------------------------------------------+

Con trỏ tới thứ tự / vị trí, trong đó thay đổi một trong các thuộc tính xảy ra, được truyền cho phương thức.

Ngay khi phát hiện thay đổi một trong các thuộc tính thứ tự / vị trí, chúng ta cần lưu trạng thái mới để kiểm tra thêm, trước tiên phương thức lưu trạng thái thuộc tính hiện tại của nó như trạng thái trước đó và ghi giá trị thuộc tính từ đơn hàng được truyền vào phương thức Như tình trạng hiện tại của nó.

Khi lưu thời gian của một sự kiện đã xảy ra, hãy sử dụng hàm chuẩn SymbolInfoTick() để nhận thời gian đánh dấu tính bằng mili giây.

Phương thức chính được gọi từ lớp CMarketCollection và xác định các thay đổi đã xảy ra:

//+------------------------------------------------------------------+
//| Check and set order parameters change flags                      |
//+------------------------------------------------------------------+
ENUM_CHANGE_TYPE COrderControl::ChangeControl(COrder *compared_order)
  {
   this.m_change_code=CHANGE_TYPE_FLAG_NO_CHANGE;
   if(compared_order==NULL || compared_order.Ticket()!=this.m_ticket)
      return CHANGE_TYPE_NO_CHANGE;
   if(compared_order.Status()==ORDER_STATUS_MARKET_ORDER || compared_order.Status()==ORDER_STATUS_MARKET_PENDING)
      this.m_change_code+=CHANGE_TYPE_FLAG_ORDER;
   if(compared_order.TypeOrder()!=this.m_type_order)
      this.m_change_code+=CHANGE_TYPE_FLAG_TYPE;
   if(compared_order.PriceOpen()!=this.m_price)
      this.m_change_code+=CHANGE_TYPE_FLAG_PRICE;
   if(compared_order.StopLoss()!=this.m_stop)
      this.m_change_code+=CHANGE_TYPE_FLAG_STOP;
   if(compared_order.TakeProfit()!=this.m_take)
      this.m_change_code+=CHANGE_TYPE_FLAG_TAKE;
   this.CalculateChangedType();
   return this.GetChangeType();
  }
//+------------------------------------------------------------------+

Phương thức nhận con trỏ đến thứ tự / vị trí đã kiểm tra và khởi tạo mã thay đổi. Nếu một đối tượng trống của lệnh so sánh được thông qua hoặc vé của nó không bằng vé của lệnh kiểm soát hiện tại, hãy trả lại mã vắng mặt thay đổi.

Sau đó kiểm tra tất cả các thuộc tính theo dõi của kiểm soát và kiểm tra đơn đặt hàng. Nếu tìm thấy sự không phù hợp, cờ cần thiết mô tả thay đổi này sẽ được thêm vào mã thay đổi.

Tiếp theo, loại thay đổi được tính bằng mã thay đổi được hình thành đầy đủ trong phương thức Tính toánChangedType() và được trả về chương trình gọi bằng phương thức GetChangeType().

Danh sách đầy đủ của lớp thứ tự kiểm soát:

//+------------------------------------------------------------------+
//|                                                 OrderControl.mqh |
//|                                   Copyright 2020, Forex365 Corp. |
//|                                              https://forex365.vn |
//+------------------------------------------------------------------+
#property copyright "Copyright 2020, Forex365 Corp."
#property link      "https://forex365.vn"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include "..\Defines.mqh"
#include "..\Objects\Orders\Order.mqh"
#include <Object.mqh>
//+------------------------------------------------------------------+
//| Order and position control class                                 |
//+------------------------------------------------------------------+
class COrderControl : public CObject
  {
private:
   ENUM_CHANGE_TYPE  m_changed_type;                                    // Order change type
   MqlTick           m_tick;                                            // Tick structure
   string            m_symbol;                                          // Symbol
   ulong             m_position_id;                                     // Position ID
   ulong             m_ticket;                                          // Order ticket
   long              m_magic;                                           // Magic number
   ulong             m_type_order;                                      // Order type
   ulong             m_type_order_prev;                                 // Previous order type
   double            m_price;                                           // Order price
   double            m_price_prev;                                      // Previous order price
   double            m_stop;                                            // StopLoss price
   double            m_stop_prev;                                       // Previous StopLoss price
   double            m_take;                                            // TakeProfit price
   double            m_take_prev;                                       // Previous TakeProfit price
   double            m_volume;                                          // Order volume
   datetime          m_time;                                            // Order placement time
   datetime          m_time_prev;                                       // Order previous placement time
   int               m_change_code;                                     // Order change code
//--- return the presence of the property change flag
   bool              IsPresentChangeFlag(const int change_flag)   const { return (this.m_change_code & change_flag)==change_flag;   }
//--- Calculate the order parameters change type
   void              CalculateChangedType(void);
public:
//--- Set the (1,2) current and previous type (2,3) current and previous price, (4,5) current and previous StopLoss,
//--- (6,7) current and previous TakeProfit, (8,9) current and previous placement time, (10) volume
   void              SetTypeOrder(const ulong type)                     { this.m_type_order=type;        }
   void              SetTypeOrderPrev(const ulong type)                 { this.m_type_order_prev=type;   }
   void              SetPrice(const double price)                       { this.m_price=price;            }
   void              SetPricePrev(const double price)                   { this.m_price_prev=price;       }
   void              SetStopLoss(const double stop_loss)                { this.m_stop=stop_loss;         }
   void              SetStopLossPrev(const double stop_loss)            { this.m_stop_prev=stop_loss;    }
   void              SetTakeProfit(const double take_profit)            { this.m_take=take_profit;       }
   void              SetTakeProfitPrev(const double take_profit)        { this.m_take_prev=take_profit;  }
   void              SetTime(const datetime time)                       { this.m_time=time;              }
   void              SetTimePrev(const datetime time)                   { this.m_time_prev=time;         }
   void              SetVolume(const double volume)                     { this.m_volume=volume;          }
//--- Set (1) change type, (2) new current status
   void              SetChangedType(const ENUM_CHANGE_TYPE type)        { this.m_changed_type=type;      }
   void              SetNewState(COrder* order);
//--- Check and set order parameters change flags and return the change type
   ENUM_CHANGE_TYPE  ChangeControl(COrder* compared_order);

//--- Return (1,2,3,4) position ID, ticket, magic and symbol, (5,6) current and previous type (7,8) current and previous price,
//--- (9,10) current and previous StopLoss, (11,12) current and previous TakeProfit, (13,14) current and previous placement time, (15) volume
   ulong             PositionID(void)                             const { return this.m_position_id;     }
   ulong             Ticket(void)                                 const { return this.m_ticket;          }
   long              Magic(void)                                  const { return this.m_magic;           }
   string            Symbol(void)                                 const { return this.m_symbol;          }
   ulong             TypeOrder(void)                              const { return this.m_type_order;      }
   ulong             TypeOrderPrev(void)                          const { return this.m_type_order_prev; }
   double            Price(void)                                  const { return this.m_price;           }
   double            PricePrev(void)                              const { return this.m_price_prev;      }
   double            StopLoss(void)                               const { return this.m_stop;            }
   double            StopLossPrev(void)                           const { return this.m_stop_prev;       }
   double            TakeProfit(void)                             const { return this.m_take;            }
   double            TakeProfitPrev(void)                         const { return this.m_take_prev;       }
   ulong             Time(void)                                   const { return this.m_time;            }
   ulong             TimePrev(void)                               const { return this.m_time_prev;       }
   double            Volume(void)                                 const { return this.m_volume;          }
//--- Return the change type
   ENUM_CHANGE_TYPE  GetChangeType(void)                          const { return this.m_changed_type;    }

//--- Constructor
                     COrderControl(const ulong position_id,const ulong ticket,const long magic,const string symbol) :
                                                                        m_change_code(CHANGE_TYPE_FLAG_NO_CHANGE),
                                                                        m_changed_type(CHANGE_TYPE_NO_CHANGE),
                                                                        m_position_id(position_id),m_symbol(symbol),m_ticket(ticket),m_magic(magic) {;}
  };
//+------------------------------------------------------------------+
//| Check and set the order parameters change flags                  |
//+------------------------------------------------------------------+
ENUM_CHANGE_TYPE COrderControl::ChangeControl(COrder *compared_order)
  {
   this.m_change_code=CHANGE_TYPE_FLAG_NO_CHANGE;
   if(compared_order==NULL || compared_order.Ticket()!=this.m_ticket)
      return CHANGE_TYPE_NO_CHANGE;
   if(compared_order.Status()==ORDER_STATUS_MARKET_ORDER || compared_order.Status()==ORDER_STATUS_MARKET_PENDING)
      this.m_change_code+=CHANGE_TYPE_FLAG_ORDER;
   if(compared_order.TypeOrder()!=this.m_type_order)
      this.m_change_code+=CHANGE_TYPE_FLAG_TYPE;
   if(compared_order.PriceOpen()!=this.m_price)
      this.m_change_code+=CHANGE_TYPE_FLAG_PRICE;
   if(compared_order.StopLoss()!=this.m_stop)
      this.m_change_code+=CHANGE_TYPE_FLAG_STOP;
   if(compared_order.TakeProfit()!=this.m_take)
      this.m_change_code+=CHANGE_TYPE_FLAG_TAKE;
   this.CalculateChangedType();
   return this.GetChangeType();
  }
//+------------------------------------------------------------------+
//| Calculate the order parameters change type                       |
//+------------------------------------------------------------------+
void COrderControl::CalculateChangedType(void)
  {
   this.m_changed_type=
     (
      //--- If the order flag is set
      this.IsPresentChangeFlag(CHANGE_TYPE_FLAG_ORDER) ? 
        (
         //--- If StopLimit order is activated
         this.IsPresentChangeFlag(CHANGE_TYPE_FLAG_TYPE)    ?  CHANGE_TYPE_ORDER_TYPE :
         //--- If an order price is modified
         this.IsPresentChangeFlag(CHANGE_TYPE_FLAG_PRICE)   ? 
           (
            //--- If StopLoss and TakeProfit are modified together with the price
            this.IsPresentChangeFlag(CHANGE_TYPE_FLAG_TAKE) && this.IsPresentChangeFlag(CHANGE_TYPE_FLAG_STOP) ? CHANGE_TYPE_ORDER_PRICE_STOP_LOSS_TAKE_PROFIT :
            //--- If TakeProfit modified together with the price
            this.IsPresentChangeFlag(CHANGE_TYPE_FLAG_TAKE) ? CHANGE_TYPE_ORDER_PRICE_TAKE_PROFIT : 
            //--- If StopLoss modified together with the price
            this.IsPresentChangeFlag(CHANGE_TYPE_FLAG_STOP) ? CHANGE_TYPE_ORDER_PRICE_STOP_LOSS   :
            //--- Only order price is modified
            CHANGE_TYPE_ORDER_PRICE
           ) : 
         //--- Price is not modified
         //--- If StopLoss and TakeProfit are modified
         this.IsPresentChangeFlag(CHANGE_TYPE_FLAG_TAKE) && this.IsPresentChangeFlag(CHANGE_TYPE_FLAG_STOP) ? CHANGE_TYPE_ORDER_STOP_LOSS_TAKE_PROFIT :
         //--- If TakeProfit is modified
         this.IsPresentChangeFlag(CHANGE_TYPE_FLAG_TAKE) ? CHANGE_TYPE_ORDER_TAKE_PROFIT : 
         //--- If StopLoss is modified
         this.IsPresentChangeFlag(CHANGE_TYPE_FLAG_STOP) ? CHANGE_TYPE_ORDER_STOP_LOSS   :
         //--- No changes
         CHANGE_TYPE_NO_CHANGE
        ) : 
      //--- Position
      //--- If position's StopLoss and TakeProfit are modified
      this.IsPresentChangeFlag(CHANGE_TYPE_FLAG_TAKE) && this.IsPresentChangeFlag(CHANGE_TYPE_FLAG_STOP) ? CHANGE_TYPE_POSITION_STOP_LOSS_TAKE_PROFIT :
      //--- If position's TakeProfit is modified
      this.IsPresentChangeFlag(CHANGE_TYPE_FLAG_TAKE) ? CHANGE_TYPE_POSITION_TAKE_PROFIT : 
      //--- If position's StopLoss is modified
      this.IsPresentChangeFlag(CHANGE_TYPE_FLAG_STOP) ? CHANGE_TYPE_POSITION_STOP_LOSS   :
      //--- No changes
      CHANGE_TYPE_NO_CHANGE
     );
  }
//+------------------------------------------------------------------+
//| Set the new relevant status                                      |
//+------------------------------------------------------------------+
void COrderControl::SetNewState(COrder* order)
  {
   if(order==NULL || !::SymbolInfoTick(this.Symbol(),this.m_tick))
      return;
   //--- New type
   this.SetTypeOrderPrev(this.TypeOrder());
   this.SetTypeOrder(order.TypeOrder());
   //--- New price
   this.SetPricePrev(this.Price());
   this.SetPrice(order.PriceOpen());
   //--- New StopLoss
   this.SetStopLossPrev(this.StopLoss());
   this.SetStopLoss(order.StopLoss());
   //--- New TakeProfit
   this.SetTakeProfitPrev(this.TakeProfit());
   this.SetTakeProfit(order.TakeProfit());
   //--- New time
   this.SetTimePrev(this.Time());
   this.SetTime(this.m_tick.time_msc);
  }
//+------------------------------------------------------------------+

Hãy cải thiện các đơn đặt hàng thị trường và bộ sưu tập vị trí của CMarketCollection.

Chúng ta cần theo dõi các thay đổi tài sản xảy ra trong các đơn đặt hàng và vị trí hoạt động. Vì chúng ta nhận được tất cả các đơn đặt hàng thị trường và vị trí trong lớp này, nên sẽ rất hợp lý khi kiểm tra sửa đổi của chúng trong đó.

Bao gồm các tập tin lớp thứ tự kiểm soát. Trong phần lớp riêng, khai báo danh sách lưu trữ các lệnh và vị trí kiểm soát, danh sách lưu trữ các lệnh và vị trí đã thay đổi, biến thành viên lớp để lưu trữ loại thay đổi đơn hàng và biến để lưu trữ tỷ lệ để chuyển đổi giá thành tổng băm.

Ngoài ra, khai báo các phương thức riêng tư:

Phương thức chuyển đổi các thuộc tính đơn hàng thành tổng băm, phương thức thêm đơn hàng hoặc vị trí vào danh sách các đơn hàng và vị trí đang chờ xử lý trên tài khoản, phương thức tạo và thêm lệnh kiểm soát vào danh sách các lệnh điều khiển và phương thức tạo và Thêm một đơn hàng đã thay đổi vào danh sách các đơn hàng đã thay đổi, phương pháp xóa đơn hàng khỏi danh sách đơn hàng kiểm soát bằng vé và ID vị trí, phương thức trả về chỉ số đơn hàng kiểm soát trong danh sách đơn hàng kiểm soát theo vé và vị trí ID và người xử lý một sự kiện thay đổi thứ tự / vị trí hiện có.

Trong phần công khai của lớp, khai báo phương thức trả về danh sách đã tạo của các đơn hàng đã thay đổi.

//+------------------------------------------------------------------+
//|                                             MarketCollection.mqh |
//|                                   Copyright 2020, Forex365 Corp. |
//|                                              https://forex365.vn |
//+------------------------------------------------------------------+
#property copyright "Copyright 2020, Forex365 Corp."
#property link      "https://forex365.vn"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include "ListObj.mqh"
#include "..\Services\Select.mqh"
#include "..\Objects\Orders\MarketOrder.mqh"
#include "..\Objects\Orders\MarketPending.mqh"
#include "..\Objects\Orders\MarketPosition.mqh"
#include "OrderControl.mqh"
//+------------------------------------------------------------------+
//| Collection of market orders and positions                        |
//+------------------------------------------------------------------+
class CMarketCollection : public CListObj
  {
private:
   struct MqlDataCollection
     {
      ulong          hash_sum_acc;           // Hash sum of all orders and positions on the account
      int            total_market;           // Number of market orders on the account
      int            total_pending;          // Number of pending orders on the account
      int            total_positions;        // Number of positions on the account
      double         total_volumes;          // Total volume of orders and positions on the account
     };
   MqlDataCollection m_struct_curr_market;   // Current data on market orders and positions on the account
   MqlDataCollection m_struct_prev_market;   // Previous data on market orders and positions on the account
   CListObj          m_list_all_orders;      // List of pending orders and positions on the account
   CArrayObj         m_list_control;         // List of control orders
   CArrayObj         m_list_changed;         // List of changed orders
   COrder            m_order_instance;       // Order object for searching by property
   ENUM_CHANGE_TYPE  m_change_type;          // Order change type
   bool              m_is_trade_event;       // Trading event flag
   bool              m_is_change_volume;     // Total volume change flag
   double            m_change_volume_value;  // Total volume change value
   ulong             m_k_pow;                // Ratio for converting the price into a hash sum
   int               m_new_market_orders;    // Number of new market orders
   int               m_new_positions;        // Number of new positions
   int               m_new_pendings;         // Number of new pending orders
//--- Save the current values of the account data status as previous ones
   void              SavePrevValues(void)                                                                { this.m_struct_prev_market=this.m_struct_curr_market;                  }
//--- Convert order data into a hash sum value
   ulong             ConvertToHS(COrder* order) const;
//--- Add an order or a position to the list of pending orders and positions on an account and sets the data on market orders and positions on the account
   bool              AddToListMarket(COrder* order);
//--- (1) Create and add a control order to the list of control orders, (2) a control order to the list of changed control orders
   bool              AddToListControl(COrder* order);
   bool              AddToListChanges(COrderControl* order_control);
//--- Remove an order by a ticket or a position ID from the list of control orders
   bool              DeleteOrderFromListControl(const ulong ticket,const ulong id);
//--- Return the control order index in the list by a position ticket and ID
   int               IndexControlOrder(const ulong ticket,const ulong id);
//--- Handler of an existing order/position change event
   void              OnChangeEvent(COrder* order,const int index);
public:
//--- Return the list of (1) all pending orders and open positions, (2) modified orders and positions
   CArrayObj*        GetList(void)                                                                       { return &this.m_list_all_orders;                                       }
   CArrayObj*        GetListChanges(void)                                                                { return &this.m_list_changed;                                          }
//--- Return the list of orders and positions with an open time from begin_time to end_time
   CArrayObj*        GetListByTime(const datetime begin_time=0,const datetime end_time=0);
//--- Return the list of orders and positions by selected (1) double, (2) integer and (3) string property fitting a compared condition
   CArrayObj*        GetList(ENUM_ORDER_PROP_DOUBLE property,double value,ENUM_COMPARER_TYPE mode=EQUAL) { return CSelect::ByOrderProperty(this.GetList(),property,value,mode);  }
   CArrayObj*        GetList(ENUM_ORDER_PROP_INTEGER property,long value,ENUM_COMPARER_TYPE mode=EQUAL)  { return CSelect::ByOrderProperty(this.GetList(),property,value,mode);  }
   CArrayObj*        GetList(ENUM_ORDER_PROP_STRING property,string value,ENUM_COMPARER_TYPE mode=EQUAL) { return CSelect::ByOrderProperty(this.GetList(),property,value,mode);  }
//--- Return the number of (1) new market order, (2) new pending orders, (3) new positions, (4) occurred trading event flag, (5) changed volume
   int               NewMarketOrders(void)                                                         const { return this.m_new_market_orders;                                      }
   int               NewPendingOrders(void)                                                        const { return this.m_new_pendings;                                           }
   int               NewPositions(void)                                                            const { return this.m_new_positions;                                          }
   bool              IsTradeEvent(void)                                                            const { return this.m_is_trade_event;                                         }
   double            ChangedVolumeValue(void)                                                      const { return this.m_change_volume_value;                                    }
//--- Constructor
                     CMarketCollection(void);
//--- Update the list of pending orders and positions
   void              Refresh(void);
  };
//+------------------------------------------------------------------+

Thêm xóa và sắp xếp danh sách các lệnh điều khiển và danh sách các lệnh đã thay đổi, cũng như tính toán tỷ lệ xác định tổng băm cho hàm tạo của lớp:

//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CMarketCollection::CMarketCollection(void) : m_is_trade_event(false),m_is_change_volume(false),m_change_volume_value(0)
  {
   this.m_list_all_orders.Sort(SORT_BY_ORDER_TIME_OPEN);
   this.m_list_all_orders.Clear();
   ::ZeroMemory(this.m_struct_prev_market);
   this.m_struct_prev_market.hash_sum_acc=WRONG_VALUE;
   this.m_list_all_orders.Type(COLLECTION_MARKET_ID);
   this.m_list_control.Clear();  
   this.m_list_control.Sort();   
   this.m_list_changed.Clear();  
   this.m_list_changed.Sort();   
   this.m_k_pow=(ulong)pow(10,6);
  }
//+------------------------------------------------------------------+

Phương pháp chuyển đổi các thuộc tính thứ tự thành số để tính tổng băm:

//+---------------------------------------------------------------------+
//| Convert the order price and its type into a number for the hash sum |
//+---------------------------------------------------------------------+
ulong CMarketCollection::ConvertToHS(COrder *order) const
  {
   if(order==NULL)
      return 0;
   ulong price=ulong(order.PriceOpen()*this.m_k_pow);
   ulong stop=ulong(order.StopLoss()*this.m_k_pow);
   ulong take=ulong(order.TakeProfit()*this.m_k_pow);
   ulong type=order.TypeOrder();
   ulong ticket=order.Ticket();
   return price+stop+take+type+ticket;
  }
//+------------------------------------------------------------------+

Phương thức nhận được một con trỏ tới thứ tự có dữ liệu nên được chuyển đổi thành một số. Sau đó, các thuộc tính kép của đơn hàng được chuyển đổi thành một số cho tổng băm bằng cách nhân đơn giản với tỷ lệ được tính trước đó trong hàm tạo của lớp, tất cả các giá trị thuộc tính được tính tổng và trả về dưới dạng số ulong.

Phương thức cập nhật dữ liệu hiện tại trên môi trường thị trường Làm mới() đã được cải thiện trong lớp. Chúng ta đã mô tả nó trong phần thứ ba của mô tả thư viện.

Các thay đổi ảnh hưởng đến việc thêm các đối tượng vào danh sách các đơn đặt hàng và vị trí. Bây giờ các chuỗi cùng loại này được đặt trong phương thức AddToListMarket() duy nhất. Sau khi khai báo một đối tượng đơn hàng trong danh sách các đơn hàng và vị trí, sự hiện diện của cùng một đơn hàng được kiểm tra trong danh sách các lệnh kiểm soát. Nếu một đơn hàng như vậy vắng mặt, một đối tượng thứ tự điều khiển được tạo và thêm vào danh sách các lệnh điều khiển bằng phương thức AddToListControl(). Nếu có thứ tự điều khiển, phương thức OnChangeEvent() để so sánh các thuộc tính thứ tự hiện tại với các thứ tự điều khiển được gọi.

Tất cả các hành động được thực hiện được mô tả trong các bình luận chuỗi và được tô sáng trong văn bản của danh sách phương thức.

//+------------------------------------------------------------------+
//| Update the list of orders                                        |
//+------------------------------------------------------------------+
void CMarketCollection::Refresh(void)
  {
   ::ZeroMemory(this.m_struct_curr_market);
   this.m_is_trade_event=false;
   this.m_is_change_volume=false;
   this.m_new_pendings=0;
   this.m_new_positions=0;
   this.m_change_volume_value=0;
   this.m_list_all_orders.Clear();
#ifdef __MQL4__
   int total=::OrdersTotal();
   for(int i=0; i<total; i++)
     {
      if(!::OrderSelect(i,SELECT_BY_POS)) continue;
      long ticket=::OrderTicket();
      //--- Get the control order index by a position ticket and ID
      int index=this.IndexControlOrder(ticket);
      ENUM_ORDER_TYPE type=(ENUM_ORDER_TYPE)::OrderType();
      if(type==ORDER_TYPE_BUY || type==ORDER_TYPE_SELL)
        {
         CMarketPosition *position=new CMarketPosition(ticket);
         if(position==NULL) continue;
         //--- Add a position object to the list of market orders and positions
         if(!this.AddToListMarket(position))
            continue;
         //--- If there is no order in the list of control orders and positions, add it
         if(index==WRONG_VALUE)
           {
            if(!this.AddToListControl(order))
              {
               ::Print(DFUN_ERR_LINE,TextByLanguage("Не удалось добавить контрольный ордер ","Failed to add control order "),order.TypeDescription()," #",order.Ticket());
              }
           }
         //--- If the order is already present in the list of control orders, check it for changed properties
         if(index>WRONG_VALUE)
           {
            this.OnChangeEvent(position,index);
           }
        }
      else
        {
         CMarketPending *order=new CMarketPending(ticket);
         if(order==NULL) continue;
         //--- Add a pending order object to the list of market orders and positions
         if(!this.AddToListMarket(order))
            continue;
         //--- If there is no order in the list of control orders and positions, add it
         if(index==WRONG_VALUE)
           {
            if(!this.AddToListControl(order))
              {
               ::Print(DFUN_ERR_LINE,TextByLanguage("Не удалось добавить контрольный ордер ","Failed to add control order "),order.TypeDescription()," #",order.Ticket());
              }
           }
         //--- If the order is already present in the list of control orders, check it for changed properties
         if(index>WRONG_VALUE)
           {
            this.OnChangeEvent(order,index);
           }
        }
     }
//--- MQ5
#else 
//--- Positions
   int total_positions=::PositionsTotal();
   for(int i=0; i<total_positions; i++)
     {
      ulong ticket=::PositionGetTicket(i);
      if(ticket==0) continue;
      CMarketPosition *position=new CMarketPosition(ticket);
      if(position==NULL) continue;
      //--- Add a position object to the list of market orders and positions
      if(!this.AddToListMarket(position))
         continue;
      //--- Get the control order index by a position ticket and ID
      int index=this.IndexControlOrder(ticket,position.PositionID());
      //--- If the order is not present in the list of control orders, add it
      if(index==WRONG_VALUE)
        {
         if(!this.AddToListControl(position))
           {
            ::Print(DFUN_ERR_LINE,TextByLanguage("Не удалось добавить контрольую позицию ","Failed to add control position "),position.TypeDescription()," #",position.Ticket());
           }
        }
      //--- If the order is already present in the list of control orders, check it for changed properties
      else if(index>WRONG_VALUE)
        {
         this.OnChangeEvent(position,index);
        }
     }
//--- Orders
   int total_orders=::OrdersTotal();
   for(int i=0; i<total_orders; i++)
     {
      ulong ticket=::OrderGetTicket(i);
      if(ticket==0) continue;
      ENUM_ORDER_TYPE type=(ENUM_ORDER_TYPE)::OrderGetInteger(ORDER_TYPE);
      //--- Market order
      if(type<ORDER_TYPE_BUY_LIMIT)
        {
         CMarketOrder *order=new CMarketOrder(ticket);
         if(order==NULL) continue;
         //--- Add a market order object to the list of market orders and positions
         if(!this.AddToListMarket(order))
            continue;
        }
      //--- Pending order
      else
        {
         CMarketPending *order=new CMarketPending(ticket);
         if(order==NULL) continue;
         //--- Add a pending order object to the list of market orders and positions
         if(!this.AddToListMarket(order))
            continue;
         //--- Get the control order index by a position ticket and ID
         int index=this.IndexControlOrder(ticket,order.PositionID());
         //--- If the order is not present in the control order list, add it
         if(index==WRONG_VALUE)
           {
            if(!this.AddToListControl(order))
              {
               ::Print(DFUN_ERR_LINE,TextByLanguage("Не удалось добавить контрольный ордер ","Failed to add control order "),order.TypeDescription()," #",order.Ticket());
              }
           }
         //--- If the order is already in the control order list, check it for changed properties
         else if(index>WRONG_VALUE)
           {
            this.OnChangeEvent(order,index);
           }
        }
     }
#endif 
//--- First launch
   if(this.m_struct_prev_market.hash_sum_acc==WRONG_VALUE)
     {
      this.SavePrevValues();
     }
//--- If the hash sum of all orders and positions changed
   if(this.m_struct_curr_market.hash_sum_acc!=this.m_struct_prev_market.hash_sum_acc)
     {
      this.m_new_market_orders=this.m_struct_curr_market.total_market-this.m_struct_prev_market.total_market;
      this.m_new_pendings=this.m_struct_curr_market.total_pending-this.m_struct_prev_market.total_pending;
      this.m_new_positions=this.m_struct_curr_market.total_positions-this.m_struct_prev_market.total_positions;
      this.m_change_volume_value=::NormalizeDouble(this.m_struct_curr_market.total_volumes-this.m_struct_prev_market.total_volumes,4);
      this.m_is_change_volume=(this.m_change_volume_value!=0 ? true : false);
      this.m_is_trade_event=true;
      this.SavePrevValues();
     }
  }

Phương pháp thêm đơn hàng và vị trí vào danh sách đơn hàng và vị trí thị trường của bộ sưu tập:

//+--------------------------------------------------------------------------------+
//| Add an order or a position to the list of orders and positions on the account  |
//+--------------------------------------------------------------------------------+
bool CMarketCollection::AddToListMarket(COrder *order)
  {
   if(order==NULL)
      return false;
   ENUM_ORDER_STATUS status=order.Status();
   if(this.m_list_all_orders.InsertSort(order))
     {
      if(status==ORDER_STATUS_MARKET_POSITION)
        {
         this.m_struct_curr_market.hash_sum_acc+=order.GetProperty(ORDER_PROP_TIME_UPDATE_MSC)+this.ConvertToHS(order);
         this.m_struct_curr_market.total_volumes+=order.Volume();
         this.m_struct_curr_market.total_positions++;
         return true;
        }
      if(status==ORDER_STATUS_MARKET_PENDING)
        {
         this.m_struct_curr_market.hash_sum_acc+=this.ConvertToHS(order);
         this.m_struct_curr_market.total_volumes+=order.Volume();
         this.m_struct_curr_market.total_pending++;
         return true;
        }
     }
   else
     {
      ::Print(DFUN,order.TypeDescription()," #",order.Ticket()," ",TextByLanguage("не удалось добавить в список","failed to add to list"));
      delete order;
     }
   return false;
  }
//+------------------------------------------------------------------+

Con trỏ tới thứ tự được thêm vào danh sách bộ sưu tập được truyền cho phương thức. Sau khi thêm một đơn đặt hàng vào danh sách bộ sưu tập, dữ liệu của cấu trúc lưu trữ trạng thái hiện tại của các lệnh và vị trí thị trường cho lần kiểm tra tiếp theo và xác định các thay đổi về số lượng đơn đặt hàng và vị trí được thay đổi tùy thuộc vào trạng thái đơn hàng.

  • Nếu đây là một vị trí, thời gian thay đổi vị trí và giá trị được tính cho tổng băm được thêm vào tổng băm chung và số vị trí tổng thể được tăng lên.
  • Nếu đây là một lệnh chờ, giá trị được tính cho tổng băm sẽ được thêm vào tổng băm chung và tổng số đơn đặt hàng đang chờ xử lý sẽ tăng lên.

Phương pháp tạo lệnh điều khiển và thêm nó vào danh sách các lệnh điều khiển:

//+------------------------------------------------------------------+
//| Create and add an order to the list of control orders            |
//+------------------------------------------------------------------+
bool CMarketCollection::AddToListControl(COrder *order)
  {
   if(order==NULL) 
      return false;
   COrderControl* order_control=new COrderControl(order.PositionID(),order.Ticket(),order.Magic(),order.Symbol());
   if(order_control==NULL)
      return false;
   order_control.SetTime(order.TimeOpenMSC());         
   order_control.SetTimePrev(order.TimeOpenMSC());     
   order_control.SetVolume(order.Volume());            
   order_control.SetTime(order.TimeOpenMSC());         
   order_control.SetTypeOrder(order.TypeOrder());      
   order_control.SetTypeOrderPrev(order.TypeOrder());  
   order_control.SetPrice(order.PriceOpen());          
   order_control.SetPricePrev(order.PriceOpen());      
   order_control.SetStopLoss(order.StopLoss());        
   order_control.SetStopLossPrev(order.StopLoss());    
   order_control.SetTakeProfit(order.TakeProfit());    
   order_control.SetTakeProfitPrev(order.TakeProfit());
   if(!this.m_list_control.Add(order_control))
     {
      delete order_control;
      return false;
     }
   return true;
  }
//+------------------------------------------------------------------+

Con trỏ tới một lệnh thị trường và vị trí được truyền cho phương thức. Nếu một đối tượng không hợp lệ được thông qua, trả về false.

Sau đó, một lệnh điều khiển mới được tạo, để hàm tạo của nó ngay lập tức nhận được ID vị trí, vé, số ma thuật và ký hiệu của một đối tượng đặt hàng được truyền cho phương thức. Tất cả dữ liệu cần thiết để xác định sửa đổi thứ tự / vị trí sau đó được điền.

Nếu việc thêm một lệnh điều khiển mới vào danh sách các lệnh điều khiển không thành công, lệnh sẽ bị xóa và ‘false’ được trả về.

Vì chúng ta luôn thêm các đơn hàng và vị trí mới vào danh sách các đơn hàng và vị trí kiểm soát, nó có thể trở nên khá cồng kềnh sau một thời gian dài làm việc. Đơn đặt hàng và vị trí không tồn tại mãi mãi và các bản sao kiểm soát của chúng không nên được lưu trữ vĩnh viễn trong danh sách chiếm bộ nhớ mà không có lý do. Để loại bỏ các đơn đặt hàng kiểm soát không cần thiết khỏi danh sách, hãy sử dụng phương thức DeleteOrderFromListControl() loại bỏ một lệnh kiểm soát khỏi danh sách các đơn hàng kiểm soát bằng một vé vị trí và ID.

Cho đến nay, phương thức chỉ được khai báo nhưng không được thực hiện. Việc thực hiện sẽ được thực hiện sau khi chuẩn bị toàn bộ chức năng để theo dõi thứ tự và sửa đổi vị trí.

Phương thức trả về chỉ mục thứ tự kiểm soát trong danh sách các lệnh kiểm soát theo vé vị trí và ID:

//+------------------------------------------------------------------+
//| Return an order index by a ticket in the list of control orders  |
//+------------------------------------------------------------------+
int CMarketCollection::IndexControlOrder(const ulong ticket,const ulong id)
  {
   int total=this.m_list_control.Total();
   for(int i=0;i<total;i++)
     {
      COrderControl* order=this.m_list_control.At(i);
      if(order==NULL)
         continue;
      if(order.PositionID()==id && order.Ticket()==ticket)
         return i;
     }
   return WRONG_VALUE;
  }
//+------------------------------------------------------------------+

Phương thức nhận vé đặt hàng / vị trí và ID vị trí. Một lệnh kiểm soát có một vé phù hợp và ID được tìm kiếm dọc theo tất cả các lệnh kiểm soát trong vòng lặp và chỉ mục của nó được trả về trong danh sách các lệnh kiểm soát. Nếu không tìm thấy thứ tự, -1 được trả về.

Phương thức xử lý sự kiện để thay đổi thứ tự / vị trí hiện có:

//+------------------------------------------------------------------+
//| Handler of changing an existing order/position                   |
//+------------------------------------------------------------------+
void CMarketCollection::OnChangeEvent(COrder* order,const int index)
  {
   COrderControl* order_control=this.m_list_control.At(index);
   if(order_control!=NULL)
     {
      this.m_change_type=order_control.ChangeControl(order);
      ENUM_CHANGE_TYPE change_type=(order.Status()==ORDER_STATUS_MARKET_POSITION ? CHANGE_TYPE_ORDER_TAKE_PROFIT : CHANGE_TYPE_NO_CHANGE);
      if(this.m_change_type>change_type)
        {
         order_control.SetNewState(order);
         if(!this.AddToListChanges(order_control))
           {
            ::Print(DFUN,TextByLanguage("Не удалось добавить модифицированный ордер в список изменённых ордеров","Could not add modified order to list of modified orders"));
           }
        }
     }
  }
//+------------------------------------------------------------------+

Phương thức nhận con trỏ tới thứ tự đã kiểm tra và chỉ mục của thứ tự điều khiển thích hợp trong danh sách các lệnh điều khiển.

Lấy thứ tự kiểm soát từ danh sách theo chỉ mục của nó và kiểm tra các thay đổi trong thuộc tính thứ tự kiểm soát tương ứng với các thuộc tính của thứ tự kiểm soát được kiểm tra bằng phương thức ChangeControl(). Phương thức nhận con trỏ tới lệnh điều khiển. Nếu tìm thấy sự khác biệt, phương thức trả về loại thay đổi được ghi vào biến thành viên lớp m_change_type.

Tiếp theo, kiểm tra trạng thái của đơn hàng đã kiểm tra và đặt giá trị, trên đó thay đổi được coi là đã xảy ra. Đối với một vị trí, giá trị này vượt quá hằng số CHANGE_TYPE_ORDER_TAKE_PROFIT từ phép liệt kê ENUM_CHANGE_TYPE vì tất cả các giá trị bằng hoặc dưới hằng số này chỉ liên quan đến một lệnh chờ xử lý. Đối với một đơn đặt hàng đang chờ xử lý, giá trị phải vượt quá hằng số CHANGE_TYPE_NO_CHANGE.

Nếu biến m_change_type thu được vượt quá biến đã chỉ định, sửa đổi được phát hiện. Trong trường hợp này, trạng thái hiện tại của lệnh điều khiển được lưu cho lần kiểm tra tiếp theo và một bản sao của lệnh điều khiển được đặt vào danh sách các lệnh đã thay đổi để xử lý danh sách tiếp theo trong lớp CEventsCollection.

Phương pháp tạo thứ tự kiểm soát đã thay đổi và thêm nó vào danh sách các đơn hàng đã thay đổi:

//+------------------------------------------------------------------+
//|Create and add a control order to the list of changed orders      |
//+------------------------------------------------------------------+
bool CMarketCollection::AddToListChanges(COrderControl* order_control)
  {
   if(order_control==NULL)
      return false;
   COrderControl* order_changed=new COrderControl(order_control.PositionID(),order_control.Ticket(),order_control.Magic(),order_control.Symbol());
   if(order_changed==NULL)
      return false;
   order_changed.SetTime(order_control.Time());                    
   order_changed.SetTimePrev(order_control.TimePrev());            
   order_changed.SetVolume(order_control.Volume());                
   order_changed.SetTypeOrder(order_control.TypeOrder());          
   order_changed.SetTypeOrderPrev(order_control.TypeOrderPrev());  
   order_changed.SetPrice(order_control.Price());                  
   order_changed.SetPricePrev(order_control.PricePrev());          
   order_changed.SetStopLoss(order_control.StopLoss());            
   order_changed.SetStopLossPrev(order_control.StopLossPrev());    
   order_changed.SetTakeProfit(order_control.TakeProfit());        
   order_changed.SetTakeProfitPrev(order_control.TakeProfitPrev());
   order_changed.SetChangedType(order_control.GetChangeType());    
   if(!this.m_list_changed.Add(order_changed))
     {
      delete order_changed;
      return false;
     }
   return true;
  }
//+------------------------------------------------------------------+

Phương thức nhận con trỏ đến thứ tự điều khiển đã sửa đổi. Bản sao của lệnh phải được đặt vào danh sách các lệnh và vị trí kiểm soát đã thay đổi.

Tiếp theo, một thứ tự kiểm soát mới được tạo ra. Nó ngay lập tức nhận được ID vị trí, vé, số ma thuật và biểu tượng khớp với thứ tự của thứ tự kiểm soát đã thay đổi.

Sau đó, các thuộc tính của thứ tự điều khiển đã thay đổi chỉ được sao chép vào các thuộc tính của một phần tử mới được tạo theo từng phần tử.

Cuối cùng, đặt bản sao mới được tạo của một lệnh điều khiển đã thay đổi vào danh sách các lệnh đã thay đổi.

Nếu không thể đặt thứ tự mới được tạo vào danh sách, đối tượng thứ tự mới được tạo sẽ bị xóa và trả về false.

Chúng ta đã hoàn thành việc thực hiện các thay đổi đối với lớp CMarketCollection. Bây giờ chúng ta hãy chuyển sang lớp CEventsCollection.

Lớp bộ sưu tập sự kiện CEventsCollection sẽ có tính năng xử lý các sự kiện, trong đó danh sách các đơn đặt hàng đã thay đổi được tạo trong thứ tự thị trường và lớp bộ sưu tập vị trí không trống. Điều này có nghĩa là nó chứa các đơn đặt hàng và vị trí đã thay đổi cần được xử lý (tạo sự kiện mới và gửi tin nhắn phù hợp đến chương trình gọi điện).

Chúng ta hãy thêm định nghĩa của hai phương thức vào phần riêng của lớp bên cạnh phương thức đã có: phương thức quá tải mới để tạo sự kiện mới và phương thức xử lý thay đổi thứ tự / vị trí hiện có, trong khi Làm mới() Phương thức nhận được khả năng chuyển danh sách các đơn hàng đã thay đổi sang phương thức:

//+------------------------------------------------------------------+
//|                                             EventsCollection.mqh |
//|                                   Copyright 2020, Forex365 Corp. |
//|                                              https://forex365.vn |
//+------------------------------------------------------------------+
#property copyright "Copyright 2020, Forex365 Corp."
#property link      "https://forex365.vn"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include "ListObj.mqh"
#include "..\Services\Select.mqh"
#include "..\Objects\Orders\Order.mqh"
#include "..\Objects\Events\EventBalanceOperation.mqh"
#include "..\Objects\Events\EventOrderPlaced.mqh"
#include "..\Objects\Events\EventOrderRemoved.mqh"
#include "..\Objects\Events\EventPositionOpen.mqh"
#include "..\Objects\Events\EventPositionClose.mqh"
//+------------------------------------------------------------------+
//| Collection of account events                                     |
//+------------------------------------------------------------------+
class CEventsCollection : public CListObj
  {
private:
   CListObj          m_list_events;                   // List of events
   bool              m_is_hedge;                      // Hedge account flag
   long              m_chart_id;                      // Control program chart ID
   int               m_trade_event_code;              // Trading event code
   ENUM_TRADE_EVENT  m_trade_event;                   // Account trading event
   CEvent            m_event_instance;                // Event object for searching by property
   
//--- Create a trading event depending on the (1) order status and (2) change type
   void              CreateNewEvent(COrder* order,CArrayObj* list_history,CArrayObj* list_market);
   void              CreateNewEvent(COrderControl* order);
//--- Create an event for a (1) hedging account, (2) netting account
   void              NewDealEventHedge(COrder* deal,CArrayObj* list_history,CArrayObj* list_market);
   void              NewDealEventNetto(COrder* deal,CArrayObj* list_history,CArrayObj* list_market);
//--- Select and return the list of market pending orders
   CArrayObj*        GetListMarketPendings(CArrayObj* list);
//--- Select from the list and return the list of historical (1) removed pending orders, (2) deals, (3) all closing orders 
   CArrayObj*        GetListHistoryPendings(CArrayObj* list);
   CArrayObj*        GetListDeals(CArrayObj* list);
   CArrayObj*        GetListCloseByOrders(CArrayObj* list);
//--- Return the list of (1) all position orders by its ID, (2) all deal positions by its ID,
//--- (3) all market entry deals by position ID, (4) all market exit deals by position ID,
//--- (5) all position reversal deals by position ID
   CArrayObj*        GetListAllOrdersByPosID(CArrayObj* list,const ulong position_id);
   CArrayObj*        GetListAllDealsByPosID(CArrayObj* list,const ulong position_id);
   CArrayObj*        GetListAllDealsInByPosID(CArrayObj* list,const ulong position_id);
   CArrayObj*        GetListAllDealsOutByPosID(CArrayObj* list,const ulong position_id);
   CArrayObj*        GetListAllDealsInOutByPosID(CArrayObj* list,const ulong position_id);
//--- Return the total volume of all deals (1) IN, (2) OUT of the position by its ID
   double            SummaryVolumeDealsInByPosID(CArrayObj* list,const ulong position_id);
   double            SummaryVolumeDealsOutByPosID(CArrayObj* list,const ulong position_id);
//--- Return the (1) first, (2) last and (3) closing order from the list of all position orders,
//--- (4) an order by ticket, (5) market position by ID,
//--- (6) the last and (7) penultimate InOut deal by position ID
   COrder*           GetFirstOrderFromList(CArrayObj* list,const ulong position_id);
   COrder*           GetLastOrderFromList(CArrayObj* list,const ulong position_id);
   COrder*           GetCloseByOrderFromList(CArrayObj* list,const ulong position_id);
   COrder*           GetHistoryOrderByTicket(CArrayObj* list,const ulong order_ticket);
   COrder*           GetPositionByID(CArrayObj* list,const ulong position_id);
//--- Return the flag of the event object presence in the event list
   bool              IsPresentEventInList(CEvent* compared_event);
//--- Handler of an existing order/position change
   void              OnChangeEvent(CArrayObj* list_changes,CArrayObj* list_history,CArrayObj* list_market,const int index);
public:
//--- Select events from the collection with time within the range from begin_time to end_time
   CArrayObj        *GetListByTime(const datetime begin_time=0,const datetime end_time=0);
//--- Return the full event collection list "as is"
   CArrayObj        *GetList(void)                                                                       { return &this.m_list_events;                                           }
//--- Return the list by selected (1) integer, (2) real and (3) string properties meeting the compared criterion
   CArrayObj        *GetList(ENUM_EVENT_PROP_INTEGER property,long value,ENUM_COMPARER_TYPE mode=EQUAL)  { return CSelect::ByEventProperty(this.GetList(),property,value,mode);  }
   CArrayObj        *GetList(ENUM_EVENT_PROP_DOUBLE property,double value,ENUM_COMPARER_TYPE mode=EQUAL) { return CSelect::ByEventProperty(this.GetList(),property,value,mode);  }
   CArrayObj        *GetList(ENUM_EVENT_PROP_STRING property,string value,ENUM_COMPARER_TYPE mode=EQUAL) { return CSelect::ByEventProperty(this.GetList(),property,value,mode);  }
//--- Update the list of events
   void              Refresh(CArrayObj* list_history,
                             CArrayObj* list_market,
                             CArrayObj* list_changes,
                             const bool is_history_event,
                             const bool is_market_event,
                             const int  new_history_orders,
                             const int  new_market_pendings,
                             const int  new_market_positions,
                             const int  new_deals);
//--- Set the control program chart ID
   void              SetChartID(const long id)        { this.m_chart_id=id;         }
//--- Return the last trading event on the account
   ENUM_TRADE_EVENT  GetLastTradeEvent(void)    const { return this.m_trade_event;  }
//--- Reset the last trading event
   void              ResetLastTradeEvent(void)        { this.m_trade_event=TRADE_EVENT_NO_EVENT;   }
//--- Constructor
                     CEventsCollection(void);
  };
//+------------------------------------------------------------------+

Hãy thực hiện các phương thức mới bên ngoài lớp cơ thể.

Phương thức quá tải để tạo sự kiện sửa đổi thứ tự / vị trí:

//+------------------------------------------------------------------+
//| Create a trading event depending on the order change type        |
//+------------------------------------------------------------------+
void CEventsCollection::CreateNewEvent(COrderControl* order)
  {
   CEvent* event=NULL;
//--- Pending StopLimit order placed
   if(order.GetChangeType()==CHANGE_TYPE_ORDER_TYPE)
     {
      this.m_trade_event_code=TRADE_EVENT_FLAG_ORDER_PLASED;
      event=new CEventOrderPlased(this.m_trade_event_code,order.Ticket());
     }
//--- 
   if(event!=NULL)
     {
      event.SetProperty(EVENT_PROP_TIME_EVENT,order.Time());                        // Event time
      event.SetProperty(EVENT_PROP_REASON_EVENT,EVENT_REASON_STOPLIMIT_TRIGGERED);  // Event reason (from the ENUM_EVENT_REASON enumeration)
      event.SetProperty(EVENT_PROP_TYPE_DEAL_EVENT,order.TypeOrderPrev());          // Type of the order that triggered an event
      event.SetProperty(EVENT_PROP_TICKET_DEAL_EVENT,order.Ticket());               // Ticket of the order that triggered an event
      event.SetProperty(EVENT_PROP_TYPE_ORDER_EVENT,order.TypeOrder());             // Event order type
      event.SetProperty(EVENT_PROP_TICKET_ORDER_EVENT,order.Ticket());              // Event order ticket
      event.SetProperty(EVENT_PROP_TYPE_ORDER_POSITION,order.TypeOrder());          // Position first order type
      event.SetProperty(EVENT_PROP_TICKET_ORDER_POSITION,order.Ticket());           // Position first order ticket
      event.SetProperty(EVENT_PROP_POSITION_ID,order.PositionID());                 // Position ID
      event.SetProperty(EVENT_PROP_POSITION_BY_ID,0);                               // Opposite position ID
      event.SetProperty(EVENT_PROP_MAGIC_BY_ID,0);                                  // Opposite position magic number
         
      event.SetProperty(EVENT_PROP_TYPE_ORD_POS_BEFORE,order.TypeOrderPrev());      // Position order type before changing the direction
      event.SetProperty(EVENT_PROP_TICKET_ORD_POS_BEFORE,order.Ticket());           // Position order ticket before changing direction
      event.SetProperty(EVENT_PROP_TYPE_ORD_POS_CURRENT,order.TypeOrder());         // Current position order type
      event.SetProperty(EVENT_PROP_TICKET_ORD_POS_CURRENT,order.Ticket());          // Current position order ticket
         
      event.SetProperty(EVENT_PROP_MAGIC_ORDER,order.Magic());                      // Order magic number
      event.SetProperty(EVENT_PROP_TIME_ORDER_POSITION,order.TimePrev());           // First position order time
      event.SetProperty(EVENT_PROP_PRICE_EVENT,order.PricePrev());                  // Event price
      event.SetProperty(EVENT_PROP_PRICE_OPEN,order.Price());                       // Order open price
      event.SetProperty(EVENT_PROP_PRICE_CLOSE,order.Price());                      // Order close price
      event.SetProperty(EVENT_PROP_PRICE_SL,order.StopLoss());                      // StopLoss order price
      event.SetProperty(EVENT_PROP_PRICE_TP,order.TakeProfit());                    // TakeProfit order price
      event.SetProperty(EVENT_PROP_VOLUME_ORDER_INITIAL,order.Volume());            // Requested order volume
      event.SetProperty(EVENT_PROP_VOLUME_ORDER_EXECUTED,0);                        // Executed order volume
      event.SetProperty(EVENT_PROP_VOLUME_ORDER_CURRENT,order.Volume());            // Remaining (unexecuted) order volume
      event.SetProperty(EVENT_PROP_VOLUME_POSITION_EXECUTED,0);                     // Executed position volume
      event.SetProperty(EVENT_PROP_PROFIT,0);                                       // Profit
      event.SetProperty(EVENT_PROP_SYMBOL,order.Symbol());                          // Order symbol
      event.SetProperty(EVENT_PROP_SYMBOL_BY_ID,order.Symbol());                    // Opposite position symbol
      //--- Set the control program chart ID, decode the event code and set the event type
      event.SetChartID(this.m_chart_id);
      event.SetTypeEvent();
      //--- Add the event object if it is not in the list
      if(!this.IsPresentEventInList(event))
        {
         this.m_list_events.InsertSort(event);
         //--- Send a message about the event and set the value of the last trading event
         event.SendEvent();
         this.m_trade_event=event.TradeEvent();
        }
      //--- If the event is already present in the list, remove a new event object and display a debugging message
      else
        {
         ::Print(DFUN_ERR_LINE,TextByLanguage("Такое событие уже есть в списке","This event already in the list."));
         delete event;
        }
     }
  }
//+------------------------------------------------------------------+

ta đã mô tả phương pháp tạo sự kiện mới trong phần thứ năm của mô tả thư viện khi tạo một bộ sưu tập sự kiện.

Phương pháp này gần như giống hệt nhau. Sự khác biệt duy nhất là loại lệnh, con trỏ được truyền cho phương thức.

Loại thay đổi thứ tự xảy ra được kiểm tra ngay khi bắt đầu phương thức và mã thay đổi được đặt trong biến thành viên lớp m_trade_event_code theo loại thay đổi.

Tiếp theo, sự kiện phù hợp với loại thay đổi được tạo, các thuộc tính của nó được điền theo loại thay đổi, sự kiện được đặt vào danh sách sự kiện và được gửi đến chương trình điều khiển.

Phương pháp cải tiến để cập nhật danh sách sự kiện:

//+------------------------------------------------------------------+
//| Update the event list                                            |
//+------------------------------------------------------------------+
void CEventsCollection::Refresh(CArrayObj* list_history,
                                CArrayObj* list_market,
                                CArrayObj* list_changes,
                                const bool is_history_event,
                                const bool is_market_event,
                                const int  new_history_orders,
                                const int  new_market_pendings,
                                const int  new_market_positions,
                                const int  new_deals)
  {
//--- Exit if the lists are empty
   if(list_history==NULL || list_market==NULL)
      return;
//--- If the event is in the market environment
   if(is_market_event)                         
     {                                         
      //--- if the order properties were changed 
      int total_changes=list_changes.Total();  
      if(total_changes>0)                      
        {                                      
         for(int i=total_changes-1;i>=0;i--)   
           {                                   
            this.OnChangeEvent(list_changes,i);
           }                                   
        }                                      
      //--- if the number of placed pending orders increased
      if(new_market_pendings>0)
        {
         //--- Receive the list of the newly placed pending orders
         CArrayObj* list=this.GetListMarketPendings(list_market);
         if(list!=NULL)
           {
            //--- Sort the new list by order placement time
            list.Sort(SORT_BY_ORDER_TIME_OPEN_MSC);
            //--- Take the number of orders equal to the number of newly placed ones from the end of the list in a loop (the last N events)
            int total=list.Total(), n=new_market_pendings;
            for(int i=total-1; i>=0 && n>0; i--,n--)
              {
               //--- Receive an order from the list, if this is a pending order, set a trading event
               COrder* order=list.At(i);
               if(order!=NULL && order.Status()==ORDER_STATUS_MARKET_PENDING)
                  this.CreateNewEvent(order,list_history,list_market);
              }
           }
        }
     }
//--- If the event is in the account history
   if(is_history_event)
     {
      //--- If the number of historical orders increased
      if(new_history_orders>0)
        {
         //--- Receive the list of removed pending orders only
         CArrayObj* list=this.GetListHistoryPendings(list_history);
         if(list!=NULL)
           {
            //--- Sort the new list by order removal time
            list.Sort(SORT_BY_ORDER_TIME_CLOSE_MSC);
            //--- Take the number of orders equal to the number of newly removed ones from the end of the list in a loop (the last N events)
            int total=list.Total(), n=new_history_orders;
            for(int i=total-1; i>=0 && n>0; i--,n--)
              {
               //--- Receive an order from the list. If this is a removed pending order without a position ID, 
               //--- this is an order removal - set a trading event
               COrder* order=list.At(i);
               if(order!=NULL && order.Status()==ORDER_STATUS_HISTORY_PENDING && order.PositionID()==0)
                  this.CreateNewEvent(order,list_history,list_market);
              }
           }
        }
      //--- If the number of deals increased
      if(new_deals>0)
        {
         //--- Receive the list of deals only
         CArrayObj* list=this.GetListDeals(list_history);
         if(list!=NULL)
           {
            //--- Sort the new list by deal time
            list.Sort(SORT_BY_ORDER_TIME_OPEN_MSC);
            //--- Take the number of deals equal to the number of new ones from the end of the list in a loop (the last N events)
            int total=list.Total(), n=new_deals;
            for(int i=total-1; i>=0 && n>0; i--,n--)
              {
               //--- Receive a deal from the list and set a trading event
               COrder* order=list.At(i);
               if(order!=NULL)
                  this.CreateNewEvent(order,list_history,list_market);
              }
           }
        }
     }
  }
//+------------------------------------------------------------------+

Phương pháp này cũng đã được xem xét trong phần thứ năm của mô tả thư viện khi tạo một bộ sưu tập sự kiện. Sự khác biệt so với phương thức đó nằm ở khối mã được thêm vào để xử lý các sự kiện sửa đổi trong trường hợp kích thước của danh sách đơn hàng đã thay đổi không bằng không. Mỗi thứ tự thay đổi từ danh sách được xử lý theo phương thức xử lý sự kiện thay đổi thứ tự trong một vòng lặp:

//+------------------------------------------------------------------+
//| The handler of an existing order/position change event           |
//+------------------------------------------------------------------+
void CEventsCollection::OnChangeEvent(CArrayObj* list_changes,const int index)
  {
   COrderControl* order_changed=list_changes.Detach(index);
   if(order_changed!=NULL)
     {
      if(order_changed.GetChangeType()==CHANGE_TYPE_ORDER_TYPE)
        {
         this.CreateNewEvent(order_changed);
        }
      delete order_changed;
     }
  }
//+------------------------------------------------------------------+

Khi xử lý danh sách các đơn hàng đã thay đổi, chúng ta cần lấy một đơn hàng đã sửa đổi từ danh sách và xóa đối tượng đơn hàng và con trỏ thích hợp khỏi danh sách sau khi xử lý xong để tránh xử lý cùng một sự kiện nhiều lần.

May mắn thay, khi làm việc với mảng động CArrayObj của các con trỏ đối tượng, thư viện chuẩn cung cấp phương thức Detach() nhận phần tử từ vị trí đã chỉ định và xóa nó khỏi mảng. Nói cách khác, chúng ta nhận được con trỏ tới đối tượng được lưu trữ trong mảng theo chỉ mục và loại bỏ con trỏ này khỏi mảng. Nếu loại thay đổi là CHANGE_TYPE_ORDER_TYPE (thay đổi loại đơn đặt hàng – kích hoạt lệnh StopLimit đang chờ xử lý và biến nó thành lệnh Giới hạn), hãy tạo một sự kiện mới – Kích hoạt đơn hàng StopLimit. Sau khi đối tượng được xử lý bởi con trỏ thu được bằng phương thức Detach(), con trỏ (không còn cần thiết) sẽ bị xóa.

Điều này kết luận sự cải tiến của lớp CEventsCollection.

Để tất cả các thay đổi có hiệu lực, phải nhận được danh sách các đơn đặt hàng đã thay đổi từ lớp thị trường và bộ sưu tập vị trí và kích thước của nó phải được ghi trong đối tượng chính của thư viện – trong lớp CEngine (phương thức TradeEventsControl()). Khi phương thức cập nhật sự kiện Làm mới() của lớp bộ sưu tập sự kiện được gọi, kích thước của danh sách đơn hàng đã thay đổi sẽ được kiểm tra bổ sung, trong khi danh sách các đơn hàng đã sửa đổi sẽ được chuyển đến phương thức Làm mới() của bộ sưu tập sự kiện để xử lý:

//+------------------------------------------------------------------+
//| Check trading events                                             |
//+------------------------------------------------------------------+
void CEngine::TradeEventsControl(void)
  {
//--- Initialize the trading events code and flag
   this.m_is_market_trade_event=false;
   this.m_is_history_trade_event=false;
//--- Update the lists 
   this.m_market.Refresh();
   this.m_history.Refresh();
//--- First launch actions
   if(this.IsFirstStart())
     {
      this.m_acc_trade_event=TRADE_EVENT_NO_EVENT;
      return;
     }
//--- Check the changes in the market status and account history 
   this.m_is_market_trade_event=this.m_market.IsTradeEvent();
   this.m_is_history_trade_event=this.m_history.IsTradeEvent();

//--- If there is any event, send the lists, the flags and the number of new orders and deals to the event collection, and update it
   int change_total=0;
   CArrayObj* list_changes=this.m_market.GetListChanges();
   if(list_changes!=NULL)
      change_total=list_changes.Total();
   if(this.m_is_history_trade_event || this.m_is_market_trade_event || change_total>0)
     {
      this.m_events.Refresh(this.m_history.GetList(),this.m_market.GetList(),list_changes,
                            this.m_is_history_trade_event,this.m_is_market_trade_event,
                            this.m_history.NewOrders(),this.m_market.NewPendingOrders(),
                            this.m_market.NewMarketOrders(),this.m_history.NewDeals());
      //--- Receive the last account trading event
      this.m_acc_trade_event=this.m_events.GetLastTradeEvent();
     }
  }
//+------------------------------------------------------------------+

Vì việc kích hoạt đơn hàng StopLimit dẫn đến việc đặt lệnh Giới hạn, chúng ta sẽ ‘đủ điều kiện’ cho sự kiện này là đặt đơn hàng đang chờ xử lý, trong khi lý do sự kiện là kích hoạt đơn hàng StopLimit EVENT_REASON_STOPLIMIT_TRIGGERED. Chúng ta đã đặt hằng số của nó trong bảng liệt kê ENUM_EVENT_REASON của tệp Defines.mqh.

Chúng ta hãy cải thiện lớp EventOrderPlasing để hiển thị chương trình sự kiện trong tạp chí và gửi nó đến chương trình điều khiển:

Chỉ cần thêm xử lý lý do sự kiện EVENT_REASON_STOPLIMIT_TRIGGERED.

//+------------------------------------------------------------------+
//|                                             EventOrderPlased.mqh |
//|                                   Copyright 2020, Forex365 Corp. |
//|                                              https://forex365.vn |
//+------------------------------------------------------------------+
#property copyright "Copyright 2020, Forex365 Corp."
#property link      "https://forex365.vn"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include "Event.mqh"
//+------------------------------------------------------------------+
//| Placing a pending order event                                    |
//+------------------------------------------------------------------+
class CEventOrderPlased : public CEvent
  {
public:
//--- Constructor
                     CEventOrderPlased(const int event_code,const ulong ticket=0) : CEvent(EVENT_STATUS_MARKET_PENDING,event_code,ticket) {}
//--- Supported order properties (1) real, (2) integer
   virtual bool      SupportProperty(ENUM_EVENT_PROP_INTEGER property);
   virtual bool      SupportProperty(ENUM_EVENT_PROP_DOUBLE property);
//--- (1) Display a brief message about the event in the journal, (2) Send the event to the chart
   virtual void      PrintShort(void);
   virtual void      SendEvent(void);
  };
//+------------------------------------------------------------------+
//| Return 'true' if the event supports the passed                   |
//| integer property, otherwise return 'false'                       |
//+------------------------------------------------------------------+
bool CEventOrderPlased::SupportProperty(ENUM_EVENT_PROP_INTEGER property)
  {
   if(property==EVENT_PROP_TYPE_DEAL_EVENT         ||
      property==EVENT_PROP_TICKET_DEAL_EVENT       ||
      property==EVENT_PROP_TYPE_ORDER_POSITION     ||
      property==EVENT_PROP_TICKET_ORDER_POSITION   ||
      property==EVENT_PROP_POSITION_ID             ||
      property==EVENT_PROP_POSITION_BY_ID          ||
      property==EVENT_PROP_TIME_ORDER_POSITION
     ) return false;
   return true;
  }
//+------------------------------------------------------------------+
//| Return 'true' if the event supports the passed                   |
//| real property, otherwise return 'false'                          |
//+------------------------------------------------------------------+
bool CEventOrderPlased::SupportProperty(ENUM_EVENT_PROP_DOUBLE property)
  {
   if(property==EVENT_PROP_PRICE_CLOSE             ||
      property==EVENT_PROP_PROFIT
     ) return false;
   return true;
  }
//+------------------------------------------------------------------+
//| Display a brief message about the event in the journal           |
//+------------------------------------------------------------------+
void CEventOrderPlased::PrintShort(void)
  {
   int    digits=(int)::SymbolInfoInteger(this.Symbol(),SYMBOL_DIGITS);
   string head="- "+this.TypeEventDescription()+": "+TimeMSCtoString(this.TimePosition())+" -\n";
   string sl=(this.PriceStopLoss()>0 ? ", sl "+::DoubleToString(this.PriceStopLoss(),digits) : "");
   string tp=(this.PriceTakeProfit()>0 ? ", tp "+::DoubleToString(this.PriceTakeProfit(),digits) : "");
   string vol=::DoubleToString(this.VolumeOrderInitial(),DigitsLots(this.Symbol()));
   string magic=(this.Magic()!=0 ? TextByLanguage(", магик ",", magic ")+(string)this.Magic() : "");
   string type=this.TypeOrderFirstDescription()+" #"+(string)this.TicketOrderEvent();
   string event=TextByLanguage(" Установлен "," Placed ");
   string price=TextByLanguage(" по цене "," at price ")+::DoubleToString(this.PriceOpen(),digits);
   string txt=head+this.Symbol()+event+vol+" "+type+price+sl+tp+magic;
   //--- If StopLimit order is activated
   if(this.Reason()==EVENT_REASON_STOPLIMIT_TRIGGERED)
     {
      head="- "+this.TypeEventDescription()+": "+TimeMSCtoString(this.TimeEvent())+" -\n";
      event=TextByLanguage(" Сработал "," Triggered ");
      type=
        (
         OrderTypeDescription(this.TypeOrderPosPrevious())+" #"+(string)this.TicketOrderEvent()+
         TextByLanguage(" по цене "," at price ")+DoubleToString(this.PriceEvent(),digits)+" -->\n"+
         vol+" "+OrderTypeDescription(this.TypeOrderPosCurrent())+" #"+(string)this.TicketOrderEvent()+
         TextByLanguage(" на цену "," on price ")+DoubleToString(this.PriceOpen(),digits)
        );
      txt=head+this.Symbol()+event+"("+TimeMSCtoString(this.TimePosition())+") "+vol+" "+type+sl+tp+magic;
     }
   ::Print(txt);
  }
//+------------------------------------------------------------------+
//| Send the event to the chart                                      |
//+------------------------------------------------------------------+
void CEventOrderPlased::SendEvent(void)
  {
   this.PrintShort();
   ::EventChartCustom(this.m_chart_id,(ushort)this.m_trade_event,this.TicketOrderEvent(),this.PriceOpen(),this.Symbol());
  }
//+------------------------------------------------------------------+

Ở đây tất cả là khá dễ hiểu. Không có điểm nào trong việc cư ngụ trên các hành động đơn giản.

Điều này kết luận việc cải thiện thư viện để theo dõi kích hoạt đơn hàng StopLimit.

Kiểm tra

Để kiểm tra các cải tiến đã thực hiện, chúng ta sẽ sử dụng EA từ bài viết trước. Chỉ cần đổi tên TestDo EASPart06.mq5 EA từ thư mục \\ MQL5 \\ Experts \\ TestDo EAS \\ Part06 thành TestDo EASPart07.mq5 và lưu nó trong thư mục con \\ MQL5 \\ Experts \\ TestDo EAS \\ Part07 mới.

Biên dịch EA, khởi chạy nó trong trình kiểm tra, đặt lệnh StopLimit và chờ kích hoạt:

Chức năng được triển khai trong bài viết bao gồm khả năng nhanh chóng thêm theo dõi các sự kiện khác: sửa đổi các thuộc tính đơn hàng đang chờ xử lý – giá của chúng, các mức StopLoss và TakeProfit, cũng như sửa đổi các vị trí của StopLoss và TakeProfit. Chúng ta sẽ xem xét các nhiệm vụ này trong bài viết tiếp theo.

Tất cả các tệp của phiên bản hiện tại của thư viện được đính kèm bên dưới cùng với các tệp EA thử nghiệm để bạn kiểm tra và tải xuống.

Để lại câu hỏi, ý kiến ​​và đề xuất của bạn trong các bình luận nhé.

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.