Gán một mảng làm bộ đệm: SetIndexBuffer
Vai trò của các bộ đệm chỉ báo có thể được thực hiện bởi bất kỳ mảng động nào kiểu double
trong suốt thời gian từ khi chương trình khởi động đến khi dừng. Cách phổ biến nhất để định nghĩa một mảng như vậy là ở cấp độ toàn cục. Nhưng trong một số trường hợp, việc đặt các mảng làm thành viên của các lớp và sau đó tạo các đối tượng toàn cục với các mảng sẽ tiện lợi hơn. Chúng ta sẽ xem xét các ví dụ về cách tiếp cận này khi triển khai một chỉ báo đa tiền tệ (xem ví dụ IndUnityPercent.mq5
trong phần Chỉ báo đa tiền tệ và đa khung thời gian) và chỉ báo khối lượng delta (xem IndDeltaVolume.mq5
trong phần Chờ dữ liệu và quản lý khả năng hiển thị).
Vậy, hãy mô tả một mảng động buffer
ở cấp độ toàn cục (không cần định kích thước).
double buffer[];
Nó có thể được đăng ký làm bộ đệm bằng hàm đặc biệt SetIndexBuffer
trong terminal. Thông thường, hàm này được gọi trong trình xử lý OnInit
, giống như nhiều hàm khác để thiết lập chỉ báo, mà chúng ta sẽ thảo luận sau.
bool SetIndexBuffer(int index, double buffer[], ENUM_INDEXBUFFER_TYPE mode = INDICATOR_DATA)
Hàm này liên kết bộ đệm chỉ báo được chỉ định bởi index
với mảng động buffer
. Giá trị của index
phải nằm trong khoảng từ 0 đến N - 1, trong đó N là số lượng bộ đệm được chỉ định bởi chỉ thị #property indicator_buffers
.
Ngay sau khi liên kết, mảng chưa sẵn sàng để làm việc với dữ liệu và thậm chí không thay đổi kích thước, vì vậy việc khởi tạo và tất cả các phép tính nên được thực hiện trong hàm OnCalculate
. Bạn không thể thay đổi kích thước của một mảng động sau khi nó đã được gán làm bộ đệm chỉ báo. Đối với các bộ đệm chỉ báo, tất cả các thao tác thay đổi kích thước đều được terminal tự thực hiện.
Hướng lập chỉ mục sau khi liên kết một mảng với bộ đệm chỉ báo được đặt mặc định như trong các mảng thông thường. Nếu cần, nó có thể được thay đổi bằng hàm ArraySetAsSeries
.
Hàm SetIndexBuffer
trả về true
khi thành công và false
khi có lỗi.
Tham số tùy chọn mode
thông báo cho hệ thống cách bộ đệm sẽ được sử dụng. Các giá trị có thể được cung cấp trong enum ENUM_INDEXBUFFER_TYPE.
Định danh | Mô tả |
---|---|
INDICATOR_DATA | Dữ liệu để hiển thị |
INDICATOR_COLOR_INDEX | Màu sắc hiển thị |
INDICATOR_CALCULATIONS | Kết quả nội bộ của các phép tính trung gian |
Theo mặc định, bộ đệm chỉ báo được dùng để vẽ dữ liệu (INDICATOR_DATA). Giá trị này có tác dụng khác ngoài việc hiển thị mảng trên biểu đồ: giá trị của mỗi bộ đệm cho thanh dưới con trỏ chuột được hiển thị trong Data window
. Tuy nhiên, hành vi này có thể được thay đổi bởi một số cài đặt chỉ báo (xem thuộc tính PLOT_SHOW_DATA trong phần Cài đặt biểu đồ đồ họa). Hầu hết các ví dụ trong chương này đề cập đến chế độ INDICATOR_DATA.
Nếu việc tính toán chỉ báo yêu cầu lưu trữ kết quả trung gian cho mỗi thanh, một bộ đệm phụ không hiển thị (INDICATOR_CALCULATIONS) có thể được phân bổ cho chúng. Điều này tiện lợi hơn so với việc sử dụng một mảng thông thường cho cùng mục đích vì khi đó lập trình viên phải tự kiểm soát kích thước của nó. Chương này sẽ trình bày hai ví dụ với INDICATOR_CALCULATIONS: IndTripleEMA.mq5
(xem Bỏ qua vẽ trên các thanh ban đầu) và IndSubChartSimple.mq5
(xem Chỉ báo đa tiền tệ và đa khung thời gian).
Một số cấu trúc cho phép đặt màu hiển thị cho mỗi thanh. Các bộ đệm màu (INDICATOR_COLOR_INDEX) được sử dụng để lưu trữ thông tin màu sắc. Màu được biểu diễn bằng kiểu số nguyên color
, nhưng tất cả các bộ đệm chỉ báo phải có kiểu double
, và trong trường hợp này, chúng lưu số màu từ một bảng màu đặc biệt do nhà phát triển đặt (xem phần Tô màu từng phần tử của biểu đồ và ví dụ chỉ báo IndColorWPR.mq5
trong đó).
Giá trị của bộ đệm màu và phụ không được hiển thị trong Data window
, và chúng không thể được lấy bằng hàm CopyBuffer
mà chúng ta sẽ khám phá sau trong chương về Sử dụng chỉ báo tích hợp và tùy chỉnh từ MQL5.
Bộ đệm chỉ báo không được khởi tạo với bất kỳ giá trị nào. Nếu một số phần tử của nó không được tính toán vì lý do nào đó (ví dụ, trong cài đặt chỉ báo có giới hạn về số lượng thanh tối đa hoặc bản thân cấu trúc đồ họa ngụ ý các phần tử quan trọng hiếm hoi giữa các khoảng trống, như giữa các đỉnh ZigZag), thì chúng nên được điền rõ ràng bằng một giá trị "rỗng" đặc biệt. Giá trị rỗng không được hiển thị trên biểu đồ và không xuất hiện trong Data Window
. Theo mặc định, có một hằng số EMPTY_VALUE (DBL_MAX) cho nó, nhưng nếu cần, nó có thể được thay thế bằng bất kỳ giá trị nào khác, chẳng hạn như 0. Điều này được thực hiện bằng hàm PlotIndexSetDouble
.
Với kiến thức mới về hàm SetIndexBuffer
, hãy hoàn thiện ví dụ tiếp theo của chúng ta IndReplica1.mq5
, mà chúng ta đã bắt đầu trong phần trước. Cụ thể, chúng ta cần trình xử lý OnInit
.
#property indicator_chart_window
#property indicator_buffers 1
#property indicator_plots 1
#include <MQL5Book/PRTF.mqh>
double buffer[]; // mảng động toàn cục
int OnInit()
{
// đăng ký một mảng làm bộ đệm chỉ báo
PRTF(SetIndexBuffer(0, buffer)); // true / ok
// lệnh gọi thứ hai không chính xác được thực hiện ở đây cố ý để hiển thị lỗi
PRTF(SetIndexBuffer(1, buffer)); // false / BUFFERS_WRONG_INDEX(4602)
// kiểm tra kích thước: vẫn là 0
PRTF(ArraySize(buffer)); // 0
return INIT_SUCCEEDED;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Số lượng bộ đệm được định nghĩa bởi chỉ thị bằng 1, vì vậy việc gán mảng cho một bộ đệm duy nhất sử dụng chỉ số 0 (tham số đầu tiên của SetIndexBuffer
). Lệnh gọi hàm thứ hai là lỗi và chỉ được thêm vào để thể hiện vấn đề: vì chỉ số 1 ngụ ý hai bộ đệm được khai báo, nó tạo ra lỗi BUFFERS_WRONG_INDEX (4602).
Ngay tại đầu hàm OnCalculate
, hãy in lại kích thước của mảng. Ở vị trí này, nó đã được phân bổ theo số lượng thanh.
int OnCalculate(const int rates_total,
const int prev_calculated,
const int begin,
const double &data[])
{
// sau khi khởi động, kiểm tra rằng nền tảng tự động quản lý kích thước của mảng
if(prev_calculated == 0)
{
PRTF(ArraySize(buffer)); // 10189 - số lượng thanh thực tế
}
...
2
3
4
5
6
7
8
9
10
11
Bây giờ hãy chuyển sang câu hỏi chỉ báo của chúng ta sẽ tính toán gì. Như đã đề cập, chúng ta chưa đưa các công thức phức tạp vào đó, mà chỉ đơn giản là cố gắng sao chép chuỗi thời gian được truyền từ tham số data
vào bộ đệm. Điều này được phản ánh trong tên của chỉ báo.
...
// trên mỗi thanh mới hoặc tập hợp thanh (bao gồm phép tính đầu tiên)
if(prev_calculated != rates_total)
{
// điền vào tất cả các thanh mới
ArrayCopy(buffer, data, prev_calculated, prev_calculated);
}
else // các tick trên thanh hiện tại
{
// cập nhật thanh cuối cùng
buffer[rates_total - 1] = data[rates_total - 1];
}
// chúng ta báo cáo số lượng thanh đã xử lý cho chính mình trong tương lai
return rates_total;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Bây giờ chỉ báo được biên dịch mà không có bất kỳ cảnh báo nào. Chúng ta có thể chạy nó trên biểu đồ, và với cài đặt mặc định, nó sẽ sao chép các giá trị của giá đóng của các thanh vào bộ đệm. Điều này là do dạng ngắn của OnCalculate
, chúng ta đã xem xét khía cạnh này trong phần Sự kiện chính của chỉ báo: OnCalculate.
Tuy nhiên, có một điều kỳ lạ: bộ đệm của chúng ta được hiển thị trong Data window
và nó chứa các giá trị chính xác, nhưng không có đường trên biểu đồ. Đây là hậu quả của việc các cấu trúc đồ họa, chứ không phải bộ đệm, chịu trách nhiệm cho việc hiển thị. Trong phiên bản hiện tại của chỉ báo, chúng ta chỉ cấu hình bộ đệm. Trong phần tiếp theo, chúng ta sẽ tạo một phiên bản mới IndReplica2.mq5
và bổ sung nó với các hướng dẫn cần thiết.
Đồng thời, hiệu ứng được mô tả có thể hữu ích để tạo các chỉ báo "ẩn" không hiển thị đường của chúng trên biểu đồ nhưng có sẵn để đọc bằng chương trình từ các chương trình MQL khác. Nếu muốn, nhà phát triển sẽ có thể ẩn cả việc đề cập đến các bộ đệm chỉ báo khỏi Data windows
(xem PLOT_SHOW_DATA trong phần tiếp theo).
Cách quản lý chỉ báo từ mã MQL5 sẽ được thảo luận trong chương tiếp theo.