Độ chính xác biểu diễn giá và các bước thay đổi
Trước đây, chúng ta đã gặp hai thuộc tính liên quan của ký hiệu đang hoạt động trên biểu đồ: bước thay đổi giá tối thiểu (Point
) và độ chính xác biểu diễn giá được biểu thị bằng số chữ số thập phân (Digits
). Chúng cũng có sẵn trong Biến định nghĩa sẵn. Để lấy các thuộc tính tương tự của một ký hiệu bất kỳ, bạn nên truy vấn các thuộc tính SYMBOL_POINT
và SYMBOL_DIGITS
, tương ứng. Thuộc tính SYMBOL_POINT
liên quan chặt chẽ đến thay đổi giá tối thiểu (được chương trình MQL biết đến dưới dạng thuộc tính SYMBOL_TRADE_TICK_SIZE
) và giá trị của nó (SYMBOL_TRADE_TICK_VALUE
), thường tính bằng tiền tệ của tài khoản giao dịch (nhưng một số ký hiệu có thể được cấu hình để sử dụng tiền tệ cơ sở; bạn có thể liên hệ với nhà môi giới để biết chi tiết nếu cần). Bảng dưới đây hiển thị toàn bộ nhóm các thuộc tính này.
Định danh | Mô tả |
---|---|
SYMBOL_DIGITS | Số chữ số thập phân |
SYMBOL_POINT | Giá trị của một điểm trong tiền tệ báo giá |
SYMBOL_TRADE_TICK_VALUE | Giá trị SYMBOL_TRADE_TICK_VALUE_PROFIT |
SYMBOL_TRADE_TICK_VALUE_PROFIT | Giá trị tick hiện tại cho vị thế có lợi nhuận |
SYMBOL_TRADE_TICK_VALUE_LOSS | Giá trị tick hiện tại cho vị thế thua lỗ |
SYMBOL_TRADE_TICK_SIZE | Thay đổi giá tối thiểu trong tiền tệ báo giá |
Tất cả các thuộc tính trừ SYMBOL_DIGITS
đều là số thực và được truy vấn bằng hàm SymbolInfoDouble
. Thuộc tính SYMBOL_DIGITS
có sẵn qua SymbolInfoInteger
. Để kiểm tra việc làm việc với các thuộc tính này, chúng ta sẽ sử dụng các lớp có sẵn SymbolFilter
(liên kết) và SymbolMonitor
(liên kết), chúng sẽ tự động gọi hàm mong muốn cho bất kỳ thuộc tính nào.
Chúng ta cũng sẽ cải thiện lớp SymbolFilter
bằng cách thêm một overload mới của phương thức select
, phương thức này có thể điền không chỉ mảng với tên của các ký hiệu phù hợp mà còn một mảng khác với các giá trị của thuộc tính cụ thể của chúng.
Trong trường hợp tổng quát hơn, chúng ta có thể quan tâm đến nhiều thuộc tính cho mỗi ký hiệu cùng một lúc, vì vậy nên sử dụng không phải một trong các kiểu dữ liệu tích hợp cho mảng đầu ra mà là một kiểu tổng hợp đặc biệt với các trường khác nhau.
Trong lập trình, các kiểu như vậy được gọi là tuple và tương đương với cấu trúc trong MQL5.
template<typename T1, typename T2, typename T3> // chúng ta có thể mô tả tối đa 64 trường
struct Tuple3 // MQL5 cho phép 64 tham số mẫu
{
T1 _1;
T2 _2;
T3 _3;
};
2
3
4
5
6
7
Tuy nhiên, các cấu trúc yêu cầu mô tả trước với tất cả các trường, trong khi chúng ta không biết trước số lượng và danh sách các thuộc tính ký hiệu được yêu cầu. Do đó, để đơn giản hóa mã, chúng ta sẽ biểu diễn tuple của mình dưới dạng vector trong chiều thứ hai của một mảng động nhận kết quả truy vấn.
T array[][S];
Là kiểu dữ liệu T
, chúng ta có thể sử dụng bất kỳ kiểu tích hợp nào và các liệt kê được dùng cho thuộc tính. Kích thước S
phải khớp với số lượng thuộc tính được yêu cầu.
Thành thật mà nói, sự đơn giản hóa này giới hạn chúng ta trong một truy vấn đối với các giá trị cùng kiểu, tức là chỉ số nguyên, chỉ số thực, hoặc chỉ chuỗi. Tuy nhiên, các điều kiện lọc có thể bao gồm bất kỳ thuộc tính nào. Chúng ta sẽ triển khai cách tiếp cận với tuple sau này, sử dụng ví dụ về bộ lọc của các thực thể giao dịch khác: lệnh, giao dịch, và vị thế.
Vì vậy, phiên bản mới của phương thức SymbolFilter::select
nhận vào một tham chiếu đến mảng property
với các định danh thuộc tính để đọc từ các ký hiệu đã lọc. Tên của các ký hiệu và giá trị của các thuộc tính này sẽ được ghi vào các mảng đầu ra symbols
và data
.
template<typename E, typename V>
bool select(const bool watch, const E &property[], string &symbols[],
V &data[][], const bool sort = false) const
{
// kích thước của mảng các thuộc tính được yêu cầu phải khớp với tuple đầu ra
const int q = ArrayRange(data, 1);
if(ArraySize(property) != q) return false;
const int n = SymbolsTotal(watch);
// lặp qua các ký hiệu
for(int i = 0; i < n; ++i)
{
const string s = SymbolName(i, watch);
// truy cập vào thuộc tính ký hiệu được cung cấp bởi monitor
SymbolMonitor m(s);
// kiểm tra tất cả điều kiện lọc
if(match(m, longs)
&& match(m, doubles)
&& match(m, strings))
{
// thuộc tính của ký hiệu phù hợp được ghi vào mảng
const int k = EXPAND(data);
for(int j = 0; j < q; ++j)
{
data[k][j] = m.get(property[j]);
}
PUSH(symbols, s);
}
}
if(sort)
{
...
}
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
30
31
32
33
34
35
36
Ngoài ra, phương thức mới có thể sắp xếp mảng đầu ra theo chiều đầu tiên (thuộc tính được yêu cầu đầu tiên): chức năng này để lại cho việc tự học bằng mã nguồn. Để bật sắp xếp, đặt tham số sort
thành true
. Các mảng với tên ký hiệu và dữ liệu được sắp xếp nhất quán.
Để tránh tuple trong mã gọi khi chỉ cần yêu cầu một thuộc tính từ các ký hiệu đã lọc, tùy chọn select
sau được triển khai trong SymbolFilter
: bên trong nó, chúng ta định nghĩa các mảng trung gian của thuộc tính (properties
) và giá trị (tuples
) với kích thước 1 trong chiều thứ hai, được dùng để gọi phiên bản đầy đủ của select
ở trên.
template<typename E, typename V>
bool select(const bool watch, const E property, string &symbols[], V &data[],
const bool sort = false) const
{
E properties[1] = {property};
V tuples[][1];
const bool result = select(watch, properties, symbols, tuples, sort);
ArrayCopy(data, tuples);
return result;
}
2
3
4
5
6
7
8
9
10
11
Sử dụng bộ lọc nâng cao, hãy thử xây dựng danh sách các ký hiệu được sắp xếp theo giá trị tick SYMBOL_TRADE_TICK_VALUE
(xem tệp SymbolFilterTickValue.mq5
). Giả sử tiền tệ ký quỹ là USD, chúng ta nên nhận được giá trị bằng 1.0 cho các công cụ Forex được báo giá bằng USD (loại XXXUSD). Đối với các tài sản khác, chúng ta sẽ thấy các giá trị không tầm thường.
#include <MQL5Book/SymbolFilter.mqh>
input bool MarketWatchOnly = true;
void OnStart()
{
SymbolFilter f; // đối tượng bộ lọc
string symbols[]; // mảng với tên ký hiệu
double tickValues[]; // mảng cho kết quả
// áp dụng bộ lọc không có điều kiện, điền và sắp xếp mảng
f.select(MarketWatchOnly, SYMBOL_TRADE_TICK_VALUE, symbols, tickValues, true);
PrintFormat("===== Giá trị tick của các ký hiệu (%d) =====", ArraySize(tickValues));
ArrayPrint(symbols);
ArrayPrint(tickValues, 5);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Đây là kết quả của việc chạy kịch bản.
===== Giá trị tick của các ký hiệu (13) =====
"BTCUSD" "USDRUB" "XAUUSD" "USDSEK" "USDCNH" "USDCAD" "USDJPY" "NZDUSD" "AUDUSD" "EURUSD" "GBPUSD" "USDCHF" "SP500m"
0.00100 0.01309 0.10000 0.10955 0.15744 0.80163 0.87319 1.00000 1.00000 1.00000 1.00000 1.09212 10.00000
2
3