Sự kiện OnTradeTransaction
Expert Advisors và các chỉ báo có thể nhận thông báo về các sự kiện giao dịch nếu mã của chúng chứa một hàm xử lý đặc biệt OnTradeTransaction
.
void OnTradeTransaction(const MqlTradeTransaction &trans,
const MqlTradeRequest &request,
const MqlTradeResult &result)
2
3
Tham số đầu tiên là cấu trúc MqlTradeTransaction
được mô tả trong phần trước. Hai tham số thứ hai và thứ ba là các cấu trúc MqlTradeRequest
và MqlTradeResult
, đã được trình bày trước đó trong các phần liên quan.
Cấu trúc MqlTradeTransaction
mô tả giao dịch thương mại được điền khác nhau tùy thuộc vào loại giao dịch được chỉ định trong trường type
. Ví dụ, đối với các giao dịch loại TRADE_TRANSACTION_REQUEST
, tất cả các trường khác không quan trọng, và để có thêm thông tin, cần phân tích tham số thứ hai và thứ ba của hàm (request
và result
). Ngược lại, đối với tất cả các loại giao dịch khác, hai tham số cuối của hàm nên được bỏ qua.
Trong trường hợp TRADE_TRANSACTION_REQUEST
, trường request_id
trong biến result
chứa một định danh (thông qua số thứ tự), mà theo đó yêu cầu giao dịch request
được đăng ký trong terminal. Con số này không liên quan gì đến vé lệnh và vé giao dịch, cũng như định danh vị thế. Trong mỗi phiên làm việc với terminal, việc đánh số bắt đầu từ đầu (1). Sự hiện diện của định danh yêu cầu cho phép liên kết hành động đã thực hiện (gọi hàm OrderSend
hoặc OrderSendAsync
) với kết quả của hành động này được truyền đến OnTradeTransaction
. Chúng ta sẽ xem xét các ví dụ sau.
Đối với các giao dịch thương mại liên quan đến lệnh đang hoạt động (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
), các trường sau được điền trong cấu trúc MqlTradeTransaction
:
order
– vé lệnhsymbol
– tên của công cụ tài chính trong lệnhtype
– loại giao dịch thương mạiorder_type
– loại lệnhorders_state
– trạng thái hiện tại của lệnhtime_type
– loại hết hạn của lệnhtime_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ạnORDER_TIME_SPECIFIED
vàORDER_TIME_SPECIFIED_DAY
)price
– giá lệnh do khách hàng/chương trình chỉ địnhprice_trigger
– giá dừng để kích hoạt lệnh giới hạn dừng (chỉ dành choORDER_TYPE_BUY_STOP_LIMIT
vàORDER_TYPE_SELL_STOP_LIMIT
)price_sl
– giá lệnhStop Loss
(được điền nếu được chỉ định trong lệnh)price_tp
– giá lệnhTake Profit
(đượ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 từ lịch sử lệnhposition
– vé của vị thế được mở, sửa đổi hoặc đóngposition_by
– vé vị thế đối lập (chỉ dành cho các lệnh đóng với vị thế đối lập)
Đối với các giao dịch thương mại liên quan đến giao dịch (TRADE_TRANSACTION_DEAL_ADD
, TRADE_TRANSACTION_DEAL_UPDATE
và TRADE_TRANSACTION_DEAL_DELETE
), các trường sau được điền trong cấu trúc MqlTradeTransaction
:
deal
– vé giao dịchorder
– vé lệnh dựa trên đó giao dịch được thực hiệnsymbol
– tên của công cụ tài chính trong giao dịchtype
– loại giao dịch thương mạideal_type
– loại giao dịchprice
– giá giao dịchprice_sl
– giáStop Loss
(được điền nếu được chỉ định trong lệnh mà giao dịch dựa vào)price_tp
– giáTake Profit
(được điền nếu được chỉ định trong lệnh mà giao dịch dựa vào)volume
– khối lượng giao dịchposition
– vé của vị thế được mở, sửa đổi hoặc đóngposition_by
– vé vị thế đối lập (đối với các giao dịch đóng với vị thế đối lập)
Đối với các giao dịch thương mại liên quan đến thay đổi vị thế (TRADE_TRANSACTION_POSITION
), các trường sau được điền trong cấu trúc MqlTradeTransaction
:
symbol
– tên của công cụ tài chính của vị thếtype
– loại giao dịch thương mạideal_type
– loại vị thế (DEAL_TYPE_BUY
hoặcDEAL_TYPE_SELL
)price
– giá mở trung bình có trọng số của vị thếprice_sl
– giáStop Loss
price_tp
– giáTake Profit
volume
– khối lượng vị thế tính bằng lôposition
– vé vị thế
Không phải tất cả thông tin có sẵn về lệnh, giao dịch và vị thế (ví dụ, bình luận) được truyền trong mô tả của một giao dịch thương mại. Để biết thêm thông tin, hãy sử dụng các hàm liên quan: OrderGet
, HistoryOrderGet
, HistoryDealGet
và PositionGet
.
Một yêu cầu giao dịch được gửi từ terminal bằng tay hoặc thông qua các hàm giao dịch OrderSend/OrderSendAsync
có thể tạo ra nhiều giao dịch thương mại liên tiếp trên máy chủ giao dịch. Đồng thời, thứ tự mà các thông báo về các giao dịch này đến terminal không được đảm bảo, vì vậy bạn không thể xây dựng thuật toán giao dịch của mình dựa trên việc chờ đợi một số giao dịch thương mại sau những giao dịch khác.
Các sự kiện giao dịch được xử lý không đồng bộ, tức là bị trì hoãn (về thời gian) so với thời điểm tạo ra. Mỗi sự kiện giao dịch được gửi đến hàng đợi của chương trình MQL, và chương trình lần lượt lấy chúng theo thứ tự của hàng đợi.
Khi một Expert Advisor đang xử lý các giao dịch thương mại bên trong bộ xử lý OnTradeTransaction
, terminal tiếp tục chấp nhận các giao dịch thương mại đến. Do đó, trạng thái của tài khoản giao dịch có thể thay đổi trong khi OnTradeTransaction
đang chạy. Trong tương lai, chương trình sẽ được thông báo về tất cả các sự kiện này theo thứ tự xuất hiện.
Độ dài của hàng đợi giao dịch là 1024 phần tử. Nếu OnTradeTransaction
xử lý giao dịch tiếp theo quá lâu, các giao dịch cũ trong hàng đợi có thể bị đẩy ra bởi những giao dịch mới hơn.
Do hoạt động đa luồng song song của terminal với các đối tượng giao dịch, đến thời điểm bộ xử lý OnTradeTransaction
được gọi, tất cả các thực thể được đề cập trong đó, bao gồm lệnh, giao dịch và vị thế, có thể đã ở trạng thái khác với trạng thái được chỉ định trong thuộc tính giao dịch. Để lấy trạng thái hiện tại của chúng, bạn nên chọn chúng trong môi trường hiện tại hoặc trong lịch sử và yêu cầu thuộc tính của chúng bằng các hàm MQL5 thích hợp.
Hãy bắt đầu với một ví dụ Expert Advisor đơn giản TradeTransactions.mq5
, ghi lại tất cả các sự kiện giao dịch OnTradeTransaction
. Tham số duy nhất của nó DetailedLog
cho phép tùy chọn sử dụng các lớp OrderMonitor
, DealMonitor
, PositionMonitor
để hiển thị tất cả các thuộc tính. Theo mặc định, Expert Advisor chỉ hiển thị nội dung của các trường được điền trong các cấu trúc MqlTradeTransaction
, MqlTradeRequest
và MqlTradeResult
, đến bộ xử lý dưới dạng tham số; đồng thời request
và result
chỉ được xử lý cho các giao dịch TRADE_TRANSACTION_REQUEST
.
input bool DetailedLog = false; // DetailedLog ('true' hiển thị chi tiết lệnh/giao dịch/vị thế)
void OnTradeTransaction(const MqlTradeTransaction &transaction,
const MqlTradeRequest &request,
const MqlTradeResult &result)
{
static ulong count = 0;
PrintFormat(">>>% 6d", ++count);
Print(TU::StringOf(transaction));
if(transaction.type == TRADE_TRANSACTION_REQUEST)
{
Print(TU::StringOf(request));
Print(TU::StringOf(result));
}
if(DetailedLog)
{
if(transaction.order != 0)
{
OrderMonitor m(transaction.order);
m.print();
}
if(transaction.deal != 0)
{
DealMonitor m(transaction.deal);
m.print();
}
if(transaction.position != 0)
{
PositionMonitor m(transaction.position);
m.print();
}
}
}
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
Hãy chạy nó trên biểu đồ EURUSD và thực hiện một số hành động thủ công, các mục tương ứng sẽ xuất hiện trong nhật ký (để đảm bảo tính thuần khiết của thí nghiệm,假 định rằng không ai và không có gì khác thực hiện các hoạt động trên tài khoản giao dịch, đặc biệt là không có Expert Advisor nào khác đang chạy).
Hãy mở một vị thế mua với lô tối thiểu.
>>> 1
TRADE_TRANSACTION_ORDER_ADD, #=1296991463(ORDER_TYPE_BUY/ORDER_STATE_STARTED), EURUSD, »
» @ 1.10947, V=0.01
>>> 2
TRADE_TRANSACTION_DEAL_ADD, D=1279627746(DEAL_TYPE_BUY), »
» #=1296991463(ORDER_TYPE_BUY/ORDER_STATE_STARTED), EURUSD, @ 1.10947, V=0.01, P=1296991463
>>> 3
TRADE_TRANSACTION_ORDER_DELETE, #=1296991463(ORDER_TYPE_BUY/ORDER_STATE_FILLED), EURUSD, »
» @ 1.10947, P=1296991463
>>> 4
TRADE_TRANSACTION_HISTORY_ADD, #=1296991463(ORDER_TYPE_BUY/ORDER_STATE_FILLED), EURUSD, »
» @ 1.10947, P=1296991463
>>> 5
TRADE_TRANSACTION_REQUEST
TRADE_ACTION_DEAL, EURUSD, ORDER_TYPE_BUY, V=0.01, ORDER_FILLING_FOK, @ 1.10947, #=1296991463
DONE, D=1279627746, #=1296991463, V=0.01, @ 1.10947, Bid=1.10947, Ask=1.10947, Req=7
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Chúng ta sẽ bán gấp đôi lô tối thiểu.
>>> 6
TRADE_TRANSACTION_ORDER_ADD, #=1296992157(ORDER_TYPE_SELL/ORDER_STATE_STARTED), EURUSD, »
» @ 1.10964, V=0.02
>>> 7
TRADE_TRANSACTION_DEAL_ADD, D=1279628463(DEAL_TYPE_SELL), »
» #=1296992157(ORDER_TYPE_BUY/ORDER_STATE_STARTED), EURUSD, @ 1.10964, V=0.02, P=1296992157
>>> 8
TRADE_TRANSACTION_ORDER_DELETE, #=1296992157(ORDER_TYPE_SELL/ORDER_STATE_FILLED), EURUSD, »
» @ 1.10964, P=1296992157
>>> 9
TRADE_TRANSACTION_HISTORY_ADD, #=1296992157(ORDER_TYPE_SELL/ORDER_STATE_FILLED), EURUSD, »
» @ 1.10964, P=1296992157
>>> 10
TRADE_TRANSACTION_REQUEST
TRADE_ACTION_DEAL, EURUSD, ORDER_TYPE_SELL, V=0.02, ORDER_FILLING_FOK, @ 1.10964, #=1296992157
DONE, D=1279628463, #=1296992157, V=0.02, @ 1.10964, Bid=1.10964, Ask=1.10964, Req=8
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Hãy thực hiện thao tác đóng đối lập.
>>> 11
TRADE_TRANSACTION_ORDER_ADD, #=1296992548(ORDER_TYPE_CLOSE_BY/ORDER_STATE_STARTED), EURUSD, »
» @ 1.10964, V=0.01, P=1296991463, b=1296992157
>>> 12
TRADE_TRANSACTION_DEAL_ADD, D=1279628878(DEAL_TYPE_SELL), »
» #=1296992548(ORDER_TYPE_BUY/ORDER_STATE_STARTED), EURUSD, @ 1.10964, V=0.01, P=1296991463
>>> 13
TRADE_TRANSACTION_POSITION, EURUSD, @ 1.10947, P=1296991463
>>> 14
TRADE_TRANSACTION_DEAL_ADD, D=1279628879(DEAL_TYPE_BUY), »
» #=1296992548(ORDER_TYPE_BUY/ORDER_STATE_STARTED), EURUSD, @ 1.10947, V=0.01, P=1296992157
>>> 15
TRADE_TRANSACTION_ORDER_DELETE, #=1296992548(ORDER_TYPE_CLOSE_BY/ORDER_STATE_FILLED), EURUSD, »
» @ 1.10964, P=1296991463, b=1296992157
>>> 16
TRADE_TRANSACTION_HISTORY_ADD, #=1296992548(ORDER_TYPE_CLOSE_BY/ORDER_STATE_FILLED), EURUSD, »
» @ 1.10964, P=1296991463, b=1296992157
>>> 17
TRADE_TRANSACTION_REQUEST
TRADE_ACTION_CLOSE_BY, EURUSD, ORDER_TYPE_BUY, V=0.01, ORDER_FILLING_FOK, #=1296992548, »
» P=1296991463, b=1296992157
DONE, D=1279628878, #=1296992548, V=0.01, @ 1.10964, Bid=1.10961, Ask=1.10965, Req=9
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Chúng ta vẫn còn một vị thế bán với lô tối thiểu. Hãy đóng nó.
>>> 18
TRADE_TRANSACTION_ORDER_ADD, #=1297002683(ORDER_TYPE_BUY/ORDER_STATE_STARTED), EURUSD, »
» @ 1.10964, V=0.01, P=1296992157
>>> 19
TRADE_TRANSACTION_ORDER_DELETE, #=1297002683(ORDER_TYPE_BUY/ORDER_STATE_FILLED), EURUSD, »
» @ 1.10964, P=1296992157
>>> 20
TRADE_TRANSACTION_HISTORY_ADD, #=1297002683(ORDER_TYPE_BUY/ORDER_STATE_FILLED), EURUSD, »
» @ 1.10964, P=1296992157
>>> 21
TRADE_TRANSACTION_DEAL_ADD, D=1279639132(DEAL_TYPE_BUY), »
» #=1297002683(ORDER_TYPE_BUY/ORDER_STATE_STARTED), EURUSD, @ 1.10964, V=0.01, P=1296992157
>>> 22
TRADE_TRANSACTION_REQUEST
TRADE_ACTION_DEAL, EURUSD, ORDER_TYPE_BUY, V=0.01, ORDER_FILLING_FOK, @ 1.10964, #=1297002683, »
» P=1296992157
DONE, D=1279639132, #=1297002683, V=0.01, @ 1.10964, Bid=1.10964, Ask=1.10964, Req=10
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Nếu bạn muốn, bạn có thể bật tùy chọn DetailedLog
để ghi lại tất cả các thuộc tính của các đối tượng giao dịch tại thời điểm xử lý sự kiện. Trong một nhật ký chi tiết, bạn có thể nhận thấy sự không nhất quán giữa trạng thái của các đối tượng được lưu trữ trong cấu trúc giao dịch (tại thời điểm khởi tạo) và trạng thái hiện tại. Ví dụ, khi thêm một lệnh để đóng một vị thế (tương phản hoặc thông thường), một vé được chỉ định trong giao dịch, theo đó đối tượng giám sát sẽ không thể đọc được gì nữa, vì vị thế đã bị xóa. Kết quả là, chúng ta sẽ thấy các dòng như thế này trong nhật ký:
TRADE_TRANSACTION_ORDER_ADD, #=1297777749(ORDER_TYPE_CLOSE_BY/ORDER_STATE_STARTED), EURUSD, »
» @ 1.10953, V=0.01, P=1297774881, b=1297776850
...
Error: PositionSelectByTicket(1297774881) failed: TRADE_POSITION_NOT_FOUND
2
3
4
Hãy khởi động lại Expert Advisor TradeTransaction.mq5
để đặt lại các sự kiện đã ghi lại cho bài kiểm tra tiếp theo. Lần này chúng ta sẽ sử dụng cài đặt mặc định (không chi tiết).
Bây giờ hãy thử thực hiện các hành động giao dịch theo chương trình trong Expert Advisor mới OrderSendTransaction1.mq5
, và đồng thời mô tả trình xử lý OnTradeTransaction
của chúng ta trong đó (giống như trong ví dụ trước).
Expert Advisor này cho phép bạn chọn hướng giao dịch và khối lượng: nếu bạn để nó ở mức 0, lô tối thiểu của biểu tượng hiện tại sẽ được sử dụng theo mặc định. Ngoài ra, trong các tham số còn có khoảng cách đến các mức bảo vệ tính bằng điểm. Thị trường được tham gia với các tham số đã chỉ định, có một khoảng dừng 5 giây giữa việc thiết lập Stop Loss
và Take Profit
, sau đó đóng vị thế, để người dùng có thể can thiệp (ví dụ, chỉnh sửa stop loss bằng tay), mặc dù điều này không cần thiết, vì chúng ta đã chắc chắn rằng các thao tác thủ công được chương trình bắt lại.
enum ENUM_ORDER_TYPE_MARKET
{
MARKET_BUY = ORDER_TYPE_BUY, // ORDER_TYPE_BUY
MARKET_SELL = ORDER_TYPE_SELL // ORDER_TYPE_SELL
};
input ENUM_ORDER_TYPE_MARKET Type;
input double Volume; // Volume (0 - minimal lot)
input uint Distance2SLTP = 1000;
2
3
4
5
6
7
8
9
Chiến lược được khởi chạy một lần, sử dụng bộ đếm thời gian 1 giây, sau đó tắt trong chính trình xử lý của nó.
int OnInit()
{
EventSetTimer(1);
return INIT_SUCCEEDED;
}
void OnTimer()
{
EventKillTimer();
...
}
2
3
4
5
6
7
8
9
10
11
Tất cả các hành động được thực hiện thông qua cấu trúc quen thuộc MqlTradeRequestSync
với các tính năng nâng cao (MqlTradeSync.mqh
): khởi tạo ngầm các trường với giá trị đúng, phương thức buy/sell
cho lệnh thị trường, adjust
cho các mức bảo vệ, và close
để đóng vị thế.
Bước 1:
MqlTradeRequestSync request;
const double volume = Volume == 0 ?
SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN) : Volume;
Print("Start trade");
const ulong order = (Type == MARKET_BUY ? request.buy(volume) : request.sell(volume));
if(order == 0 || !request.completed())
{
Print("Failed Open");
return;
}
Print("OK Open");
2
3
4
5
6
7
8
9
10
11
12
13
14
Bước 2:
Sleep(5000); // wait 5 seconds (user can edit position)
Print("SL/TP modification");
const double price = PositionGetDouble(POSITION_PRICE_OPEN);
const double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
TU::TradeDirection dir((ENUM_ORDER_TYPE)Type);
const double SL = dir.negative(price, Distance2SLTP * point);
const double TP = dir.positive(price, Distance2SLTP * point);
if(request.adjust(SL, TP) && request.completed())
{
Print("OK Adjust");
}
else
{
Print("Failed Adjust");
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Bước 3:
Sleep(5000); // wait another 5 seconds
Print("Close down");
if(request.close(request.result.position) && request.completed())
{
Print("Finish");
}
else
{
Print("Failed Close");
}
}
2
3
4
5
6
7
8
9
10
11
Các khoảng dừng trung gian không chỉ giúp có thời gian xem xét quá trình mà còn thể hiện một khía cạnh quan trọng của lập trình MQL5, đó là đơn luồng. Trong khi Expert Advisor giao dịch của chúng ta đang ở trong OnTimer
, các sự kiện giao dịch do terminal tạo ra được tích lũy trong hàng đợi của nó và sẽ được chuyển tiếp đến trình xử lý nội bộ OnTradeTransaction
theo kiểu trì hoãn, chỉ sau khi thoát khỏi OnTimer
.
Đồng thời, Expert Advisor TradeTransactions
chạy song song không bận rộn với bất kỳ tính toán nào và sẽ nhận các sự kiện giao dịch nhanh nhất có thể.
Kết quả thực thi của hai Expert Advisor được trình bày trong nhật ký sau với thời gian (để ngắn gọn, OrderSendTransaction1
được gắn thẻ là OS1
, và TradeTransactions
được gắn thẻ là TTs
).
19:09:08.078 OS1 Start trade
19:09:08.109 TTs >>> 1
19:09:08.125 TTs TRADE_TRANSACTION_ORDER_ADD, #=1298021794(ORDER_TYPE_BUY/ORDER_STATE_STARTED), »
EURUSD, @ 1.10913, V=0.01
19:09:08.125 TTs >>> 2
19:09:08.125 TTs TRADE_TRANSACTION_DEAL_ADD, D=1280661362(DEAL_TYPE_BUY), »
#=1298021794(ORDER_TYPE_BUY/ORDER_STATE_STARTED), EURUSD, @ 1.10913, V=0.01, »
P=1298021794
19:09:08.125 TTs >>> 3
19:09:08.125 TTs TRADE_TRANSACTION_ORDER_DELETE, #=1298021794(ORDER_TYPE_BUY/ORDER_STATE_FILLED), »
EURUSD, @ 1.10913, P=1298021794
19:09:08.125 TTs >>> 4
19:09:08.125 TTs TRADE_TRANSACTION_HISTORY_ADD, #=1298021794(ORDER_TYPE_BUY/ORDER_STATE_FILLED), »
EURUSD, @ 1.10913, P=1298021794
19:09:08.125 TTs >>> 5
19:09:08.125 TTs TRADE_TRANSACTION_REQUEST
19:09:08.125 TTs TRADE_ACTION_DEAL, EURUSD, ORDER_TYPE_BUY, V=0.01, ORDER_FILLING_FOK, @ 1.10913, »
D=10, #=1298021794, M=1234567890
19:09:08.125 TTs DONE, D=1280661362, #=1298021794, V=0.01, @ 1.10913, Bid=1.10913, Ask=1.10913, »
Req=9
19:09:08.125 OS1 Waiting for position for deal D=1280661362
19:09:08.125 OS1 OK Open
19:09:13.133 OS1 SL/TP modification
19:09:13.164 TTs >>> 6
19:09:13.164 TTs TRADE_TRANSACTION_POSITION, EURUSD, @ 1.10913, SL=1.09913, TP=1.11913, V=0.01, »
P=1298021794
19:09:13.164 OS1 OK Adjust
19:09:13.164 TTs >>> 7
19:09:13.164 TTs TRADE
19:09:13.164 TTs TRADE_TRANSACTION_REQUEST
19:09:13.164 TTs TRADE_ACTION_SLTP, EURUSD, ORDER_TYPE_BUY, V=0.01, ORDER_FILLING_FOK, SL=1.09913, »
TP=1.11913, D=10, P=1298021794, M=1234567890
19:09:13.164 TTs DONE, Req=10
19:09:18.171 OS1 Close down
19:09:18.187 OS1 Finish
19:09:18.218 TTs >>> 8
19:09:18.218 TTs TRADE_TRANSACTION_ORDER_ADD, #=1298022443(ORDER_TYPE_SELL/ORDER_STATE_STARTED), »
EURUSD, @ 1.10901, V=0.01, P=1298021794
19:09:18.218 TTs >>> 9
19:09:18.218 TTs TRADE_TRANSACTION_DEAL_ADD, D=1280661967(DEAL_TYPE_SELL), »
#=1298022443(ORDER_TYPE_BUY/ORDER_STATE_STARTED), EURUSD, @ 1.10901, »
SL=1.09913, TP=1.11913, V=0.01, P=1298021794
19:09:18.218 TTs >>> 10
19:09:18.218 TTs TRADE_TRANSACTION_ORDER_DELETE, #=1298022443(ORDER_TYPE_SELL/ORDER_STATE_FILLED), »
EURUSD, @ 1.10901, P=1298021794
19:09:18.218 TTs >>> 11
19:09:18.218 TTs TRADE_TRANSACTION_HISTORY_ADD, #=1298022443(ORDER_TYPE_SELL/ORDER_STATE_FILLED), »
EURUSD, @ 1.10901, P=1298021794
19:09:18.218 TTs >>> 12
19:09:18.218 TTs TRADE_TRANSACTION_REQUEST
19:09:18.218 TTs TRADE_ACTION_DEAL, EURUSD, ORDER_TYPE_SELL, V=0.01, ORDER_FILLING_FOK, @ 1.10901, »
D=10, #=1298022443, P=1298021794, M=1234567890
19:09:18.218 TTs DONE, D=1280661967, #=1298022443, V=0.01, @ 1.10901, Bid=1.10901, Ask=1.10901, »
Req=11
19:09:18.218 OS1 >>> 1
19:09:18.218 OS1 TRADE_TRANSACTION_ORDER_ADD, #=1298021794(ORDER_TYPE_BUY/ORDER_STATE_STARTED), »
EURUSD, @ 1.10913, V=0.01
19:09:18.218 OS1 >>> 2
19:09:18.218 OS1 TRADE_TRANSACTION_DEAL_ADD, D=1280661362(DEAL_TYPE_BUY), »
#=1298021794(ORDER_TYPE_BUY/ORDER_STATE_STARTED), EURUSD, »
@ 1.10913, V=0.01, P=1298021794
19:09:18.218 OS1 >>> 3
19:09:18.218 OS1 TRADE_TRANSACTION_ORDER_DELETE, #=1298021794(ORDER_TYPE_BUY/ORDER_STATE_FILLED), »
EURUSD, @ 1.10913, P=1298021794
19:09:18.218 OS1 >>> 4
19:09:18.218 OS1 TRADE_TRANSACTION_HISTORY_ADD, #=1298021794(ORDER_TYPE_BUY/ORDER_STATE_FILLED), »
EURUSD, @ 1.10913, P=1298021794
19:09:18.218 OS1 >>> 5
19:09:18.218 OS1 TRADE_TRANSACTION_REQUEST
19:09:18.218 OS1 TRADE_ACTION_DEAL, EURUSD, ORDER_TYPE_BUY, V=0.01, ORDER_FILLING_FOK, @ 1.10913, »
D=10, #=1298021794, M=1234567890
19:09:18.218 OS1 DONE, D=1280661362, #=1298021794, V=0.01, @ 1.10913, Bid=1.10913, Ask=1.10913, »
Req=9
19:09:18.218 OS1 >>> 6
19:09:18.218 OS1 TRADE_TRANSACTION_POSITION, EURUSD, @ 1.10913, SL=1.09913, TP=1.11913, V=0.01, »
P=1298021794
19:09:18.218 OS1 >>> 7
19:09:18.218 OS1 TRADE_TRANSACTION_REQUEST
19:09:18.218 OS1 TRADE_ACTION_SLTP, EURUSD, ORDER_TYPE_BUY, V=0.01, ORDER_FILLING_FOK, »
SL=1.09913, TP=1.11913, D=10, P=1298021794, M=1234567890
19:09:18.218 OS1 DONE, Req=10
19:09:18.218 OS1 >>> 8
19:09:18.218 OS1 TRADE_TRANSACTION_ORDER_ADD, #=1298022443(ORDER_TYPE_SELL/ORDER_STATE_STARTED), »
EURUSD, @ 1.10901, V=0.01, P=1298021794
19:09:18.218 OS1 >>> 9
19:09:18.218 OS1 TRADE_TRANSACTION_DEAL_ADD, D=1280661967(DEAL_TYPE_SELL), »
#=1298022443(ORDER_TYPE_BUY/ORDER_STATE_STARTED), EURUSD, @ 1.10901, »
SL=1.09913, TP=1.11913, V=0.01, P=1298021794
19:09:18.218 OS1 >>> 10
19:09:18.218 OS1 TRADE_TRANSACTION_ORDER_DELETE, #=1298022443(ORDER_TYPE_SELL/ORDER_STATE_FILLED), »
EURUSD, @ 1.10901, P=1298021794
19:09:18.218 OS1 >>> 11
19:09:18.218 OS1 TRADE_TRANSACTION_HISTORY_ADD, #=1298022443(ORDER_TYPE_SELL/ORDER_STATE_FILLED), »
EURUSD, @ 1.10901, P=1298021794
19:09:18.218 OS1 >>> 12
19:09:18.218 OS1 TRADE_TRANSACTION_REQUEST
19:09:18.218 OS1 TRADE_ACTION_DEAL, EURUSD, ORDER_TYPE_SELL, V=0.01, ORDER_FILLING_FOK, @ 1.10901, »
D=10, #=1298022443, P=1298021794, M=1234567890
19:09:18.218 OS1 DONE, D=1280661967, #=1298022443, V=0.01, @ 1.10901, Bid=1.10901, Ask=1.10901, »
Req=11
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
Việc đánh số các sự kiện trong các chương trình là giống nhau (với điều kiện chúng được khởi động một cách sạch sẽ, như khuyến nghị). Lưu ý rằng cùng một sự kiện được in ra trước tiên từ TTs
ngay sau khi yêu cầu được thực thi, và lần thứ hai chỉ vào cuối bài kiểm tra, nơi mà thực tế tất cả các sự kiện được xuất ra từ hàng đợi đến OS1
.
Nếu chúng ta loại bỏ các khoảng dừng nhân tạo, kịch bản sẽ chạy nhanh hơn, nhưng trình xử lý OnTradeTransaction
vẫn sẽ nhận được thông báo (nhiều lần) sau cả ba bước, chứ không phải sau mỗi yêu cầu tương ứng. Điều này nghiêm trọng đến mức nào?
Bây giờ các ví dụ sử dụng phiên bản sửa đổi của chúng ta về cấu trúc MqlTradeRequestSync
, cố ý sử dụng tùy chọn đồng bộ OrderSend
, cũng thực hiện một phương thức completed
phổ quát kiểm tra xem yêu cầu có hoàn thành thành công hay không. Với sự kiểm soát này, chúng ta có thể đặt các mức bảo vệ cho một vị thế, vì chúng ta biết cách đợi vé của nó xuất hiện. Trong khuôn khổ của khái niệm đồng bộ như vậy (được áp dụng vì sự tiện lợi), chúng ta không cần phân tích kết quả truy vấn trong OnTradeTransaction
. Tuy nhiên, điều này không phải lúc nào cũng đúng.
Khi một Expert Advisor cần gửi nhiều yêu cầu cùng lúc, như trong trường hợp ví dụ về việc thiết lập lưới lệnh PendingOrderGrid2.mq5
được thảo luận trong phần về thuộc tính vị thế, việc đợi mỗi vị thế hoặc lệnh "sẵn sàng" có thể làm giảm hiệu suất tổng thể của Expert Advisor. Trong những trường hợp như vậy, nên sử dụng hàm OrderSendAsync
. Nhưng nếu thành công, nó chỉ điền vào trường request_id
trong MqlTradeResult
, với đó bạn cần theo dõi sự xuất hiện của các lệnh, giao dịch và vị thế trong OnTradeTransaction
.
Một trong những thủ thuật rõ ràng nhất nhưng không đặc biệt thanh lịch để thực hiện kế hoạch này là lưu trữ các định danh của các yêu cầu hoặc toàn bộ cấu trúc của các yêu cầu đang được gửi trong một mảng, trong bối cảnh toàn cục. Những định danh này sau đó có thể được tra cứu trong các giao dịch đến trong OnTradeTransaction
, các vé có thể được tìm thấy trong tham số MqlTradeResult
và các hành động tiếp theo có thể được thực hiện. Kết quả là, logic giao dịch được tách thành các hàm khác nhau. Ví dụ, trong bối cảnh của Expert Advisor cuối cùng OrderSendTransaction1.mq5
, sự "đa dạng hóa" này nằm ở chỗ sau khi gửi lệnh đầu tiên, các đoạn mã phải được chuyển sang OnTradeTransaction
và kiểm tra các điều sau:
- Loại giao dịch trong
MqlTradeTransaction
(transaction type
); - Loại yêu cầu trong
MqlTradeRequest
(request action
); - ID yêu cầu trong
MqlTradeResult
(result.request_id
);
Tất cả điều này nên được bổ sung bằng logic ứng dụng cụ thể (ví dụ, kiểm tra sự tồn tại của một vị thế), cung cấp phân nhánh theo trạng thái chiến lược giao dịch. Một chút sau, chúng ta sẽ thực hiện một sửa đổi tương tự của Expert Advisor OrderSendTransaction
dưới một số khác để hiển thị trực quan lượng mã nguồn bổ sung. Và sau đó chúng ta sẽ đưa ra một cách tổ chức chương trình tuyến tính hơn, nhưng không từ bỏ các sự kiện giao dịch.
Hiện tại, chúng ta chỉ ghi nhận rằng nhà phát triển nên chọn liệu có xây dựng một thuật toán xung quanh OnTradeTransaction
hay không. Trong nhiều trường hợp, khi không cần gửi hàng loạt lệnh, có thể duy trì trong mô hình lập trình đồng bộ. Tuy nhiên, OnTradeTransaction
là cách thực tế nhất để kiểm soát việc kích hoạt các lệnh chờ và các mức bảo vệ, cũng như các sự kiện khác do máy chủ tạo ra. Sau một chút chuẩn bị, chúng ta sẽ trình bày hai ví dụ liên quan: sửa đổi cuối cùng của Expert Advisor lưới và triển khai thiết lập phổ biến của hai lệnh OCO (One Cancels Other) (xem phần On Trade
).
Một giải pháp thay thế cho việc áp dụng OnTradeTransaction
bao gồm việc phân tích định kỳ môi trường giao dịch, tức là thực tế ghi nhớ số lượng lệnh và vị thế và tìm kiếm sự thay đổi trong số đó. Phương pháp này phù hợp với các chiến lược dựa trên lịch trình hoặc cho phép một số độ trễ thời gian nhất định.
Chúng ta nhấn mạnh lại rằng việc sử dụng OnTradeTransaction
không có nghĩa là chương trình phải chuyển từ OrderSend
sang OrderSendAsync
: Bạn có thể sử dụng bất kỳ loại nào hoặc cả hai. Hãy nhớ rằng hàm OrderSend
cũng không hoàn toàn đồng bộ, vì nó trả về, trong trường hợp tốt nhất, vé của lệnh và giao dịch nhưng không phải vị thế. Sắp tới, chúng ta sẽ có thể đo thời gian thực thi của một loạt lệnh trong cùng chiến lược lưới bằng cả hai biến thể của hàm: OrderSend
và OrderSendAsync
.
Để thống nhất việc phát triển các chương trình đồng bộ và không đồng bộ, sẽ rất tuyệt nếu hỗ trợ OrderSendAsync
trong cấu trúc MqlTradeRequestSync
của chúng ta (bất chấp tên của nó). Điều này có thể được thực hiện chỉ với một vài sửa đổi. Đầu tiên, bạn cần thay thế tất cả các lệnh gọi OrderSend
hiện có bằng phương thức riêng orderSend
, và trong đó chuyển đổi lệnh gọi sang OrderSend
hoặc OrderSendAsync
tùy thuộc vào một cờ.
struct MqlTradeRequestSync: public MqlTradeRequest
{
...
static bool AsyncEnabled;
...
private:
bool orderSend(const MqlTradeRequest &req, MqlTradeResult &res)
{
return AsyncEnabled ? ::OrderSendAsync(req, res) : ::OrderSend(req, res);
}
};
2
3
4
5
6
7
8
9
10
11
Bằng cách đặt biến công khai AsyncEnabled
thành true
hoặc false
, bạn có thể chuyển đổi từ chế độ này sang chế độ khác, ví dụ, trong đoạn mã nơi các lệnh hàng loạt được gửi.
Thứ hai, những phương thức của cấu trúc trả về một vé (ví dụ, để vào thị trường) bạn nên trả về trường request_id
thay vì order
. Ví dụ, bên trong các phương thức _pending
và _market
, chúng ta có toán tử sau:
if(OrderSend(this, result)) return result.order;
Bây giờ nó được thay thế bằng:
if(orderSend(this, result)) return result.order ? result.order :
(result.retcode == TRADE_RETCODE_PLACED ? result.request_id : 0);
2
Tất nhiên, khi chế độ không đồng bộ được bật, chúng ta không còn có thể sử dụng phương thức completed
để đợi kết quả truy vấn sẵn sàng ngay sau khi nó được gửi. Nhưng phương thức này, về cơ bản, là tùy chọn: bạn có thể bỏ qua nó ngay cả khi làm việc qua OrderSend
.
Vì vậy, xét đến sửa đổi mới của tệp MqlTradeSync.mqh
, hãy tạo OrderSendTransaction2.mq5
.
Expert Advisor này sẽ gửi yêu cầu ban đầu như trước từ OnTimer
, trong khi đặt các mức bảo vệ và đóng vị thế trong OnTradeTransaction
từng bước. Mặc dù lần này chúng ta sẽ không có khoảng dừng nhân tạo giữa các giai đoạn, nhưng chính chuỗi trạng thái là tiêu chuẩn cho nhiều Expert Advisor: mở vị thế, sửa đổi, đóng (nếu đáp ứng một số điều kiện thị trường nhất định, ở đây được bỏ qua).
Hai biến toàn cục sẽ cho phép bạn theo dõi trạng thái: RequestID
với id của yêu cầu cuối cùng được gửi (kết quả mà chúng ta mong đợi) và Position Ticket
với vé của vị thế đang mở. Khi vị thế chưa xuất hiện, hoặc không còn tồn tại, vé bằng 0.
uint RequestID = 0;
ulong PositionTicket = 0;
2
Chế độ không đồng bộ được bật trong trình xử lý OnInit
.
int OnInit()
{
...
MqlTradeRequestSync::AsyncEnabled = true;
...
}
2
3
4
5
6
Hàm OnTimer
giờ đây ngắn hơn nhiều.
void OnTimer()
{
...
// gửi một yêu cầu TRADE_ACTION_DEAL (không đồng bộ!)
const ulong order = (Type == MARKET_BUY ? request.buy(volume) : request.sell(volume));
if(order) // trong chế độ không đồng bộ, đây giờ là request_id
{
Print("OK Open?");
RequestID = request.result.request_id; // giống như order
}
else
{
Print("Failed Open");
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Khi hoàn thành yêu cầu thành công, chúng ta chỉ nhận được request_id
và lưu trữ nó trong biến RequestID
. Thông báo trạng thái giờ đây chứa dấu hỏi, như "OK Open?", vì kết quả thực sự chưa được biết.
OnTradeTransaction
trở nên phức tạp hơn đáng kể do việc xác minh kết quả và thực hiện các lệnh giao dịch tiếp theo theo điều kiện. Hãy xem xét nó dần dần.
Trong trường hợp này, toàn bộ logic giao dịch đã chuyển vào nhánh cho các giao dịch loại TRADE_TRANSACTION_REQUEST. Tất nhiên, nhà phát triển có thể sử dụng các loại khác nếu muốn, nhưng chúng ta sử dụng loại này vì nó chứa thông tin dưới dạng cấu trúc quen thuộc MqlTradeResult
, tức là, nó đại diện cho một kết thúc bị trì hoãn của lệnh gọi không đồng bộ OrderSendAsync
.
void OnTradeTransaction(const MqlTradeTransaction &transaction,
const MqlTradeRequest &request,
const MqlTradeResult &result)
{
static ulong count = 0;
PrintFormat(">>>% 6d", ++count);
Print(TU::StringOf(transaction));
if(transaction.type == TRADE_TRANSACTION_REQUEST)
{
Print(TU::StringOf(request));
Print(TU::StringOf(result));
...
// toàn bộ thuật toán ở đây
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Chúng ta chỉ nên quan tâm đến các yêu cầu có ID mà chúng ta mong đợi. Vì vậy, câu lệnh tiếp theo sẽ là if
lồng nhau. Trong khối của nó, chúng ta mô tả trước đối tượng MqlTradeRequestSync
, vì nó sẽ cần thiết để gửi các yêu cầu giao dịch thông thường theo kế hoạch.
if(result.request_id == RequestID)
{
MqlTradeRequestSync next;
next.magic = Magic;
next.deviation = Deviation;
...
}
2
3
4
5
6
7
Chúng ta chỉ có hai loại yêu cầu đang hoạt động, vì vậy chúng ta thêm một if
lồng nhau nữa cho chúng.
if(request.action == TRADE_ACTION_DEAL)
{
... // phản ứng với việc mở và đóng vị thế ở đây
}
else if(request.action == TRADE_ACTION_SLTP)
{
... // phản ứng với việc đặt SLTP cho vị thế đang mở ở đây
}
2
3
4
5
6
7
8
Lưu ý rằng TRADE_ACTION_DEAL được sử dụng cho cả việc mở và đóng vị thế, và do đó cần thêm một if
nữa, trong đó chúng ta sẽ phân biệt hai trạng thái này tùy thuộc vào giá trị của biến PositionTicket
.
if(PositionTicket == 0)
{
... // không có vị thế, vì vậy đây là thông báo mở
}
else
{
... // có vị thế, vì vậy đây là đóng
}
2
3
4
5
6
7
8
Không có tăng vị thế (cho netting) hoặc nhiều vị thế (cho hedging) trong chiến lược giao dịch đang xem xét, đó là lý do tại sao phần này logic đơn giản. Các Expert Advisor thực sự sẽ yêu cầu nhiều đánh giá hơn về các trạng thái trung gian.
Trong trường hợp thông báo mở vị thế, khối mã trông như thế này:
if(PositionTicket == 0)
{
// cố gắng lấy kết quả từ giao dịch: chọn lệnh theo vé
if(!HistoryOrderSelect(result.order))
{
Print("Can't select order in history");
RequestID = 0;
return;
}
// lấy ID và vé vị thế
const ulong posid = HistoryOrderGetInteger(result.order, ORDER_POSITION_ID);
PositionTicket = TU::PositionSelectById(posid);
...
2
3
4
5
6
7
8
9
10
11
12
13
Để đơn giản, chúng ta đã bỏ qua việc kiểm tra lỗi và báo giá lại ở đây. Bạn có thể xem ví dụ về xử lý chúng trong mã nguồn đính kèm. Hãy nhớ rằng tất cả các kiểm tra này đã được triển khai trong các phương thức của cấu trúc MqlTradeRequestSync
, nhưng chúng chỉ hoạt động ở chế độ đồng bộ, và do đó chúng ta phải lặp lại chúng một cách rõ ràng.
Đoạn mã tiếp theo để đặt các mức bảo vệ không thay đổi nhiều.
if(PositionTicket == 0)
{
...
const double price = PositionGetDouble(POSITION_PRICE_OPEN);
const double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
TU::TradeDirection dir((ENUM_ORDER_TYPE)Type);
const double SL = dir.negative(price, Distance2SLTP * point);
const double TP = dir.positive(price, Distance2SLTP * point);
// gửi yêu cầu TRADE_ACTION_SLTP (không đồng bộ!)
if(next.adjust(PositionTicket, SL, TP))
{
Print("OK Adjust?");
RequestID = next.result.request_id;
}
else
{
Print("Failed Adjust");
RequestID = 0;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Sự khác biệt duy nhất ở đây là: chúng ta điền biến RequestID
với ID của yêu cầu TRADE_ACTION_SLTP mới.
Việc nhận thông báo về một giao dịch với PositionTicket
không bằng 0 ngụ ý rằng vị thế đã được đóng.
if(PositionTicket == 0)
{
... // xem ở trên
}
else
{
if(!PositionSelectByTicket(PositionTicket))
{
Print("Finish");
RequestID = 0;
PositionTicket = 0;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
Trong trường hợp xóa thành công, vị thế không thể được chọn bằng PositionSelectByTicket
, vì vậy chúng ta đặt lại RequestID
và PositionTicket
. Sau đó, Expert Advisor trở về trạng thái ban đầu và sẵn sàng thực hiện chu kỳ mua/bán-sửa đổi-đóng tiếp theo.
Chúng ta còn lại việc xem xét gửi yêu cầu để đóng vị thế. Trong chiến lược đơn giản hóa đến mức tối thiểu của chúng ta, điều này xảy ra ngay sau khi sửa đổi thành công các mức bảo vệ.
if(request.action == TRADE_ACTION_DEAL)
{
... // xem ở trên
}
else if(request.action == TRADE_ACTION_SLTP)
{
// gửi yêu cầu TRADE_ACTION_DEAL để đóng (không đồng bộ!)
if(next.close(PositionTicket))
{
Print("OK Close?");
RequestID = next.result.request_id;
}
else
{
PrintFormat("Failed Close %lld", PositionTicket);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Đó là toàn bộ hàm OnTradeTransaction
. Expert Advisor đã sẵn sàng.
Hãy chạy OrderSendTransaction2.mq5
với cài đặt mặc định trên EURUSD. Dưới đây là một nhật ký ví dụ.
Start trade
OK Open?
>>> 1
TRADE_TRANSACTION_ORDER_ADD, #=1299508203(ORDER_TYPE_BUY/ORDER_STATE_STARTED), EURUSD, »
» @ 1.10640, V=0.01
>>> 2
TRADE_TRANSACTION_DEAL_ADD, D=1282135720(DEAL_TYPE_BUY), »
» #=1299508203(ORDER_TYPE_BUY/ORDER_STATE_STARTED), EURUSD, @ 1.10640, V=0.01, P=1299508203
>>> 3
TRADE_TRANSACTION_ORDER_DELETE, #=1299508203(ORDER_TYPE_BUY/ORDER_STATE_FILLED), EURUSD, »
» @ 1.10640, P=1299508203
>>> 4
TRADE_TRANSACTION_HISTORY_ADD, #=1299508203(ORDER_TYPE_BUY/ORDER_STATE_FILLED), EURUSD, »
» @ 1.10640, P=1299508203
>>> 5
TRADE_TRANSACTION_REQUEST
TRADE_ACTION_DEAL, EURUSD, ORDER_TYPE_BUY, V=0.01, ORDER_FILLING_FOK, @ 1.10640, D=10, »
» #=1299508203, M=1234567890
DONE, D=1282135720, #=1299508203, V=0.01, @ 1.1064, Bid=1.1064, Ask=1.1064, Req=7
OK Adjust?
>>> 6
TRADE_TRANSACTION_POSITION, EURUSD, @ 1.10640, SL=1.09640, TP=1.11640, V=0.01, P=1299508203
>>> 7
TRADE_TRANSACTION_REQUEST
TRADE_ACTION_SLTP, EURUSD, ORDER_TYPE_BUY, V=0.01, ORDER_FILLING_FOK, SL=1.09640, TP=1.11640, »
» D=10, P=1299508203, M=1234567890
DONE, Req=8
OK Close?
>>> 8
TRADE_TRANSACTION_ORDER_ADD, #=1299508215(ORDER_TYPE_SELL/ORDER_STATE_STARTED), EURUSD, »
» @ 1.10638, V=0.01, P=1299508203
>>> 9
TRADE_TRANSACTION_ORDER_DELETE, #=1299508215(ORDER_TYPE_SELL/ORDER_STATE_FILLED), EURUSD, »
» @ 1.10638, P=1299508203
>>> 10
TRADE_TRANSACTION_HISTORY_ADD, #=1299508215(ORDER_TYPE_SELL/ORDER_STATE_FILLED), EURUSD, »
» @ 1.10638, P=1299508203
>>> 11
TRADE_TRANSACTION_DEAL_ADD, D=1282135730(DEAL_TYPE_SELL), »
» #=1299508215(ORDER_TYPE_BUY/ORDER_STATE_STARTED), EURUSD, @ 1.10638, »
» SL=1.09640, TP=1.11640, V=0.01, P=1299508203
>>> 12
TRADE_TRANSACTION_REQUEST
TRADE_ACTION_DEAL, EURUSD, ORDER_TYPE_SELL, V=0.01, ORDER_FILLING_FOK, @ 1.10638, D=10, »
» #=1299508215, P=1299508203, M=1234567890
DONE, D=1282135730, #=1299508215, V=0.01, @ 1.10638, Bid=1.10638, Ask=1.10638, Req=9
Finish
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
Logic giao dịch hoạt động như kỳ vọng, và các sự kiện giao dịch đến nghiêm ngặt sau mỗi lệnh tiếp theo được gửi. Nếu bây giờ chúng ta chạy Expert Advisor mới của mình và bộ chặn giao dịch TradeTransactions.mq5
song song, các thông báo nhật ký từ hai Expert Advisor sẽ xuất hiện đồng bộ.
Tuy nhiên, việc làm lại từ phiên bản thẳng đầu tiên OrderSendTransaction1.mq5
sang phiên bản không đồng bộ thứ hai OrderSendTransaction2.mq5
đòi hỏi mã phức tạp hơn đáng kể. Câu hỏi đặt ra: liệu có thể kết hợp nguyên tắc mô tả tuần tự của logic giao dịch (tính minh bạch của mã) và xử lý song song (tốc độ) không?
Về lý thuyết, điều này là có thể, nhưng sẽ đòi hỏi phải dành thời gian ở một số điểm để tạo ra một cơ chế phụ trợ nào đó.