Hỗ trợ nhiều ký hiệu và khung thời gian
Cho đến nay, trong tất cả các ví dụ về chỉ báo, chúng ta đã tạo các descriptor cho cùng ký hiệu và khung thời gian với biểu đồ hiện tại. Tuy nhiên, không có giới hạn như vậy. Chúng ta có thể tạo các chỉ báo phụ trợ trên bất kỳ ký hiệu và khung thời gian nào. Tất nhiên, trong trường hợp này, cần phải đợi sẵn sàng của chuỗi thời gian bên thứ ba, như chúng ta đã làm trước đây, ví dụ, bằng bộ đếm thời gian.
Hãy triển khai chỉ báo WPR đa khung thời gian (xem tệp UseWPRMTF.mq5
), cũng có thể được gán tính toán trên một ký hiệu bất kỳ (khác với biểu đồ).
Chúng ta sẽ hiển thị giá trị WPR của một chu kỳ nhất định cho tất cả các khung thời gian tiêu chuẩn từ liệt kê ENUM_TIMEFRAMES
. Số lượng khung thời gian là 21, vì vậy chỉ báo sẽ luôn được hiển thị trên 21 thanh cuối cùng. Thanh số 0 ở bên phải sẽ chứa WPR cho M1, thanh tiếp theo sẽ chứa WPR cho M2, và cứ thế cho đến thanh thứ 20 với WPR cho khung thời gian tháng. Để dễ đọc hơn, chúng ta sẽ tô màu các biểu đồ bằng các màu khác nhau: khung thời gian phút sẽ màu đỏ, giờ màu xanh lá, và ngày trở lên sẽ màu xanh dương.
Vì sẽ có thể đặt một ký hiệu làm việc trong chỉ báo và tạo nhiều bản sao cho các ký hiệu khác nhau trên cùng một biểu đồ, chúng ta sẽ chọn kiểu vẽ DRAW_ARROW
và cung cấp một tham số đầu vào để gán ký hiệu. Bằng cách này, có thể phân biệt các chỉ số cho các ký hiệu khác nhau. Việc tô màu yêu cầu một bộ đệm bổ sung.
#property indicator_separate_window
#property indicator_buffers 2
#property indicator_plots 1
#property indicator_type1 DRAW_COLOR_ARROW
#property indicator_color1 clrRed,clrGreen,clrBlue
#property indicator_width1 3
#property indicator_label1 "WPR"
2
3
4
5
6
7
8
Giá trị WPR được chuyển đổi sang khoảng [-1,+1]. Hãy chọn tỷ lệ của cửa sổ phụ với một khoảng dư từ phạm vi. Các mức với giá trị ±0.6 tương ứng với chuẩn -20 và -80 trước khi chuyển đổi WPR.
#property indicator_maximum +1.2
#property indicator_minimum -1.2
#property indicator_level1 +0.6
#property indicator_level2 -0.6
#property indicator_levelstyle STYLE_DOT
#property indicator_levelcolor clrSilver
#property indicator_levelwidth 1
2
3
4
5
6
7
8
Trong các biến đầu vào: chu kỳ WPR, ký hiệu làm việc và mã của mũi tên được hiển thị. Khi ký hiệu để trống, ký hiệu của biểu đồ hiện tại được sử dụng.
input int WPRPeriod = 14;
input string WorkSymbol = ""; // Symbol
input int Mark = 0;
const string _WorkSymbol = (WorkSymbol == "" ? _Symbol : WorkSymbol);
2
3
4
5
Để tiện lập trình, tập hợp các khung thời gian được liệt kê trong mảng TF
.
#define TFS 21
ENUM_TIMEFRAMES TF[TFS] =
{
PERIOD_M1,
PERIOD_M2,
PERIOD_M3,
...
PERIOD_D1,
PERIOD_W1,
PERIOD_MN1,
};
2
3
4
5
6
7
8
9
10
11
12
Các descriptor của chỉ báo cho mỗi khung thời gian được lưu trong mảng Handle
.
int Handle[TFS];
Chúng ta sẽ cấu hình các bộ đệm chỉ báo và lấy các handle trong OnInit
.
double WPRBuffer[];
double Colors[];
int OnInit()
{
SetIndexBuffer(0, WPRBuffer);
SetIndexBuffer(1, Colors, INDICATOR_COLOR_INDEX);
ArraySetAsSeries(WPRBuffer, true);
ArraySetAsSeries(Colors, true);
PlotIndexSetString(0, PLOT_LABEL, _WorkSymbol + " WPR");
if(Mark != 0)
{
PlotIndexSetInteger(0, PLOT_ARROW, Mark);
}
for(int i = 0; i < TFS; ++i)
{
Handle[i] = iCustom(_WorkSymbol, TF[i], "IndWPR", WPRPeriod);
if(Handle[i] == INVALID_HANDLE) return INIT_FAILED;
}
IndicatorSetInteger(INDICATOR_DIGITS, 2);
IndicatorSetString(INDICATOR_SHORTNAME,
"%Rmtf" + "(" + _WorkSymbol + "/" + (string)WPRPeriod + ")");
return INIT_SUCCEEDED;
}
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
Tính toán trong OnCalculate
diễn ra theo sơ đồ thông thường: đợi dữ liệu sẵn sàng, khởi tạo, điền vào trên các thanh mới. Các hàm phụ trợ IsDataReady
và FillData
thực hiện công việc trực tiếp với các descriptor (xem bên dưới).
int OnCalculate(const int rates_total,
const int prev_calculated,
const int begin,
const double &data[])
{
// đợi các chỉ báo phụ sẵn sàng
if(!IsDataReady())
{
EventSetTimer(1); // nếu chưa sẵn sàng, hoãn tính toán
return prev_calculated;
}
if(prev_calculated == 0) // khởi tạo
{
ArrayInitialize(WPRBuffer, EMPTY_VALUE);
ArrayInitialize(Colors, EMPTY_VALUE);
// màu cố định cho TFS thanh mới nhất
for(int i = 0; i < TFS; ++i)
{
Colors[i] = i < 11 ? 0 : (i < 18 ? 1 : 2);
}
}
else // chuẩn bị thanh mới
{
for(int i = prev_calculated; i < rates_total; ++i)
{
WPRBuffer[i] = EMPTY_VALUE;
Colors[i] = 0;
}
}
if(prev_calculated != rates_total) // thanh mới
{
// xóa nhãn trên thanh cũ nhất đã dịch sang trái quá TFS thanh
WPRBuffer[TFS] = EMPTY_VALUE;
// cập nhật màu thanh
for(int i = 0; i < TFS; ++i)
{
Colors[i] = i < 11 ? 0 : (i < 18 ? 1 : 2);
}
}
// sao chép dữ liệu từ các chỉ báo phụ vào bộ đệm của chúng ta
FillData();
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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
Nếu cần, chúng ta khởi tạo tính toán lại bằng bộ đếm thời gian.
void OnTimer()
{
ChartSetSymbolPeriod(0, _Symbol, _Period);
EventKillTimer();
}
2
3
4
5
Và đây là các hàm IsDataReady
và FillData
.
bool IsDataReady()
{
for(int i = 0; i < TFS; ++i)
{
if(BarsCalculated(Handle[i]) != iBars(_WorkSymbol, TF[i]))
{
Print("Waiting for ", _WorkSymbol, " ", EnumToString(TF[i]));
return false;
}
}
return true;
}
void FillData()
{
for(int i = 0; i < TFS; ++i)
{
double data[1];
// lấy giá trị thực tế cuối cùng (bộ đệm 0, chỉ số 0)
if(CopyBuffer(Handle[i], 0, 0, 1, data) == 1)
{
WPRBuffer[i] = (data[0] + 50) / 50;
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Hãy biên dịch chỉ báo và xem nó trông như thế nào trên biểu đồ. Ví dụ, hãy tạo ba bản sao cho EURUSD
, USDRUB
và XAUUSD
.
Chú thích hình ảnh: Ba phiên bản của WPR đa khung thời gian cho các ký hiệu làm việc khác nhau
Trong lần tính toán đầu tiên, chỉ báo có thể yêu cầu một lượng thời gian đáng kể để chuẩn bị chuỗi thời gian cho tất cả các khung thời gian.
Về phần tính toán, chỉ báo hoàn toàn giống UseWPRMTFDashboard.mq5
được thiết kế dưới dạng bảng điều khiển phổ biến với các nhà giao dịch. Đối với mỗi ký hiệu, chúng ta đặt các khoảng thụt dọc riêng trong tham số Level
của chỉ báo. Đây là nơi các giá trị WPR của tất cả các khung thời gian được hiển thị dưới dạng một dòng các điểm đánh dấu, và các giá trị được mã hóa màu. Trong phiên bản này, giá trị WPR được chuẩn hóa sang khoảng [0..1], vì vậy việc sử dụng các thước kẻ tại các mức cách nhau vài chục (ví dụ, 20, như trong ảnh chụp màn hình dưới đây) cho phép đặt nhiều phiên bản của chỉ báo trong cửa sổ phụ mà không bị chồng lấn (80, 100, 120, v.v.). Mỗi bản sao được sử dụng cho ký hiệu làm việc riêng của nó. Hơn nữa, do Level
lớn hơn 1.0, và giá trị WPR nhỏ hơn, chúng hiển thị trong các giá trị trong Data window
riêng biệt: bên trái và bên phải của dấu thập phân.
Nhãn cho các thước kẻ được cung cấp bởi các mức được thêm động trong OnInit
.
Chú thích hình ảnh: Bảng điều khiển của ba dòng WPR đa khung thời gian cho các ký hiệu làm việc khác nhau
Bạn có thể khám phá mã nguồn của UseWPRMTFDashboard.mq5
và so sánh nó với UseWPRMTF.mq5
. Để tạo bảng màu sắc, chúng ta đã sử dụng tệp ColorMix.mqh
.
Sau khi hoàn thành việc nghiên cứu các chỉ báo tích hợp sẵn, bao gồm iWPR
, chúng ta có thể thay thế IndWPR
tùy chỉnh bằng iWPR
tích hợp sẵn.
Về hiệu quả và mức độ tiêu tốn tài nguyên của các chỉ báo phức hợp
Cách tiếp cận được trình bày ở trên, với việc tạo ra nhiều chỉ báo phụ trợ, không hiệu quả về tốc độ và mức tiêu thụ tài nguyên. Đây chủ yếu là một ví dụ về việc tích hợp các chương trình MQL và trao đổi dữ liệu giữa chúng. Nhưng như bất kỳ công nghệ nào, nó nên được sử dụng một cách phù hợp.
Mỗi trong hai chỉ báo được tạo ra tính toán WPR trên tất cả các thanh của chuỗi thời gian, và sau đó chỉ giá trị cuối cùng được lấy vào chỉ báo gọi. Chúng ta lãng phí cả bộ nhớ và thời gian xử lý.
Nếu mã nguồn của các chỉ báo phụ trợ có sẵn hoặc khái niệm hoạt động của chúng được biết, cách tối ưu nhất là đặt thuật toán tính toán bên trong chỉ báo chính (hoặc Expert Advisor) và áp dụng nó cho một lịch sử tức thời giới hạn, với độ sâu tối thiểu cần thiết.
Trong một số trường hợp, bạn có thể không cần tham chiếu đến các khung thời gian cao hơn bằng cách thực hiện các tính toán tương đương trên khung thời gian hiện tại: ví dụ, thay vì phạm vi giá trên 14 thanh ngày (yêu cầu xây dựng toàn bộ chuỗi thời gian D1), bạn có thể lấy phạm vi trên 14 * 24 thanh H1, với điều kiện giao dịch 24 giờ và chạy chỉ báo trên biểu đồ H1.
Đồng thời, khi một chỉ báo thương mại được sử dụng trong hệ thống giao dịch (không có mã nguồn), dữ liệu chỉ có thể được lấy từ nó thông qua các giao diện lập trình mở. Trong trường hợp này, việc tạo handle và sau đó đọc dữ liệu từ bộ đệm chỉ báo qua
CopyBuffer
là lựa chọn duy nhất có sẵn, nhưng đồng thời là cách tiện lợi, phổ quát. Chỉ cần luôn ghi nhớ rằng việc gọi các hàm API là một thao tác "đắt đỏ" hơn so với việc thao tác mảng của riêng bạn bên trong chương trình MQL và gọi các hàm cục bộ. Nếu bạn cần giữ nhiều terminal mở, có lẽ mỗi terminal với một tập hợp các chương trình MQL không tối ưu như vậy, và nếu tài nguyên của bạn bị giới hạn, thì hiệu suất có thể sẽ giảm.