Một cách đơn giản để tạo các phiên bản chỉ báo: iCustom
MQL5 cung cấp hai hàm để tạo các phiên bản chỉ báo từ chương trình: iCustom
và IndicatorCreate
. Hàm đầu tiên yêu cầu truyền một danh sách các tham số, mà phải được biết tại thời điểm biên dịch chương trình. Hàm thứ hai cho phép bạn tạo động một mảng với các tham số của chỉ báo được gọi trong quá trình thực thi chương trình. Chế độ nâng cao này sẽ được thảo luận trong phần Cách nâng cao để tạo chỉ báo: IndicatorCreate.
int iCustom(const string symbol, ENUM_TIMEFRAMES timeframe, const string pathname, ...)
Hàm này tạo một chỉ báo cho biểu tượng và khung thời gian được chỉ định. NULL
trong tham số symbol
có thể được sử dụng để chỉ biểu tượng của biểu đồ hiện tại, trong khi 0
trong tham số timeframe
đặt khung thời gian hiện tại.
Trong tham số pathname
, chỉ định tên chỉ báo (tên tệp ex5 không có phần mở rộng) và tùy chọn, đường dẫn. Chi tiết hơn về đường dẫn được đưa ra dưới đây.
Chỉ báo được tham chiếu bởi pathname
phải được biên dịch.
Hàm trả về một tay cầm chỉ báo hoặc INVALID_HANDLE
trong trường hợp xảy ra lỗi. Tay cầm sẽ cần thiết để gọi các hàm khác được mô tả trong chương này và được bao gồm trong nhóm điều khiển chương trình chỉ báo. Tay cầm là một số nguyên mô tả duy nhất phiên bản chỉ báo được tạo trong chương trình gọi.
Dấu ba chấm trong nguyên mẫu hàm iCustom
biểu thị một danh sách các tham số thực tế cho chỉ báo. Loại và thứ tự của chúng phải tương ứng với các tham số chính thức (trong mã chỉ báo). Tuy nhiên, có thể bỏ qua các giá trị bắt đầu từ cuối danh sách tham số. Đối với các tham số không được chỉ định trong mã gọi, chỉ báo được tạo sẽ sử dụng các giá trị mặc định của các input
tương ứng.
Ví dụ, nếu chỉ báo nhận hai biến đầu vào: chu kỳ (input int WorkPeriod = 14
) và loại giá (input ENUM_APPLIED_PRICE WorkPrice = PRICE_CLOSE
), thì bạn có thể gọi iCustom
với các mức độ chi tiết khác nhau:
iCustom(_Symbol, _Period, 21, PRICE_TYPICAL)
: đặt giá trị cho toàn bộ danh sách tham sốiCustom(_Symbol, _Period, 21)
: đặt tham số đầu tiên, tham số thứ hai bị bỏ qua và sẽ nhận giá trịPRICE_CLOSE
iCustom(_Symbol, _Period)
: cả hai tham số đều bị bỏ qua và sẽ nhận giá trị14
vàPRICE_CLOSE
Bạn không thể bỏ qua một tham số ở đầu hoặc giữa danh sách tham số.
Nếu chỉ báo đang được tạo có dạng ngắn của OnCalculate
, thì tham số bổ sung cuối cùng (ngoài danh sách các biến đầu vào được mô tả bên trong chỉ báo) có thể là loại giá được sử dụng để xây dựng chỉ báo. Nó giống như danh sách thả xuống Apply to
trong hộp thoại thuộc tính chỉ báo. Ngoài ra, trong tham số bổ sung này, bạn có thể truyền một tay cầm của một chỉ báo khác đã được tạo trước đó (xem ví dụ dưới đây). Trong trường hợp này, chỉ báo mới được tạo sẽ được tính toán bằng cách sử dụng bộ đệm đầu tiên của chỉ báo với tay cầm được chỉ định. Nói cách khác, lập trình viên có thể thiết lập việc tính toán của một chỉ báo từ một chỉ báo khác.
MQL5 không cung cấp phương tiện lập trình để tìm hiểu liệu một chỉ báo bên thứ ba cụ thể được triển khai bằng dạng ngắn hay dạng dài của
OnCalculate
, tức là liệu có được phép truyền một tay cầm bổ sung khi tạo quaiCustom
hay không. Ngoài ra, MQL5 không cho phép chọn số bộ đệm nếu chỉ báo được xác định bởi tay cầm bổ sung có nhiều bộ đệm.
Quay lại tham số pathname
.
Đường dẫn là một chuỗi chứa ít nhất một dấu gạch chéo ngược (\
) hoặc dấu gạch chéo xuôi (/
), là một ký tự đặc biệt được sử dụng trong hệ thống tệp như một dấu phân cách trong hệ thống phân cấp thư mục và tệp. Bạn có thể sử dụng dấu gạch chéo xuôi hoặc ngược, nhưng dấu gạch chéo ngược yêu cầu "thoát ký tự", nghĩa là phải được viết hai lần. Điều này là do dấu gạch chéo ngược là một ký tự điều khiển tạo ra nhiều mã dịch vụ, chẳng hạn như tabulation (\t
), xuống dòng (\n
), v.v. (xem phần Loại ký tự).
Nếu đường dẫn bắt đầu bằng một dấu gạch chéo, nó được gọi là tuyệt đối, và thư mục gốc của nó là thư mục của tất cả các mã nguồn MQL5. Ví dụ, chỉ định chuỗi /MyIndicator
trong tham số pathname
sẽ tìm kiếm tệp MQL5/MyIndicator.ex5
, và đường dẫn dài hơn với thư mục /Exercise/MyIndicator
sẽ tham chiếu đến MQL5/Exercise/MyIndicator.ex5
.
Nếu tham số pathname
chứa một hoặc nhiều dấu gạch chéo nhưng không bắt đầu bằng một dấu, thì đường dẫn được gọi là tương đối vì nó được xem xét tương đối so với một trong hai vị trí được xác định trước. Đầu tiên, tệp chỉ báo được tìm kiếm tương đối so với thư mục nơi chương trình MQL gọi được đặt. Nếu không tìm thấy ở đó, thì việc tìm kiếm tiếp tục bên trong thư mục chung của các chỉ báo MQL5/Indicators
.
Trong một dòng có dấu gạch chéo, đoạn nằm ở bên phải của dấu gạch chéo cuối cùng được coi là tên tệp, và tất cả các đoạn trước đó mô tả hệ thống phân cấp thư mục. Ví dụ, đường dẫn Folder/SubFolder/Filename
khớp với hai thư mục con: SubFolder
bên trong Folder
, và tệp Filename
bên trong SubFolder
.
Trường hợp đơn giản nhất là khi pathname
không chứa dấu gạch chéo. Theo cách này, nó chỉ chỉ định tên tệp. Nó cũng được xem xét trong bối cảnh hai điểm bắt đầu tìm kiếm được đề cập ở trên.
Ví dụ, Expert Advisor MyExpert.ex5
nằm trong thư mục MQL5/Experts/Examples
, và nó chứa lời gọi của iCustom(_Symbol, _Period, "MyIndicator")
. Ở đây đường dẫn tương đối bị thoái hóa (trống) và chỉ có tên tệp hiện diện. Do đó, việc tìm kiếm chỉ báo bắt đầu từ thư mục MQL5/Experts/Examples/
và tên MyIndicator
, điều này cho ra MQL5/Experts/Examples/MyIndicator.ex5
. Nếu không tìm thấy chỉ báo như vậy trong thư mục này, việc tìm kiếm sẽ tiếp tục trong thư mục gốc của các chỉ báo, tức là bằng đường dẫn và tên được kết nối MQL5/Indicators/MyIndicator.ex5
.
Nếu chỉ báo không được tìm thấy ở cả hai nơi, hàm sẽ trả về INVALID_HANDLE
và đặt mã lỗi 4802 (ERR_INDICATOR_CANNOT_CREATE
) vào _LastError
.
Trường hợp khó hơn là nếu pathname
chứa không chỉ tên mà còn thư mục, ví dụ TradeSignals/MyIndicator
. Đường dẫn được chỉ định sau đó được thêm vào thư mục của chương trình gọi, dẫn đến mục tiêu tìm kiếm sau: MQL5/Experts/Examples/TradeSignals/MyIndicator.ex5
. Sau đó, nếu thất bại, cùng đường dẫn đó được thêm vào MQL5/Indicators
, tức là tệp được tìm kiếm MQL5/Indicators/TradeSignals/MyIndicator.ex5
. Vui lòng lưu ý rằng nếu bạn sử dụng dấu gạch chéo ngược làm dấu phân cách, bạn không nên quên viết nó hai lần, ví dụ, iCustom(_Symbol, _Period, "TradeSignals\\MyIndicator")
.
Để giải phóng bộ nhớ máy tính khỏi một chỉ báo không còn được sử dụng, hãy sử dụng hàm IndicatorRelease
bằng cách truyền tay cầm của chỉ báo này vào đó.
Cần chú ý đặc biệt đến việc kiểm tra một chương trình sử dụng chỉ báo. Nếu tham số pathname
trong lời gọi iCustom
được chỉ định dưới dạng chuỗi hằng số, thì chỉ báo cần thiết tương ứng sẽ tự động được trình biên dịch phát hiện và truyền đến trình kiểm tra cùng với chương trình đang được kiểm tra. Ngược lại, nếu tham số được tính toán trong một biểu thức hoặc thu thập từ bên ngoài (ví dụ, qua input
từ người dùng), bạn phải chỉ định thuộc tính trong mã nguồn #property tester_indicator
:
#property tester_indicator "indicator_name.ex5"
Điều này có nghĩa là chỉ các chỉ báo tùy chỉnh đã biết trước đó mới có thể được kiểm tra trong các chương trình.
Hãy xem xét một ví dụ về một chỉ báo mới UseWPR1.mq5
, mà bên trong trình xử lý OnInit
của nó, sẽ tạo một tay cầm của chỉ báo IndWPR
mà chúng ta đã thảo luận trong chương trước (đừng quên biên dịch IndWPR
vì iCustom
tải các tệp ex5). Tay cầm nhận được trong UseWPR1
chưa được sử dụng theo bất kỳ cách nào vì chúng ta sẽ chỉ nghiên cứu khả năng này và kiểm tra dấu hiệu thành công. Do đó, chúng ta không cần bộ đệm trong chỉ báo mới.
#property indicator_separate_window
#property indicator_buffers 0
#property indicator_plots 0
2
3
Chỉ báo sẽ tạo một cửa sổ phụ trống nhưng chưa hiển thị bất cứ điều gì trong đó. Đây là hành vi bình thường.
Hãy kiểm tra một số tùy chọn để lấy mô tả, với các giá trị khác nhau của pathname
:
- Một đường dẫn tuyệt đối bắt đầu bằng dấu gạch chéo và do đó bao gồm toàn bộ hệ thống phân cấp thư mục (bắt đầu từ MQL5) với các ví dụ về chỉ báo của Chương 5, tức là
/Indicators/MQL5Book/p5/IndWPR
- Chỉ có tên
IndWPR
để tìm kiếm trong cùng thư mục nơi chỉ báo gọiUseWPR1.mq5
được đặt (cả hai chỉ báo đều được cung cấp trong cùng một thư mục) - Đường dẫn với hệ thống phân cấp thư mục của các ví dụ chỉ báo tương đối so với thư mục tiêu chuẩn
MQL5/Indicators
, tức làMQL5Book/p5/IndWPR
(lưu ý rằng không có dấu gạch chéo ở đầu) - Chỉ có tên như ở điểm 2 nhưng cho chỉ báo không tồn tại
IndWPR NonExistent
- Đường dẫn tuyệt đối như ở điểm 1 nhưng với các dấu gạch chéo ngược không thoát ký tự, tức là
\Indicators\MQL5Book\p5\IndWPR
- Sao chép hoàn toàn điểm 2.
int OnInit()
{
int handle1 = PRTF(iCustom(_Symbol, _Period, "/Indicators/MQL5Book/p5/IndWPR"));
int handle2 = PRTF(iCustom(_Symbol, _Period, "IndWPR"));
int handle3 = PRTF(iCustom(_Symbol, _Period, "MQL5Book/p5/IndWPR"));
int handle4 = PRTF(iCustom(_Symbol, _Period, "IndWPR NonExistent"));
int handle5 = PRTF(iCustom(_Symbol, _Period, "\Indicators\MQL5Book\p5\IndWPR"));
int handle6 = PRTF(iCustom(_Symbol, _Period, "IndWPR"));
return INIT_SUCCEEDED;
}
2
3
4
5
6
7
8
9
10
Vì các biến tay cầm không được sử dụng, chúng được khai báo cục bộ. Hãy giải thích cụ thể rằng mặc dù các biến handle
cục bộ bị xóa khi thoát khỏi OnInit
, điều này không ảnh hưởng đến các tay cầm: chúng tiếp tục tồn tại miễn là chỉ báo "cha" UseWPR
được thực thi. Chúng ta chỉ mất giá trị của các tay cầm này trong mã của mình, điều này không phải là vấn đề, vì chúng không được sử dụng ở đây. Trong các ví dụ chỉ báo thực tế mà chúng ta sẽ xem xét sau, các tay cầm tất nhiên được lưu trữ (thường trong các biến toàn cục) và sử dụng.
Đừng lo lắng về việc rò rỉ tài nguyên: khi xóa chỉ báo UseWPR
khỏi biểu đồ, tất cả các tay cầm do nó tạo ra sẽ tự động được dọn sạch bởi terminal. Các nguyên tắc và sự cần thiết của việc giải phóng tay cầm rõ ràng sẽ được mô tả chi tiết hơn trong phần về xóa các phiên bản chỉ báo bằng cách sử dụng IndicatorRelease
.
Mã OnInit
ở trên tạo ra các mục nhập nhật ký sau:
iCustom(_Symbol,_Period,/Indicators/MQL5Book/p5/IndWPR)=10 / ok
iCustom(_Symbol,_Period,IndWPR)=11 / ok
iCustom(_Symbol,_Period,MQL5Book/p5/IndWPR)=12 / ok
cannot load custom indicator 'IndWPR NonExistent' [4802]
iCustom(_Symbol,_Period,IndWPR NonExistent)=-1 / INDICATOR_CANNOT_CREATE(4802)
iCustom(_Symbol,_Period,\Indicators\MQL5Book\p5\IndWPR)=13 / ok
iCustom(_Symbol,_Period,IndWPR)=11 / ok
2
3
4
5
6
7
Như chúng ta có thể thấy, các tay cầm có ý nghĩa 10, 11, 12 và 13 được nhận trong tất cả các trường hợp trừ trường hợp thứ 4, với một chỉ báo được gọi không tồn tại. Giá trị của tay cầm là -1 (INVALID_HANDLE
).
Cũng lưu ý rằng dòng thứ 5 tạo ra một số cảnh báo "chuỗi thoát ký tự không được nhận diện" khi biên dịch. Đây là hậu quả của việc chúng ta không thoát ký tự dấu gạch chéo ngược. Và chúng ta cũng may mắn rằng lệnh được thực thi thành công, vì nếu tên của bất kỳ thư mục hoặc tệp nào bắt đầu bằng một trong những chữ cái trong các chuỗi thoát được hỗ trợ, thì việc giải thích chuỗi sẽ vi phạm cách đọc tên dự kiến. Ví dụ, nếu chúng ta có một chỉ báo tên là test
trong cùng thư mục và cố gắng tạo nó qua đường dẫn MQL5Book\p5\test
, chúng ta sẽ nhận được INVALID_HANDLE
và lỗi 4802. Điều này là do \t
là ký tự tab, vì vậy terminal sẽ tìm kiếm MQL5Book\p5<nbsp> est
. Ghi đúng phải là MQL5Book\\p5\\test
. Do đó, sử dụng dấu gạch chéo xuôi sẽ dễ hơn.
Cũng cần lưu ý rằng mặc dù tất cả các biến thể thành công đều tham chiếu đến cùng một chỉ báo MQL5/Indicators/MQL5Book/p5/IndWPR.ex5
, và thực tế các đường dẫn 1, 2, 3 và 5 là tương đương, terminal coi chúng như các chuỗi khác nhau, đó là lý do tại sao chúng ta nhận được các giá trị mô tả khác nhau. Và chỉ tùy chọn 6, hoàn toàn sao chép tùy chọn 2, trả về một mô tả giống hệt - 11.
Tại sao đánh số tay cầm bắt đầu từ 10? Các giá trị nhỏ hơn được dành sẵn cho hệ thống. Như đã đề cập ở trên, đối với các chỉ báo có dạng ngắn của OnCalculate
, tham số cuối cùng có thể được sử dụng để truyền loại giá hoặc tay cầm của một chỉ báo khác, bộ đệm của nó sẽ được sử dụng để tính toán phiên bản mới được tạo. Vì các phần tử của liệt kê ENUM_APPLIED_PRICE
có các giá trị hằng số riêng, chúng chiếm khu vực dưới 10. Để biết thêm chi tiết, vui lòng xem Xác định nguồn dữ liệu cho một chỉ báo.
Trong ví dụ tiếp theo của UseWPR2.mq5
, chúng ta sẽ triển khai một chỉ báo sẽ tạo một phiên bản của IndWPR
và sẽ kiểm tra tiến trình tính toán của nó bằng cách sử dụng tay cầm. Nhưng để làm điều này, bạn cần làm quen với hàm mới BarsCalculated
.