Hiển thị các khoảng trống dữ liệu (các phần tử rỗng)
Trong nhiều trường hợp, các giá trị chỉ báo chỉ nên được hiển thị trên một số thanh, để lại các thanh còn lại không bị thay đổi (về mặt hình ảnh, không có thêm đường hoặc nhãn). Ví dụ, nhiều chỉ báo tín hiệu hiển thị mũi tên lên hoặc xuống trên những thanh xuất hiện khuyến nghị mua hoặc bán. Nhưng tín hiệu thì hiếm.
Giá trị rỗng, không được hiển thị trên biểu đồ hoặc trong Data Window
, được thiết lập bằng hàm PlotIndexSetDouble
.
bool PlotIndexSetDouble(int index, ENUM_PLOT_PROPERTY_DOUBLE property, double value)
Hàm này thiết lập các thuộc tính kiểu double
cho biểu đồ tại chỉ số được chỉ định index
. Tập hợp các thuộc tính này được tổng hợp trong liệt kê ENUM_PLOT_PROPERTY_DOUBLE
, nhưng hiện tại nó chỉ có một phần tử: PLOT_EMPTY_VALUE
. Nó cũng thiết lập giá trị rỗng. Giá trị đó được truyền qua tham số cuối cùng value
.
Ví dụ về một chỉ báo có giá trị hiếm, chúng ta sẽ xem xét một bộ phát hiện fractal. Nó đánh dấu trên biểu đồ các giá cao (High
) cao hơn N thanh lân cận và các giá thấp (Low
) thấp hơn N thanh lân cận, ở cả hai hướng. Tệp chỉ báo được gọi là IndFractals.mq5
.
Chỉ báo sẽ có hai bộ đệm và hai biểu đồ đồ họa loại DRAW_ARROW
.
#property indicator_chart_window
#property indicator_buffers 2
#property indicator_plots 2
// cài đặt hiển thị
#property indicator_type1 DRAW_ARROW
#property indicator_type2 DRAW_ARROW
#property indicator_color1 clrBlue
#property indicator_color2 clrRed
#property indicator_label1 "Fractal Up"
#property indicator_label2 "Fractal Down"
// bộ đệm chỉ báo
double UpBuffer[];
double DownBuffer[];
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Biến đầu vào FractalOrder
sẽ cho phép bạn thiết lập số lượng thanh lân cận, qua đó xác định cực đại hoặc cực tiểu.
input int FractalOrder = 3;
Đối với các ký hiệu mũi tên, chúng ta sẽ cung cấp một khoảng cách 10 pixel từ các cực trị để dễ nhìn hơn.
const int ArrowShift = 10;
Trong hàm OnInit
, khai báo các mảng làm bộ đệm và liên kết chúng với các biểu đồ đồ họa.
int OnInit()
{
// liên kết bộ đệm
SetIndexBuffer(0, UpBuffer, INDICATOR_DATA);
SetIndexBuffer(1, DownBuffer, INDICATOR_DATA);
// mã ký tự mũi tên lên và xuống
PlotIndexSetInteger(0, PLOT_ARROW, 217);
PlotIndexSetInteger(1, PLOT_ARROW, 218);
// khoảng cách cho mũi tên
PlotIndexSetInteger(0, PLOT_ARROW_SHIFT, -ArrowShift);
PlotIndexSetInteger(1, PLOT_ARROW_SHIFT, +ArrowShift);
// thiết lập giá trị rỗng (có thể bỏ qua vì EMPTY_VALUE là mặc định)
PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, EMPTY_VALUE);
PlotIndexSetDouble(1, PLOT_EMPTY_VALUE, EMPTY_VALUE);
return FractalOrder > 0 ? INIT_SUCCEEDED : INIT_PARAMETERS_INCORRECT;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Lưu ý rằng giá trị rỗng mặc định là hằng số đặc biệt EMPTY_VALUE
, vì vậy các lời gọi PlotIndexSetDouble
ở trên là tùy chọn.
Trong trình xử lý OnCalculate
, tại lần gọi đầu tiên, chúng ta khởi tạo cả hai mảng bằng EMPTY_VALUE
, sau đó gán nó cho các phần tử mới khi các thanh hình thành. Việc đệm là cần thiết vì bộ nhớ được cấp cho bộ đệm có thể chứa dữ liệu ngẫu nhiên (rác).
int OnCalculate(const int rates_total,
const int prev_calculated,
const datetime &time[],
const double &open[],
const double &high[],
const double &low[],
const double &close[],
const long &tick_volume[],
const long &volume[],
const int &spread[])
{
if(prev_calculated == 0)
{
// lúc bắt đầu, điền toàn bộ mảng
ArrayInitialize(UpBuffer, EMPTY_VALUE);
ArrayInitialize(DownBuffer, EMPTY_VALUE);
}
else
{
// trên các thanh mới, cũng làm sạch các phần tử
for(int i = prev_calculated; i < rates_total; ++i)
{
UpBuffer[i] = EMPTY_VALUE;
DownBuffer[i] = EMPTY_VALUE;
}
}
...
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
Trong vòng lặp chính, so sánh từng thanh giá high
và low
với cùng loại giá trên các thanh lân cận và đặt dấu nơi tìm thấy cực trị trong số FractalOrder
thanh ở mỗi bên.
// xem tất cả hoặc các thanh mới có thanh trong môi trường FractalOrder
for(int i = fmax(prev_calculated - FractalOrder - 1, FractalOrder);
i < rates_total - FractalOrder; ++i)
{
// kiểm tra xem giá trên có cao hơn các thanh lân cận không
UpBuffer[i] = high[i];
for(int j = 1; j <= FractalOrder; ++j)
{
if(high[i] <= high[i + j] || high[i] <= high[i - j])
{
UpBuffer[i] = EMPTY_VALUE;
break;
}
}
// kiểm tra xem giá dưới có thấp hơn các thanh lân cận không
DownBuffer[i] = low[i];
for(int j = 1; j <= FractalOrder; ++j)
{
if(low[i] >= low[i + j] || low[i] >= low[i - j])
{
DownBuffer[i] = EMPTY_VALUE;
break;
}
}
}
return rates_total;
}
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
Hãy xem chỉ báo này trông như thế nào trên biểu đồ.
Fractal indicator
Bây giờ hãy thay đổi kiểu vẽ từ DRAW_ARROW
sang DRAW_ZIGZAG
và so sánh hiệu quả của các giá trị rỗng cho cả hai tùy chọn. Kết quả sẽ là một đường zigzag trên các fractal. Phiên bản sửa đổi của chỉ báo được đính kèm trong tệp IndFractalsZigZag.mq5
.
Một trong những thay đổi chính liên quan đến số lượng biểu đồ: giờ đây chỉ còn một vì DRAW_ZIGZAG
"sử dụng" cả hai bộ đệm.
#property indicator_chart_window
#property indicator_buffers 2
#property indicator_plots 1
// cài đặt hiển thị
#property indicator_type1 DRAW_ZIGZAG
#property indicator_color1 clrMediumOrchid
#property indicator_width1 2
#property indicator_label1 "ZigZag Up;ZigZag Down"
...
2
3
4
5
6
7
8
9
10
Tất cả các lời gọi hàm liên quan đến việc thiết lập mũi tên đã được xóa khỏi OnInit
.
int OnInit()
{
SetIndexBuffer(0, UpBuffer, INDICATOR_DATA);
SetIndexBuffer(1, DownBuffer, INDICATOR_DATA);
PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, EMPTY_VALUE);
return FractalOrder > 0 ? INIT_SUCCEEDED : INIT_PARAMETERS_INCORRECT;
}
2
3
4
5
6
7
8
9
Phần còn lại của mã nguồn không thay đổi.
Hình ảnh sau cho thấy một biểu đồ mà trên đó một đường zigzag được áp dụng ngoài các fractal: nhờ đó, bạn có thể so sánh trực quan kết quả của chúng. Cả hai chỉ báo hoạt động hoàn toàn độc lập, nhưng do cùng thuật toán, các cực trị tìm thấy là giống nhau.
Zig-Zag indicator by fractals
Điều quan trọng cần lưu ý là nếu các cực trị cùng loại xuất hiện liên tiếp, ZigZag
sử dụng cái đầu tiên trong số chúng. Đây là hệ quả của việc fractal được sử dụng làm cực trị. Tất nhiên, điều này không thể xảy ra trong một zigzag tiêu chuẩn. Nếu cần, những ai muốn có thể cải thiện thuật toán bằng cách trước tiên làm mỏng các chuỗi fractal.
Cũng cần lưu ý rằng đối với việc vẽ DRAW_ZIGZAG
(cũng như DRAW_SECTION
), các đoạn có thể nhìn thấy kết nối các phần tử không rỗng và do đó, nghiêm túc mà nói, một số đoạn của đoạn được vẽ trên mỗi thanh, bao gồm cả những thanh có giá trị EMPTY_VALUE
(hoặc một giá trị khác được chỉ định thay thế). Tuy nhiên, bạn có thể thấy trong Data Window
rằng các phần tử rỗng thực sự là rỗng: không có giá trị nào được hiển thị cho chúng.