Tạo tick trong tester
Sự hiện diện của trình xử lý OnTick
trong Expert Advisor không phải là bắt buộc để nó được kiểm tra trong tester. Expert Advisor có thể sử dụng một hoặc nhiều hàm quen thuộc khác:
OnTick
— trình xử lý sự kiện cho việc đến của một tick mớiOnTrade
— trình xử lý sự kiện giao dịchOnTradeTransaction
— trình xử lý giao dịchOnTimer
— trình xử lý tín hiệu bộ đếm thời gianOnChartEvent
— trình xử lý sự kiện trên biểu đồ, bao gồm các biểu đồ tùy chỉnh
Đồng thời, bên trong tester, tương đương chính của dòng thời gian là một chuỗi các tick, chứa không chỉ thay đổi giá mà còn thời gian chính xác đến mili giây. Do đó, để kiểm tra Expert Advisors, cần phải tạo ra các chuỗi tick. Tester MetaTrader 5 có 4 chế độ tạo tick:
- Tick thực (nếu lịch sử của chúng được cung cấp bởi nhà môi giới)
- Mọi tick (mô phỏng dựa trên báo giá khung thời gian M1 có sẵn)
- Giá OHLC từ thanh phút (1 Minute OHLC)
- Chỉ giá mở (1 tick mỗi thanh)
Một chế độ hoạt động khác — tính toán toán học — chúng ta sẽ phân tích sau vì nó không liên quan đến báo giá và tick.
Bất kể người dùng chọn chế độ nào trong 4 chế độ, terminal sẽ tải dữ liệu lịch sử có sẵn để kiểm tra. Nếu chế độ tick thực được chọn, và nhà môi giới không có chúng cho công cụ này, thì chế độ "Mọi tick" sẽ được sử dụng. Tester thể hiện tính chất của việc tạo tick trong báo cáo của nó bằng đồ họa và phần trăm (nơi 100% có nghĩa là tất cả các tick đều là thực).
Lịch sử của công cụ được chọn trong cài đặt tester được đồng bộ hóa và tải xuống bởi terminal từ máy chủ giao dịch trước khi bắt đầu quá trình kiểm tra. Đồng thời, lần đầu tiên, terminal tải lịch sử từ máy chủ giao dịch đến độ sâu cần thiết (với một biên độ nhất định, tùy thuộc vào khung thời gian, ít nhất 1 năm trước khi bắt đầu kiểm tra), để không phải yêu cầu lại sau này. Trong tương lai, chỉ việc tải dữ liệu mới sẽ xảy ra. Tất cả điều này được kèm theo các thông báo tương ứng trong nhật ký của tester.
Tác nhân kiểm tra nhận lịch sử của công cụ được kiểm tra từ terminal khách ngay sau khi kiểm tra bắt đầu. Nếu quá trình kiểm tra sử dụng dữ liệu trên các công cụ khác (ví dụ, đây là một Expert Advisor đa tiền tệ), thì trong trường hợp này, tác nhân kiểm tra yêu cầu lịch sử cần thiết từ terminal khách tại lần gọi đầu tiên. Nếu dữ liệu lịch sử có sẵn trên terminal, chúng sẽ được chuyển ngay lập tức đến các tác nhân kiểm tra. Nếu dữ liệu bị thiếu, terminal sẽ yêu cầu và tải xuống từ máy chủ, sau đó chuyển nó đến các tác nhân kiểm tra.
Các công cụ bổ sung cũng được sử dụng khi giá tỷ giá chéo được tính toán trong các hoạt động giao dịch. Ví dụ, khi kiểm tra một chiến lược trên EURCHF với loại tiền gửi là đô la Mỹ, trước khi xử lý hoạt động giao dịch đầu tiên, tác nhân kiểm tra sẽ yêu cầu lịch sử của EURUSD và USDCHF từ terminal khách, mặc dù chiến lược không trực tiếp đề cập đến các công cụ này.
Về vấn đề này, trước khi kiểm tra một chiến lược đa tiền tệ, nên tải trước tất cả dữ liệu lịch sử cần thiết vào terminal khách. Điều này sẽ giúp tránh các chậm trễ kiểm tra/tối ưu hóa liên quan đến việc tiếp tục dữ liệu. Bạn có thể tải lịch sử, ví dụ, bằng cách mở các biểu đồ tương ứng và cuộn chúng đến đầu lịch sử.
Bây giờ chúng ta hãy xem xét chi tiết hơn về các chế độ tạo tick.
Tick thực từ lịch sử
Kiểm tra và tối ưu hóa trên tick thực gần với điều kiện thực tế nhất có thể. Đây là các tick từ sàn giao dịch và nhà cung cấp thanh khoản.
Nếu có một thanh phút trong lịch sử của biểu tượng, nhưng không có dữ liệu tick cho phút đó, tester sẽ tạo tick ở chế độ "Mọi tick" (xem thêm). Điều này cho phép xây dựng biểu đồ chính xác trong tester trong trường hợp dữ liệu tick không đầy đủ từ nhà môi giới. Hơn nữa, dữ liệu tick có thể không khớp với các thanh phút vì nhiều lý do khác nhau. Ví dụ, do ngắt kết nối hoặc các lỗi khác trong việc truyền dữ liệu từ nguồn đến terminal khách. Khi kiểm tra, dữ liệu phút được coi là đáng tin cậy hơn.
Tick được lưu trữ trong bộ nhớ cache biểu tượng trong tester chiến lược. Kích thước bộ nhớ cache không vượt quá 128,000 tick. Khi các tick mới đến, dữ liệu cũ nhất sẽ bị đẩy ra khỏi nó. Tuy nhiên, sử dụng hàm CopyTicks
, bạn có thể lấy tick ngoài bộ nhớ cache (chỉ khi kiểm tra bằng tick thực). Trong trường hợp này, dữ liệu sẽ được yêu cầu từ cơ sở dữ liệu tick của tester, tương ứng hoàn toàn với cơ sở dữ liệu tương tự của terminal khách. Không có điều chỉnh nào theo thanh phút được thực hiện cho cơ sở này. Do đó, các tick trong đó có thể khác với các tick trong bộ nhớ cache.
Mọi tick (mô phỏng)
Nếu lịch sử tick thực không có sẵn hoặc nếu bạn cần giảm thiểu lưu lượng mạng (vì kho lưu trữ tick thực có thể tiêu tốn tài nguyên đáng kể), bạn có thể chọn tạo tick nhân tạo dựa trên báo giá khung thời gian M1 có sẵn.
Lịch sử báo giá cho các công cụ tài chính được truyền từ máy chủ giao dịch đến terminal khách MetaTrader 5 dưới dạng các khối thanh phút được nén chặt. Quy trình truy vấn lịch sử và xây dựng các khung thời gian cần thiết đã được xem xét chi tiết trong phần Đặc điểm kỹ thuật của tổ chức và lưu trữ chuỗi thời gian.
Yếu tố tối thiểu của lịch sử giá là một thanh phút, từ đó bạn có thể lấy thông tin về bốn giá trị giá OHLC: Open, High, Low và Close.
Một thanh phút mới mở không phải vào thời điểm một phút mới bắt đầu (số giây trở thành 0) mà khi một tick — một thay đổi giá ít nhất một điểm — xảy ra. Tương tự, chúng ta không thể xác định từ thanh với độ chính xác giây khi tick tương ứng với giá đóng của thanh phút này đến: chúng ta chỉ biết giá cuối cùng của thanh một phút, được ghi nhận là giá Close.
Do đó, đối với mỗi thanh phút, chúng ta biết 4 điểm kiểm soát, mà chúng ta có thể chắc chắn rằng giá đã ở đó. Nếu thanh chỉ có 4 tick, thì thông tin này đủ để kiểm tra, nhưng thường, khối lượng tick nhiều hơn 4. Điều này có nghĩa là cần tạo thêm các điểm kiểm soát cho các tick đến giữa các giá Open
, High
, Low
và Close
. Các nguyên tắc cơ bản của việc tạo tick trong chế độ "Mọi tick" được mô tả trong tài liệu.
Khi kiểm tra ở chế độ "Mọi tick", hàm OnTick
của Expert Advisor sẽ được gọi trên mỗi tick được tạo. Expert Advisor sẽ nhận thời gian và giá Ask/Bid/Last
giống như khi làm việc trực tuyến.
Chế độ kiểm tra "Mọi tick" là chính xác nhất (sau chế độ tick thực), nhưng cũng tốn thời gian nhất. Đối với việc đánh giá ban đầu của hầu hết các chiến lược giao dịch, thường đủ để sử dụng một trong hai chế độ kiểm tra đơn giản hóa: tại giá OHLC M1 hoặc tại thời điểm mở thanh của khung thời gian đã chọn.
1 phút OHLC
Ở chế độ "1 phút OHLC", chuỗi tick được xây dựng chỉ bằng giá OHLC của các thanh phút, số lần gọi hàm OnTick
giảm đáng kể; do đó, thời gian kiểm tra cũng giảm. Đây là một chế độ rất hiệu quả, hữu ích, cung cấp sự thỏa hiệp giữa độ chính xác và tốc độ kiểm tra. Tuy nhiên, bạn cần cẩn thận với nó khi sử dụng Expert Advisor của người khác.
Việc từ chối tạo các tick trung gian bổ sung giữa các giá Open
, High
, Low
và Close
dẫn đến sự xuất hiện của tính xác định cứng nhắc trong sự phát triển của giá từ khoảnh khắc giá Open
được xác định. Điều này cho phép tạo ra một "Testing Grail" hiển thị biểu đồ số dư có xu hướng tăng đẹp mắt khi kiểm tra.
Đối với một thanh phút, 4 giá được biết đến, trong đó giá đầu tiên là
Open
, và giá cuối cùng làClose
. Các giá được ghi nhận giữa chúng làHigh
vàLow
, và thông tin về thứ tự xuất hiện của chúng bị mất đi, nhưng chúng ta biết rằng giáHigh
lớn hơn hoặc bằngOpen
, vàLow
nhỏ hơn hoặc bằngOpen
.Sau khi nhận được giá
Open
, chúng ta chỉ cần phân tích tick tiếp theo để xác định xem nó làHigh
hayLow
. Nếu giá thấp hơnOpen
, đây làLow
— mua trên tick này, vì tick tiếp theo sẽ tương ứng với giáHigh
, trên đó chúng ta đóng giao dịch mua và mở một giao dịch bán. Tick tiếp theo là tick cuối cùng trên thanh,Close
, trên đó chúng ta đóng bán.Nếu một tick với giá cao hơn giá mở đến sau giá của chúng ta, thì thứ tự các giao dịch sẽ đảo ngược. Có vẻ như người ta có thể giao dịch trên mỗi thanh trong chế độ này. Khi kiểm tra một Expert Advisor như vậy trên lịch sử, mọi thứ diễn ra hoàn hảo, nhưng trực tuyến nó sẽ thất bại.
Hiệu ứng tương tự có thể xảy ra không chủ ý, do sự kết hợp của các đặc điểm của thuật toán tính toán (ví dụ, tính toán thống kê) và việc tạo tick.
Do đó, luôn quan trọng để kiểm tra nó trong chế độ "Mọi tick" hoặc, tốt hơn, dựa trên tick thực sau khi tìm thấy các cài đặt tối ưu của Expert Advisor trên các chế độ kiểm tra thô ("1 phút OHLC" và "Chỉ giá mở").
Chỉ giá mở
Trong chế độ này, tick được tạo bằng cách sử dụng giá OHLC của khung thời gian được chọn để kiểm tra. Trong trường hợp này, hàm OnTick
chỉ chạy một lần, vào đầu mỗi thanh. Do đặc điểm này, các mức dừng và lệnh chờ có thể được kích hoạt ở mức giá khác với mức đã yêu cầu (đặc biệt khi kiểm tra trên các khung thời gian cao hơn). Đổi lại điều này, chúng ta có cơ hội tiến hành kiểm tra đánh giá nhanh chóng của Expert Advisor.
Ví dụ, Expert Advisor được kiểm tra trên EURUSD H1 trong chế độ "Chỉ giá mở". Trong trường hợp này, tổng số tick (điểm kiểm soát) sẽ nhiều hơn 4 lần so với số thanh giờ nằm trong khoảng thời gian được kiểm tra. Nhưng trong trường hợp này, trình xử lý OnTick
sẽ chỉ được gọi khi mở các thanh giờ. Đối với các tick còn lại ("ẩn" khỏi Expert Advisor), các kiểm tra cần thiết sau đây để kiểm tra chính xác được thực hiện:
- Tính toán yêu cầu ký quỹ
- Kích hoạt
Stop Loss
vàTake Profit
- Kích hoạt các lệnh chờ
- Xóa các lệnh chờ khi hết hạn
Nếu không có vị thế mở hoặc lệnh chờ, thì không cần các kiểm tra này trên các tick ẩn, và tốc độ tăng có thể đáng kể.
Một ngoại lệ khi tạo tick trong chế độ "Chỉ giá mở" là các kỳ W1 và MN1: đối với các khung thời gian này, tick được tạo cho giá OHLC của mỗi ngày, không phải hàng tuần hoặc hàng tháng, tương ứng.
Chế độ "Chỉ giá mở" này rất phù hợp để kiểm tra các chiến lược chỉ thực hiện giao dịch khi mở thanh và không sử dụng lệnh chờ, cũng như không sử dụng mức Stop Loss
và Take Profit
. Đối với lớp chiến lược này, tất cả độ chính xác kiểm tra cần thiết được duy trì.
API MQL5 không cho phép chương trình tìm hiểu nó đang chạy trong chế độ nào trong tester. Đồng thời, điều này có thể quan trọng đối với Expert Advisors hoặc các chỉ báo mà chúng sử dụng, không được thiết kế, ví dụ, để hoạt động chính xác tại giá mở hoặc OHLC. Về vấn đề này, chúng ta triển khai một cơ chế phát hiện chế độ đơn giản. Mã nguồn được đính kèm trong tệp TickModel.mqh
.
Hãy khai báo liệt kê của chúng ta với các chế độ hiện có.
enum TICK_MODEL
{
TICK_MODEL_UNKNOWN = -1, // Unknown (any) // chưa biết/chưa được xác định
TICK_MODEL_REAL = 0, // Real ticks // chất lượng tốt nhất
TICK_MODEL_GENERATED = 1, // Generated ticks // chất lượng tốt
TICK_MODEL_OHLC_M1 = 2, // OHLC M1 // chất lượng chấp nhận được và nhanh
TICK_MODEL_OPEN_PRICES = 3, // Open prices // chất lượng kém hơn, nhưng rất nhanh
TICK_MODEL_MATH_CALC = 4, // Math calculations// không có tick (không xác định)
};
2
3
4
5
6
7
8
9
Trừ phần tử đầu tiên, được dành sẵn cho trường hợp chế độ chưa được xác định hoặc không thể xác định vì lý do nào đó, tất cả các phần tử khác được sắp xếp theo thứ tự giảm dần của chất lượng mô phỏng, bắt đầu từ thực và kết thúc bằng giá mở (đối với chúng, nhà phát triển phải kiểm tra tính tương thích của chiến lược với việc giao dịch chỉ được thực hiện khi mở thanh mới). Chế độ cuối cùng TICK_MODEL_MATH_CALC hoạt động hoàn toàn không có tick; chúng ta sẽ xem xét nó riêng.
Nguyên tắc phát hiện chế độ dựa trên việc kiểm tra sự có sẵn của tick và thời gian của chúng trên hai tick đầu tiên khi bắt đầu kiểm tra. Bản thân việc kiểm tra được bao bọc trong hàm getTickModel
, mà Expert Advisor nên gọi từ trình xử lý OnTick
. Vì việc kiểm tra chỉ được thực hiện một lần, biến tĩnh model được mô tả bên trong hàm, ban đầu được đặt là TICK_MODEL_UNKNOWN. Nó sẽ lưu trữ và chuyển đổi trạng thái hiện tại của việc kiểm tra, cần thiết để phân biệt giữa các chế độ OHLC và giá mở.
TICK_MODEL getTickModel()
{
static TICK_MODEL model = TICK_MODEL_UNKNOWN;
...
2
3
4
Trên tick đầu tiên được phân tích, model bằng TICK_MODEL_UNKNOWN, và một nỗ lực được thực hiện để lấy tick thực bằng cách gọi CopyTicks
.
if(model == TICK_MODEL_UNKNOWN)
{
MqlTick ticks[];
const int n = CopyTicks(_Symbol, ticks, COPY_TICKS_ALL, 0, 10);
if(n == -1)
{
switch(_LastError)
{
case ERR_NOT_ENOUGH_MEMORY: // mô phỏng tick
model = TICK_MODEL_GENERATED;
break;
case ERR_FUNCTION_NOT_ALLOWED: // giá mở và OHLC
if(TimeCurrent() != iTime(_Symbol, _Period, 0))
{
model = TICK_MODEL_OHLC_M1;
}
else if(model == TICK_MODEL_UNKNOWN)
{
model = TICK_MODEL_OPEN_PRICES;
}
break;
}
Print(E2S(_LastError));
}
else
{
model = TICK_MODEL_REAL;
}
}
...
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
Nếu thành công, việc phát hiện ngay lập tức kết thúc bằng cách đặt model thành TICK_MODEL_REAL. Nếu tick thực không có sẵn, hệ thống sẽ trả về một mã lỗi nhất định, theo đó chúng ta có thể rút ra các kết luận sau. Mã lỗi ERR_NOT_ENOUGH_MEMORY tương ứng với chế độ mô phỏng tick. Tại sao mã lại như vậy không hoàn toàn rõ ràng, nhưng đây là một đặc điểm đặc trưng, và chúng ta sử dụng nó ở đây. Trong hai chế độ tạo tick khác, chúng ta sẽ nhận được lỗi ERR_FUNCTION_NOT_ALLOWED.
Bạn có thể phân biệt một chế độ với chế độ kia bằng thời gian tick. Nếu nó không phải là bội số của khung thời gian cho một tick, thì chúng ta đang nói về chế độ OHLC. Tuy nhiên, vấn đề ở đây là tick đầu tiên trong cả hai chế độ có thể được căn chỉnh với thời gian mở thanh. Do đó, chúng ta sẽ nhận được giá trị TICK_MODEL_OPEN_PRICES, nhưng nó cần được làm rõ. Vì vậy, để đưa ra kết luận cuối cùng, cần phân tích thêm một tick nữa (gọi lại hàm trên nó nếu TICK_MODEL_OPEN_PRICES đã được nhận trước đó). Cho trường hợp này, nhánh if
sau được cung cấp bên trong hàm.
else if(model == TICK_MODEL_OPEN_PRICES)
{
if(TimeCurrent() != iTime(_Symbol, _Period, 0))
{
model = TICK_MODEL_OHLC_M1;
}
}
return model;
}
2
3
4
5
6
7
8
9
Hãy kiểm tra hoạt động của bộ phát hiện trong một Expert Advisor đơn giản TickModel.mq5
. Trong tham số đầu vào TickCount
, chúng ta chỉ định số lượng tối đa các tick được phân tích, tức là bao nhiêu lần hàm getTickModel
sẽ được gọi. Chúng ta biết rằng hai là đủ, nhưng để chắc chắn rằng mô hình không thay đổi sau đó, 5 tick được đề xuất mặc định. Chúng ta cũng cung cấp tham số RequireTickModel
hướng dẫn Expert Advisor chấm dứt hoạt động nếu mức mô phỏng thấp hơn mức yêu cầu. Theo mặc định, giá trị của nó là TICK_MODEL_UNKNOWN, có nghĩa là không có hạn chế chế độ.
input int TickCount = 5;
input TICK_MODEL RequireTickModel = TICK_MODEL_UNKNOWN;
2
Trong trình xử lý OnTick
, chúng ta chỉ chạy mã của mình nếu nó hoạt động trong tester.
void OnTick()
{
if(MQLInfoInteger(MQL_TESTER))
{
static int count = 0;
if(count++ < TickCount)
{
// xuất thông tin tick để tham khảo
static MqlTick tick[1];
SymbolInfoTick(_Symbol, tick[0]);
ArrayPrint(tick);
// xác định và hiển thị mô hình (sơ bộ)
const TICK_MODEL model = getTickModel();
PrintFormat("%d %s", count, EnumToString(model));
// nếu bộ đếm tick là 2+, kết luận là cuối cùng và chúng ta hành động dựa trên nó
if(count >= 2)
{
if(RequireTickModel != TICK_MODEL_UNKNOWN
&& RequireTickModel < model) // chất lượng thấp hơn yêu cầu
{
PrintFormat("Tick model is incorrect (%s %sis required), terminating",
EnumToString(RequireTickModel),
(RequireTickModel != TICK_MODEL_REAL ? "or better " : ""));
ExpertRemove(); // kết thúc hoạt động
}
}
}
}
}
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 thử chạy Expert Advisor trong tester với các chế độ tạo tick khác nhau bằng cách chọn tổ hợp phổ biến EURUSD H1.
Tham số RequireTickModel
trong Expert Advisor được đặt thành OHLC M1. Nếu chế độ tester là "Mọi tick", chúng ta sẽ nhận được thông báo tương ứng trong nhật ký, và Expert Advisor sẽ tiếp tục hoạt động.
[time] [bid] [ask] [last] [volume] [time_msc] [flags] [volume_real]
[0] 2022.04.01 00:00:30 1.10656 1.10679 1.10656 0 1648771230000 14 0.00000
NOT_ENOUGH_MEMORY
1 TICK_MODEL_GENERATED
[time] [bid] [ask] [last] [volume] [time_msc] [flags] [volume_real]
[0] 2022.04.01 00:01:00 1.10656 1.10680 1.10656 0 1648771260000 12 0.00000
2 TICK_MODEL_GENERATED
[time] [bid] [ask] [last] [volume] [time_msc] [flags] [volume_real]
[0] 2022.04.01 00:01:30 1.10608 1.10632 1.10608 0 1648771290000 14 0.00000
3 TICK_MODEL_GENERATED
2
3
4
5
6
7
8
9
10
Các chế độ OHLC M1 và tick thực cũng phù hợp, và trong trường hợp sau, sẽ không có mã lỗi.
[time] [bid] [ask] [last] [volume] [time_msc] [flags] [volume_real]
[0] 2022.04.01 00:00:00 1.10656 1.10687 0.0000 0 1648771200122 134 0.00000
1 TICK_MODEL_REAL
[time] [bid] [ask] [last] [volume] [time_msc] [flags] [volume_real]
[0] 2022.04.01 00:00:00 1.10656 1.10694 0.0000 0 1648771200417 4 0.00000
2 TICK_MODEL_REAL
[time] [bid] [ask] [last] [volume] [time_msc] [flags] [volume_real]
[0] 2022.04.01 00:00:00 1.10656 1.10691 0.0000 0 1648771200816 4 0.00000
3 TICK_MODEL_REAL
2
3
4
5
6
7
8
9
Tuy nhiên, nếu bạn thay đổi chế độ trong tester thành "Chỉ giá mở", Expert Advisor sẽ dừng lại sau tick thứ hai.
[time] [bid] [ask] [last] [volume] [time_msc] [flags] [volume_real]
[0] 2022.04.01 00:00:00 1.10656 1.10679 1.10656 0 1648771200000 14 0.00000
FUNCTION_NOT_ALLOWED
1 TICK_MODEL_OPEN_PRICES
[time] [bid] [ask] [last] [volume] [time_msc] [flags] [volume_real]
[0] 2022.04.01 01:00:00 1.10660 1.10679 1.10660 0 1648774800000 14 0.00000
2 TICK_MODEL_OPEN_PRICES
Tick model is incorrect (TICK_MODEL_OHLC_M1 or better is required), terminating
ExpertRemove() function called
2
3
4
5
6
7
8
9
Phương pháp này yêu cầu chạy một bài kiểm tra và chờ vài tick để xác định chế độ. Nói cách khác, chúng ta không thể dừng bài kiểm tra sớm bằng cách trả về lỗi từ OnInit
. Hơn nữa, khi bắt đầu một tối ưu hóa với loại tạo tick sai, chúng ta sẽ không thể dừng tối ưu hóa, điều này chỉ có thể thực hiện từ hàm OnTesterInit
. Do đó, tester sẽ cố gắng hoàn thành tất cả các lượt trong quá trình tối ưu hóa, mặc dù chúng sẽ bị dừng ngay từ đầu. Đây là giới hạn hiện tại của nền tảng.