Đọc giá, khối lượng, chênh lệch giá và thời gian theo chỉ số thanh
Đôi khi bạn cần tìm hiểu thông tin không phải về một chuỗi thanh mà chỉ về một thanh duy nhất. Về lý thuyết, điều này có thể được thực hiện bằng cách sử dụng các hàm Copy
đã được thảo luận trước đó, chỉ định trong đó số lượng (tham số count
) bằng 1, nhưng điều này không thực sự tiện lợi. Một phiên bản đơn giản hơn được cung cấp bởi các hàm sau, trả về một giá trị của một loại cụ thể cho một thanh theo số thứ tự của nó trong chuỗi thời gian.
Tất cả các hàm có nguyên mẫu tương tự nhưng khác nhau về tên và loại trả về. Theo lịch sử, tên bắt đầu bằng tiền tố i
, tức là có dạng iValue
(các hàm này thuộc về một nhóm lớn các chỉ báo kỹ thuật tích hợp sẵn: sau cùng, các đặc điểm của báo giá là nguồn chính cho phân tích kỹ thuật, và hầu hết các chỉ báo đều là dẫn xuất của chúng, do đó có chữ i
).
type iValue(const string symbol, ENUM_TIMEFRAMES timeframe, int offset)
Ở đây, type
tương ứng với một trong các loại datetime
, double
, long
, hoặc int
, tùy thuộc vào hàm cụ thể. Ký hiệu và khung thời gian xác định chuỗi thời gian được yêu cầu. Chỉ số thanh cần thiết offset
được truyền theo ký hiệu chuỗi thời gian: 0 có nghĩa là thanh gần nhất, thanh bên phải (thường chưa hoàn thành), và các số lớn hơn có nghĩa là các thanh cũ hơn. Như trong trường hợp của các hàm Copy, NULL
và 0 có thể được sử dụng để đặt ký hiệu và chu kỳ bằng với thuộc tính của biểu đồ hiện tại.
Vì các hàm i
tương đương với việc gọi các hàm Copy
, tất cả các đặc điểm của việc yêu cầu chuỗi thời gian từ các loại chương trình khác nhau, được mô tả trong phần Tổng quan về các hàm Copy để lấy mảng báo giá, đều áp dụng cho chúng.
Hàm | Mô tả |
---|---|
iTime | Thời gian mở thanh |
iOpen | Giá mở thanh |
iHigh | Giá cao nhất của thanh |
iLow | Giá thấp nhất của thanh |
iClose | Giá đóng thanh |
iTickVolume | Khối lượng tick của thanh (tương tự iVolume ) |
iVolume | Khối lượng tick của thanh (tương tự iTickVolume ) |
iRealVolume | Khối lượng giao dịch thực tế của thanh |
iSpread | Chênh lệch giá tối thiểu của thanh (tính bằng điểm) |
Các hàm trả về giá trị được yêu cầu hoặc 0 khi có lỗi (thật không may, 0 cũng có thể là giá trị thực trong một số trường hợp). Để biết thêm thông tin về lỗi, hãy gọi hàm GetLastError
.
Các hàm không lưu trữ kết quả vào bộ nhớ đệm. Mỗi lần gọi, chúng trả về dữ liệu thực tế từ chuỗi thời gian cho ký hiệu/chu kỳ được chỉ định. Điều này có nghĩa là khi không có dữ liệu sẵn sàng (ở lần gọi đầu tiên, hoặc sau khi mất đồng bộ), hàm có thể mất một chút thời gian để chuẩn bị kết quả.
Ví dụ, hãy thử lấy một ước lượng thực tế hơn về kích thước chênh lệch giá cho mỗi thanh. Giá trị chênh lệch tối thiểu được lưu trữ trong báo giá, điều này có thể gây ra kỳ vọng cao không hợp lý khi thiết kế chiến lược giao dịch. Để có được giá trị tuyệt đối chính xác của chênh lệch trung bình, trung vị hoặc tối đa cho mỗi thanh, cần phải phân tích các tick thực tế, nhưng chúng ta chưa học cách làm việc với chúng. Hơn nữa, đó sẽ là một quá trình rất tốn tài nguyên. Một cách tiếp cận hợp lý hơn là phân tích chênh lệch giá trên khung thời gian M1 thấp hơn: đối với các thanh của khung thời gian cao hơn, chỉ cần tìm chênh lệch giá tối đa trong các thanh bên trong của M1. Tất nhiên, nghiêm ngặt mà nói, đó không phải là tối đa thực sự, mà là tối đa của các giá trị tối thiểu, nhưng với tính chất thoáng qua của các phép đo phút, chúng ta có thể hy vọng phát hiện ra các đợt mở rộng chênh lệch đặc trưng ít nhất trên một số thanh M1, và điều này đủ để đạt được tỷ lệ chấp nhận được giữa độ chính xác phân tích và tốc độ.
Một trong những phiên bản của thuật toán được triển khai trong script SeriesSpread.mq5
. Trong các biến đầu vào, bạn có thể đặt ký hiệu, khung thời gian và số lượng thanh để phân tích. Theo mặc định, ký hiệu của biểu đồ hiện tại và chu kỳ của nó được xử lý (nên lớn hơn M1).
input string WorkSymbol = NULL; // Ký hiệu (để trống cho ký hiệu hiện tại)
input ENUM_TIMEFRAMES TimeFrame = PERIOD_CURRENT;
input int BarCount = 100;
2
3
Vì chỉ thông tin về thời gian và chênh lệch giá của mỗi thanh là quan trọng, một cấu trúc đặc biệt với hai trường đã được mô tả. Chúng ta có thể sử dụng cấu trúc tiêu chuẩn MqlRates
và thêm chênh lệch "tối đa" vào một trường không sử dụng (ví dụ, real_volume
cho các ký hiệu Forex), nhưng như vậy dữ liệu cho hầu hết các trường sẽ được sao chép và lãng phí bộ nhớ.
struct SpreadPerBar
{
datetime time;
int spread;
};
2
3
4
5
Sử dụng loại cấu trúc mới, chúng ta chuẩn bị mảng peaks
để tính toán dữ liệu của số lượng thanh được chỉ định.
void OnStart()
{
SpreadPerBar peaks[];
ArrayResize(peaks, BarCount);
ZeroMemory(peaks);
...
2
3
4
5
6
Tiếp theo, phần chính của thuật toán được thực thi trong vòng lặp thanh. Đối với mỗi thanh, chúng ta sử dụng hàm iTime
để xác định hai dấu thời gian xác định ranh giới của thanh. Thực tế, đây là thời gian mở của thanh thứ i và thanh lân cận (i+1). Theo nguyên tắc lập chỉ mục, có thể nói rằng thanh (i+1) là thanh trước đó (cũ hơn, xem biến prev
) và thanh thứ i là thanh tiếp theo (mới hơn, xem biến next
). Thời gian mở thanh chỉ thuộc về một thanh duy nhất, tức là nhãn prev
nằm trong thanh thứ (i+1), và nhãn next
nằm trong thanh thứ i. Do đó, khi xử lý mỗi thanh, ranh giới bên phải của nó nên được loại trừ khỏi khoảng [prev;next)
.
Chúng ta quan tâm đến chênh lệch giá trên khung thời gian một phút, và do đó chúng ta sẽ sử dụng hàm CopySpread
cho PERIOD_M1
. Trong trường hợp này, khoảng nửa mở được đạt được bằng cách đặt các tham số start/stop
thành giá trị chính xác của prev
và giá trị next
giảm đi 1 giây. Thông tin chênh lệch giá được sao chép vào mảng động spreads
(bộ nhớ cho nó được hàm tự động phân bổ).
for(int i = 0; i < BarCount; ++i)
{
int spreads[]; // mảng nhận cho chênh lệch giá M1 bên trong thanh thứ i
const datetime next = iTime(WorkSymbol, TimeFrame, i);
const datetime prev = iTime(WorkSymbol, TimeFrame, i + 1);
const int n = CopySpread(WorkSymbol, PERIOD_M1, prev, next - 1, spreads);
const int m = ArrayMaximum(spreads);
if(m > -1)
{
peaks[i].spread = spreads[m];
peaks[i].time = prev;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
Sau đó, chúng ta tìm giá trị tối đa trong mảng này và lưu nó vào cấu trúc SpreadPerBar
thích hợp cùng với thời gian của thanh. Lưu ý rằng thanh chưa hoàn thành số 0 không được đưa vào phân tích (bạn có thể bổ sung thuật toán nếu cần).
Sau khi vòng lặp hoàn tất, chúng ta xuất mảng cấu trúc ra nhật ký.
PrintFormat("Maximal spreads per intraday bar\nProcessed %d bars on %s %s",
BarCount, StringLen(WorkSymbol) > 0 ? WorkSymbol : _Symbol,
EnumToString(TimeFrame == PERIOD_CURRENT ? _Period : TimeFrame));
ArrayPrintM(peaks);
2
3
4
Bằng cách chạy script trên biểu đồ EURUSD,H1, chúng ta sẽ nhận được thống kê chênh lệch giá bên trong các thanh hàng giờ (được rút gọn):
Maximal spreads per intraday bar
Processed 100 bars on EURUSD PERIOD_H1
[ 0] 2021.10.12 14:00 1
[ 1] 2021.10.12 13:00 1
[ 2] 2021.10.12 12:00 1
[ 3] 2021.10.12 11:00 1
[ 4] 2021.10.12 10:00 0
[ 5] 2021.10.12 09:00 1
[ 6] 2021.10.12 08:00 2
[ 7] 2021.10.12 07:00 2
[ 8] 2021.10.12 06:00 1
[ 9] 2021.10.12 05:00 1
[10] 2021.10.12 04:00 1
[11] 2021.10.12 03:00 1
[12] 2021.10.12 02:00 4
[13] 2021.10.12 01:00 16
[14] 2021.10.12 00:00 65
[15] 2021.10.11 23:00 15
[16] 2021.10.11 22:00 2
[17] 2021.10.11 21:00 1
[18] 2021.10.11 20:00 1
[19] 2021.10.11 19:00 2
[20] 2021.10.11 18:00 1
[21] 2021.10.11 17:00 1
[22] 2021.10.11 16:00 1
[23] 2021.10.11 15:00 2
[24] 2021.10.11 14:00 1
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
Có sự gia tăng rõ ràng về chênh lệch giá vào ban đêm: ví dụ, gần nửa đêm, báo giá chứa chênh lệch giá từ 7-15 điểm, và trong phép đo của chúng ta, chúng là 15-65. Tuy nhiên, các giá trị khác không cũng được tìm thấy trong các khoảng thời gian khác, mặc dù số liệu của các thanh hàng giờ thường chứa số không.