Loại giá để xây dựng biểu đồ ký hiệu
Các thanh trên biểu đồ giá MetaTrader 5 có thể được vẽ dựa trên giá Bid
hoặc giá Last
, và loại vẽ được chỉ định trong thông số kỹ thuật của từng công cụ. Một chương trình MQL có thể tìm ra đặc tính này bằng cách gọi hàm SymbolInfoInteger
cho thuộc tính SYMBOL_CHART_MODE. Giá trị trả về là một thành viên của liệt kê ENUM_SYMBOL_CHART_MODE.
Định danh | Mô tả |
---|---|
SYMBOL_CHART_MODE_BID | Thanh được xây dựng tại giá Bid |
SYMBOL_CHART_MODE_LAST | Thanh được xây dựng tại giá Last |
Chế độ với giá Last
được sử dụng cho các ký hiệu được giao dịch trên sàn giao dịch (trái ngược với thị trường Forex phi tập trung), và Độ sâu của Thị trường có sẵn cho các ký hiệu như vậy. Độ sâu của thị trường có thể được tìm thấy dựa trên thuộc tính SYMBOL_TICKS_BOOKDEPTH.
Thuộc tính SYMBOL_CHART_MODE hữu ích để điều chỉnh tín hiệu của các chỉ báo hoặc chiến lược được xây dựng, ví dụ, tại giá Last
của biểu đồ, trong khi các lệnh sẽ được thực thi "theo giá thị trường", tức là tại giá Ask
hoặc Bid
tùy thuộc vào hướng.
Loại giá cũng cần thiết khi tính toán các thanh của công cụ tùy chỉnh: nếu nó phụ thuộc vào các ký hiệu tiêu chuẩn, có thể hợp lý khi xem xét cài đặt của chúng theo loại giá. Khi người dùng nhập công thức của công cụ tổng hợp trong cửa sổ Custom Symbol
(mở bằng cách chọn Create Symbol
trong hộp thoại Symbols
), có thể chọn các loại giá theo thông số kỹ thuật của các ký hiệu tiêu chuẩn tương ứng được sử dụng. Tuy nhiên, khi thuật toán tính toán được hình thành trong một chương trình MQL, chính nó chịu trách nhiệm cho việc lựa chọn đúng loại giá.
Trước tiên, hãy thu thập số liệu thống kê về việc sử dụng giá Bid
và Last
để xây dựng biểu đồ trên một tài khoản cụ thể. Đây là điều mà kịch bản SymbolStatsByPriceType.mq5
sẽ thực hiện.
const bool MarketWatchOnly = false;
void OnStart()
{
const int n = SymbolsTotal(MarketWatchOnly);
int k = 0;
// lặp qua tất cả các ký hiệu có sẵn
for(int i = 0; i < n; ++i)
{
if(SymbolInfoInteger(SymbolName(i, MarketWatchOnly), SYMBOL_CHART_MODE)
== SYMBOL_CHART_MODE_LAST)
{
k++;
}
}
PrintFormat("Symbols in total: %d", n);
PrintFormat("Symbols using price types: Bid=%d, Last=%d", n - k, k);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Thử nó trên các tài khoản khác nhau (một số có thể không có ký hiệu cổ phiếu). Đây là kết quả có thể trông như thế nào:
Symbols in total: 52304
Symbols using price types: Bid=229, Last=52075
2
Một ví dụ thực tế hơn là chỉ báo SymbolBidAskChart.mq5
, được thiết kế để vẽ một biểu đồ dưới dạng các thanh được hình thành dựa trên giá của loại được chỉ định. Điều này sẽ cho phép bạn so sánh các nến của biểu đồ sử dụng giá từ thuộc tính SYMBOL_CHART_MODE để xây dựng với các thanh trên loại giá thay thế. Ví dụ, bạn có thể thấy các thanh tại giá Bid
trên biểu đồ công cụ tại giá Last
hoặc nhận các thanh cho giá Ask
, điều mà các biểu đồ terminal tiêu chuẩn không hỗ trợ.
Làm cơ sở cho một chỉ báo mới, chúng ta sẽ lấy một chỉ báo có sẵn IndDeltaVolume.mq5
được trình bày trong phần Chờ dữ liệu và quản lý khả năng hiển thị. Trong chỉ báo đó, chúng ta đã tải xuống lịch sử tick cho một số lượng thanh BarCount
nhất định và tính toán delta của khối lượng, tức là khối lượng mua và bán riêng biệt. Trong chỉ báo mới, chúng ta chỉ cần thay thế thuật toán tính toán bằng việc tìm kiếm giá Open
, High
, Low
, và Close
dựa trên các tick bên trong mỗi thanh.
Cài đặt chỉ báo bao gồm bốn bộ đệm và một biểu đồ thanh (DRAW_BARS) được hiển thị trong cửa sổ chính.
#property indicator_chart_window
#property indicator_buffers 4
#property indicator_plots 1
#property indicator_type1 DRAW_BARS
#property indicator_color1 clrDodgerBlue
#property indicator_width1 2
#property indicator_label1 "Open;High;Low;Close;"
2
3
4
5
6
7
8
Việc hiển thị dưới dạng thanh được chọn để dễ đọc hơn khi chạy trên các nến của biểu đồ chính để cả hai phiên bản của mỗi thanh đều có thể nhìn thấy.
Tham số đầu vào mới ChartMode
cho phép người dùng chọn một trong ba loại giá (lưu ý rằng Ask
là bổ sung của chúng ta so với tập hợp các phần tử tiêu chuẩn trong ENUM_SYMBOL_CHART_MODE).
enum ENUM_SYMBOL_CHART_MODE_EXTENDED
{
_SYMBOL_CHART_MODE_BID, // SYMBOL_CHART_MODE_BID
_SYMBOL_CHART_MODE_LAST, // SYMBOL_CHART_MODE_LAST
_SYMBOL_CHART_MODE_ASK, // SYMBOL_CHART_MODE_ASK*
};
input int BarCount = 100;
input COPY_TICKS TickType = INFO_TICKS;
input ENUM_SYMBOL_CHART_MODE_EXTENDED ChartMode = _SYMBOL_CHART_MODE_BID;
2
3
4
5
6
7
8
9
10
Lớp CalcDeltaVolume
trước đây đã đổi tên thành CalcCustomBars
nhưng hầu như không thay đổi. Sự khác biệt bao gồm một tập hợp mới gồm bốn bộ đệm và trường chartMode
được khởi tạo trong hàm tạo từ biến đầu vào ChartMode
.
class CalcCustomBars
{
const int limit;
const COPY_TICKS tickType;
const ENUM_SYMBOL_CHART_MODE_EXTENDED chartMode;
double open[];
double high[];
double low[];
double close[];
...
public:
CalcCustomBars(
const int bars,
const COPY_TICKS type,
const ENUM_SYMBOL_CHART_MODE_EXTENDED mode)
: limit(bars), tickType(type), chartMode(mode) ...
{
// đăng ký các mảng làm bộ đệm chỉ báo
SetIndexBuffer(0, open);
SetIndexBuffer(1, high);
SetIndexBuffer(2, low);
SetIndexBuffer(3, close);
const static string defTitle[] = {"Open;High;Low;Close;"};
const static string types[] = {"Bid", "Last", "Ask"};
string name = defTitle[0];
StringReplace(name, ";", types[chartMode] + ";");
PlotIndexSetString(0, PLOT_LABEL, name);
IndicatorSetInteger(INDICATOR_DIGITS, _Digits);
}
...
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
Tùy thuộc vào chế độ của chartMode
, phương thức phụ trợ price
trả về một loại giá cụ thể từ mỗi tick.
protected:
double price(const MqlTick &t) const
{
switch(chartMode)
{
case _SYMBOL_CHART_MODE_BID:
return t.bid;
case _SYMBOL_CHART_MODE_LAST:
return t.last;
case _SYMBOL_CHART_MODE_ASK:
return t.ask;
}
return 0; // lỗi
}
...
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Sử dụng phương thức price
, chúng ta có thể dễ dàng thực hiện sửa đổi phương thức tính toán chính calc
điền vào các bộ đệm cho thanh được đánh số i
dựa trên một mảng ticks
cho thanh này.
void calc(const int i, const MqlTick &ticks[], const int skip = 0)
{
const int n = ArraySize(ticks);
for(int j = skip; j < n; ++j)
{
const double p = price(ticks[j]);
if(open[i] == EMPTY_VALUE)
{
open[i] = p;
}
if(p > high[i] || high[i] == EMPTY_VALUE)
{
high[i] = p;
}
if(p < low[i])
{
low[i] = p;
}
close[i] = p;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Các đoạn mã nguồn còn lại và nguyên tắc hoạt động của chúng tương ứng với mô tả của IndDeltaVolume.mq5
.
Trong trình xử lý OnInit
, chúng ta hiển thị thêm loại giá hiện tại của biểu đồ và trả về cảnh báo nếu người dùng quyết định xây dựng một chỉ báo dựa trên loại giá Last
cho công cụ mà giá Last
không có.
int OnInit()
{
...
ENUM_SYMBOL_CHART_MODE mode =
(ENUM_SYMBOL_CHART_MODE)SymbolInfoInteger(_Symbol, SYMBOL_CHART_MODE);
Print("Chart mode: ", EnumToString(mode));
if(mode == SYMBOL_CHART_MODE_BID
&& ChartMode == _SYMBOL_CHART_MODE_LAST)
{
Alert("Last price is not available for ", _Symbol);
}
return INIT_SUCCEEDED;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Dưới đây là ảnh chụp màn hình của một công cụ với chế độ vẽ biểu đồ dựa trên giá Last
; một chỉ báo với loại giá Bid
được phủ lên biểu đồ.
Chỉ báo với các thanh tại giá Bid trên biểu đồ tại giá Last
Cũng thú vị khi xem các thanh cho giá Ask
chạy trên biểu đồ giá Bid
thông thường.
Chỉ báo với các thanh tại giá Ask trên biểu đồ tại giá Bid
Trong giờ thanh khoản thấp, khi chênh lệch giá mở rộng, bạn có thể thấy sự khác biệt đáng kể giữa biểu đồ Bid
và Ask
.