Các hàm để đọc thuộc tính lệnh từ lịch sử
Các hàm để đọc thuộc tính của các lệnh lịch sử được chia thành 3 nhóm theo loại cơ bản của giá trị thuộc tính, phù hợp với việc chia các định danh của các thuộc tính có sẵn thành ba liệt kê: ENUM_ORDER_PROPERTY_INTEGER
, ENUM_ORDER_PROPERTY_DOUBLE
và ENUM_ORDER_PROPERTY_STRING
đã được thảo luận trước đó trong một phần riêng khi khám phá các lệnh đang hoạt động.
Trước khi gọi các hàm này, bạn cần phải chọn tập hợp vé phù hợp trong lịch sử bằng cách nào đó.
Nếu bạn cố gắng đọc thuộc tính của một lệnh hoặc giao dịch có vé ngoài ngữ cảnh lịch sử đã chọn, môi trường có thể tạo ra lỗi WRONG_INTERNAL_PARAMETER (4002), có thể được phân tích qua _LastError
.
Đối với mỗi loại thuộc tính cơ bản, có hai dạng hàm: một dạng trả về trực tiếp giá trị của thuộc tính được yêu cầu, dạng thứ hai ghi nó vào một tham số được truyền bằng tham chiếu và trả về chỉ báo thành công (true
) hoặc lỗi (false
).
Đối với các loại số nguyên và các loại tương thích (datetime
, enums) của thuộc tính, có một hàm chuyên dụng là HistoryOrderGetInteger
.
long HistoryOrderGetInteger(ulong ticket, ENUM_ORDER_PROPERTY_INTEGER property)
bool HistoryOrderGetInteger(ulong ticket, ENUM_ORDER_PROPERTY_INTEGER property, long &value)
Hàm này cho phép bạn tìm hiểu thuộc tính property
của lệnh từ lịch sử đã chọn theo số vé của nó.
Đối với các thuộc tính số thực, hàm HistoryOrderGetDouble
được chỉ định.
double HistoryOrderGetDouble(ulong ticket, ENUM_ORDER_PROPERTY_DOUBLE property)
bool HistoryOrderGetDouble(ulong ticket, ENUM_ORDER_PROPERTY_DOUBLE property, double &value)
Cuối cùng, các thuộc tính chuỗi có thể được đọc bằng HistoryOrderGetString
.
string HistoryOrderGetString(ulong ticket, ENUM_ORDER_PROPERTY_STRING property)
bool HistoryOrderGetString(ulong ticket, ENUM_ORDER_PROPERTY_STRING property, string &value)
Bây giờ chúng ta có thể bổ sung lớp OrderMonitor
(OrderMonitor.mqh
) để làm việc với các lệnh lịch sử. Trước tiên, hãy thêm một biến boolean vào lớp history
, mà chúng ta sẽ điền trong hàm tạo dựa trên phân đoạn mà lệnh với vé đã truyền được chọn: trong số các lệnh đang hoạt động (OrderSelect
) hoặc trong lịch sử (HistoryOrderSelect
).
class OrderMonitor: public OrderMonitorInterface
{
bool history;
public:
const ulong ticket;
OrderMonitor(const long t): ticket(t), history(!OrderSelect(t))
{
if(history && !HistoryOrderSelect(ticket))
{
PrintFormat("Error: OrderSelect(%lld) failed: %s", ticket, E2S(_LastError));
}
else
{
ResetLastError();
ready = true;
}
}
...
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Chúng ta cần gọi hàm ResetLastError
trong nhánh if
thành công để đặt lại lỗi có thể xảy ra, lỗi này có thể được thiết lập bởi hàm OrderSelect
(nếu lệnh nằm trong lịch sử).
Trên thực tế, phiên bản này của hàm tạo chứa một lỗi logic nghiêm trọng, và chúng ta sẽ quay lại vấn đề này sau vài đoạn.
Để đọc thuộc tính trong các phương thức get, giờ đây chúng ta gọi các hàm tích hợp khác nhau, tùy thuộc vào giá trị của biến history
.
virtual long get(const ENUM_ORDER_PROPERTY_INTEGER property) const override
{
return history ? HistoryOrderGetInteger(ticket, property) : OrderGetInteger(property);
}
virtual double get(const ENUM_ORDER_PROPERTY_DOUBLE property) const override
{
return history ? HistoryOrderGetDouble(ticket, property) : OrderGetDouble(property);
}
virtual string get(const ENUM_ORDER_PROPERTY_STRING property) const override
{
return history ? HistoryOrderGetString(ticket, property) : OrderGetString(property);
}
...
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Mục đích chính của lớp OrderMonitor
là cung cấp dữ liệu cho các lớp phân tích khác. Các đối tượng OrderMonitor
được sử dụng để lọc các lệnh đang hoạt động trong lớp OrderFilter
, và chúng ta cần một lớp tương tự để chọn các lệnh theo điều kiện tùy ý trên lịch sử: HistoryOrderFilter
.
Hãy viết lớp này trong cùng tệp OrderFilter.mqh
. Nó sử dụng hai hàm mới để làm việc với lịch sử: HistoryOrdersTotal
và HistoryOrderGetTicket
.
class HistoryOrderFilter: public TradeFilter<OrderMonitor,
ENUM_ORDER_PROPERTY_INTEGER,
ENUM_ORDER_PROPERTY_DOUBLE,
ENUM_ORDER_PROPERTY_STRING>
{
protected:
virtual int total() const override
{
return HistoryOrdersTotal();
}
virtual ulong get(const int i) const override
{
return HistoryOrderGetTicket(i);
}
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Mã đơn giản này kế thừa từ lớp mẫu TradeFilter
, trong đó lớp được truyền làm tham số đầu tiên của mẫu OrderMonitor
để đọc các thuộc tính của các đối tượng tương ứng (chúng ta đã thấy một tương tự cho các vị thế, và sẽ sớm tạo một cái cho các giao dịch).
Vấn đề nằm ở hàm tạo của OrderMonitor
. Như chúng ta đã học trong phần Lựa chọn lệnh và giao dịch từ lịch sử, để phân tích tài khoản, chúng ta phải thiết lập ngữ cảnh trước bằng một trong các hàm như HistorySelect
. Vì vậy, trong mã nguồn của HistoryOrderFilter
,假定 rằng chương trình MQL đã chọn đoạn lịch sử cần thiết. Tuy nhiên, phiên bản trung gian mới của hàm tạo OrderMonitor
sử dụng cuộc gọi HistoryOrderSelect
để kiểm tra sự tồn tại của một vé trong lịch sử. Trong khi đó, hàm này đặt lại ngữ cảnh trước đó của các lệnh lịch sử và chọn một lệnh duy nhất.
Vì vậy, chúng ta cần một phương thức trợ giúp historyOrderSelectWeak
để xác thực vé một cách "nhẹ nhàng" mà không làm phá vỡ ngữ cảnh hiện tại. Để làm điều này, chúng ta có thể đơn giản kiểm tra xem thuộc tính ORDER_TICKET
có bằng với vé đã truyền t
hay không: (HistoryOrderGetInteger(t, ORDER_TICKET) == t)
. Nếu vé đó đã được chọn (có sẵn), kiểm tra sẽ thành công, và bộ giám sát không cần thao tác với lịch sử.
class OrderMonitor: public OrderMonitorInterface
{
bool historyOrderSelectWeak(const ulong t) const
{
return (((HistoryOrderGetInteger(t, ORDER_TICKET) == t) ||
(HistorySelect(0, LONG_MAX) && (HistoryOrderGetInteger(t, ORDER_TICKET) == t))));
}
bool history;
public:
const ulong ticket;
OrderMonitor(const long t): ticket(t), history(!OrderSelect(t))
{
if(history && !historyOrderSelectWeak(ticket))
{
PrintFormat("Error: OrderSelect(%lld) failed: %s", ticket, E2S(_LastError));
}
else
{
ResetLastError();
ready = true;
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Một ví dụ về việc áp dụng lọc lệnh trên lịch sử sẽ được xem xét trong phần tiếp theo sau khi chúng ta chuẩn bị chức năng tương tự cho các giao dịch.