
거래 EA를 프로그래밍하는 데 도움이 되는 완전한 MQL4 Expert Advisor 예제 기사에서 완전한 기능을 갖춘 MA Expert Advisor를 작성하는 방법을 알아보세요.
Expert Advisors 구성을 논의하는 몇 가지 매뉴얼과 가이드에서는 이동 평균 교차(MACross)를 예로 사용하는 경향이 있습니다. 그 이유는 현재 가장 인기 있는 지표 기반 전략이며, 대부분의 사람들에게 이미 익숙한 거래 개념을 사용하여 새로운 코딩 개념을 가르치는 것이 훨씬 쉽기 때문입니다.
이 익숙한 경로를 따라 간단한 이동 크로스오버(20-200)를 기반으로 한 기본 전문 조언자를 제출했습니다.
// 섹션 1:
// 전처리기 지시어, 외부 및 내부 변수
#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&&> < 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&&>
이전에 프로그래밍 경험이 없다면 위의 코드가 다소 신비스럽고 위협적으로 보일 수 있습니다. 위협 요인을 극복하는 한 가지 방법은 작은 세부 사항에 대해 덜 걱정하고 큰 그림에 집중하는 것입니다.
언어의 모든 부분이 어떻게 작동하는지 알아내거나 프로세서 수준에서 뒤에서 무슨 일이 벌어지고 있는지 궁금해하지 마세요. 일하고 있습니다. 언어의 세부사항과 형식에 집착할 필요가 없습니다. EA를 이해하고 구축하기 위해 특정 세부 사항에 주의를 기울일 필요는 없습니다. 이 시점에서는 퍼즐 조각이 어떻게 맞춰지는지, 가장 중요한 조각 중 어떤 조각을 조작하여 새로운 전략을 만들 수 있는지만 알면 됩니다.
저는 당신이 퍼즐 조각을 맞추고 가장 중요한 조각의 방향을 알려줄 수 있도록 도와드리겠습니다. 각 섹션을 안내할 때 상호 참조하기 쉽도록 EA의 각 섹션에 번호를 매기고 레이블을 지정했습니다.
먼저 몇 가지 설명입니다. // 뒤에 포함된 몇 가지 설명을 볼 수 있습니다.
/로 시작하는 모든 줄은 자유 텍스트이며 프로그램에서 무시됩니다.
컴퓨터가 무시하더라도 프로그래밍 명령문의 의미를 일반 영어로 설명하는 데 도움이 되는 주석을 포함합니다. 네, 프로그래밍 언어는 언뜻 이해하기 어려울 수 있으며, 코드를 작성할 때 주석을 추가하면 생활이 더 편해지는 데 유용할 수 있습니다.
다음으로 전처리기 지시문에 대해 이야기해 보겠습니다. 각 명령은 파운드 기호(#)로 시작됩니다. #import 및 #include와 같은 고급 형태의 지시문이 많이 있지만 우리는 그 중 가장 간단한 것, 즉 코드를 우리 코드로 식별하는 #property 저작권 전처리기 지시문만 사용하겠습니다. 그 외에는 그다지 중요하지도 않고 특별할 것도 없습니다.
다음은 외부 변수입니다. 매우 중요합니다. 이전 기사에서 변수가 나중에 사용하기 위해 물건을 저장할 수 있는 작은 상자와 같다는 점을 설명했습니다. 외부 변수(extern이라는 단어 앞에 오는)는 사용자가 쉽게 조작할 수 있도록 전문가 대화 상자의 프로그램 외부에 해당 매개변수를 표시하므로 중요합니다.
위의 기본 EA에서 볼 수 있는 많은 외부 변수는 설명이 필요하지 않습니다. 나중에 OrderSend 함수의 구문을 배울 때 EAName, MagicNumber, Lotssize, TakeProfit 및 Stoploss에 대해 논의하겠습니다. 섹션 3E, OrderPlacement를 참조하세요. 이러한 변수는 주로 해당 기능을 참조합니다.
이 섹션에서 흥미로운 외부 변수는 이동 평균 매개변수 변수(특히 MAPeriod), OppositeClose 및 EnterOpenBar입니다.
참고로 이동평균 매개변수 값은 모두 외부변수로 두었습니다. 이런 일을 할 필요는 없어요. 섹션 3B "인디케이터 호출"에서 호출할 때 가장 중요한 변수 MAPeriod만 외부 변수로 만들고 나머지 매개변수는 인디케이터 내에서 기본값으로 둘 수 있었습니다. 나중에 매개변수를 최적화하려는 경우를 대비해 거의 모든 매개변수를 외부 변수로 선언했습니다. 지금은 MAPeriod만 최적화할 것입니다. 하지만 다른 것들도 최적화하면 나중에 유용할 수 있습니다. 섹션 3B "지표 호출"을 다룰 때 이러한 매개변수에 대해 자세히 논의할 것입니다.
변수에 bool이 표시되면 true 값에 사용되는 유형입니다. bool 유형은 논리 미적분학 창시자의 성(姓)인 Boolean에서 유래되었습니다. bool OppositeClose를 확인해 보겠습니다.
외부 부울 OpositeClose=True
이 변수의 외부 부울을 사용하면 다음을 열고 반대 닫기 조건을 닫습니다. 코드에서 reverseclose가 참조될 때마다 기본값은 true로 설정됩니다. 즉, 해당 항목이 열리길 원한다는 뜻입니다. false로 설정하면 꺼집니다. 또는 true 또는 false를 사용하는 대신 false에는 0을, true에는 1을 사용할 수 있습니다.
OppositeClose bool은 반대 신호에 따라 주문을 청산할 수 있다는 아이디어를 의미합니다. 무슨 뜻이에요? true로 설정하고 현재 매수 포지션에 있고 매도 진입 주문이 실행되면 매도 진입 주문은 매도 거래를 하기 전에 현재 매수 포지션을 청산합니다. 매도 진입 신호는 현재 매수 포지션을 청산하는 반대 신호입니다(그 반대도 마찬가지). 나는 확실히 활성화되기를 원하기 때문에 true에 반대쪽에 가깝습니다. 거짓을 선택하면, 즉 반대쪽 청산을 비활성화하면 매도 진입 신호는 이전 매수 거래를 청산하지 않으며 매수 거래는 손절매나 이익실현을 눌러 청산될 때까지 열린 상태로 유지됩니다. 보통은 reverseclose를 true로 설정하고 활성화하는 것이 좋습니다. 섹션 3D "닫기 조건"에서 reverseclose의 인코딩에 대해 논의하고 섹션 4A "닫기 함수"에서 찾을 수 있는 관련 함수를 논의합니다.
EnterOpenBar bool은 인터바나 마감이 아닌 각 새 바의 개시 시에만 거래를 입력한다는 아이디어를 나타냅니다. 지표를 기반으로 새로운 전략을 만들 때 저는 전략이 어떻게 백테스트되고 있는지 빠르게 확인하기 위해 EnterOpenBar를 true로 기본 설정하는 것을 선호합니다. strategytester의 드롭다운 메뉴에는 모든 틱, 제어점, 공개 틱의 세 가지 유형의 백테스팅 모드가 있습니다. 각 틱은 다른 틱보다 더 정확하지만 느립니다. 시가는 다른 가격에 비해 정확도는 떨어지지만 빠릅니다. 제어점은 정확성과 속도 모두에서 둘 사이의 어딘가에 있습니다. 그러나 EnterOpenBar가 true로 설정되면 공개 가격 전용 모드에서 안전하게 백테스트할 수 있으므로 백테스트 속도가 크게 높아지면서 모든 틱 모드와 매우 유사한 정확도와 결과를 얻을 수 있습니다. 백테스트 속도 외에도 enteronopenbar를 true로 설정하면 특히 공통 메트릭을 기반으로 하는 경우 시스템의 전반적인 성능과 안정성이 향상된다는 점도 확인했습니다. 결과의 차이를 확인하려면 enteronopenbar를 true 및 false로 설정해 보시기 바랍니다. EnterOpenBar 뒤에 있는 코딩은 섹션 3C, "입력 논리"에서 찾을 수 있습니다.
마지막으로 이 섹션에서는
복권, 번호, vPoint;
각 식별자에 대해 구체적인 값을 선언하지 않았음을 참고하시기 바랍니다. 값이 선언되지 않으면 각 식별자의 기본값은 0이며 나중에 결정됩니다. 판정이 완료되면 0으로 되돌아갑니다. 또한 세미콜론으로 명령문을 끝낼 때까지 이중 뒤에 식별자를 쉼표로 구분하여 하나씩 나열한다는 점에 유의하세요. 이는 그 중 어느 것도 전역적으로 다른 값을 가지지 않기 때문에 수행될 수 있습니다. 여기 대신 start() 함수에서 이를 선언할 수도 있지만 이 섹션에 선언하면 내 코드의 모든 함수에서 전역적으로 참조할 수 있습니다. 이는 매우 편리하며 불필요한 중복을 방지합니다.
보시다시피 이 섹션에는 많은 내용이 없습니다.
이 섹션에 포함된 코드는 브로커의 통화 번호를 기준으로 pip 값을 설정하는 데 사용됩니다(브로커는 4자리 또는 5자리 견적 시스템으로 설정됨):
if(Digits== 3 | | 숫자==5)
{ vPoint=Point*10; vSlippage=Slippage*10; }
else{ vPoint=Point; vSlippage=Slippage; }
< /strong>
간단한 영어 번역: 통화 쌍이 3 또는 5의 숫자로 표시되는 경우 pip 값은 포인트*10과 동일합니다. 그렇지 않은 경우(예: 2 또는 4), pip 값은 배수가 없는 pip 값으로 유지됩니다.
소수점 3자리 또는 5자리의 브로커를 자동으로 감지하고 조정하는 코드를 삽입하는 것은 제가 자체 기사 "자동으로 미끄러짐 감지 및 이는 포인트 가치에서 자세히 설명했습니다.
구문, 언어 및 구조를 알아보세요. if 조건이 어떻게 괄호()로 묶여 있고 명령문이 중괄호 {}로 묶여 있는지 확인하세요. 이는 if 조건 뒤에 해당 문이 오는 일반적인 구조입니다. 이 경우 if 조건은 if(Digits==3 || Digits==5)이며 이중 등호(==)는 같음을 의미하고 이중 수직 막대(||)는 "또는"을 의미한다는 점을 기억하세요. , 당신은 당신의 단어가 기계어로 어떻게 번역되는지 알아야 합니다: 단지 "and" 또는 "or"라고 말하면 편리하겠지만, 이러한 단어를 사용하면 프로그램은 당신을 이해하지 못할 것입니다. 대신에 당신은 다음을 사용해야 합니다. "or"를 나타내는 이중 수직 막대(||)와 "and"를 나타내는 이중 기호(&&)