Tổng quan về các hàm lấy thuộc tính biểu tượng
Thông số đầy đủ của mỗi biểu tượng có thể được lấy bằng cách truy vấn các thuộc tính của nó: cho mục đích này, API MQL5 cung cấp ba hàm, cụ thể là SymbolInfoInteger
, SymbolInfoDouble
và SymbolInfoString
, mỗi hàm chịu trách nhiệm cho các thuộc tính của một loại cụ thể. Các thuộc tính được mô tả dưới dạng thành viên của ba kiểu liệt kê: ENUM_SYMBOL_INFO_INTEGER, ENUM_SYMBOL_INFO_DOUBLE và ENUM_SYMBOL_INFO_STRING, tương ứng. Một kỹ thuật tương tự được sử dụng trong các API biểu đồ và đối tượng mà chúng ta đã biết.
Tên của biểu tượng và định danh của thuộc tính được yêu cầu được truyền vào bất kỳ hàm nào trong số các hàm này.
Mỗi hàm được trình bày dưới hai dạng: dạng rút gọn và dạng đầy đủ. Phiên bản rút gọn trực tiếp trả về thuộc tính được yêu cầu, trong khi phiên bản đầy đủ ghi nó vào tham số đầu ra được truyền bằng tham chiếu. Ví dụ, đối với các thuộc tính tương thích với kiểu số nguyên, các hàm có nguyên mẫu như sau:
long SymbolInfoInteger(const string symbol, ENUM_SYMBOL_INFO_INTEGER property)
bool SymbolInfoInteger(const string symbol, ENUM_SYMBOL_INFO_INTEGER property, long &value)
Dạng thứ hai trả về một chỉ báo boolean về thành công (true
) hoặc lỗi (false
). Các lý do có thể khiến hàm trả về false
bao gồm tên biểu tượng không hợp lệ (MARKET_UNKNOWN_SYMBOL
, 4301) hoặc định danh không hợp lệ cho thuộc tính được yêu cầu (MARKET_WRONG_PROPERTY
, 4303). Chi tiết được cung cấp trong _LastError
.
Như trước đây, các thuộc tính trong kiểu liệt kê ENUM_SYMBOL_INFO_INTEGER thuộc nhiều loại tương thích với số nguyên: bool
, int
, long
, color
, datetime
, và các kiểu liệt kê đặc biệt (tất cả sẽ được thảo luận trong các phần riêng biệt).
Đối với các thuộc tính có kiểu số thực, hai dạng sau của hàm SymbolInfoDouble
được định nghĩa.
double SymbolInfoDouble(const string symbol, ENUM_SYMBOL_INFO_DOUBLE property)
bool SymbolInfoDouble(const string symbol, ENUM_SYMBOL_INFO_DOUBLE property, double &value)
Cuối cùng, đối với các thuộc tính chuỗi, các hàm tương tự trông như sau:
string SymbolInfoString(const string symbol, ENUM_SYMBOL_INFO_STRING property)
bool SymbolInfoString(const string symbol, ENUM_SYMBOL_INFO_STRING property, string &value)
Các thuộc tính của nhiều loại khác nhau, thường được sử dụng sau này khi phát triển Expert Advisors, được nhóm lại một cách hợp lý trong phần mô tả của các mục tiếp theo trong chương này.
Dựa trên các hàm trên, chúng ta sẽ tạo một lớp đa năng SymbolMonitor
(tệp SymbolMonitor.mqh
) để lấy bất kỳ thuộc tính nào của biểu tượng. Nó sẽ dựa trên một tập hợp các phương thức get
được nạp chồng cho ba kiểu liệt kê.
class SymbolMonitor
{
public:
const string name;
SymbolMonitor(): name(_Symbol) { }
SymbolMonitor(const string s): name(s) { }
long get(const ENUM_SYMBOL_INFO_INTEGER property) const
{
return SymbolInfoInteger(name, property);
}
double get(const ENUM_SYMBOL_INFO_DOUBLE property) const
{
return SymbolInfoDouble(name, property);
}
string get(const ENUM_SYMBOL_INFO_STRING property) const
{
return SymbolInfoString(name, property);
}
...
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Ba phương thức tương tự khác cho phép loại bỏ kiểu liệt kê trong tham số đầu tiên và chọn nạp chồng cần thiết bởi trình biên dịch nhờ tham số giả thứ hai (loại của nó ở đây luôn khớp với loại kết quả). Chúng ta sẽ sử dụng điều này trong các lớp mẫu sau này.
long get(const int property, const long) const
{
return SymbolInfoInteger(name, (ENUM_SYMBOL_INFO_INTEGER)property);
}
double get(const int property, const double) const
{
return SymbolInfoDouble(name, (ENUM_SYMBOL_INFO_DOUBLE)property);
}
string get(const int property, const string) const
{
return SymbolInfoString(name, (ENUM_SYMBOL_INFO_STRING)property);
}
...
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Do đó, bằng cách tạo một đối tượng với tên biểu tượng mong muốn, bạn có thể truy vấn đồng nhất các thuộc tính của nó thuộc bất kỳ loại nào. Để truy vấn và ghi lại tất cả các thuộc tính của cùng một loại, chúng ta có thể thực hiện như sau.
// dự án (bản nháp)
template<typename E,typename R>
void list2log()
{
E e = (E)0;
int array[];
const int n = EnumToArray(e, array, 0, USHORT_MAX);
for(int i = 0; i < n; ++i)
{
e = (E)array[i];
R r = get(e);
PrintFormat("% 3d %s=%s", i, EnumToString(e), (string)r);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
Tuy nhiên, do thực tế là trong các thuộc tính kiểu long
, các giá trị của các loại khác thực sự được "ẩn", cần được hiển thị theo cách cụ thể (ví dụ, bằng cách gọi EnumToString
cho các kiểu liệt kê, TimeToString
cho ngày giờ, v.v.), nên việc định nghĩa thêm ba phương thức nạp chồng khác để trả về biểu diễn chuỗi của thuộc tính là hợp lý. Hãy gọi chúng là stringify
. Sau đó, trong bản nháp list2log
ở trên, có thể sử dụng stringify
thay vì ép giá trị sang (string)
, và phương thức này sẽ loại bỏ một tham số mẫu.
template<typename E>
void list2log()
{
E e = (E)0;
int array[];
const int n = EnumToArray(e, array, 0, USHORT_MAX);
for(int i = 0; i < n; ++i)
{
e = (E)array[i];
PrintFormat("% 3d %s=%s", i, EnumToString(e), stringify(e));
}
}
2
3
4
5
6
7
8
9
10
11
12
Đối với các loại thực và chuỗi, việc triển khai stringify
khá đơn giản.
string stringify(const ENUM_SYMBOL_INFO_DOUBLE property, const string format = NULL) const
{
if(format == NULL) return (string)SymbolInfoDouble(name, property);
return StringFormat(format, SymbolInfoDouble(name, property));
}
string stringify(const ENUM_SYMBOL_INFO_STRING property) const
{
return SymbolInfoString(name, property);
}
2
3
4
5
6
7
8
9
10
Nhưng đối với ENUM_SYMBOL_INFO_INTEGER, mọi thứ phức tạp hơn một chút. Tất nhiên, khi thuộc tính là kiểu long
hoặc int
, chỉ cần ép nó sang (string)
là đủ. Tất cả các trường hợp khác cần được phân tích riêng lẻ và chuyển đổi trong toán tử switch
.
string stringify(const ENUM_SYMBOL_INFO_INTEGER property) const
{
const long v = SymbolInfoInteger(name, property);
switch(property)
{
...
}
return (string)v;
}
2
3
4
5
6
7
8
9
10
Ví dụ, nếu một thuộc tính có kiểu boolean, sẽ thuận tiện để biểu diễn nó bằng chuỗi "true" hoặc "false" (do đó nó sẽ khác trực quan với các số đơn giản 1 và 0). Nhìn trước, để đưa ra một ví dụ, giả sử trong số các thuộc tính có SYMBOL_EXIST, tương đương với hàm SymbolExist
, tức là trả về chỉ báo boolean về việc ký tự được chỉ định có tồn tại hay không. Để xử lý nó và các thuộc tính logic khác, việc triển khai một phương thức phụ trợ boolean
là hợp lý.
static string boolean(const long v)
{
return v ? "true" : "false";
}
string stringify(const ENUM_SYMBOL_INFO_INTEGER property) const
{
const long v = SymbolInfoInteger(name, property);
switch(property)
{
case SYMBOL_EXIST:
return boolean(v);
...
}
return (string)v;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Đối với các thuộc tính là kiểu liệt kê, giải pháp phù hợp nhất sẽ là một phương thức mẫu sử dụng hàm EnumToString
.
template<typename E>
static string enumstr(const long v)
{
return EnumToString((E)v);
}
2
3
4
5
Ví dụ, thuộc tính SYMBOL_SWAP_ROLLOVER3DAYS xác định ngày nào trong tuần áp dụng swap gấp ba cho các vị thế mở của một biểu tượng, và thuộc tính này có kiểu ENUM_DAY_OF_WEEK
. Vì vậy, để xử lý nó, chúng ta có thể viết như sau trong switch
:
case SYMBOL_SWAP_ROLLOVER3DAYS:
return enumstr<ENUM_DAY_OF_WEEK>(v);
2
Một trường hợp đặc biệt được thể hiện bởi các thuộc tính có giá trị là tổ hợp của các cờ bit. Cụ thể, đối với mỗi biểu tượng, nhà môi giới đặt quyền cho các lệnh thuộc loại cụ thể, chẳng hạn như thị trường, giới hạn, dừng lỗ, chốt lời, và các loại khác (chúng ta sẽ xem xét các quyền này riêng). Mỗi loại lệnh được biểu thị bằng một hằng số với một bit được bật, vì vậy sự chồng chất của chúng (kết hợp bởi toán tử OR bitwise '|') được lưu trữ trong thuộc tính SYMBOL_ORDER_MODE, và khi không có hạn chế, tất cả các bit được bật cùng lúc. Đối với các thuộc tính như vậy, chúng ta sẽ định nghĩa các kiểu liệt kê riêng trong tệp tiêu đề của mình, ví dụ:
enum SYMBOL_ORDER
{
_SYMBOL_ORDER_MARKET = 1,
_SYMBOL_ORDER_LIMIT = 2,
_SYMBOL_ORDER_STOP = 4,
_SYMBOL_ORDER_STOP_LIMIT = 8,
_SYMBOL_ORDER_SL = 16,
_SYMBOL_ORDER_TP = 32,
_SYMBOL_ORDER_CLOSEBY = 64,
};
2
3
4
5
6
7
8
9
10
Ở đây, cho mỗi hằng số tích hợp, như SYMBOL_ORDER_MARKET, một phần tử tương ứng được khai báo, với định danh giống như hằng số nhưng được thêm dấu gạch dưới ở đầu để tránh xung đột đặt tên.
Để biểu diễn tổ hợp các cờ từ các kiểu liệt kê này dưới dạng chuỗi, chúng ta triển khai một phương thức mẫu khác, maskstr
.
template<typename E>
static string maskstr(const long v)
{
string text = "";
for(int i = 0; ; ++i)
{
ResetLastError();
const string s = EnumToString((E)(1 << i));
if(_LastError != 0)
{
break;
}
if((v & (1 << i)) != 0)
{
text += s + " ";
}
}
return text;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Ý nghĩa của nó giống như enumstr
, nhưng hàm EnumToString
được gọi cho mỗi bit được bật trong giá trị thuộc tính, sau đó các chuỗi kết quả được "dán" lại.
Bây giờ, việc xử lý SYMBOL_ORDER_MODE trong câu lệnh switch
có thể thực hiện tương tự:
case SYMBOL_ORDER_MODE:
return maskstr<SYMBOL_ORDER>(v);
2
Đây là mã đầy đủ của phương thức stringify
cho ENUM_SYMBOL_INFO_INTEGER. Với tất cả các thuộc tính và kiểu liệt kê, chúng ta sẽ dần làm quen trong các phần tiếp theo.
string stringify(const ENUM_SYMBOL_INFO_INTEGER property) const
{
const long v = SymbolInfoInteger(name, property);
switch(property)
{
case SYMBOL_SELECT:
case SYMBOL_SPREAD_FLOAT:
case SYMBOL_VISIBLE:
case SYMBOL_CUSTOM:
case SYMBOL_MARGIN_HEDGED_USE_LEG:
case SYMBOL_EXIST:
return boolean(v);
case SYMBOL_TIME:
return TimeToString(v, TIME_DATE|TIME_SECONDS);
case SYMBOL_TRADE_CALC_MODE:
return enumstr<ENUM_SYMBOL_CALC_MODE>(v);
case SYMBOL_TRADE_MODE:
return enumstr<ENUM_SYMBOL_TRADE_MODE>(v);
case SYMBOL_TRADE_EXEMODE:
return enumstr<ENUM_SYMBOL_TRADE_EXECUTION>(v);
case SYMBOL_SWAP_MODE:
return enumstr<ENUM_SYMBOL_SWAP_MODE>(v);
case SYMBOL_SWAP_ROLLOVER3DAYS:
return enumstr<ENUM_DAY_OF_WEEK>(v);
case SYMBOL_EXPIRATION_MODE:
return maskstr<SYMBOL_EXPIRATION>(v);
case SYMBOL_FILLING_MODE:
return maskstr<SYMBOL_FILLING>(v);
case SYMBOL_START_TIME:
case SYMBOL_EXPIRATION_TIME:
return TimeToString(v);
case SYMBOL_ORDER_MODE:
return maskstr<SYMBOL_ORDER>(v);
case SYMBOL_OPTION_RIGHT:
return enumstr<ENUM_SYMBOL_OPTION_RIGHT>(v);
case SYMBOL_OPTION_MODE:
return enumstr<ENUM_SYMBOL_OPTION_MODE>(v);
case SYMBOL_CHART_MODE:
return enumstr<ENUM_SYMBOL_CHART_MODE>(v);
case SYMBOL_ORDER_GTC_MODE:
return enumstr<ENUM_SYMBOL_ORDER_GTC_MODE>(v);
case SYMBOL_SECTOR:
return enumstr<ENUM_SYMBOL_SECTOR>(v);
case SYMBOL_INDUSTRY:
return enumstr<ENUM_SYMBOL_INDUSTRY>(v);
case SYMBOL_BACKGROUND_COLOR: // Bytes: Transparency Blue Green Red
return StringFormat("TBGR(0x%08X)", v);
}
return (string)v;
}
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
Để kiểm tra lớp SymbolMonitor
, chúng ta đã tạo một kịch bản đơn giản SymbolMonitor.mq5
. Nó ghi lại tất cả các thuộc tính của biểu tượng trên biểu đồ đang hoạt động.
#include <MQL5Book/SymbolMonitor.mqh>
void OnStart()
{
SymbolMonitor m;
m.list2log<ENUM_SYMBOL_INFO_INTEGER>();
m.list2log<ENUM_SYMBOL_INFO_DOUBLE>();
m.list2log<ENUM_SYMBOL_INFO_STRING>();
}
2
3
4
5
6
7
8
9
Ví dụ, nếu chúng ta chạy kịch bản trên biểu đồ EURUSD, chúng ta có thể nhận được các bản ghi sau (được đưa ra dưới dạng rút gọn).
ENUM_SYMBOL_INFO_INTEGER Count=36
0 SYMBOL_SELECT=true
...
4 SYMBOL_TIME=2022.01.12 10:52:22
5 SYMBOL_DIGITS=5
6 SYMBOL_SPREAD=0
7 SYMBOL_TICKS_BOOKDEPTH=10
8 SYMBOL_TRADE_CALC_MODE=SYMBOL_CALC_MODE_FOREX
9 SYMBOL_TRADE_MODE=SYMBOL_TRADE_MODE_FULL
10 SYMBOL_TRADE_STOPS_LEVEL=0
11 SYMBOL_TRADE_FREEZE_LEVEL=0
12 SYMBOL_TRADE_EXEMODE=SYMBOL_TRADE_EXECUTION_INSTANT
13 SYMBOL_SWAP_MODE=SYMBOL_SWAP_MODE_POINTS
14 SYMBOL_SWAP_ROLLOVER3DAYS=WEDNESDAY
15 SYMBOL_SPREAD_FLOAT=true
16 SYMBOL_EXPIRATION_MODE=_SYMBOL_EXPIRATION_GTC _SYMBOL_EXPIRATION_DAY »
_SYMBOL_EXPIRATION_SPECIFIED _SYMBOL_EXPIRATION_SPECIFIED_DAY
17 SYMBOL_FILLING_MODE=_SYMBOL_FILLING_FOK
...
23 SYMBOL_ORDER_MODE=_SYMBOL_ORDER_MARKET _SYMBOL_ORDER_LIMIT _SYMBOL_ORDER_STOP »
_SYMBOL_ORDER_STOP_LIMIT _SYMBOL_ORDER_SL _SYMBOL_ORDER_TP _SYMBOL_ORDER_CLOSEBY
...
26 SYMBOL_VISIBLE=true
27 SYMBOL_CUSTOM=false
28 SYMBOL_BACKGROUND_COLOR=TBGR(0xFF000000)
29 SYMBOL_CHART_MODE=SYMBOL_CHART_MODE_BID
30 SYMBOL_ORDER_GTC_MODE=SYMBOL_ORDERS_GTC
31 SYMBOL_MARGIN_HEDGED_USE_LEG=false
32 SYMBOL_EXIST=true
33 SYMBOL_TIME_MSC=1641984742149
34 SYMBOL_SECTOR=SECTOR_CURRENCY
35 SYMBOL_INDUSTRY=INDUSTRY_UNDEFINED
ENUM_SYMBOL_INFO_DOUBLE Count=57
0 SYMBOL_BID=1.13681
1 SYMBOL_BIDHIGH=1.13781
2 SYMBOL_BIDLOW=1.13552
3 SYMBOL_ASK=1.13681
4 SYMBOL_ASKHIGH=1.13781
5 SYMBOL_ASKLOW=1.13552
...
12 SYMBOL_POINT=1e-05
13 SYMBOL_TRADE_TICK_VALUE=1.0
14 SYMBOL_TRADE_TICK_SIZE=1e-05
15 SYMBOL_TRADE_CONTRACT_SIZE=100000.0
16 SYMBOL_VOLUME_MIN=0.01
17 SYMBOL_VOLUME_MAX=500.0
18 SYMBOL_VOLUME_STEP=0.01
19 SYMBOL_SWAP_LONG=-0.7
20 SYMBOL_SWAP_SHORT=-1.0
21 SYMBOL_MARGIN_INITIAL=0.0
22 SYMBOL_MARGIN_MAINTENANCE=0.0
...
28 SYMBOL_TRADE_TICK_VALUE_PROFIT=1.0
29 SYMBOL_TRADE_TICK_VALUE_LOSS=1.0
...
43 SYMBOL_MARGIN_HEDGED=100000.0
...
47 SYMBOL_PRICE_CHANGE=0.0132
ENUM_SYMBOL_INFO_STRING Count=15
0 SYMBOL_BANK=
1 SYMBOL_DESCRIPTION=Euro vs US Dollar
2 SYMBOL_PATH=Forex\EURUSD
3 SYMBOL_CURRENCY_BASE=EUR
4 SYMBOL_CURRENCY_PROFIT=USD
5 SYMBOL_CURRENCY_MARGIN=EUR
...
13 SYMBOL_SECTOR_NAME=Currency
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
Cụ thể, bạn có thể thấy rằng giá biểu tượng được truyền với 5 chữ số (SYMBOL_DIGITS
), biểu tượng thực sự tồn tại (SYMBOL_EXIST
), kích thước hợp đồng là 100000.0 (SYMBOL_TRADE_CONTRACT_SIZE
), v.v. Tất cả thông tin đều tương ứng với thông số kỹ thuật.