Kiểm tra đa tiền tệ
Như bạn đã biết, tester MetaTrader 5 cho phép kiểm tra các chiến lược giao dịch trên nhiều công cụ tài chính. Về mặt kỹ thuật, tùy thuộc vào tài nguyên phần cứng của máy tính, có thể mô phỏng giao dịch đồng thời cho tất cả các công cụ có sẵn.
Việc kiểm tra các chiến lược như vậy đặt ra một số yêu cầu kỹ thuật bổ sung đối với tester:
- Tạo chuỗi tick cho tất cả các công cụ
- Tính toán chỉ báo cho tất cả các công cụ
- Tính toán yêu cầu ký quỹ và mô phỏng các điều kiện giao dịch khác cho tất cả các công cụ
Tester tự động tải xuống lịch sử của các công cụ cần thiết từ terminal khi truy cập lịch sử lần đầu tiên. Nếu terminal không chứa lịch sử cần thiết, nó sẽ yêu cầu từ máy chủ giao dịch. Do đó, trước khi kiểm tra một Expert Advisor đa tiền tệ, nên chọn các công cụ cần thiết trong Market Watch
của terminal và tải xuống lượng dữ liệu mong muốn.
Tác nhân tải lịch sử còn thiếu với một khoảng dự phòng nhỏ để cung cấp dữ liệu cần thiết cho việc tính toán chỉ báo hoặc sao chép bởi Expert Advisor tại thời điểm kiểm tra. Lượng lịch sử tối thiểu tải từ máy chủ giao dịch phụ thuộc vào khung thời gian. Ví dụ, đối với khung thời gian D1 trở xuống, là một năm. Nói cách khác, lịch sử sơ bộ được tải từ đầu năm trước so với ngày bắt đầu tester. Điều này cung cấp ít nhất 1 năm lịch sử nếu kiểm tra được yêu cầu từ ngày 1 tháng 1 và tối đa gần hai năm nếu kiểm tra được yêu cầu từ tháng 12. Đối với khung thời gian hàng tuần, lịch sử 100 thanh được yêu cầu, tức là khoảng hai năm (có 52 tuần trong một năm). Khi kiểm tra trên khung thời gian hàng tháng, tác nhân sẽ yêu cầu 100 tháng (tương đương với lịch sử khoảng 8 năm: 12 tháng * 8 năm = 96). Trong mọi trường hợp, trên các khung thời gian thấp hơn khung thời gian làm việc, sẽ có số lượng thanh lớn hơn tương ứng. Nếu dữ liệu hiện có không đủ cho độ sâu lịch sử sơ bộ đã xác định, sự kiện này sẽ được ghi lại trong nhật ký kiểm tra.
Bạn không thể cấu hình (thay đổi) hành vi này. Do đó, nếu bạn cần cung cấp một số lượng thanh lịch sử cụ thể của khung thời gian hiện tại ngay từ đầu, bạn nên đặt ngày bắt đầu kiểm tra sớm hơn và sau đó "chờ" trong mã Expert Advisor đến ngày bắt đầu giao dịch cần thiết hoặc đủ số lượng thanh. Trước đó, bạn nên bỏ qua tất cả các sự kiện.
Tester cũng mô phỏng Market Watch
của riêng nó, từ đó chương trình có thể lấy thông tin về các công cụ. Theo mặc định, khi bắt đầu kiểm tra, Market Watch
của tester chỉ chứa một biểu tượng: biểu tượng mà việc kiểm tra được bắt đầu. Tất cả các biểu tượng bổ sung được thêm vào Market Watch
của tester tự động khi truy cập chúng thông qua các hàm API. Khi truy cập lần đầu vào một biểu tượng "bên thứ ba" từ chương trình MQL, tác nhân kiểm tra sẽ đồng bộ hóa dữ liệu biểu tượng với terminal.
Dữ liệu của các biểu tượng bổ sung có thể được truy cập trong các trường hợp sau:
Sử dụng các chỉ báo kỹ thuật,
iCustom
, hoặcIndicatorCreate
cho cặp biểu tượng/khung thời gianTruy vấn
Market Watch
của biểu tượng khác:SeriesInfoInteger
Bars
SymbolSelect
SymbolIsSynchronized
SymbolInfoDouble
SymbolInfoInteger
SymbolInfoString
SymbolInfoTick
SymbolInfoSessionQuote
SymbolInfoSessionTrade
MarketBookAdd
MarketBookGet
Truy vấn chuỗi thời gian của cặp biểu tượng/khung thời gian bằng các hàm sau:
CopyBuffer
CopyRates
CopyTime
CopyOpen
CopyHigh
CopyLow
CopyClose
CopyTickVolume
CopyRealVolume
CopySpread
Ngoài ra, bạn có thể yêu cầu lịch sử rõ ràng cho các biểu tượng mong muốn bằng cách gọi hàm SymbolSelect
trong trình xử lý OnInit
. Lịch sử sẽ được tải trước khi kiểm tra Expert Advisor bắt đầu.
Tại thời điểm một biểu tượng khác được truy cập lần đầu tiên, quá trình kiểm tra dừng lại và lịch sử của cặp biểu tượng/khung thời gian được tải từ terminal vào tác nhân kiểm tra. Việc tạo chuỗi tick cũng được kích hoạt tại thời điểm này.
Mỗi công cụ tạo ra chuỗi tick riêng theo chế độ tạo tick đã đặt.
Việc đồng bộ hóa các thanh của các biểu tượng khác nhau đặc biệt quan trọng khi triển khai Expert Advisors đa tiền tệ vì tính đúng đắn của các phép tính phụ thuộc vào điều này. Một trạng thái được coi là đồng bộ khi các thanh cuối cùng của tất cả các biểu tượng được sử dụng có cùng thời gian mở.
Tester tạo và phát chuỗi tick của nó cho mỗi công cụ. Đồng thời, một thanh mới trên mỗi công cụ được mở bất kể các thanh được mở như thế nào trên các công cụ khác. Điều này có nghĩa là khi kiểm tra một Expert Advisor đa tiền tệ, có thể xảy ra tình huống (và thường xuyên xảy ra) khi một thanh mới đã mở trên một công cụ, nhưng chưa mở trên công cụ khác.
Ví dụ, nếu chúng ta đang kiểm tra một Expert Advisor sử dụng dữ liệu biểu tượng EURUSD và một cây nến hàng giờ mới đã mở cho biểu tượng này, chúng ta sẽ nhận được sự kiện OnTick
. Nhưng đồng thời, không có gì đảm bảo rằng một cây nến mới đã mở trên GBPUSD, mà chúng ta cũng có thể đang sử dụng.
Do đó, thuật toán đồng bộ hóa ngụ ý rằng bạn cần kiểm tra báo giá của tất cả các công cụ và đợi thời gian mở của các thanh cuối cùng bằng nhau.
Điều này không gây ra bất kỳ câu hỏi nào miễn là chế độ kiểm tra tick thực, mô phỏng tất cả các tick, hoặc OHLC M1 được sử dụng. Với các chế độ này, một số lượng tick đủ được tạo ra trong một cây nến để đợi thời điểm đồng bộ hóa các thanh từ các biểu tượng khác nhau. Chỉ cần hoàn thành hàm OnTick
và kiểm tra sự xuất hiện của thanh mới trên GBPUSD tại tick tiếp theo. Nhưng khi kiểm tra ở chế độ "Chỉ giá mở", sẽ không có tick khác, vì Expert Advisor chỉ được gọi một lần cho mỗi thanh, và có vẻ như chế độ này không phù hợp để kiểm tra Expert Advisors đa tiền tệ. Trên thực tế, tester cho phép phát hiện thời điểm một thanh mới mở trên biểu tượng khác bằng hàm Sleep
(trong vòng lặp) hoặc bộ đếm thời gian.
Đầu tiên, hãy xem xét một ví dụ về Expert Advisor SyncBarsBySleep.mq5
, thể hiện việc đồng bộ hóa các thanh thông qua Sleep
.
Một cặp tham số đầu vào cho phép đặt kích thước Pause
tính bằng giây để đợi các thanh của biểu tượng khác, cũng như tên của biểu tượng khác đó (OtherSymbol
), phải khác với biểu tượng biểu đồ.
input uint Pause = 1; // Pause (seconds)
input string OtherSymbol = "USDJPY";
2
Để xác định các mẫu trong độ trễ của thời gian mở thanh, chúng ta mô tả một lớp đơn giản BarTimeStatistics
. Nó chứa một trường để đếm tổng số thanh (total
) và số thanh mà ban đầu không có đồng bộ hóa (late
), tức là biểu tượng khác bị trễ.
class BarTimeStatistics
{
public:
int total;
int late;
BarTimeStatistics(): total(0), late(0) { }
~BarTimeStatistics()
{
PrintFormat("%d bars on %s was late among %d total bars on %s (%2.1f%%)",
late, OtherSymbol, total, _Symbol, late * 100.0 / total);
}
};
2
3
4
5
6
7
8
9
10
11
12
13
14
Đối tượng của lớp này in thống kê nhận được trong hàm hủy của nó. Vì chúng ta sẽ làm đối tượng này tĩnh, báo cáo sẽ được in vào cuối bài kiểm tra.
Nếu chế độ tạo tick được chọn trong tester khác với giá mở, chúng ta sẽ phát hiện điều này bằng hàm getTickModel
đã xem xét trước đó và sẽ trả về một cảnh báo.
void OnTick()
{
const TICK_MODEL model = getTickModel();
if(model != TICK_MODEL_OPEN_PRICES)
{
static bool shownOnce = false;
if(!shownOnce)
{
Print("This Expert Advisor is intended to run in \"Open Prices\" mode");
shownOnce = true;
}
}
2
3
4
5
6
7
8
9
10
11
12
Tiếp theo, OnTick
cung cấp thuật toán đồng bộ hóa hoạt động.
// time of the last known bar for _Symbol
static datetime lastBarTime = 0;
// attribute of synchronization
static bool synchronized = false;
// bar counters
static BarTimeStatistics stats;
const datetime currentTime = iTime(_Symbol, _Period, 0);
// if it is executed for the first time or the bar has changed, save the bar
if(lastBarTime != currentTime)
{
stats.total++;
lastBarTime = currentTime;
PrintFormat("Last bar on %s is %s", _Symbol, TimeToString(lastBarTime));
synchronized = false;
}
// time of the last known bar for another symbol
datetime otherTime;
bool late = false;
// wait until the times of two bars become the same
while(currentTime != (otherTime = iTime(OtherSymbol, _Period, 0)))
{
late = true;
PrintFormat("Wait %d seconds...", Pause);
Sleep(Pause * 1000);
}
if(late) stats.late++;
// here we are after synchronization, save the new status
if(!synchronized)
{
// use TimeTradeServer() because TimeCurrent() does not change in the absence of ticks
Print("Bars are in sync at ", TimeToString(TimeTradeServer(),
TIME_DATE | TIME_SECONDS));
// no longer print a message until the next out of sync
synchronized = true;
}
// here is your synchronous algorithm
// ...
}
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
Hãy thiết lập tester để chạy Expert Advisor trên EURUSD, H1, là công cụ có tính thanh khoản cao nhất. Hãy sử dụng các tham số mặc định của Expert Advisor, tức là USDJPY sẽ là biểu tượng "khác".
Kết quả của bài kiểm tra, nhật ký sẽ chứa các mục sau (chúng ta cố ý hiển thị các nhật ký liên quan đến việc tải lịch sử USDJPY, xảy ra trong lần gọi iTime
đầu tiên).
2022.04.15 00:00:00 Last bar on EURUSD is 2022.04.15 00:00
USDJPY: load 27 bytes of history data to synchronize in 0:00:00.001
USDJPY: history synchronized from 2020.01.02 to 2022.04.20
USDJPY,H1: history cache allocated for 8109 bars and contains 8006 bars from 2021.01.04 00:00 to 2022.04.14 23:00
USDJPY,H1: 1 bar from 2022.04.15 00:00 added
USDJPY,H1: history begins from 2021.01.04 00:00
2022.04.15 00:00:00 Bars are in sync at 2022.04.15 00:00:00
2022.04.15 01:00:00 Last bar on EURUSD is 2022.04.15 01:00
2022.04.15 01:00:00 Wait 1 seconds...
2022.04.15 01:00:01 Bars are in sync at 2022.04.15 01:00:01
2022.04.15 02:00:00 Last bar on EURUSD is 2022.04.15 02:00
2022.04.15 02:00:00 Wait 1 seconds...
2022.04.15 02:00:01 Bars are in sync at 2022.04.15 02:00:01
...
2022.04.20 23:59:59 95 bars on USDJPY was late among 96 total bars on EURUSD (99.0%)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Bạn có thể thấy rằng các thanh USDJPY thường xuyên bị trễ. Nếu bạn chọn USDJPY, H1 trong cài đặt tester và EURUSD trong tham số Expert Advisor, bạn sẽ nhận được bức tranh ngược lại.
2022.04.15 00:00:00 Last bar on USDJPY is 2022.04.15 00:00
EURUSD: load 27 bytes of history data to synchronize in 0:00:00.002
EURUSD: history synchronized from 2018.01.02 to 2022.04.20
EURUSD,H1: history cache allocated for 8109 bars and contains 8006 bars from 2021.01.04 00:00 to 2022.04.14 23:00
EURUSD,H1: 1 bar from 2022.04.15 00:00 added
EURUSD,H1: history begins from 2021.01.04 00:00
2022.04.15 00:00:00 Bars are in sync at 2022.04.15 00:00:00
2022.04.15 01:00:00 Last bar on USDJPY is 2022.04.15 01:00
2022.04.15 01:00:00 Wait 1 seconds...
2022.04.15 01:00:01 Bars are in sync at 2022.04.15 01:00:01
2022.04.15 02:00:00 Last bar on USDJPY is 2022.04.15 02:00
2022.04.15 02:00:00 Wait 1 seconds...
2022.04.15 02:00:01 Bars are in sync at 2022.04.15 02:00:01
...
2022.04.20 23:59:59 23 bars on EURUSD was late among 96 total bars on USDJPY (24.0%)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Ở đây, trong hầu hết các trường hợp, không cần phải đợi: các thanh EURUSD đã tồn tại tại thời điểm thanh USDJPY được hình thành.
Có một cách khác để đồng bộ hóa các thanh: sử dụng bộ đếm thời gian. Một ví dụ về Expert Advisor như vậy, SyncBarsByTimer.mq5
, được bao gồm trong sách. Lưu ý rằng các sự kiện bộ đếm thời gian, theo quy luật, xảy ra bên trong thanh (vì xác suất trúng chính xác thời điểm bắt đầu là rất thấp). Do đó, các thanh hầu như luôn được đồng bộ hóa.
Chúng ta cũng có thể nhắc bạn về khả năng đồng bộ hóa các thanh bằng chỉ báo gián điệp EventTickSpy.mq5
, nhưng nó dựa trên các sự kiện tùy chỉnh chỉ hoạt động khi kiểm tra trực quan. Ngoài ra, đối với các chỉ báo như vậy yêu cầu phản hồi trên mỗi tick, điều quan trọng là sử dụng chỉ thị #property tester_everytick_calculate
. Chúng ta đã nói về nó trong phần Kiểm tra chỉ báo, và chúng ta sẽ nhắc lại một lần nữa trong phần về các chỉ thị tester cụ thể.