MQL4 Expert Advisor Example

Tìm hiểu cách viết một MA Expert Advisor đầy đủ chức năng trong bài viết ví dụ hoàn chỉnh về Expert Advisor MQL4 này để giúp bạn lập trình EA giao dịch của mình.


Một số sổ tay và hướng dẫn thảo luận về việc xây dựng Expert Advisor có xu hướng sử dụng Đường trung bình động chéo (MACross) làm ví dụ. Lý do cho điều này là vì đây hiện là chiến lược dựa trên chỉ báo phổ biến nhất và việc dạy các khái niệm mã hóa mới bằng cách sử dụng các khái niệm giao dịch mà hầu hết mọi người đã quen thuộc sẽ dễ dàng hơn nhiều.


Theo con đường quen thuộc này, tôi đã gửi một chuyên gia cố vấn cơ bản dựa trên chuyển động chéo đơn giản (20-200):


// Phần 1:

// Chỉ thị tiền xử lý, các biến bên ngoài và bên trong

#property Copyright “Copyright © 2008- 2010, Excel Markets”
#property link “/article/”

extern string EAName = “MACross”;
extern double MagicNumber = 59483;

extern double Lots =0.1;
extern double LotDigits =2;
extern int Slippage = 5;

extern double StopLoss = 80;
extern double TakeProfit =0;

extern bool OppositeClose = true;
extern bool EnterOpenBar = true;

extern int FastMATime = 0;
extern int FastMAPeriod = 2;
extern int FastMAType = 0; //0:SMA 1:EMA 2:SMMA 3:LWMA
extern int FastMAPrice = 0;
extern int FastMAShift = 0;
extern int SlowMATime = 0;
extern int SlowMAPeriod = 30;
extern int SlowMAType = 1; //0:SMA 1:EMA 2:SMMA 3:LWMA
extern int SlowMAPrice = 0;
extern int SlowMAShift = 0;

// Global Variables

int Counter, vSlippage;
double ticket, number, vPoint;

double
FastMACurrent,
FastMAPrevious,
SlowMACurrent,
SlowMAPrevious;

// Section 2: Initialization

int init(){

if(Digits==3 || Digits==5)
{ vPoint=Point*10; vSlippage=Slippage*10; }
else{ vPoint=Point; vSlippage=Slippage; }

return(0); }

//——————————————————-
// Section 3: Start

int start()
{

if(Bars<100) { Print(“Bars less than 100”);
return(0); }

//——————————————————–
// Section 3A: Define ShortCuts to Common Functions

int Total, OType=-1, Ticket;
double Price, SL, TP, Lot;
bool CloseBuy=false, CloseSell=false, OpenBuy=false, OpenSell=false;

for(int Counter=1; Counter<=OrdersTotal(); Counter++)
{
if (OrderSelect(Counter-1,SELECT_BY_POS)==true)
if (OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)

{
Ticket=OrderTicket();
OType =OrderType();
Price =OrderOpenPrice();
SL =OrderStopLoss();
TP =OrderTakeProfit();
Lot =OrderLots();
}
}
//—————————————————-
// Section 3B: Indicator Calling

int Current = 0;

FastMACurrent = iMA(NULL, FastMATime, FastMAPeriod, FastMAShift, FastMAType, FastMAPrice, Current + 0);

FastMAPrevious = iMA(NULL, FastMATime, FastMAPeriod, FastMAShift, FastMAType, FastMAPrice, Current + 1);

SlowMACurrent = iMA(NULL, SlowMATime, SlowMAPeriod, SlowMAShift, SlowMAType, SlowMAPrice, Current + 0);

SlowMAPrevious = iMA(NULL, SlowMATime, SlowMAPeriod, SlowMAShift, SlowMAType, SlowMAPrice, Current + 1);

//————————————————
// Section 3C: Entry Conditions

bool OpenBar=true;
if(EnterOpenBar) if(iVolume(NULL,0,0)>1) OpenBar=false;

if (FastMACurrent > SlowMACurrent&& FastMAPrevious < SlowMAPrevious
&& OpenBar){
OpenBuy=true;
if (OppositeClose) CloseSell=true;
}

if (FastMACurrent<slowmacurrent&&amp> < SlowMACurrent&& FastMAPrevious > SlowMAPrevious
&& OpenBar){
OpenSell=true;
if (OppositeClose) CloseBuy=true;
}
//————————————————-
// Section 3D: Close Conditions

while(true)
{
if (OType==0 && CloseBuy==true)
{
close (OP_BUY); // Close Buy
return;
}

if (OType==1 && CloseSell==true)
{
close (OP_SELL); // Close Sell
return;
}
break;
}
//————————————————–
// Section 3E: Order Placement

while(true)

{
if (OrdersTotalMagicOpen()==0 && OpenBuy==true)
{

if(StopLoss>0){SL=Bid – StopLoss*vPoint;}else{SL=0;} if(TakeProfit>0){TP=Bid+TakeProfit*vPoint;}else{TP=0;}
ticket=0;number=0;
while(ticket<=0 && number<100){
RefreshRates();
ticket = OrderSend(Symbol(),OP_BUY,NormalizeDouble(Lots,LotDigits), Ask,vSlippage,SL,TP,EAName, MagicNumber, 0, Green);
return (ticket);
}}

if (OrdersTotalMagicOpen()==0 && OpenSell==true)
{
if(StopLoss>0){SL=Ask + StopLoss*vPoint;}else{SL=0;} if(TakeProfit>0){TP=Ask-TakeProfit*vPoint;}else{TP=0;}
ticket=0;number=0;
while(ticket<=0 && number<100){
RefreshRates();
ticket= OrderSend(Symbol(),OP_SELL, NormalizeDouble(Lots,LotDigits), Bid,vSlippage,SL,TP, EAName, MagicNumber, 0, Red);
return (ticket);
}}
break;
}
//———————————————————
return; // End of start()
}

