Đặt lệnh chờ
Trong Các loại lệnh, chúng ta đã xem xét lý thuyết về tất cả các tùy chọn để đặt lệnh chờ được nền tảng hỗ trợ. Từ góc độ thực tế, các lệnh được tạo bằng hàm OrderSend
/OrderSendAsync
, trong đó cấu trúc yêu cầu MqlTradeRequest
được điền trước theo các quy tắc đặc biệt. Cụ thể, trường action
phải chứa giá trị TRADE_ACTION_PENDING
từ bảng liệt kê ENUM_TRADE_REQUEST_ACTIONS. Với điều này, các trường sau là bắt buộc:
action
symbol
volume
price
type
(giá trị mặc định 0 tương ứng vớiORDER_TYPE_BUY
)type_filling
(mặc định 0 tương ứng vớiORDER_FILLING_FOK
)type_time
(giá trị mặc định 0 tương ứng vớiORDER_TIME_GTC
)expiration
(mặc định 0, không sử dụng choORDER_TIME_GTC
)
Nếu các giá trị mặc định bằng 0 phù hợp với nhiệm vụ, một số trường trong bốn trường cuối có thể được bỏ qua.
Trường stoplimit
chỉ bắt buộc đối với các lệnh loại ORDER_TYPE_BUY_STOP_LIMIT
và ORDER_TYPE_SELL_STOP_LIMIT
.
Các trường sau là tùy chọn:
sl
tp
magic
comment
Giá trị bằng 0 trong sl
và tp
cho biết không có mức bảo vệ.
Hãy thêm các phương thức để kiểm tra giá trị và điền các trường vào cấu trúc của chúng ta trong tệp MqlTradeSync.mqh
. Nguyên tắc hình thành tất cả các loại lệnh là giống nhau, vì vậy hãy xem xét một vài trường hợp đặc biệt khi đặt lệnh mua giới hạn và bán giới hạn. Các loại còn lại chỉ khác nhau ở giá trị của trường type
. Các phương thức công khai với đầy đủ các trường bắt buộc, cũng như các mức bảo vệ, được đặt tên theo loại: buyLimit
và sellLimit
.
ulong buyLimit(const string name, const double lot, const double p,
const double stop = 0, const double take = 0,
ENUM_ORDER_TYPE_TIME duration = ORDER_TIME_GTC, datetime until = 0)
{
type = ORDER_TYPE_BUY_LIMIT;
return _pending(name, lot, p, stop, take, duration, until);
}
ulong sellLimit(const string name, const double lot, const double p,
const double stop = 0, const double take = 0,
ENUM_ORDER_TYPE_TIME duration = ORDER_TIME_GTC, datetime until = 0)
{
type = ORDER_TYPE_SELL_LIMIT;
return _pending(name, lot, p, stop, take, duration, until);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Vì cấu trúc chứa trường symbol
được khởi tạo tùy chọn trong hàm tạo, có các phương thức tương tự không có tham số name
: chúng gọi các phương thức trên bằng cách truyền symbol
làm tham số đầu tiên. Do đó, để tạo một lệnh với nỗ lực tối thiểu, hãy viết như sau:
MqlTradeRequestSync request; // mặc định sử dụng biểu tượng biểu đồ hiện tại
request.buyLimit(volume, price);
2
Phần mã chung để kiểm tra các giá trị đã truyền, chuẩn hóa chúng, lưu chúng vào các trường cấu trúc và tạo lệnh chờ đã được chuyển sang phương thức trợ giúp _pending
. Nó trả về vé lệnh nếu thành công hoặc 0 nếu thất bại.
ulong _pending(const string name, const double lot, const double p,
const double stop = 0, const double take = 0,
ENUM_ORDER_TYPE_TIME duration = ORDER_TIME_GTC, datetime until = 0,
const double origin = 0)
{
action = TRADE_ACTION_PENDING;
if(!setSymbol(name)) return 0;
if(!setVolumePrices(lot, p, stop, take, origin)) return 0;
if(!setExpiration(duration, until)) return 0;
if((SymbolInfoInteger(name, SYMBOL_ORDER_MODE) & (1 << (type / 2))) == 0)
{
Print(StringFormat("pending orders %s not allowed for %s",
EnumToString(type), name));
return 0;
}
ZeroMemory(result);
if(OrderSend(this, result)) return result.order;
return 0;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Chúng ta đã biết cách điền trường action
và cách gọi các phương thức setSymbol
và setVolumePrices
từ các hoạt động giao dịch trước đó.
Toán tử if
nhiều dòng đảm bảo rằng hoạt động đang được chuẩn bị có trong số các hoạt động biểu tượng được phép, được chỉ định trong thuộc tính SYMBOL_ORDER_MODE. Phép chia số nguyên của type
chia đôi và dịch chuyển giá trị kết quả bằng 1, đặt bit đúng trong mặt nạ của các loại lệnh được phép. Điều này là do sự kết hợp của các hằng số trong bảng liệt kê ENUM_ORDER_TYPE
và thuộc tính SYMBOL_ORDER_MODE
. Ví dụ, ORDER_TYPE_BUY_STOP
và ORDER_TYPE_SELL_STOP
có giá trị 4 và 5, khi chia cho 2 đều cho ra 2 (bỏ phần thập phân). Phép toán 1 << 2
cho kết quả 4 bằng với SYMBOL_ORDER_STOP
.
Một đặc điểm đặc biệt của lệnh chờ là xử lý ngày hết hạn. Phương thức setExpiration
xử lý việc này. Trong phương thức này, cần đảm bảo rằng chế độ hết hạn được chỉ định ENUM_ORDER_TYPE_TIME
của duration
được phép cho biểu tượng và ngày giờ trong until
được điền chính xác.
bool setExpiration(ENUM_ORDER_TYPE_TIME duration = ORDER_TIME_GTC, datetime until = 0)
{
const int modes = (int)SymbolInfoInteger(symbol, SYMBOL_EXPIRATION_MODE);
if(((1 << duration) & modes) != 0)
{
type_time = duration;
if((duration == ORDER_TIME_SPECIFIED || duration == ORDER_TIME_SPECIFIED_DAY)
&& until == 0)
{
Print(StringFormat("datetime is 0, but it's required for order expiration mode %s",
EnumToString(duration)));
return false;
}
if(until > 0 && until <= TimeTradeServer())
{
Print(StringFormat("expiration datetime %s is in past, server time is %s",
TimeToString(until), TimeToString(TimeTradeServer())));
return false;
}
expiration = until;
}
else
{
Print(StringFormat("order expiration mode %s is not allowed for %s",
EnumToString(duration), symbol));
return false;
}
return true;
}
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
Mặt nạ bit của các chế độ được phép có sẵn trong thuộc tính SYMBOL_EXPIRATION_MODE. Sự kết hợp của các bit trong mặt nạ và các hằng số ENUM_ORDER_TYPE_TIME
là như vậy mà chúng ta chỉ cần đánh giá biểu thức 1 << duration
và áp dụng nó lên mặt nạ: giá trị khác không cho biết sự hiện diện của chế độ.
Đối với các chế độ ORDER_TIME_SPECIFIED
và ORDER_TIME_SPECIFIED_DAY
, trường expiration
với giá trị datetime
cụ thể không được để trống. Ngoài ra, ngày và giờ được chỉ định không được nằm trong quá khứ.
Vì phương thức _pending
được trình bày trước đó gửi yêu cầu đến máy chủ bằng OrderSend
ở cuối, chương trình của chúng ta phải đảm bảo rằng lệnh với vé nhận được thực sự đã được tạo (điều này đặc biệt quan trọng đối với lệnh giới hạn có thể được xuất ra hệ thống giao dịch bên ngoài). Do đó, trong phương thức completed
, được sử dụng để kiểm soát "chặn" kết quả, chúng ta sẽ thêm một nhánh cho hoạt động TRADE_ACTION_PENDING
.
bool completed()
{
// mã xử lý cũ
// TRADE_ACTION_DEAL
// TRADE_ACTION_SLTP
// TRADE_ACTION_CLOSE_BY
...
else if(action == TRADE_ACTION_PENDING)
{
return result.order != 0 && OrderSelect(result.order);
}
return false;
}
2
3
4
5
6
7
8
9
10
11
12
13
Ví dụ, hệ số -0.5 cho ORDER_TYPE_BUY_LIMIT
có nghĩa là lệnh sẽ được đặt dưới giá hiện tại một nửa phạm vi ngày (phản hồi trong phạm vi), và hệ số +1.0 cho ORDER_TYPE_BUY_STOP
có nghĩa là lệnh sẽ ở biên trên của phạm vi (phá vỡ).
Phạm vi ngày được tính như sau:
const double range = iHigh(symbol, PERIOD_D1, 1) - iLow(symbol, PERIOD_D1, 1);
Print("Autodetected daily range:", (float)range);
...
2
3
Chúng ta tìm giá trị khối lượng và điểm sẽ cần thiết dưới đây:
const double volume = lot == 0 ? SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN) : lot;
const double point = SymbolInfoDouble(symbol, SYMBOL_POINT);
2
Mức giá để đặt lệnh được tính trong biến price
dựa trên các hệ số đã cho từ tổng phạm vi:
const double price = TU::GetCurrentPrice(type, symbol) + range * coefficients[type];
Trường stoplimit
phải được điền chỉ cho các lệnh *_STOP_LIMIT
. Các giá trị cho nó được lưu trong biến origin
:
const bool stopLimit =
type == ORDER_TYPE_BUY_STOP_LIMIT ||
type == ORDER_TYPE_SELL_STOP_LIMIT;
const double origin = stopLimit ? TU::GetCurrentPrice(type, symbol) : 0;
2
3
4
Khi hai loại lệnh này được kích hoạt, một lệnh chờ mới sẽ được đặt ở mức giá hiện tại. Thực tế, trong kịch bản này, giá di chuyển từ giá trị hiện tại đến mức price
, nơi lệnh được kích hoạt, và do đó giá "hiện tại trước đây" trở thành mức phản hồi chính xác được chỉ định bởi lệnh giới hạn.
Các mức bảo vệ được xác định bằng đối tượng TU::TradeDirection
. Đối với lệnh stop-limit, chúng ta tính toán từ origin
:
TU::TradeDirection dir(type);
const double stop = sltp == 0 ? 0 :
dir.negative(stopLimit ? origin : price, sltp * point);
const double take = sltp == 0 ? 0 :
dir.positive(stopLimit ? origin : price, sltp * point);
2
3
4
5
Tiếp theo, cấu trúc được mô tả và các trường tùy chọn được điền:
MqlTradeRequestSync request(symbol);
request.magic = magic;
request.comment = comment;
// request.type_filling = SYMBOL_FILLING_FOK;
2
3
4
5
Ở đây bạn có thể chọn chế độ điền. Theo mặc định, MqlTradeRequestSync
tự động chọn chế độ đầu tiên trong số các chế độ được phép, ENUM_ORDER_TYPE_FILLING.
Tùy thuộc vào loại lệnh do người dùng chọn, chúng ta gọi phương thức giao dịch này hoặc phương thức khác:
ResetLastError();
// điền và kiểm tra các trường bắt buộc, gửi yêu cầu
ulong order = 0;
switch(type)
{
case ORDER_TYPE_BUY_STOP:
order = request.buyStop(volume, price, stop, take, expiration, until);
break;
case ORDER_TYPE_SELL_STOP:
order = request.sellStop(volume, price, stop, take, expiration, until);
break;
case ORDER_TYPE_BUY_LIMIT:
order = request.buyLimit(volume, price, stop, take, expiration, until);
break;
case ORDER_TYPE_SELL_LIMIT:
order = request.sellLimit(volume, price, stop, take, expiration, until);
break;
case ORDER_TYPE_BUY_STOP_LIMIT:
order = request.buyStopLimit(volume, price, origin, stop, take, expiration, until);
break;
case ORDER_TYPE_SELL_STOP_LIMIT:
order = request.sellStopLimit(volume, price, origin, stop, take, expiration, until);
break;
}
...
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Nếu vé được nhận, chúng ta đợi nó xuất hiện trong môi trường giao dịch của terminal:
if(order != 0)
{
Print("OK order sent: #=", order);
if(request.completed()) // mong đợi kết quả (xác nhận lệnh)
{
Print("OK order placed");
}
}
Print(TU::StringOf(request));
Print(TU::StringOf(request.result));
return order;
2
3
4
5
6
7
8
9
10
11
Hãy chạy Expert Advisor trên biểu đồ EURUSD với cài đặt mặc định và thêm khoảng cách đến các mức bảo vệ là 1000 điểm. Chúng ta sẽ thấy các mục sau trong nhật ký (giả sử cài đặt mặc định khớp với quyền cho EURUSD trong tài khoản của bạn):
Autodetected daily range: 0.01413
OK order sent: #=1282106395
OK order placed
TRADE_ACTION_PENDING, EURUSD, ORDER_TYPE_BUY_STOP, V=0.01, ORDER_FILLING_FOK, »
» @ 1.11248, SL=1.10248, TP=1.12248, ORDER_TIME_GTC, M=1234567890
DONE, #=1282106395, V=0.01, Request executed, Req=91
Alert: Pending order placed - remove it manually, please
2
3
4
5
6
7
Đây là giao diện trên biểu đồ:
Lệnh chờ ORDER_TYPE_BUY_STOP
Hãy xóa lệnh thủ công và thay đổi loại lệnh thành ORDER_TYPE_BUY_STOP_LIMIT
. Kết quả là một hình ảnh phức tạp hơn:
Lệnh chờ ORDER_TYPE_BUY_STOP_LIMIT
Mức giá nơi cặp đường nét đứt trên cùng nằm là giá kích hoạt lệnh, kết quả là một lệnh ORDER_TYPE_BUY_LIMIT
sẽ được đặt ở mức giá hiện tại, với các giá trị Stop Loss
và Take Profit
được đánh dấu bằng đường đỏ. Mức Take Profit
của lệnh ORDER_TYPE_BUY_LIMIT
trong tương lai gần như trùng với mức kích hoạt của lệnh sơ bộ mới tạo ORDER_TYPE_BUY_STOP_LIMIT
.
Là một ví dụ bổ sung để tự học, Expert Advisor AllPendingsOrderSend.mq5
được bao gồm trong sách; Expert Advisor này đặt 6 lệnh chờ cùng lúc: một của mỗi loại.
Lệnh chờ của tất cả các loại
Kết quả của việc chạy nó với cài đặt mặc định, bạn có thể nhận được các mục nhật ký như sau:
Autodetected daily range: 0.01413
OK order placed: #=1282032135
TRADE_ACTION_PENDING, EURUSD, ORDER_TYPE_BUY_LIMIT, V=0.01, ORDER_FILLING_FOK, »
» @ 1.08824, ORDER_TIME_GTC, M=1234567890
DONE, #=1282032135, V=0.01, Request executed, Req=73
OK order placed: #=1282032136
TRADE_ACTION_PENDING, EURUSD, ORDER_TYPE_SELL_LIMIT, V=0.01, ORDER_FILLING_FOK, »
» @ 1.10238, ORDER_TIME_GTC, M=1234567890
DONE, #=1282032136, V=0.01, Request executed, Req=74
OK order placed: #=1282032138
TRADE_ACTION_PENDING, EURUSD, ORDER_TYPE_BUY_STOP, V=0.01, ORDER_FILLING_FOK, »
» @ 1.10944, ORDER_TIME_GTC, M=1234567890
DONE, #=1282032138, V=0.01, Request executed, Req=75
OK order placed: #=1282032141
TRADE_ACTION_PENDING, EURUSD, ORDER_TYPE_SELL_STOP, V=0.01, ORDER_FILLING_FOK, »
» @ 1.08118, ORDER_TIME_GTC, M=1234567890
DONE, #=1282032141, V=0.01, Request executed, Req=76
OK order placed: #=1282032142
TRADE_ACTION_PENDING, EURUSD, ORDER_TYPE_BUY_STOP_LIMIT, V=0.01, ORDER_FILLING_FOK, »
» @ 1.10520, X=1.09531, ORDER_TIME_GTC, M=1234567890
DONE, #=1282032142, V=0.01, Request executed, Req=77
OK order placed: #=1282032144
TRADE_ACTION_PENDING, EURUSD, ORDER_TYPE_SELL_STOP_LIMIT, V=0.01, ORDER_FILLING_FOK, »
» @ 1.08542, X=1.09531, ORDER_TIME_GTC, M=1234567890
DONE, #=1282032144, V=0.01, Request executed, Req=78
Alert: 6 pending orders placed - remove them manually, please
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