Thời gian cục bộ và máy chủ
Trên nền tảng MetaTrader 5 luôn tồn tại hai loại thời gian: thời gian cục bộ (khách hàng) và thời gian máy chủ (môi giới).
Thời gian cục bộ tương ứng với thời gian của máy tính mà terminal đang chạy, và tăng liên tục, với tốc độ giống như trong thế giới thực.
Thời gian máy chủ thì diễn biến khác. Cơ sở cho nó được thiết lập bởi thời gian trên máy tính của nhà môi giới, tuy nhiên, khách hàng chỉ nhận được thông tin về nó cùng với các thay đổi giá tiếp theo, được đóng gói thành các cấu trúc đặc biệt gọi là tick (xem phần về MqlTick
) và được truyền đến các chương trình MQL thông qua sự kiện.
Do đó, thời gian máy chủ được cập nhật chỉ trở nên biết đến trong terminal khi có sự thay đổi giá của ít nhất một công cụ tài chính trên thị trường, tức là từ những công cụ được chọn trong cửa sổ Market Watch. Thời gian cuối cùng được biết đến của máy chủ được hiển thị trên thanh tiêu đề của cửa sổ này. Nếu không có tick, thời gian máy chủ trong terminal sẽ đứng yên. Điều này đặc biệt dễ nhận thấy vào cuối tuần và ngày lễ khi tất cả các sàn giao dịch và nền tảng Forex đóng cửa.
Cụ thể, vào Chủ nhật, thời gian máy chủ rất có thể sẽ hiển thị là tối thứ Sáu. Ngoại lệ duy nhất là những phiên bản MetaTrader 5 cung cấp các công cụ giao dịch liên tục như tiền điện tử. Tuy nhiên, ngay cả trong trường hợp này, trong những giai đoạn biến động thấp, thời gian máy chủ có thể chậm hơn đáng kể so với thời gian cục bộ.
Tất cả các hàm trong phần này hoạt động với thời gian có độ chính xác đến giây (độ chính xác của cách biểu diễn thời gian trong kiểu datetime
).
Để lấy thời gian cục bộ và máy chủ, API MQL5 cung cấp ba hàm: TimeLocal
, TimeCurrent
, và TimeTradeServer
. Cả ba hàm này đều có hai phiên bản nguyên mẫu: phiên bản đầu tiên trả về thời gian dưới dạng giá trị kiểu datetime
, và phiên bản thứ hai nhận thêm tham chiếu và điền vào cấu trúc MqlDateTime
với các thành phần thời gian.
datetime TimeLocal()
datetime TimeLocal(MqlDateTime &dt)
Hàm này trả về thời gian cục bộ của máy tính dưới định dạng datetime
.
Điều quan trọng cần lưu ý là thời gian bao gồm Giờ Tiết kiệm Ánh sáng Ban ngày (DST) nếu được bật. Tức là, TimeLocal
bằng thời gian tiêu chuẩn của múi giờ máy tính trừ đi hiệu chỉnh TimeDaylightSavings
. Công thức có thể được biểu diễn một cách có điều kiện như sau:
TimeLocal summer() = TimeLocal winter() - TimeDaylightSavings()
Ở đây, TimeDaylightSavings
thường bằng -3600, tức là dịch chuyển đồng hồ lên 1 giờ (mất 1 giờ). Vì vậy, giá trị mùa hè của TimeLocal
lớn hơn giá trị mùa đông (với cùng thời gian thiên văn trong ngày) so với UTC. Ví dụ, nếu vào mùa đông TimeLocal
bằng UTC+2, thì vào mùa hè nó là UTC+3. UTC có thể được lấy bằng hàm TimeGMT
.
datetime TimeCurrent()
datetime TimeCurrent(MqlDateTime &dt)
Hàm này trả về thời gian máy chủ cuối cùng được biết đến dưới định dạng datetime
. Đây là thời gian đến của báo giá cuối cùng từ danh sách tất cả các công cụ tài chính trong Market Watch. Ngoại lệ duy nhất là trình xử lý sự kiện OnTick
trong Expert Advisors, nơi hàm này sẽ trả về thời gian của tick đang được xử lý (ngay cả khi các tick với thời gian mới hơn đã xuất hiện trong Market Watch).
Cũng cần lưu ý rằng thời gian trên trục ngang của tất cả các biểu đồ trong MetaTrader 5 tương ứng với thời gian máy chủ (trong lịch sử). Thanh cuối cùng (hiện tại, ở bên phải) chứa TimeCurrent
. Xem chi tiết trong phần Biểu đồ.
datetime TimeTradeServer()
datetime TimeTradeServer(MqlDateTime &dt)
Hàm này trả về thời gian hiện tại ước tính của máy chủ giao dịch. Không giống như TimeCurrent
, kết quả của nó có thể không thay đổi nếu không có báo giá mới, TimeTradeServer
cho phép bạn lấy ước tính thời gian máy chủ tăng liên tục. Việc tính toán dựa trên sự khác biệt cuối cùng được biết đến giữa các múi giờ của khách hàng và máy chủ, được cộng vào thời gian cục bộ hiện tại.
Trong trình kiểm tra, giá trị TimeTradeServer
luôn bằng TimeCurrent
.
Ví dụ về cách hoạt động của các hàm được đưa ra trong script TimeCheck.mq5
.
Hàm chính có một vòng lặp vô hạn ghi lại tất cả các loại thời gian mỗi giây cho đến khi người dùng dừng script.
void OnStart()
{
while(!IsStopped())
{
PRTF(TimeLocal());
PRTF(TimeCurrent());
PRTF(TimeTradeServer());
PRTF(TimeTradeServerExact());
Sleep(1000);
}
}
2
3
4
5
6
7
8
9
10
11
Ngoài các hàm tiêu chuẩn, một hàm tùy chỉnh TimeTradeServerExact
được áp dụng ở đây.
datetime TimeTradeServerExact()
{
enum LOCATION
{
LOCAL,
SERVER,
};
static datetime now[2] = {}, then[2] = {};
static int shiftInHours = 0;
static long shiftInSeconds = 0;
// liên tục phát hiện hai dấu thời gian cuối cùng ở đây và ở đó
then[LOCAL] = now[LOCAL];
then[SERVER] = now[SERVER];
now[LOCAL] = TimeLocal();
now[SERVER] = TimeCurrent();
// tại lần gọi đầu tiên, chúng ta chưa có 2 nhãn,
// cần thiết để tính toán sự khác biệt ổn định
if(then[LOCAL] == 0 && then[SERVER] == 0) return 0;
// khi dòng chảy thời gian giống nhau trên khách hàng và máy chủ,
// và máy chủ không bị "đóng băng" do cuối tuần/ngày lễ,
// cập nhật sự khác biệt
if(now[LOCAL] - now[SERVER] == then[LOCAL] - then[SERVER]
&& now[SERVER] != then[SERVER])
{
shiftInSeconds = now[LOCAL] - now[SERVER];
shiftInHours = (int)MathRound(shiftInSeconds / 3600.0);
// in gỡ lỗi
PrintFormat("Shift update: hours: %d; seconds: %lld", shiftInHours, shiftInSeconds);
}
// Lưu ý: Hàm tích hợp TimeTradeServer tính toán như thế này:
// TimeLocal() - shiftInHours * 3600
return (datetime)(TimeLocal() - shiftInSeconds);
}
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
Hàm này cần thiết vì thuật toán của hàm tích hợp TimeTradeServer
có thể không phù hợp với tất cả mọi người. Hàm tích hợp tìm ra sự khác biệt giữa thời gian cục bộ và máy chủ tính bằng giờ (tức là sự khác biệt múi giờ), sau đó lấy thời gian máy chủ như một hiệu chỉnh thời gian cục bộ cho sự khác biệt này. Kết quả là, nếu phút và giây trên khách hàng và máy chủ không đồng bộ (điều này rất có thể xảy ra), phép xấp xỉ tiêu chuẩn của thời gian máy chủ sẽ hiển thị phút và giây của khách hàng, không phải của máy chủ.
Lý tưởng nhất, đồng hồ cục bộ của tất cả các máy tính nên được đồng bộ với thời gian toàn cầu, nhưng trên thực tế, các sai lệch xảy ra. Vì vậy, nếu có dù chỉ một sự dịch chuyển nhỏ ở một trong hai bên, TimeTradeServer
không còn có thể lặp lại thời gian trên máy chủ với độ chính xác cao nhất.
Trong triển khai của chúng ta cho cùng một hàm trong MQL5, chúng ta không làm tròn sự khác biệt giữa thời gian khách hàng và máy chủ thành các múi giờ theo giờ. Thay vào đó, sự khác biệt chính xác tính bằng giây được sử dụng trong phép tính. Đó là lý do tại sao TimeTradeServerExact
trả về thời gian mà phút và giây diễn ra giống như trên máy chủ.
Dưới đây là một ví dụ về nhật ký được tạo bởi script.
TimeLocal()=2021.09.02 16:03:34 / ok
TimeCurrent()=2021.09.02 15:59:39 / ok
TimeTradeServer()=2021.09.02 16:03:34 / ok
TimeTradeServerExact()=1970.01.01 00:00:00 / ok
2
3
4
Có thể thấy rằng các múi giờ của khách hàng và máy chủ giống nhau, nhưng có sự không đồng bộ vài phút (để rõ ràng). Trong lần gọi đầu tiên, TimeTradeServerExact
trả về 0. Sau đó, dữ liệu để tính toán sự khác biệt sẽ đến, và chúng ta sẽ thấy cả bốn loại thời gian, đồng đều "di chuyển" với khoảng cách vài giây.
TimeLocal()=2021.09.02 16:03:35 / ok
TimeCurrent()=2021.09.02 15:59:40 / ok
TimeTradeServer()=2021.09.02 16:03:35 / ok
Shift update: hours: 0; seconds: 235
TimeTradeServerExact()=2021.09.02 15:59:40 / ok
TimeLocal()=2021.09.02 16:03:36 / ok
TimeCurrent()=2021.09.02 15:59:41 / ok
TimeTradeServer()=2021.09.02 16:03:36 / ok
Shift update: hours: 0; seconds: 235
TimeTradeServerExact()=2021.09.02 15:59:41 / ok
TimeLocal()=2021.09.02 16:03:37 / ok
TimeCurrent()=2021.09.02 15:59:41 / ok
TimeTradeServer()=2021.09.02 16:03:37 / ok
TimeTradeServerExact()=2021.09.02 15:59:42 / ok
TimeLocal()=2021.09.02 16:03:38 / ok
TimeCurrent()=2021.09.02 15:59:43 / ok
TimeTradeServer()=2021.09.02 16:03:38 / ok
TimeTradeServerExact()=2021.09.02 15:59:43 / ok
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18