Tạo Expert Advisors đa biểu tượng
Đến nay, trong khuôn khổ cuốn sách, chúng ta chủ yếu phân tích các ví dụ về Expert Advisors giao dịch trên biểu tượng làm việc hiện tại của biểu đồ. Tuy nhiên, MQL5 cho phép tạo lệnh giao dịch cho bất kỳ biểu tượng nào của Market Watch
, bất kể biểu tượng làm việc của biểu đồ là gì.
Trên thực tế, nhiều ví dụ trong các phần trước đã có tham số đầu vào symbol
, trong đó bạn có thể chỉ định một biểu tượng bất kỳ. Theo mặc định, đó là một chuỗi rỗng, được coi là biểu tượng hiện tại của biểu đồ. Vì vậy, chúng ta đã xem xét các ví dụ sau:
CustomOrderSend.mq5
trong Gửi yêu cầu giao dịchMarketOrderSend.mq5
trong Hoạt động mua và bánMarketOrderSendMonitor.mq5
trong Các hàm đọc thuộc tính của lệnh đang hoạt độngPendingOrderSend.mq5
trong Đặt lệnh chờPendingOrderModify.mq5
trong Sửa đổi lệnh chờPendingOrderDelete.mq5
trong Xóa lệnh chờ
Bạn có thể thử chạy các ví dụ này với một biểu tượng khác và đảm bảo rằng các hoạt động giao dịch được thực hiện giống hệt như với biểu tượng gốc.
Hơn nữa, như chúng ta đã thấy trong mô tả về sự kiện OnBookEven
([../../automation/marketbook/marketbook_events]) và OnTradeTransaction
([./experts_ontradetransaction]), chúng mang tính phổ quát và thông báo về các thay đổi trong môi trường giao dịch liên quan đến các biểu tượng bất kỳ. Nhưng điều này không đúng với sự kiện OnTick
([./experts_ontick]), chỉ được tạo ra khi có sự thay đổi trong giá mới của biểu tượng hiện tại. Thông thường, điều này không phải là vấn đề, nhưng giao dịch đa tiền tệ tần suất cao đòi hỏi một số bước kỹ thuật bổ sung, chẳng hạn như đăng ký sự kiện OnBookEvent
cho các biểu tượng khác hoặc thiết lập bộ đếm thời gian tần suất cao. Một lựa chọn khác để vượt qua giới hạn này dưới dạng chỉ báo gián điệp EventTickSpy.mq5
đã được trình bày trong phần Tạo sự kiện tùy chỉnh.
Trong bối cảnh nói về hỗ trợ giao dịch đa biểu tượng, cần lưu ý rằng khái niệm về Expert Advisors đa khung thời gian không hoàn toàn chính xác. Giao dịch tại thời điểm mở thanh mới chỉ là một trường hợp đặc biệt của việc nhóm các tick theo các khoảng thời gian tùy ý, không nhất thiết phải là các khoảng tiêu chuẩn. Tất nhiên, việc phân tích sự xuất hiện của một thanh mới trên một khung thời gian cụ thể được đơn giản hóa bởi lõi hệ thống nhờ các hàm như iTime(_Symbol, PERIOD_XX, 0)
, nhưng phân tích này vẫn dựa trên các tick.
Bạn có thể xây dựng các thanh ảo bên trong Expert Advisor của mình theo số lượng tick (equivolume), theo phạm vi giá (renko, range), v.v. Trong một số trường hợp, bao gồm để rõ ràng, việc tạo các "khung thời gian" như vậy một cách rõ ràng bên ngoài Expert Advisor, dưới dạng biểu tượng tùy chỉnh, là hợp lý. Nhưng cách tiếp cận này có những hạn chế: chúng ta sẽ nói về chúng trong phần tiếp theo của cuốn sách.
Tuy nhiên, nếu hệ thống giao dịch vẫn yêu cầu phân tích báo giá dựa trên việc mở thanh hoặc sử dụng chỉ báo đa tiền tệ, cần phải chờ đồng bộ hóa các thanh trên tất cả các công cụ liên quan theo một cách nào đó. Chúng ta đã cung cấp một ví dụ về một lớp thực hiện nhiệm vụ này trong phần Theo dõi sự hình thành thanh.
Khi phát triển một Expert Advisor đa biểu tượng, nhiệm vụ cấp bách là tách biệt một thuật toán giao dịch phổ quát thành các khối riêng biệt. Các khối này sau đó có thể được áp dụng cho các biểu tượng khác nhau với các cài đặt khác nhau. Cách tiếp cận logic nhất để đạt được điều này là xây dựng một hoặc nhiều lớp trong khuôn khổ khái niệm Lập trình Hướng Đối tượng (OOP).
Hãy minh họa phương pháp này bằng một ví dụ về Expert Advisor sử dụng chiến lược martingale nổi tiếng. Như thường được hiểu, chiến lược martingale vốn dĩ rủi ro, do thực hành tăng gấp đôi lô sau mỗi giao dịch thua với kỳ vọng thu hồi các khoản lỗ trước đó. Việc giảm thiểu rủi ro này là cần thiết, và một cách tiếp cận hiệu quả là giao dịch đồng thời trên nhiều biểu tượng, tốt nhất là những biểu tượng có mối tương quan yếu. Bằng cách này, các khoản lỗ tạm thời trên một công cụ có thể được bù đắp bởi lợi nhuận trên các công cụ khác.
Việc kết hợp nhiều công cụ (hoặc các cài đặt đa dạng trong một hệ thống giao dịch, hoặc thậm chí các hệ thống giao dịch khác nhau) trong Expert Advisor giúp giảm tác động tổng thể của các thất bại riêng lẻ của các thành phần. Về cơ bản, sự đa dạng càng lớn trong các công cụ hoặc hệ thống, kết quả cuối cùng càng ít phụ thuộc vào các thất bại riêng lẻ của các phần cấu thành.
Hãy gọi Expert Advisor mới này là MultiMartingale.mq5
. Các cài đặt thuật toán giao dịch bao gồm:
UseTime
— cờ logic để bật/tắt giao dịch theo lịch trìnhHourStart
vàHourEnd
— phạm vi giờ mà giao dịch được phép, nếuUseTime
bằngtrue
Lots
— khối lượng của giao dịch đầu tiên trong chuỗiFactor
— hệ số tăng khối lượng cho các giao dịch tiếp theo sau khi thuaLimit
— số lượng giao dịch tối đa trong một chuỗi thua với việc nhân khối lượng (sau đó, quay lại lô ban đầu)Stop Loss
vàTake Profit
— khoảng cách đến các mức bảo vệ tính bằng điểmStartType
— loại giao dịch đầu tiên (mua hoặc bán)Trailing
— chỉ báo của việc theo dõi stop loss
Trong mã nguồn, chúng được mô tả như sau:
input bool UseTime = true; // UseTime (hourStart and hourEnd)
input uint HourStart = 2; // HourStart (0...23)
input uint HourEnd = 22; // HourEnd (0...23)
input double Lots = 0.01; // Lots (initial)
input double Factor = 2.0; // Factor (lot multiplication)
input uint Limit = 5; // Limit (max number of multiplications)
input uint StopLoss = 500; // StopLoss (points)
input uint TakeProfit = 500; // TakeProfit (points)
input ENUM_POSITION_TYPE StartType = 0; // StartType (first order type: BUY or SELL)
input bool Trailing = true; // Trailing
2
3
4
5
6
7
8
9
10
Về lý thuyết, việc thiết lập các mức bảo vệ không tính bằng điểm mà dựa trên tỷ lệ của chỉ báo Average True Range (ATR) là hợp lý. Tuy nhiên, hiện tại, đây không phải là nhiệm vụ chính.
Ngoài ra, Expert Advisor tích hợp một cơ chế tạm dừng hoạt động giao dịch trong khoảng thời gian do người dùng chỉ định (được điều khiển bởi tham số SkipTimeOnError
) trong trường hợp xảy ra lỗi. Chúng ta sẽ bỏ qua thảo luận chi tiết về khía cạnh này tại đây, vì nó có thể được tham khảo trong mã nguồn.
Để hợp nhất toàn bộ tập hợp cấu hình thành một thực thể thống nhất, một cấu trúc có tên Settings
được định nghĩa. Cấu trúc này có các trường phản ánh các biến đầu vào. Hơn nữa, cấu trúc bao gồm trường symbol
, giải quyết bản chất đa tiền tệ của chiến lược. Nói cách khác, biểu tượng có thể là bất kỳ và khác với biểu tượng làm việc trên biểu đồ.
struct Settings
{
bool useTime;
uint hourStart;
uint hourEnd;
double lots;
double factor;
uint limit;
uint stopLoss;
uint takeProfit;
ENUM_POSITION_TYPE startType;
ulong magic;
bool trailing;
string symbol;
...
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Trong giai đoạn phát triển ban đầu, chúng ta điền cấu trúc với các biến đầu vào. Tuy nhiên, điều này chỉ đủ để giao dịch trên một biểu tượng duy nhất. Sau đó, khi chúng ta mở rộng thuật toán để bao gồm nhiều biểu tượng, chúng ta sẽ cần đọc các tập hợp cài đặt khác nhau (sử dụng một cách tiếp cận khác) và thêm chúng vào một mảng các cấu trúc.
Cấu trúc cũng bao gồm một số phương thức hữu ích. Cụ thể, phương thức validate
kiểm tra tính đúng đắn của các cài đặt, xác nhận sự tồn tại của biểu tượng được chỉ định và trả về một chỉ báo thành công (true
).
struct Settings
{
...
bool validate()
{
... // kiểm tra kích thước lô và các mức bảo vệ (xem mã nguồn)
double rates[1];
const bool success = CopyClose(symbol, PERIOD_CURRENT, 0, 1, rates) > -1;
if(!success)
{
Print("Unknown symbol:", symbol);
}
return success;
}
...
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Gọi CopyClose
không chỉ kiểm tra xem biểu tượng có trực tuyến trong Market Watch
hay không mà còn khởi tạo việc tải báo giá của nó (của khung thời gian mong muốn) và các tick trong bộ kiểm tra. Nếu điều này không được thực hiện, chỉ có báo giá và tick (trong chế độ tick thực) của công cụ và khung thời gian hiện đang chọn mới có sẵn trong bộ kiểm tra theo mặc định. Vì chúng ta đang viết một Expert Advisor đa tiền tệ, chúng ta sẽ cần báo giá và tick từ bên thứ ba.
struct Settings
{
...
void print() const
{
Print(symbol, (startType == POSITION_TYPE_BUY ? "+" : "-"), (float)lots,
"*", (float)factor,
"^", limit,
"(", stopLoss, ",", takeProfit, ")",
useTime ? "[" + (string)hourStart + "," + (string)hourEnd + "]" : "");
}
};
2
3
4
5
6
7
8
9
10
11
12
Phương thức print
xuất tất cả các trường vào nhật ký dưới dạng rút gọn trong một dòng. Ví dụ:
EURUSD+0.01*2.0^5(500,1000)[2,22]
| | | | | | | |
| | | | | | | `cho đến giờ này giao dịch được phép
| | | | | | `từ giờ này giao dịch được phép
| | | | | `take profit tính bằng điểm
| | | | `stop loss tính bằng điểm
| | | `số lượng tối đa của chuỗi giao dịch thua (sau '^')
| | `hệ số nhân lô (sau '*')
| `lô ban đầu trong chuỗi
| `+ bắt đầu với Mua
| `- bắt đầu với Bán
`công cụ
2
3
4
5
6
7
8
9
10
11
12
Chúng ta sẽ cần các phương thức khác trong cấu trúc Settings
khi chuyển sang đa tiền tệ. Bây giờ, hãy tưởng tượng một phiên bản đơn giản hóa của trình xử lý OnInit
của Expert Advisor giao dịch trên một biểu tượng có thể trông như thế nào.
int OnInit()
{
Settings settings =
{
UseTime, HourStart, HourEnd,
Lots, Factor, Limit,
StopLoss, TakeProfit,
StartType, Magic, SkipTimeOnError, Trailing, _Symbol
};
if(settings.validate())
{
settings.print();
...
// tại đây bạn sẽ cần khởi tạo thuật toán giao dịch với các cài đặt này
}
...
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Tuân thủ OOP, hệ thống giao dịch ở dạng tổng quát nên được mô tả như một giao diện phần mềm. Một lần nữa, để đơn giản hóa ví dụ, chúng ta sẽ chỉ sử dụng một phương thức trong giao diện này: trade
.
interface TradingStrategy
{
virtual bool trade(void);
};
2
3
4
Chà, nhiệm vụ chính của thuật toán là giao dịch, và thậm chí không quan trọng chúng ta quyết định gọi phương thức này từ đâu: trên mỗi tick từ OnTick
, khi mở thanh, hay có thể trên bộ đếm thời gian.
Expert Advisors hoạt động của bạn rất có thể sẽ cần các phương thức giao diện bổ sung để thiết lập và hỗ trợ các chế độ khác nhau. Nhưng chúng không cần thiết trong ví dụ này.
Hãy bắt đầu tạo một lớp của hệ thống giao dịch cụ thể dựa trên giao diện. Trong trường hợp của chúng ta, tất cả các thể hiện sẽ thuộc lớp SimpleMartingale
. Tuy nhiên, cũng có thể triển khai nhiều lớp khác nhau kế thừa giao diện trong một Expert Advisor và sau đó sử dụng chúng một cách thống nhất trong một sự kết hợp bất kỳ. Một danh mục các chiến lược (tốt nhất là rất khác nhau về bản chất) thường được đặc trưng bởi sự ổn định tài chính cao hơn.
class SimpleMartingale: public TradingStrategy
{
protected:
Settings settings;
SymbolMonitor symbol;
AutoPtr<PositionState> position;
AutoPtr<TrailingStop> trailing;
...
};
2
3
4
5
6
7
8
9
Bên trong lớp, chúng ta thấy cấu trúc quen thuộc Settings
và bộ giám sát biểu tượng làm việc SymbolMonitor
. Ngoài ra, chúng ta sẽ cần kiểm soát sự hiện diện của các vị thế và theo dõi mức stop-loss cho chúng, vì vậy chúng ta đã giới thiệu các biến với các con trỏ tự động đến các đối tượng PositionState
và TrailingStop
. Các con trỏ tự động cho phép chúng ta trong mã của mình không phải lo lắng về việc xóa đối tượng một cách rõ ràng vì điều này sẽ được thực hiện tự động khi thoát khỏi phạm vi hoặc khi một con trỏ mới được gán cho con trỏ tự động.
Lớp
TrailingStop
là một lớp cơ sở, với việc triển khai đơn giản nhất của việc theo dõi giá, từ đó bạn có thể kế thừa rất nhiều thuật toán phức tạp hơn, một ví dụ mà chúng ta đã xem xét là dẫn xuấtTrailingStopByMA
. Do đó, để mang lại sự linh hoạt cho chương trình trong tương lai, mong muốn đảm bảo rằng mã gọi có thể truyền...
Phương thức hoạt động close
phần lớn tương tự như openBuy
nên chúng ta sẽ không xem xét nó ở đây. Một phương thức khác, scheduled
, chỉ trả về true
hoặc false
, tùy thuộc vào việc thời gian hiện tại có rơi vào phạm vi giờ làm việc được chỉ định (hourStart
, hourEnd
) hay không.
Vậy là lớp giao dịch đã sẵn sàng. Nhưng để làm việc đa tiền tệ, bạn sẽ cần tạo nhiều bản sao của nó. Lớp TradingStrategyPool
sẽ quản lý chúng, trong đó chúng ta mô tả một mảng các con trỏ đến TradingStrategy
và các phương thức để bổ sung nó: hàm tạo có tham số và push
.
class TradingStrategyPool: public TradingStrategy
{
private:
AutoPtr<TradingStrategy> pool[];
public:
TradingStrategyPool(const int reserve = 0)
{
ArrayResize(pool, 0, reserve);
}
TradingStrategyPool(TradingStrategy *instance)
{
push(instance);
}
void push(TradingStrategy *instance)
{
int n = ArraySize(pool);
ArrayResize(pool, n + 1);
pool[n] = instance;
}
virtual bool trade() override
{
for(int i = 0; i < ArraySize(pool); i++)
{
pool[i][].trade();
}
return true;
}
};
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
Không nhất thiết phải làm cho pool dẫn xuất từ giao diện TradingStrategy
, nhưng nếu chúng ta làm như vậy, điều này cho phép đóng gói các pool chiến lược trong tương lai thành các pool chiến lược lớn hơn, v.v. Phương thức trade
chỉ đơn giản gọi cùng phương thức trên tất cả các đối tượng mảng.
Trong bối cảnh toàn cục, hãy thêm một con trỏ tự động đến pool giao dịch, và trong trình xử lý OnInit
, chúng ta sẽ đảm bảo việc điền nó. Chúng ta có thể bắt đầu với một chiến lược duy nhất (chúng ta sẽ xử lý đa tiền tệ sau một chút).
AutoPtr<TradingStrategyPool> pool;
int OnInit()
{
... // khởi tạo cài đặt đã được đưa ra trước đó
if(settings.validate())
{
settings.print();
pool = new TradingStrategyPool(new SimpleMartingale(settings));
return INIT_SUCCEEDED;
}
else
{
return INIT_FAILED;
}
...
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Để bắt đầu giao dịch, chúng ta chỉ cần viết trình xử lý OnTick
nhỏ sau đây.
void OnTick()
{
if(pool[] != NULL)
{
pool[].trade();
}
}
2
3
4
5
6
7
Nhưng còn hỗ trợ đa tiền tệ thì sao?
Bộ tham số đầu vào hiện tại được thiết kế chỉ cho một công cụ. Chúng ta có thể sử dụng điều này để kiểm tra và tối ưu hóa Expert Advisor trên một biểu tượng duy nhất, nhưng sau khi tìm thấy cài đặt tối ưu cho tất cả các biểu tượng, chúng cần được kết hợp và truyền cho thuật toán theo một cách nào đó.
Trong trường hợp này, chúng ta áp dụng giải pháp đơn giản nhất. Mã trên chứa một dòng với các cài đặt được tạo bởi phương thức print
do cấu trúc Settings
tạo ra. Chúng ta triển khai phương thức trong cấu trúc parse
thực hiện thao tác ngược lại: khôi phục trạng thái của các trường bằng mô tả dòng. Ngoài ra, vì chúng ta cần nối nhiều cài đặt cho các ký tự khác nhau, chúng ta sẽ đồng ý rằng chúng có thể được nối thành một chuỗi dài duy nhất thông qua một ký tự phân cách đặc biệt, ví dụ ';'. Sau đó, dễ dàng viết phương thức tĩnh parseAll
để đọc tập hợp cài đặt đã hợp nhất, sẽ gọi parse
để điền vào mảng các cấu trúc Settings
được truyền bằng tham chiếu. Mã nguồn đầy đủ của các phương thức có thể được tìm thấy trong tệp đính kèm.
struct Settings
{
...
bool parse(const string &line);
void static parseAll(const string &line, Settings &settings[])
...
};
2
3
4
5
6
7
Ví dụ, chuỗi nối sau chứa cài đặt cho ba biểu tượng.
EURUSD+0.01*2.0^7(500,500)[2,22];AUDJPY+0.01*2.0^8(300,500)[2,22];GBPCHF+0.01*1.7^8(1000,2000)[2,22]
Chính những dòng như thế này mà phương thức parseAll
có thể phân tích. Để nhập một chuỗi như vậy vào Expert Advisor, chúng ta mô tả biến đầu vào WorkSymbols
.
input string WorkSymbols = ""; // WorkSymbols (name±lots*factor^limit(sl,tp)[start,stop];...)
Nếu nó trống, Expert Advisor sẽ hoạt động với các cài đặt từ các biến đầu vào riêng lẻ được trình bày trước đó. Nếu chuỗi được chỉ định, trình xử lý OnInit
sẽ điền pool của các hệ thống giao dịch dựa trên kết quả phân tích dòng này.
int OnInit()
{
if(WorkSymbols == "")
{
... // làm việc với ký tự đơn hiện tại, như trước đây
}
else
{
Print("Parsed settings:");
Settings settings[];
Settings::parseAll(WorkSymbols, settings);
const int n = ArraySize(settings);
pool = new TradingStrategyPool(n);
for(int i = 0; i < n; i++)
{
settings[i].trailing = Trailing;
// hỗ trợ nhiều hệ thống trên một biểu tượng cho các tài khoản hedging
settings[i].magic = Magic + i; // số ma thuật khác nhau cho mỗi hệ thống con
pool[].push(new SimpleMartingale(settings[i]));
}
}
return INIT_SUCCEEDED;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Điều quan trọng cần lưu ý là trong MQL5, độ dài của chuỗi đầu vào bị giới hạn ở 250 ký tự. Ngoài ra, trong quá trình tối ưu hóa trong bộ kiểm tra, các chuỗi bị cắt ngắn thêm xuống tối đa 63 ký tự. Do đó, để tối ưu hóa giao dịch đồng thời trên nhiều biểu tượng, việc nghĩ ra một phương pháp thay thế để tải cài đặt, chẳng hạn như lấy chúng từ một tệp văn bản, trở nên cần thiết. Điều này có thể dễ dàng thực hiện bằng cách sử dụng cùng biến đầu vào, miễn là nó được chỉ định bằng tên tệp thay vì một chuỗi chứa cài đặt.
Cách tiếp cận này được triển khai trong phương thức Settings::parseAll
đã đề cập. Tên của tệp văn bản mà một chuỗi đầu vào sẽ được truyền vào Expert Advisor mà không bị giới hạn độ dài được đặt theo nguyên tắc phổ quát phù hợp với tất cả các trường hợp tương tự: tên tệp bắt đầu bằng tên của Expert Advisor, và sau đó, sau dấu gạch ngang, phải là tên của biến mà dữ liệu của tệp chứa. Ví dụ, trong trường hợp của chúng ta, trong biến đầu vào WorkSymbols
, bạn có thể tùy chọn chỉ định tên tệp "MultiMartingale-WorkSymbols.txt". Sau đó, phương thức parseAll
sẽ cố gắng đọc văn bản từ tệp (nó nên nằm trong sandbox tiêu chuẩn MQL5/Files
).
Việc truyền tên tệp trong các tham số đầu vào đòi hỏi các bước bổ sung để tiếp tục kiểm tra và tối ưu hóa Expert Advisor như vậy: chỉ thị
#property tester_file "MultiMartingale-WorkSymbols.txt"
nên được thêm vào mã nguồn. Điều này sẽ được thảo luận chi tiết trong phần Chỉ thị tiền xử lý của Tester. Khi chỉ thị này được thêm vào, Expert Advisor sẽ yêu cầu sự hiện diện của tệp và sẽ không khởi động nếu không có nó trong bộ kiểm tra!
Expert Advisor đã sẵn sàng. Chúng ta có thể kiểm tra nó trên các biểu tượng khác nhau một cách riêng biệt, chọn cài đặt tốt nhất cho mỗi biểu tượng và xây dựng một danh mục giao dịch. Trong chương tiếp theo, chúng ta sẽ nghiên cứu API của bộ kiểm tra, bao gồm tối ưu hóa, và Expert Advisor này sẽ hữu ích. Trong lúc đó, hãy kiểm tra hoạt động đa tiền tệ của nó.
WorkSymbols=EURUSD+0.01*1.2^4(300,600)[9,11];GBPCHF+0.01*2.0^7(300,400)[14,16];AUDJPY+0.01*2.0^6(500,800)[18,16]
Trong quý đầu tiên của năm 2022, chúng ta sẽ nhận được báo cáo sau (báo cáo của MetaTrader 5 không cung cấp số liệu thống kê phân theo biểu tượng, vì vậy chỉ có thể phân biệt báo cáo đơn tiền tệ với báo cáo đa tiền tệ qua bảng giao dịch/lệnh/vị thế).
Báo cáo của Tester cho Expert Advisor chiến lược Martingale đa tiền tệ
Cần lưu ý rằng do chiến lược được khởi chạy từ trình xử lý OnTick
, các lần chạy trên các biểu tượng chính khác nhau (tức là những biểu tượng được chọn trong danh sách thả xuống cài đặt của bộ kiểm tra) sẽ cho kết quả hơi khác nhau. Trong bài kiểm tra của chúng ta, chúng ta chỉ sử dụng EURUSD làm công cụ thanh khoản cao nhất và thường xuyên có tick nhất, điều này đủ cho hầu hết các ứng dụng. Tuy nhiên, nếu bạn muốn phản ứng với tick của tất cả các công cụ, bạn có thể sử dụng một chỉ báo như EventTickSpy.mq5
. Tùy chọn, bạn có thể chạy logic giao dịch trên bộ đếm thời gian mà không bị ràng buộc với tick của một công cụ cụ thể.
Và đây là cách chiến lược giao dịch trông như thế nào cho một biểu tượng duy nhất, trong trường hợp này là AUDJPY.
Biểu đồ với bài kiểm tra Expert Advisor chiến lược Martingale đa tiền tệ
Nhân tiện, đối với tất cả Expert Advisors đa tiền tệ, có một vấn đề quan trọng khác bị bỏ qua ở đây. Chúng ta đang nói về phương pháp chọn kích thước lô, ví dụ, dựa trên mức tải của khoản tiền gửi hoặc rủi ro. Trước đó, chúng ta đã trình bày các ví dụ về tính toán như vậy trong Expert Advisor không giao dịch LotMarginExposureTable.mq5
([./experts_ordercalcmargin]). Trong MultiMartingale.mq5
, chúng ta đã đơn giản hóa nhiệm vụ bằng cách chọn một lô cố định và hiển thị nó trong cài đặt cho mỗi biểu tượng. Tuy nhiên, trong các Expert Advisor đa tiền tệ hoạt động, việc chọn lô theo tỷ lệ với giá trị của các công cụ (theo biên hoặc độ biến động) là hợp lý.
Kết luận, tôi muốn lưu ý rằng các chiến lược đa tiền tệ có thể yêu cầu các nguyên tắc tối ưu hóa khác nhau. Chiến lược được xem xét cho phép tìm riêng các tham số cho các biểu tượng và sau đó kết hợp chúng. Tuy nhiên, một số chiến lược arbitrage và cluster (ví dụ, giao dịch cặp) dựa trên việc phân tích đồng thời tất cả các công cụ để đưa ra quyết định giao dịch. Trong trường hợp này, các cài đặt liên quan đến tất cả các biểu tượng nên được bao gồm riêng trong các tham số đầu vào.