Mở và đóng biểu đồ
Một chương trình MQL không chỉ có thể phân tích danh sách các biểu đồ mà còn sửa đổi nó: mở các biểu đồ mới hoặc đóng các biểu đồ hiện có. Hai hàm được phân bổ cho các mục đích này: ChartOpen
và ChartClose
.
long ChartOpen(const string symbol, ENUM_TIMEFRAMES timeframe)
Hàm mở một biểu đồ mới với biểu tượng và khung thời gian được chỉ định và trả về ID của biểu đồ mới. Nếu xảy ra lỗi trong quá trình thực thi, kết quả là 0, và mã lỗi có thể được đọc trong biến tích hợp sẵn _LastError
.
Nếu tham số symbol
là NULL, nó có nghĩa là biểu tượng của biểu đồ hiện tại (nơi chương trình MQL đang được thực thi). Giá trị 0 trong tham số timeframe
tương ứng với PERIOD_CURRENT.
Số lượng tối đa các biểu đồ có thể mở đồng thời trong terminal không được vượt quá CHARTS_MAX (100).
Chúng ta sẽ thấy một ví dụ sử dụng hàm ChartOpen
trong phần tiếp theo, sau khi nghiên cứu các hàm làm việc với mẫu tpl.
Xin lưu ý rằng terminal cho phép tạo không chỉ các cửa sổ đầy đủ chức năng với biểu đồ mà còn các đối tượng biểu đồ. Chúng được đặt bên trong các biểu đồ thông thường giống như các đối tượng đồ họa khác như đường xu hướng, kênh, nhãn giá, v.v. Các đối tượng biểu đồ cho phép hiển thị trong một biểu đồ tiêu chuẩn nhiều đoạn nhỏ của chuỗi giá cho các biểu tượng và khung thời gian thay thế.
bool ChartClose(long chartId = 0)
Hàm đóng biểu đồ với ID được chỉ định (giá trị mặc định 0 có nghĩa là biểu đồ hiện tại). Hàm trả về chỉ báo thành công.
Ví dụ, hãy triển khai script ChartCloseIdle.mq5
, script này sẽ đóng các biểu đồ trùng lặp với sự kết hợp biểu tượng và khung thời gian lặp lại nếu chúng không chứa chương trình MQL và đối tượng đồ họa.
Đầu tiên, chúng ta cần lập danh sách đếm các biểu đồ cho một cặp biểu tượng/khung thời gian cụ thể. Nhiệm vụ này được thực hiện bởi hàm ChartIdleList
, rất giống với những gì chúng ta đã thấy trong script ChartList.mq5
. Danh sách chính nó được hình thành trong mảng bản đồ MapArray<string,int> chartCounts
.
#include <MQL5Book/Periods.mqh>
#include <MQL5Book/MapArray.mqh>
#define PUSH(A,V) (A[ArrayResize(A, ArraySize(A) + 1) - 1] = V)
void OnStart()
{
MapArray<string,int> chartCounts;
ulong duplicateChartIDs[];
// thu thập các biểu đồ trống trùng lặp
if(ChartIdleList(chartCounts, duplicateChartIDs))
{
...
}
else
{
Print("No idle charts.");
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Trong khi đó, hàm ChartIdleList
điền mảng duplicateChartIDs
với các định danh của các biểu đồ trống khớp với điều kiện đóng.
int ChartIdleList(MapArray<string,int> &map, ulong &duplicateChartIDs[])
{
// liệt kê các biểu đồ cho đến khi danh sách của chúng kết thúc
for(long id = ChartFirst(); id != -1; id = ChartNext(id))
{
// bỏ qua các đối tượng
if(ChartGetInteger(id, CHART_IS_OBJECT)) continue;
// lấy các thuộc tính chính của biểu đồ
const int win = (int)ChartGetInteger(id, CHART_WINDOWS_TOTAL);
const string expert = ChartGetString(id, CHART_EXPERT_NAME);
const string script = ChartGetString(id, CHART_SCRIPT_NAME);
const int objectCount = ObjectsTotal(id);
// đếm số lượng chỉ báo
int indicators = 0;
for(int i = 0; i < win; ++i)
{
indicators += ChartIndicatorsTotal(id, i);
}
const string key = ChartSymbol(id) + "/" + PeriodToString(ChartPeriod(id));
if(map[key] == 0 // lần đầu tiên chúng ta luôn đọc một kết hợp biểu tượng/TF mới
// nếu không, chỉ các biểu đồ trống được đếm:
|| (indicators == 0 // không có chỉ báo
&& StringLen(expert) == 0 // không có Expert Advisor
&& StringLen(script) == 0 // không có script
&& objectCount == 0)) // không có đối tượng
{
const int i = map.inc(key);
if(map[i] > 1) // trùng lặp
{
PUSH(duplicateChartIDs, id);
}
}
}
return map.getSize();
}
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
Sau khi danh sách để xóa được hình thành, trong OnStart
chúng ta gọi hàm ChartClose
trong một vòng lặp qua danh sách.
void OnStart()
{
...
if(ChartIdleList(chartCounts, duplicateChartIDs))
{
for(int i = 0; i < ArraySize(duplicateChartIDs); ++i)
{
const ulong id = duplicateChartIDs[i];
// yêu cầu đưa biểu đồ lên phía trước
ChartSetInteger(id, CHART_BRING_TO_TOP, true);
// cập nhật trạng thái của các cửa sổ, xử lý hàng đợi với yêu cầu
ChartRedraw(id);
// hỏi người dùng để xác nhận
const int button = MessageBox(
"Remove idle chart: "
+ ChartSymbol(id) + "/" + PeriodToString(ChartPeriod(id)) + "?",
__FILE__, MB_YESNOCANCEL);
if(button == IDCANCEL) break;
if(button == IDYES)
{
ChartClose(id);
}
}
...
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Đối với mỗi biểu đồ, đầu tiên hàm ChartSetInteger(id, CHART_BRING_TO_TOP, true)
được gọi để hiển thị cho người dùng cửa sổ nào sẽ bị đóng. Vì hàm này không đồng bộ (chỉ đặt lệnh kích hoạt cửa sổ vào hàng đợi sự kiện), bạn cần gọi thêm ChartRedraw
, hàm này xử lý tất cả các tin nhắn tích lũy. Sau đó, người dùng được yêu cầu xác nhận hành động. Biểu đồ chỉ đóng khi nhấp vào Yes
. Chọn No
sẽ bỏ qua biểu đồ hiện tại (giữ nó mở), và vòng lặp tiếp tục. Bằng cách nhấn Cancel
, bạn có thể ngắt vòng lặp trước thời hạn.