// Section 4A: Close Function

void close(int type){
if(OrdersTotal()>0){
for(Counter=OrdersTotal()-1;Counter>=0;Counter–){
OrderSelect(Counter,SELECT_BY_POS,MODE_TRADES);

if(type==OP_BUY && OrderType()==OP_BUY){
if(OrderSymbol()==Symbol() && OrderMagicNumber()==MagicNumber) {
RefreshRates();
OrderClose(OrderTicket(),OrderLots(),NormalizeDouble(Bid,Digits), vSlippage);
} }

if(type==OP_SELL && OrderType()==OP_SELL){
if(OrderSymbol()==Symbol() && OrderMagicNumber()==MagicNumber) {
RefreshRates(); OrderClose(OrderTicket(),OrderLots(),NormalizeDouble(Ask,Digits),vSlippage);
}}
}}}

// Section 4B: OrdersTotalMagicOpen Function

int OrdersTotalMagicOpen() {
int l_count_0 = 0;
for (int l_pos_4 = OrdersTotal() – 1; l_pos_4 >= 0; l_pos_4–) {
OrderSelect(l_pos_4, SELECT_BY_POS, MODE_TRADES);
if (OrderSymbol() != Symbol() || OrderMagicNumber() != MagicNumber) continue;
if (OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
if (OrderType() == OP_SELL || OrderType() == OP_BUY) l_count_0++;
}
return (l_count_0);
}
</slowmacurrent&&amp>

Nếu bạn chưa có kinh nghiệm lập trình trước đó, đoạn mã trên có vẻ hơi bí ẩn và đáng sợ. Một cách để vượt qua yếu tố đe dọa là bớt lo lắng về những chi tiết nhỏ và tập trung vào bức tranh lớn.


Cố gắng đừng tìm hiểu xem mọi phần của ngôn ngữ hoạt động như thế nào hoặc tự hỏi điều gì đang diễn ra đằng sau hậu trường ở cấp độ bộ xử lý, mà hãy chấp nhận rằng nó là như vậy. đang làm việc . Bạn không cần phải lo lắng về các chi tiết của ngôn ngữ và định dạng của nó. Bạn không cần phải chú ý đến các chi tiết cụ thể để hiểu và xây dựng EA. Tại thời điểm này, bạn chỉ cần biết các mảnh ghép khớp với nhau như thế nào và mảnh nào quan trọng nhất có thể được vận dụng để tạo ra các chiến lược mới.


Tôi sẽ giúp bạn ghép các mảnh ghép lại với nhau và chỉ cho bạn hướng đi của những mảnh ghép quan trọng nhất. Tôi đã đánh số và dán nhãn cho từng phần trong EA để giúp bạn tham khảo chéo dễ dàng hơn khi tôi hướng dẫn bạn qua từng phần.

Phần 1: Chỉ thị tiền xử lý, các biến bên ngoài và bên trong

Đầu tiên là một số nhận xét. Bạn có thể nhận thấy một số nhận xét tôi đưa vào sau // .


Bất kỳ dòng nào bắt đầu bằng // đều là văn bản tự do và sẽ bị chương trình bỏ qua.


Chúng tôi đưa vào các nhận xét để giúp giải thích bằng tiếng Anh dễ hiểu ý nghĩa của các câu lệnh lập trình của chúng tôi, ngay cả khi máy tính bỏ qua chúng. Có, ngôn ngữ lập trình có thể khó hiểu ngay từ cái nhìn đầu tiên và việc thêm nhận xét trong khi viết mã có thể hữu ích để giúp cuộc sống của bạn dễ dàng hơn.


Tiếp theo, hãy nói về các chỉ thị tiền xử lý. Mỗi lệnh bắt đầu bằng dấu thăng (#). Có nhiều dạng chỉ thị nâng cao như #import và #include, nhưng chúng tôi sẽ chỉ sử dụng dạng đơn giản nhất trong số đó, chỉ thị tiền xử lý bản quyền #property, xác định mã là của chúng tôi. Ngoài ra, nó không quan trọng và không có gì đặc biệt.


Tiếp theo là các biến bên ngoài, chúng rất quan trọng. Trong bài viết trước, tôi đã giải thích biến giống như một chiếc hộp nhỏ nơi bạn có thể lưu trữ mọi thứ để sử dụng sau này. Một biến bên ngoài (đứng trước từ extern) rất quan trọng vì nó hiển thị các tham số bên ngoài chương trình trong hộp thoại chuyên gia để người dùng dễ dàng thao tác.


Nhiều biến bên ngoài mà bạn thấy trong EA cơ bản ở trên có thể tự giải thích được. Chúng ta sẽ thảo luận về EAName, MagicNumber, Lotsize, TakeProfit và Stoploss khi bạn tìm hiểu cú pháp của hàm OrderSend sau, xem Phần 3E, OrderPlacement. Các biến này chủ yếu đề cập đến chức năng đó.


Các biến bên ngoài thú vị trong phần này là: Các biến tham số trung bình động (đặc biệt là MAPeriod), OppositeClose và EnterOpenBar.

Biến tham số trung bình di chuyển.

Xin lưu ý rằng tôi đã đặt tất cả các giá trị tham số trung bình di chuyển làm các biến bên ngoài. Tôi không phải làm việc này. Khi tôi gọi chúng trong Phần 3B "Cuộc gọi chỉ báo", tôi chỉ có thể đặt biến quan trọng nhất MAPeriod thành biến bên ngoài và để các tham số còn lại ở giá trị mặc định của chúng trong chỉ báo. Tôi đã khai báo gần như tất cả các tham số dưới dạng biến ngoài trong trường hợp tôi muốn tối ưu hóa bất kỳ tham số nào sau này. Hiện tại có lẽ tôi sẽ chỉ tối ưu hóa MATeriod nhưng việc tối ưu hóa một số thứ khác có thể hữu ích trong tương lai. Chúng ta sẽ thảo luận chi tiết về các tham số này khi xử lý Phần 3B "Gọi chỉ báo".

Biến Bool (Boolean) Đúng/Sai của tôi: Đối diệnClose và EnterOpenBar

Khi bạn thấy bool trong một biến, đó là loại được sử dụng cho các giá trị thực. Loại bool xuất phát từ Boolean, họ của người phát minh ra phép tính logic. Hãy kiểm tra bool OppositeClose.


Bool bên ngoài OpositeClose=True


Bool bên ngoài của biến này cho phép tôi mở và Đóng điều kiện đóng ngược lại. Bất cứ khi nào đóng đối lập được tham chiếu trong mã, nó sẽ mặc định là true, có nghĩa là tôi muốn nó được mở. Nếu được đặt thành sai, nó sẽ bị tắt. Ngoài ra, thay vì sử dụng đúng hoặc sai, bạn có thể sử dụng 0 cho sai và 1 cho đúng.


OppositeClose bool đề cập đến ý tưởng có thể đóng lệnh khi có tín hiệu ngược lại. Nó có nghĩa là gì? Nếu được đặt thành true và tôi hiện đang ở vị thế mua và lệnh nhập ngắn được kích hoạt, lệnh nhập ngắn sẽ đóng vị thế mua hiện tại của tôi trước khi đặt giao dịch bán. Tín hiệu vào lệnh bán là tín hiệu ngược lại để đóng vị thế mua hiện tại (và ngược lại). Tôi mặc định ngược lạigần đúng vì tôi chắc chắn muốn nó được kích hoạt. Nếu tôi chọn sai, tức là tắt lệnh đóng đối diện, tín hiệu vào lệnh bán sẽ không đóng giao dịch mua trước đó của tôi và giao dịch mua của tôi sẽ vẫn mở cho đến khi nó bị đóng bằng cách nhấn mức dừng lỗ hoặc chốt lời. Thông thường, bạn nên đặt đối lậpgần với giá trị đúng và kích hoạt nó. Chúng ta thảo luận về việc mã hóa đối diệnđóng trong Phần 3D "Điều kiện đóng" và các chức năng liên quan được tìm thấy trong Phần 4A "Chức năng đóng".


EnterOpenBar bool đề cập đến ý tưởng chỉ thực hiện giao dịch khi mở mỗi thanh mới chứ không phải trên liên thanh hoặc đóng. Khi thực hiện các chiến lược mới dựa trên các chỉ báo, tôi thích đặt mặc định EnterOpenBar thành true để nhanh chóng xem chiến lược đang được kiểm tra lại như thế nào. chiến lượctester có ba loại chế độ kiểm tra ngược trong menu thả xuống: mọi đánh dấu, điểm kiểm soát và chỉ đánh dấu mở. Mỗi tích tắc chính xác hơn nhưng chậm hơn những tích tắc khác. Giá mở cửa kém chính xác hơn nhưng nhanh hơn các mức giá khác. Điểm kiểm soát nằm ở đâu đó ở giữa cả hai về độ chính xác và tốc độ. Tuy nhiên, nếu EnterOpenBar được đặt thành true, bạn có thể kiểm tra lại một cách an toàn ở chế độ chỉ giá mở, nhờ đó tăng đáng kể tốc độ kiểm tra lại trong khi có độ chính xác và kết quả rất giống với chế độ mọi dấu kiểm. Ngoài tốc độ backtest, tôi cũng nhận thấy rằng khi enteronopenbar được đặt thành true, nó sẽ cải thiện hiệu suất tổng thể và độ tin cậy của hệ thống, đặc biệt nếu hệ thống dựa trên các số liệu chung. Tôi khuyến khích bạn thử đặt enteronopenbar thành true và false để thấy sự khác biệt trong kết quả. Mã hóa đằng sau EnterOpenBar có thể được tìm thấy trong Phần 3C, "Logic đầu vào".


Cuối cùng, trong phần này tôi khai báo một số biến nội bộ (đôi khi được gọi là biến toàn cục), chẳng hạn như


Vé đôi, số, vPoint;


Xin lưu ý rằng tôi không khai báo giá trị cụ thể cho từng mã định danh. Nếu không có giá trị nào được khai báo thì mỗi mã định danh mặc định là 0, sẽ được xác định sau. Nó sẽ trở về 0 khi quá trình xác định hoàn tất. Cũng lưu ý rằng tôi liệt kê các mã định danh sau dấu kép, nối tiếp nhau, phân tách bằng dấu phẩy, cho đến khi tôi kết thúc câu lệnh bằng dấu chấm phẩy. Điều này có thể được thực hiện vì không ai trong số chúng có giá trị khác nhau trên toàn cầu. Tôi có thể đã khai báo những thứ này trong hàm start() thay vì ở đây, nhưng việc có chúng ở đây trong phần này cho phép tôi tham chiếu chúng trên toàn cầu từ bất kỳ hàm nào trong mã của tôi. Điều này rất thuận tiện và tránh sự trùng lặp không cần thiết.

Mẹo!

Hãy nhớ bất cứ khi nào bạn gặp số nhận dạng cụ thể và thật khó để biết chúng đề cập đến phần nào của mã, có một cách nhanh chóng để tìm trận đấu của họ. Chỉ cần sao chép và dán mã định danh (ví dụ: ExpertName) vào trường tra cứu (Cnt+F) để nhanh chóng chuyển sang mã định danh trùng khớp nằm ở vị trí khác trong mã của bạn. Trừ khi bạn thích chơi ISPY với các từ, có thể bạn sẽ thấy mình làm điều này thường xuyên để khớp các phần khác nhau trong mã của mình.

Phần 2: Khởi tạo

Như bạn có thể thấy, phần này không có gì nhiều.


Mã tôi đưa vào phần này là để đặt giá trị pip tương ứng với số tiền tệ của nhà môi giới của bạn (nhà môi giới được đặt với 4 hoặc 5 chữ số Hệ thống báo giá ):

if(Digits==3 || Digits==5)
{ vPoint=Point*10; vSlippage=Slippage*10;
else{ vPoint= Point; vSlippage=Slippage;

Bản dịch tiếng Anh đơn giản: Nếu cặp tiền tệ của bạn được báo giá bằng số 3 hoặc 5, giá trị pip sẽ bằng Point *10, nếu không (ví dụ 2 hoặc 4), giá trị điểm sẽ vẫn là giá trị điểm không có bội số.


Chèn mã để tự động phát hiện và điều chỉnh các nhà môi giới có 3 hoặc 5 chữ số thập phân là một dự án hữu ích mà tôi đề cập trong bài viết riêng của mình "Tự động phát hiện trượt giá và Đây là được giải thích thêm trong Giá trị điểm.


Học cú pháp, ngôn ngữ và cấu trúc. Lưu ý cách điều kiện if được đặt trong dấu ngoặc đơn () và câu lệnh được đặt trong dấu ngoặc nhọn {}. Đây là cấu trúc phổ biến của một điều kiện if theo sau là câu lệnh của nó. Trong trường hợp này, điều kiện if là if(Digits==3 || Digits==5), hãy nhớ rằng dấu bằng kép (==) có nghĩa là bằng nhau và thanh dọc kép (||) có nghĩa là "hoặc". , bạn phải biết các từ của bạn được dịch sang ngôn ngữ máy như thế nào: mặc dù sẽ thuận tiện nếu chúng ta chỉ nói "và" hoặc "hoặc", chương trình sẽ không hiểu bạn nếu bạn sử dụng những từ này. Thay vào đó, bạn phải sử dụng đôi thanh dọc (||) để biểu thị "hoặc" và các ký hiệu kép (&&) để biểu thị "và".

Note

Mặc dù việc nhập ký hiệu kép cho "và" (&&) thật dễ dàng nhưng việc nhập ký hiệu kép dọc (||) cho "or" lại khó hơn, vì vậy, một phím tắt nhanh là sao chép và dán ký hiệu đó.

Cuối cùng, câu lệnh đầu tiên nằm trong ngoặc đơn{ vPoint=Point*10; vSlippage=Slippage*10; } thực tế có hai câu lệnh được phân tách bằng dấu chấm phẩy: một câu lệnh xác định ý nghĩa của vPoint và một câu lệnh khác xác định ý nghĩa của vSlippage. Khi điều kiện không được đáp ứng, sẽ có hàm else lồng vào nhau trỏ đến một câu lệnh ghép thay thế trong ngoặc { vPoint=Point; vSlippage=Slippage; }.
Cuối cùng, câu lệnh đầu tiên trong ngoặc { vPoint=Point*10; vSlippage=slippage*10; } thực tế có hai câu lệnh cách nhau bằng dấu chấm phẩy: một câu lệnh xác định ý nghĩa của vPoint và một câu lệnh khác xác định ý nghĩa của vSlippage. Khi điều kiện không được đáp ứng, sẽ có các hàm khác lồng vào nhau trỏ đến câu lệnh ghép thay thế trong ngoặc { vPoint=Point; vSlippage=slippage; }.

Phần 3: Hàm Start()

Phần này là quan trọng nhất và dài nhất, nó sẽ tốt hơn hết là chia phần này thành các phần riêng biệt mà tôi viết là 3A, 3B, v.v.


Khi bắt đầu hàm start() này, tôi đã bao gồm các dòng sau:


< p>if(Thanh<100) { Print(“Thanh nhỏ hơn 100”);

Trả về (0);


Dịch: Nếu Thanh nhỏ hơn 100, không giao dịch và in thanh nhỏ hơn 100 trên màn hình. Sẽ rất hữu ích nếu bao gồm mã này để ngăn giao dịch diễn ra nếu không tải đủ thanh trên biểu đồ.


Học cú pháp, ngôn ngữ và cấu trúc. Đây là một điều kiện if khác được đặt bên trong dấu ngoặc sau "if" (Thanh < 100). Bây giờ hãy lưu ý rằng biểu thức theo sau điều kiện if, nếu nó chứa hai hoặc nhiều câu lệnh ghép, thì phải được đặt trong dấu ngoặc nhọn {} và mỗi câu lệnh trong dấu ngoặc nhọn phải được phân tách bằng dấu chấm phẩy. Trong ví dụ này, chúng ta có hai câu lệnh theo sau điều kiện if. Trong câu lệnh đầu tiên, Print là một hàm thường trú và cần được mô tả trong dấu ngoặc kép và đặt trong dấu ngoặc đơn. Khi điều kiện được đáp ứng, nó sẽ in mô tả đó ra màn hình. Dấu chấm phẩy hoàn thành biểu thức. Trong câu lệnh thứ hai, lợi nhuận (0) có nghĩa là nếu có ít hơn 100 thanh thì sẽ không có giao dịch nào xảy ra.

Lưu ý

Mỗi dấu ngoặc mở phải có một dấu ngoặc nhọn đóng phù hợp, nếu không nó sẽ không biên dịch được, vì vậy chúng ta đóng cả hai câu lệnh bằng một dấu ngoặc nhọn đóng.

Phần 3A: Xác định các thẻ ngắn cho các chức năng giao dịch phổ biến

Ở đây, tôi đã xác định một số thẻ ngắn thể hiện các chức năng giao dịch phổ biến Thẻ ngắn và được trang bị để sử dụng với MagicNumbers.


Tại sao tôi muốn chức năng giao dịch của mình hoạt động với MagicNumbers?


MagicNumber là dấu vân tay của EA của bạn, cho phép chương trình phân biệt EA này với các EA (hoặc giao dịch) khác hoạt động trong cùng loại tiền tệ và khung thời gian. Ví dụ: nếu tôi muốn chương trình chỉ theo dõi các vị trí mua mở của tôi cho EA này chứ không phải các vị trí mua mở của chính nền tảng đó. Vì vậy, khi tôi tham chiếu bất kỳ chức năng thông tin thương mại nào của mình, tôi muốn chúng được liên kết với MagicNumber.

Để có danh sách đầy đủ và định nghĩa về các chức năng thông tin giao dịch này, vui lòng nhấp vào đây: http://docs.mql4.com/trading


< p>Tôi đã làm cho các hàm giao dịch của mình hoạt động với các số ma thuật bằng cách đặt chúng dưới hàm OrderSelect():

for(int Counter=1; Counter<=OrdersTotal(); Counter++)
{ if ( OrderSelect(Counter-1,SELECT_BY_POS, MODE_TRADES)==true)
if (OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
{
tên thẻ = các chức năng giao dịch phổ biến;

}>

Dịch: Nếu có bất kỳ giao dịch nào đang mở hoặc đang chờ xử lý với MagicNumber của tôi, thì tên thẻ sau sẽ đại diện cho các chức năng giao dịch phổ biến


Cú pháp, ngôn ngữ và cấu trúc tinh gọn. Bạn sẽ thường thấy một số biến thể của hàm OrderSelect trong các EA khác nhau, thường là ở dòng đầu tiên của bất kỳ hàm tùy chỉnh nào (Tôi đã sử dụng hàm này trong hai hàm của riêng tôi, 4A và 4B). Hàm OrderSelect chọn thứ tự để xử lý tiếp và trả về true nếu hàm thành công hoặc trả về false nếu thất bại.


Vì hàm OrderSelect() rất quan trọng nên mình đã tạo bài viết riêng, các bạn có thể tham khảo bài viết Lấy thông tin đơn hàng bằng OrderSelect

< p >

Với mục đích của mình, tôi sử dụng hàm OrderSelect để chọn theo giao dịch, MODE_TRADES (đại diện cho các lệnh mở và đang chờ xử lý) và MagicNumber. Nói cách khác, tôi muốn chức năng giao dịch mà tôi đưa vào trong chức năng này có thể xử lý các lệnh mở và đang chờ xử lý thuộc về con số kỳ diệu của tôi. Dòng thứ ba, đặc biệt là phần có nội dung OrderMagicNumber() == MagicNumber, thể hiện điều kiện để đưa chức năng giao dịch vào MagicNumber. Trong số tất cả các hàm giao dịch mà tôi đã nhóm theo hàm này, hàm tôi sử dụng sau này trong mã là OType=OrderType(), mà tôi đã sử dụng trong Phần 3D "Chức năng đóng".


Tôi cũng nên đề cập đến sự liên quan của dòng đầu tiên trong khối mã này:


< p >for(int Counter=1; Counter<=OrdersTotal(); Counter++)


Đây được gọi là toán tử for, được sử dụng để lặp một số được xác định trước khối mã lần. Biểu thức đầu tiên, int = Counter =1, khởi tạo biến Counter của chúng ta với giá trị 1. Biểu thức thứ hai, Counter <=OrdersTotal(), là điều kiện, nếu đúng, sẽ thực thi mã trong dấu ngoặc nhọn (nếu có 3 lệnh mở, nó sẽ thực thi vòng lặp ba lần). Biểu thức thứ ba, Counter++, có nghĩa là "tăng giá trị của Counter lên một". Mỗi khi vòng lặp hoàn thành, bộ đếm trong trường hợp này sẽ tăng thêm 1 cho đến khi tất cả các lệnh mở đều được tính.


Phần 3B: Lệnh gọi chỉ báo

Ở đây tôi khai báo bốn đường trung bình động khác nhau:


FastMACurrent = iMA(NULL, FastMATime, FastMAPeriod, FastMAShift, FastMAType, FastMAPrice, Current + 0);

FastMAPrevious = iMA(NULL, FastMATime, FastMAPeriod, FastMAShift, FastMAType , FastMAprice, Current + 1);

SlowMACurrent = iMA(NULL, SlowMATime, SlowMAPeriod, SlowMAShift, SlowMAType, SlowMAprice, Current + 0);

SlowMAPrevious = iMA(NULL, SlowMATime , SlowMAPeriod, SlowMAShift, SlowMAType, SlowMAPrice, Hiện tại + 1);


Mỗi cái đề cập đến chỉ báo Trung bình trượt gốc cho MT4, có cú pháp cụ thể riêng:


double iMA (String Symbo), int Timeframe, int MAPeriod, int MAShift, int MAMethod, int MAPrice, int Shift)


Tôi thích nghĩ về cấu trúc trong ngoặc sau mã định danh iMA là ô tô Xe buýt với nhiều chỗ ngồi được chỉ định. Mỗi chỗ ngồi trên xe buýt được phân tách bằng dấu phẩy và được gọi là một tham số. Chỉ báo iMA có bảy tham số. Lần lượt, mỗi tham số có một giá trị mặc định có thể được tùy chỉnh (hoặc được cá nhân hóa, để phù hợp với phép ẩn dụ về xe buýt). Sẽ rất hữu ích khi hiểu từng tham số làm gì, giá trị mặc định của mỗi tham số là gì, cách tùy chỉnh chúng và tham số nào thực sự điều khiển bus.


Bảng sau mô tả từng tham số của đường trung bình động:

< colgroup>
MA
Thông số
Mô tả
Biểu tượngBiểu tượng giao dịch , chẳng hạn như EURUSD. Symbol() đại diện cho cặp biểu đồ tiền tệ
Khung thời gian Giai đoạn biểu đồ áp dụng đường trung bình động, thường được đặt thành 0, cho biết EA được đính kèm các Biểu tượng vào biểu đồ.
MAPeriodGiai đoạn nhìn lại của đường trung bình động. Đây là biến quan trọng nhất.
MAShiftChuyển động thuận của đường trung bình động, tính theo đơn vị thanh, thường được đặt thành 0.
MAMethodPhương pháp tính trung bình động, bạn có thể chọn trọng số đơn giản, hàm mũ, làm mịn hoặc tuyến tính. Biến quan trọng thứ hai.
MAPriceMảng giá được sử dụng khi tính toán đường trung bình động, có thể là giá đóng cửa, giá mở cửa, giá cao nhất, giá thấp nhất hoặc một số loại giá trung bình. Thường sử dụng giá trị mặc định là 0 hoặc tắt.
ShiftTrả về dịch chuyển lùi được tính toán của thanh. Giá trị 0 sẽ trả về giá trị chỉ báo của thanh hiện tại và giá trị 3 sẽ trả về giá trị chỉ báo của 3 thanh trước đó. Như chúng ta sẽ thấy, đây là biến quan trọng thứ ba.

Có thể tìm thấy ở đây Bạn có thể tìm thấy tài liệu tham khảo nhanh thuận tiện về các tham số MA (và tham số của tất cả 20 chỉ báo gốc) tại: http://docs.mql4.com/indicators/iMA < /span> Dành cho chúng tôi trực tiếp Vì mục đích của chúng tôi, chúng tôi sẽ sử dụng các giá trị tham số mặc định, tham số quan trọng nhất cho mục đích của chúng tôi là MAPeriod, là độ dài của đường trung bình động, đối với FastMAPeriod tôi mặc định là 2 và đối với SlowMAPeriod tôi mặc định là 30. Điều thúc đẩy xe buýt là MAPeriod vì nó phân biệt giữa các đường trung bình động nhanh và chậm. MAPhương thức này cũng quan trọng, đặc biệt là Đơn giản (Số nguyên=0) và Số mũ (Số nguyên=1). Đối với các đường trung bình động nhanh, tôi mặc định là 0 hoặc Đơn giản và đối với các đường trung bình động chậm, tôi mặc định là 1 hoặc Hàm mũ. Do đó, tôi kỳ vọng đường trung bình động hàm mũ 30 kỳ sẽ vượt qua đường trung bình động đơn giản 2 kỳ để kích hoạt tín hiệu mua. MAShift và MAPrice thường được để ở mức 0 và việc thay đổi các tham số này ít có tác động. Tham số cuối cùng Shift không liên quan gì đến tham số thứ tư MAShift, vì vậy đừng nhầm lẫn cả hai. Trên thực tế, tham số cuối cùng là tham số quan trọng để định vị đường trung bình động theo thời gian. Điều đặc biệt quan trọng là phải phân biệt thanh trước đó với thanh hiện tại, đây là một phần không thể thiếu trong logic vào và ra của chúng tôi. Hãy nhớ rằng tất cả các tham số này đã được đặt dưới dạng các biến bên ngoài để chúng có thể dễ dàng sửa đổi hoặc tối ưu hóa ở giai đoạn sau. Câu hỏi nhanh: Nếu tôi chỉ sử dụng các đường trung bình động nhanh và chậm cho một đường MA giao nhau kép, tại sao tôi phải khai báo bốn đường trung bình động? Khi tôi muốn thực hiện giao thoa MA kép, cần phải chỉ ra điều gì đã xảy ra trước và sau khi giao nhau. Như chúng ta sẽ thấy, một ví dụ về giao cắt mua là khi MA nhanh hiện tại cao hơn MA chậm hiện tại và MA nhanh trước đó nằm dưới MA chậm trước đó. Điều này khiến cần phải xác định bốn đường trung bình động: FastMACurrent, FastMAPrevious, SlowMACurrent, SlowMAPrevious. Sự khác biệt giữa đường trung bình động hiện tại và đường trung bình động trước đó là gì? Sự khác biệt duy nhất giữa đường trung bình động Hiện tại và Trước đó là tham số cuối cùng, tham số Shift: Shift hiện tại là 0 và tham số trước đó là 1.

Phần 3C: Logic đầu vào:

Trong phần đầu tiên của logic đầu vào, chúng ta sẽ viết logic EnterOpenBar đã đề cập trước đó. Điều thú vị là đây là một đoạn mã ngắn nhưng quan trọng thường bị nhiều chuyên gia tư vấn bỏ qua. Đoạn mã như sau:


Thanh mở Boolean = true;

if(EnterOpenBar) if(iVolume(NULL,0,0 ) >1) openbar=false;


Chương trình tìm giá mở cửa của một thanh mới như thế nào? Nó phải tìm dấu tích đầu tiên xuất hiện trên thanh mới. Vì vậy, trong đoạn mã trên, tôi đang kiểm tra khối lượng và trì hoãn việc nhập giao dịch cho đến khi nó phát hiện thấy dấu tích đầu tiên của thanh mới được tìm thấy. Bạn có thể thấy rằng tôi có hai câu lệnh if liên tiếp nhau.


"if (enteronopenbar)" đầu tiên đề cập đến biến bool mà trước đây tôi đã đặt mặc định là true. Khi đúng, nó được chuyển sang câu lệnh điều kiện if tiếp theo, "if (iVolume(NULL,0,0)>1)". Điều kiện if thứ hai kiểm tra xem âm lượng có bằng 1 hay không, trong trường hợp đó openbar trở thành đúng (bất kỳ giá trị nào lớn hơn 1 đều sai) vì nó tìm thấy số thứ tự đầu tiên của thanh mới. Vì việc kiểm tra thanh mở này là một thành phần đơn giản nhưng quan trọng của bất kỳ hệ thống mới nào nên tôi sẽ thảo luận chi tiết hơn về nó trong bài viết riêng của nó, Enter on Open Bar.


Tiếp theo, chúng ta tiếp tục thảo luận về bộ não của EA, các điều kiện chiến lược để gia nhập và rút lui.


Sau đây là các điều kiện mua bán mà tôi dự định viết mã:


Mua điều kiện một:

Nếu đường trung bình động 3 kỳ vượt quá đường trung bình động 30 kỳ, hãy mua trên thị trường (đồng thời đóng vị thế bán mở);


< /p> p>

Bán điều kiện 1:

Nếu đường trung bình động 3 kỳ nằm dưới đường trung bình động 30 kỳ, hãy bán trên thị trường (đồng thời đóng các vị thế mua đang mở).


Hai điều kiện này được chuyển đổi thành mã MQL4 như thế nào?


Có nhiều cách để viết điều kiện chéo, nhưng với mục đích giảng dạy chúng ta sẽ sử dụng phương pháp đơn giản nhất. MT4 không có chức năng chéo tích hợp nên chúng tôi sẽ xây dựng giải pháp chung gồm hai bước. Chúng tôi sẽ chỉ ra điều kiện giao nhau để mua bằng cách xem xét liệu đường trung bình động nhanh của thanh trước đó có nằm dưới mức trung bình động chậm hay không và liệu đường trung bình động của thanh hiện tại có nằm trên đường trung bình động chậm hay không. Vì vậy, nó đã vượt quá giới hạn. Có lẽ bây giờ bạn có thể hiểu đoạn mã sau tốt hơn.


If (

FastMA Current > SlowMA Current &&

FastMAP trước < SlowMAP trước

&& open bar)


{

Mở để mua=True;

if (Đối diệnClose) CloseSell=true;

If (

FastMA Current FastMAPrevious > SlowMAPrevious && openbar)

{

OpenBuy=true;

if (OppositeClose) CloseBuy=true;

>


Trong Về mặt cú pháp, khi bạn khai báo một điều kiện if, bạn phải đặt logic trong dấu ngoặc nhọn {}, đặc biệt nếu nó chứa hai câu lệnh trở lên. Để chỉ ra rằng FastMACurrent phải lớn hơn SlowMACurrent, tôi đã sử dụng ký hiệu >, được gọi là toán tử. Về cơ bản, chúng tôi sẽ nói rằng nếu đường trung bình động 20 kỳ của thanh trước đó nằm dưới đường trung bình động 200 kỳ và nếu đường trung bình động 20 kỳ của thanh hiện tại hiện ở trên đường trung bình động 200 kỳ của thanh hiện tại , sau đó trên thị trường Mua. Vì các toán tử rất quan trọng đối với các điều kiện giao dịch nên tôi đã viết một bài viết ngắn về chúng Các toán tử logic đơn giản


Sau điều kiện if, có các dấu ngoặc nhọn Hai câu lệnh kèm theo {} và được phân tách bằng dấu chấm phẩy: một câu lệnh đặt OpenBuy thành true nếu đáp ứng điều kiện trung bình động, điều này đơn giản và dễ hiểu. Tuyên bố thứ hai tinh tế hơn một chút. Nếu điều kiện trung bình động trước đó được đáp ứng, nó sẽ đặt CloseSell thành true và extern bool OppositeClose cũng thành true. Lưu ý cách nó yêu cầu điều kiện if nội bộ của chính nó, trong trường hợp này OppositeClose bool = true hoặc false, trước khi nó có thể kích hoạt bool CloseSell hoặc CloseBuy. Tôi thích coi các điều kiện bool nội bộ này như một cơ chế khóa và khóa, cho phép người dùng cuối dễ dàng mở và đóng cơ chế (trong trường hợp này là OppositeClose) từ tab thuộc tính chuyên gia.


第 3D 节:关闭条件

Chúng ta bắt đầu phần này với toán tử while. Đây là một phương thức vòng lặp đơn giản trong MQL4, tương tự như vòng lặp for đã thảo luận ở trên, nhưng phù hợp hơn nếu bạn không chắc chắn về số lần lặp. Vòng lặp while của chúng tôi về cơ bản là như thế này:

while (true) {
/ / loop code
>

Tiếp theo, chúng ta đặt điều kiện để đóng lệnh mua và bán:

if (OType==0 && CloseBuy==true)
{
đóng (OP_BUY); // Đóng Mua
return;

OType là một biến đại diện cho hàm thông tin giao dịch OderType(), mỗi biến Mỗi loại lệnh giao dịch có một số nguyên tương ứng. OrderType == 0 đề cập đến OP_BUY, là vị thế mua, trong khi OrderType = 1 đề cập đến OP_SELL, là vị thế bán.


Sau đây là các loại đơn đặt hàng khác nhau và các giá trị nguyên tương ứng của chúng:

< td class="rowhead">OP_SELL< td>3
OrderTypeSố nguyên Mô tả
OP_BUY0Vị trí mua
1Vị thế bán
OP_BUYLIMITGiới hạn mua đang chờ xử lý
OP_BUYSTOP4Dừng mua Đang chờ xử lý
OP_SELLLIMIT5Giới hạn bán đang chờ xử lý
OP_SELLSTOP6Bán Dừng chờ xử lý

Nếu hiện tại có mua hàng Nếu bạn nhập một vị trí (OType==1) và bool CloseBuy là (==) đúng, bạn có thể thực hiện chức năng đóng tùy chỉnh của tôi (OP_BUY). Để tìm hiểu về tính năng đóng tùy chỉnh của tôi, hãy nhấp vào đây.


Tôi kết thúc phần này bằng toán tử break. Toán tử 'break' dừng thực thi toán tử bên ngoài gần nhất thuộc loại 'while', 'for' hoặc 'switch'. Việc thực thi toán tử 'break' bao gồm việc chuyển điều khiển vượt ra ngoài toán tử ghép thuộc loại 'while', 'for' hoặc 'switch' sang toán tử tiếp theo gần nhất.


Phần 3E: Đặt hàng

Sau toán tử break ở phần trước, tôi bắt đầu phần này với một toán tử while khác. Ngắt từ phần trước đã chuyển quyền điều khiển hoặc chuyển sang vòng lặp while thứ hai.


Ở phần này chương trình sẽ đặt lệnh mua và bán.


Nó bắt đầu với điều kiện sau:


if (OrdersTotalMagicOpen()== 0 && OpenBuy==true)


OrdersTotalMagicOpen() là một chương trình tùy chỉnh mà chúng ta sẽ sớm truy cập để tính toán phép thuật có trong EA Số lệnh mở trong số. Nếu tổng số đơn hàng là 0 (==0) thì chúng ta có thể tiếp tục. và (&&) nếu bool OpenBuy đúng, chúng tôi có thể tiếp tục.


Tiếp theo là đoạn mã để xác định giá trị mục tiêu dừng lỗ và lợi nhuận:


if (StopLoss>0){SL=Bid – StopLoss*vPoint;}else{SL=0;} if(TakeProfit>0){TP=Bid+TakeProfit*vPoint;}else{TP=0;

< p>

Ở đây chúng ta sử dụng hai câu lệnh if-else tuần tự đối lưng nhau. Hãy quay lại một chút. Hãy nhớ rằng, điều kiện khác đánh giá điều kiện thay thế nếu câu lệnh if trước đó là sai. Chúng tôi đang kết hợp else và if để tạo một điều kiện thay thế sẽ chỉ thực thi nếu đúng. Trong trường hợp này, chúng tôi nói rằng nếu StopLoss > 0 thì chúng tôi có thể xác định giá trị của StopLoss (Bid-StopLoss *vPoint). Nếu đó là điểm dừng lỗ của chúng tôi, thay vì 0, thì chúng tôi không chắc chắn về giá trị của điểm dừng lỗ và phương án này sẽ là điểm dừng lỗ vẫn ở mức 0. Logic tương tự được lặp lại cho chốt lời. Các giá trị được xác định dựa trên các điều kiện if-else này xuất hiện trong tham số StopLoss và TakeProfit của hàm OrderSend().


Tiếp theo, chúng tôi muốn tiếp tục làm mới tỷ giá và đẩy các lệnh của mình cho đến khi chúng được thực thi:


Ticket=0; number=0;

while(ticket<=0 && number<100){

Tốc độ làm mới();< /p>< p>

Chúng tôi đang nói rằng nếu vé là 0 (đơn hàng chưa được điền) và số lần thử điền vào đó nhỏ hơn 100 thì chúng tôi sẽ tiếp tục làm mới tỷ lệ và cố gắng điền vào nó. Đây là một mã hữu ích nếu có báo giá lại trong một thị trường biến động nhanh và bạn vẫn muốn được khớp lệnh. Một lần nữa, bạn sẽ thấy toán tử while đang chạy, lần này lặp qua phiếu và số lần thử đặt hàng.


Tiếp theo là hàm OrderSend(). Bản thân nó là một tính năng đa diện và tôi đã viết một bài viết ngắn ở đây Lệnh thị trường với OrderSend