Cấu trúc của một Giao dịch Thương mại (MqlTradeTransaction)
Khi thực hiện một số hành động nhất định trên tài khoản giao dịch, trạng thái của nó thay đổi. Các hành động này bao gồm:
Gửi yêu cầu giao dịch từ bất kỳ ứng dụng MQL5 nào trong terminal khách hàng bằng các hàm OrderSend và OrderSendAsync và việc thực thi tiếp theo của nó;
Gửi yêu cầu giao dịch qua giao diện đồ họa của terminal và việc thực thi tiếp theo của nó;
Kích hoạt lệnh chờ và lệnh dừng trên máy chủ;
Thực hiện các thao tác ở phía máy chủ giao dịch.
Các giao dịch thương mại sau đây được thực hiện như kết quả của những hành động này:
- Xử lý một yêu cầu giao dịch;
- Thay đổi các lệnh đang mở;
- Thay đổi lịch sử lệnh;
- Thay đổi lịch sử giao dịch;
- Thay đổi vị thế.
Ví dụ, khi gửi một lệnh mua thị trường, nó được xử lý, một lệnh mua phù hợp được tạo cho tài khoản, sau đó lệnh được thực thi và xóa khỏi danh sách các lệnh đang mở, rồi được thêm vào lịch sử lệnh, một giao dịch phù hợp được thêm vào lịch sử và một vị thế mới được tạo. Tất cả những hành động này là các giao dịch thương mại.
Một trình xử lý đặc biệt OnTradeTransaction() được cung cấp trong MQL5 để lấy các giao dịch thương mại áp dụng cho một tài khoản. Tham số đầu tiên của trình xử lý nhận cấu trúc MqlTradeTransaction
mô tả các giao dịch thương mại.
struct MqlTradeTransaction
{
ulong deal; // Vé giao dịch
ulong order; // Vé lệnh
string symbol; // Tên biểu tượng giao dịch
ENUM_TRADE_TRANSACTION_TYPE type; // Loại giao dịch thương mại
ENUM_ORDER_TYPE order_type; // Loại lệnh
ENUM_ORDER_STATE order_state; // Trạng thái lệnh
ENUM_DEAL_TYPE deal_type; // Loại giao dịch
ENUM_ORDER_TYPE_TIME time_type; // Loại lệnh theo thời gian hoạt động
datetime time_expiration; // Thời gian hết hạn của lệnh
double price; // Giá
double price_trigger; // Giá kích hoạt lệnh giới hạn dừng
double price_sl; // Mức dừng lỗ
double price_tp; // Mức chốt lời
double volume; // Khối lượng tính bằng lô
ulong position; // Vé vị thế
ulong position_by; // Vé của vị thế đối lập
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Mô tả các trường
Trường | Mô tả |
---|---|
deal | Vé giao dịch. |
order | Vé lệnh. |
symbol | Tên của biểu tượng giao dịch mà giao dịch được thực hiện. |
type | Loại giao dịch thương mại. Giá trị có thể là một trong các giá trị của liệt kê ENUM_TRADE_TRANSACTION_TYPE. |
order_type | Loại lệnh giao dịch. Giá trị có thể là một trong các giá trị của liệt kê ENUM_ORDER_TYPE. |
order_state | Trạng thái lệnh giao dịch. Giá trị có thể là một trong các giá trị của liệt kê ENUM_ORDER_STATE. |
deal_type | Loại giao dịch. Giá trị có thể là một trong các giá trị của liệt kê ENUM_DEAL_TYPE. |
time_type | Loại lệnh theo thời hạn. Giá trị có thể là một trong các giá trị của ENUM_ORDER_TYPE_TIME. |
time_expiration | Thời hạn hết hạn của lệnh chờ (đối với các lệnh có loại ORDER_TIME_SPECIFIED và ORDER_TIME_SPECIFIED_DAY). |
price | Giá. Tùy thuộc vào loại giao dịch thương mại, nó có thể là giá của lệnh, giao dịch hoặc vị thế. |
price_trigger | Giá dừng (kích hoạt) của lệnh giới hạn dừng (ORDER_TYPE_BUY_STOP_LIMIT và ORDER_TYPE_SELL_STOP_LIMIT). |
price_sl | Giá dừng lỗ. Tùy thuộc vào loại giao dịch thương mại, nó có thể liên quan đến lệnh, giao dịch hoặc vị thế. |
price_tp | Giá chốt lời. Tùy thuộc vào loại giao dịch thương mại, nó có thể liên quan đến lệnh, giao dịch hoặc vị thế. |
volume | Khối lượng tính bằng lô. Tùy thuộc vào loại giao dịch thương mại, nó có thể chỉ ra khối lượng hiện tại của lệnh, giao dịch hoặc vị thế. |
position | Vé của vị thế bị ảnh hưởng bởi giao dịch. |
position_by | Vé của vị thế đối lập. Được sử dụng khi đóng vị thế bằng một vị thế đối lập, tức là bằng một vị thế của cùng biểu tượng được mở theo hướng ngược lại. |
Tham số quan trọng để phân tích giao dịch nhận được là loại của nó được chỉ định trong trường type
. Ví dụ, nếu một giao dịch thuộc loại TRADE_TRANSACTION_REQUEST (kết quả xử lý yêu cầu giao dịch bởi máy chủ đã được nhận), cấu trúc chỉ có một trường được điền đầy đủ - type
. Các trường khác không được phân tích. Trong trường hợp này, chúng ta có thể phân tích hai tham số bổ sung request
và result
được gửi đến trình xử lý OnTradeTransaction()
, như được hiển thị dưới đây.
Có dữ liệu về loại hoạt động giao dịch, bạn có thể quyết định việc phân tích trạng thái hiện tại của các lệnh, vị thế và giao dịch trên tài khoản giao dịch. Hãy nhớ rằng một yêu cầu giao dịch được gửi đến máy chủ từ terminal có thể tạo ra nhiều giao dịch mới. Thứ tự ưu tiên đến terminal của chúng không được đảm bảo.
Cấu trúc MqlTradeTransaction
được điền theo các cách khác nhau tùy thuộc vào loại giao dịch thương mại (ENUM_TRADE_TRANSACTION_TYPE):
TRADE_TRANSACTION_ORDER_ và TRADE_TRANSACTION_HISTORY_**
Các trường sau trong cấu trúc MqlTradeTransaction
được điền cho các giao dịch thương mại liên quan đến việc xử lý các lệnh đang mở (TRADE_TRANSACTION_ORDER_ADD
, TRADE_TRANSACTION_ORDER_UPDATE
và TRADE_TRANSACTION_ORDER_DELETE
) và lịch sử lệnh (TRADE_TRANSACTION_HISTORY_ADD
, TRADE_TRANSACTION_HISTORY_UPDATE
, TRADE_TRANSACTION_HISTORY_DELETE
):
order
- vé lệnh;symbol
- tên biểu tượng của lệnh;type
- loại giao dịch thương mại;order_type
- loại lệnh;order_state
- trạng thái hiện tại của lệnh;time_type
- loại hết hạn của lệnh;time_expiration
- thời gian hết hạn của lệnh (đối với các lệnh có loại hết hạn ORDER_TIME_SPECIFIED và ORDER_TIME_SPECIFIED_DAY);price
- giá lệnh được chỉ định bởi khách hàng;price_trigger
- giá dừng của lệnh giới hạn dừng (chỉ áp dụng cho ORDER_TYPE_BUY_STOP_LIMIT và ORDER_TYPE_SELL_STOP_LIMIT);price_sl
- giá dừng lỗ của lệnh (được điền nếu được chỉ định trong lệnh);price_tp
- giá chốt lời của lệnh (được điền nếu được chỉ định trong lệnh);volume
- khối lượng hiện tại của lệnh (chưa thực hiện). Khối lượng ban đầu của lệnh có thể được tìm thấy trong lịch sử lệnh bằng hàm HistoryOrders*.position
- vé của vị thế được mở, sửa đổi hoặc đóng do thực thi lệnh. Chỉ được điền cho các lệnh thị trường, không được điền choTRADE_TRANSACTION_ORDER_ADD
.position_by
- vé của vị thế đối lập. Chỉ được điền cho các lệnh đóng bằng cách đối lập (để đóng một vị thế bằng một vị thế ngược lại).
TRADE_TRANSACTION_DEAL_*
Các trường sau trong cấu trúc MqlTradeTransaction
được điền cho các giao dịch thương mại liên quan đến việc xử lý giao dịch (TRADE_TRANSACTION_DEAL_ADD
, TRADE_TRANSACTION_DEAL_UPDATE
và TRADE_TRANSACTION_DEAL_DELETE
):
deal
- vé giao dịch;order
- vé lệnh, dựa trên đó giao dịch đã được thực hiện;symbol
- tên biểu tượng của giao dịch;type
- loại giao dịch thương mại;deal_type
- loại giao dịch;price
- giá giao dịch;price_sl
- giá dừng lỗ (được điền nếu được chỉ định trong lệnh mà giao dịch dựa trên);price_tp
- giá chốt lời (được điền nếu được chỉ định trong lệnh mà giao dịch dựa trên);volume
- khối lượng giao dịch tính bằng lô;position
- vé của vị thế được mở, sửa đổi hoặc đóng do thực thi giao dịch;position_by
- vé của vị thế đối lập. Chỉ được điền cho các giao dịch thoát bằng cách đối lập (đóng vị thế bằng một vị thế ngược lại).
TRADE_TRANSACTION_POSITION
Các trường sau trong cấu trúc MqlTradeTransaction
được điền cho các giao dịch thương mại liên quan đến việc thay đổi vị thế không liên quan đến thực thi giao dịch (TRADE_TRANSACTION_POSITION
):
symbol
- tên biểu tượng của vị thế;type
- loại giao dịch thương mại;deal_type
- loại vị thế (DEAL_TYPE_BUY hoặc DEAL_TYPE_SELL);price
- giá mở trung bình có trọng số của vị thế;price_sl
- giá dừng lỗ;price_tp
- giá chốt lời;volume
- khối lượng vị thế tính bằng lô, nếu nó đã thay đổi.
| Việc thay đổi vị thế (thêm, thay đổi hoặc đóng), do kết quả của việc thực thi một giao dịch, không dẫn đến sự xuất hiện của giao dịch TRADE_TRANSACTION_POSITION
. |
TRADE_TRANSACTION_REQUEST
Chỉ một trường trong cấu trúc MqlTradeTransaction
được điền cho các giao dịch thương mại mô tả việc một yêu cầu giao dịch đã được máy chủ xử lý và kết quả xử lý đã được nhận (TRADE_TRANSACTION_REQUEST
):
type
- loại giao dịch thương mại;
| Chỉ trường type
(loại giao dịch thương mại) cần được phân tích cho các giao dịch như vậy. Các tham số thứ hai và thứ ba của hàm OnTradeTransaction (request
và result
) phải được phân tích để lấy dữ liệu bổ sung. |
Ví dụ:
input int MagicNumber = 1234567;
//--- kích hoạt lớp giao dịch CTrade và khai báo biến của lớp này
#include <Trade\Trade.mqh>
CTrade trade;
//--- cờ để cài đặt và xóa lệnh chờ
bool pending_done = false;
bool pending_deleted = false;
//--- vé lệnh chờ sẽ được lưu trữ tại đây
ulong order_ticket;
//+------------------------------------------------------------------+
//| Hàm khởi tạo Expert |
//+------------------------------------------------------------------+
int OnInit()
{
//--- đặt MagicNumber để đánh dấu tất cả các lệnh của chúng ta
trade.SetExpertMagicNumber(MagicNumber);
//--- các yêu cầu giao dịch sẽ được gửi ở chế độ không đồng bộ bằng hàm OrderSendAsync()
trade.SetAsyncMode(true);
//--- khởi tạo biến bằng 0
order_ticket = 0;
//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Hàm xử lý tick của Expert |
//+------------------------------------------------------------------+
void OnTick()
{
//--- cài đặt lệnh chờ
if(!pending_done)
{
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double buy_stop_price = NormalizeDouble(ask + 1000 * _Point, (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS));
bool res = trade.BuyStop(0.1, buy_stop_price, _Symbol);
//--- nếu hàm BuyStop() thực hiện thành công
if(res)
{
pending_done = true;
//--- lấy kết quả của việc gửi yêu cầu từ ctrade
MqlTradeResult trade_result;
trade.Result(trade_result);
//--- lấy request_id cho yêu cầu đã gửi
uint request_id = trade_result.request_id;
Print("Yêu cầu đã được gửi để đặt lệnh chờ. Request_ID=", request_id);
//--- lưu vé lệnh (sẽ bằng 0 nếu sử dụng chế độ không đồng bộ của việc gửi tới CTrade)
order_ticket = trade_result.order;
//--- tất cả đã hoàn tất, thoát sớm khỏi trình xử lý OnTick()
return;
}
}
//--- xóa lệnh chờ
if(!pending_deleted)
//--- kiểm tra bổ sung
if(pending_done && (order_ticket != 0))
{
//--- thử xóa lệnh chờ
bool res = trade.OrderDelete(order_ticket);
Print("OrderDelete=", res);
//--- khi yêu cầu xóa được gửi thành công
if(res)
{
pending_deleted = true;
//--- lấy kết quả thực thi yêu cầu
MqlTradeResult trade_result;
trade.Result(trade_result);
//--- lấy ID yêu cầu từ kết quả
uint request_id = trade_result.request_id;
//--- hiển thị trong Nhật ký
Print("Yêu cầu đã được gửi để xóa lệnh chờ #", order_ticket,
". Request_ID=", request_id,
"\r\n");
//--- sửa vé lệnh từ kết quả yêu cầu
order_ticket = trade_result.order;
}
}
//---
}
//+------------------------------------------------------------------+
//| Hàm TradeTransaction |
//+------------------------------------------------------------------+
void OnTradeTransaction(const MqlTradeTransaction &trans,
const MqlTradeRequest &request,
const MqlTradeResult &result)
{
//--- lấy loại giao dịch dưới dạng giá trị liệt kê
ENUM_TRADE_TRANSACTION_TYPE type = (ENUM_TRADE_TRANSACTION_TYPE)trans.type;
//--- nếu giao dịch là kết quả xử lý yêu cầu, chỉ tên của nó được hiển thị
if(type == TRADE_TRANSACTION_REQUEST)
{
Print(EnumToString(type));
//--- hiển thị tên chuỗi của yêu cầu đã xử lý
Print("------------RequestDescription\r\n", RequestDescription(request));
//--- hiển thị mô tả kết quả yêu cầu
Print("------------ResultDescription\r\n", TradeResultDescription(result));
//--- lưu vé lệnh để xóa nó trong lần xử lý tiếp theo trong OnTick()
if(result.order != 0)
{
//--- xóa lệnh này bằng vé của nó trong lần gọi OnTick() tiếp theo
order_ticket = result.order;
Print(" Vé lệnh chờ ", order_ticket, "\r\n");
}
}
else // hiển thị mô tả đầy đủ cho các giao dịch thuộc loại khác
//--- hiển thị mô tả của giao dịch nhận được trong Nhật ký
Print("------------TransactionDescription\r\n", TransactionDescription(trans));
//---
}
//+------------------------------------------------------------------+
//| Trả về mô tả văn bản của giao dịch |
//+------------------------------------------------------------------+
string TransactionDescription(const MqlTradeTransaction &trans)
{
//---
string desc = EnumToString(trans.type) + "\r\n";
desc += "Symbol: " + trans.symbol + "\r\n";
desc += "Deal ticket: " + (string)trans.deal + "\r\n";
desc += "Deal type: " + EnumToString(trans.deal_type) + "\r\n";
desc += "Order ticket: " + (string)trans.order + "\r\n";
desc += "Order type: " + EnumToString(trans.order_type) + "\r\n";
desc += "Order state: " + EnumToString(trans.order_state) + "\r\n";
desc += "Order time type: " + EnumToString(trans.time_type) + "\r\n";
desc += "Order expiration: " + TimeToString(trans.time_expiration) + "\r\n";
desc += "Price: " + StringFormat("%G", trans.price) + "\r\n";
desc += "Price trigger: " + StringFormat("%G", trans.price_trigger) + "\r\n";
desc += "Stop Loss: " + StringFormat("%G", trans.price_sl) + "\r\n";
desc += "Take Profit: " + StringFormat("%G", trans.price_tp) + "\r\n";
desc += "Volume: " + StringFormat("%G", trans.volume) + "\r\n";
desc += "Position: " + (string)trans.position + "\r\n";
desc += "Position by: " + (string)trans.position_by + "\r\n";
//--- trả về chuỗi thu được
return desc;
}
//+------------------------------------------------------------------+
//| Trả về mô tả văn bản của yêu cầu giao dịch |
//+------------------------------------------------------------------+
string RequestDescription(const MqlTradeRequest &request)
{
//---
string desc = EnumToString(request.action) + "\r\n";
desc += "Symbol: " + request.symbol + "\r\n";
desc += "Magic Number: " + StringFormat("%d", request.magic) + "\r\n";
desc += "Order ticket: " + (string)request.order + "\r\n";
desc += "Order type: " + EnumToString(request.type) + "\r\n";
desc += "Order filling: " + EnumToString(request.type_filling) + "\r\n";
desc += "Order time type: " + EnumToString(request.type_time) + "\r\n";
desc += "Order expiration: " + TimeToString(request.expiration) + "\r\n";
desc += "Price: " + StringFormat("%G", request.price) + "\r\n";
desc += "Deviation points: " + StringFormat("%G", request.deviation) + "\r\n";
desc += "Stop Loss: " + StringFormat("%G", request.sl) + "\r\n";
desc += "Take Profit: " + StringFormat("%G", request.tp) + "\r\n";
desc += "Stop Limit: " + StringFormat("%G", request.stoplimit) + "\r\n";
desc += "Volume: " + StringFormat("%G", request.volume) + "\r\n";
desc += "Comment: " + request.comment + "\r\n";
//--- trả về chuỗi thu được
return desc;
}
//+------------------------------------------------------------------+
//| Trả về mô tả văn bản của kết quả xử lý yêu cầu |
//+------------------------------------------------------------------+
string TradeResultDescription(const MqlTradeResult &result)
{
//---
string desc = "Retcode " + (string)result.retcode + "\r\n";
desc += "Request ID: " + StringFormat("%d", result.request_id) + "\r\n";
desc += "Order ticket: " + (string)result.order + "\r\n";
desc += "Deal ticket: " + (string)result.deal + "\r\n";
desc += "Volume: " + StringFormat("%G", result.volume) + "\r\n";
desc += "Price: " + StringFormat("%G", result.price) + "\r\n";
desc += "Ask: " + StringFormat("%G", result.ask) + "\r\n";
desc += "Bid: " + StringFormat("%G", result.bid) + "\r\n";
desc += "Comment: " + result.comment + "\r\n";
//--- trả về chuỗi thu được
return desc;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
Xem thêm