English Русский 中文 Español Deutsch 日本語 Português Français Italiano Türkçe
다중 통화 다중 시스템 Expert Advisor 만들기

다중 통화 다중 시스템 Expert Advisor 만들기

MetaTrader 5 | 3 9월 2021, 11:17
220 0
Maxim Khrolenko
Maxim Khrolenko

소개

하나 이상의 거래 기호를 거래하고 여러 전략을 사용하는 트레이더가 꽤 있다고 생각합니다. 이 접근 방식을 사용하면 잠재적으로 수익을 늘릴 수 있을 뿐만 아니라 효율적인 자금 관리에 따른 상당한 손실 위험을 최소화할 수 있습니다. Expert Advisor를 생성할 때 프로그램 전략의 효율성을 확인하는 첫 번째 자연스러운 단계는 최상의 입력 매개변수를 결정하기 위한 최적화입니다.

매개변수 값이 식별되면 Expert Advisors는 기술적으로 거래할 준비가 됩니다. 그러나 그렇게 하면 한 가지 중요한 질문에 대한 답을 얻을 수 없습니다. 트레이더가 자신의 모든 전략을 하나의 Expert Advisor에 통합할 수 있다면 테스트 결과는 어떻게 될까요? 여러 기호 또는 전략에 대한 드로다운이 어느 시점에서 중복되어 무시무시한 총 드로다운 또는 심지어 마진 콜이 발생할 수 있다는 사실을 깨닫는 것은 때때로 불쾌한 놀라움으로 올 수 있습니다.

이 글에서는 이 중요한 질문에 대한 답을 찾을 수 있도록 하는 다중 통화 다중 시스템 Expert Advisor를 만드는 개념을 소개합니다.


1. Expert Advisor의 구조

일반적으로 Expert Advisor의 구조는 다음과 같습니다.

그림 1. 다중 통화 다중 시스템 Expert Advisor의 구조

그림 1. 다중 통화 다중 시스템 Expert Advisor의 구조

보시다시피 프로그램은 for 루프를 기반으로 합니다. 각 전략은 각 반복이 각 기호를 개별적으로 거래하는 루프로 배열됩니다. 여기에서 루프에서 무제한의 전략을 정렬할 수 있습니다. 중요한 것은 이러한 프로그램을 "처리"할 수 있는 충분한 리소스가 컴퓨터에 있어야 한다는 것입니다.

MetaTrader 5에서 거래되는 각 기호에 대해 하나의 위치만 있을 수 있음을 명심해야 합니다. 이러한 위치는 이전에 실행된 매수 및 매도 랏의 합계를 나타냅니다. 따라서 하나의 심볼에 대한 다중 전략 테스트의 결과는 동일한 심볼에 대한 동일한 전략의 개별 테스트 결과의 합과 동일하지 않습니다.

Expert Advisor의 구조를 자세히 고려하기 위해 각각 두 가지 기호를 거래하는 두 가지 전략을 취합니다.

전략 A:

  • 매수: 매도호가가 저가를 기준으로 계산된 볼린저 밴드 지표의 하단 밴드에 도달합니다.
    종가: 고가를 기준으로 계산된 볼린저 밴드 지표의 하한 밴드에 입찰 가격이 도달합니다.
  • 매도: 입찰가가 고가를 기준으로 계산된 볼린저 밴드 지표의 상단 밴드에 도달합니다.
    마감: 매도호가는 저가를 기준으로 계산된 볼린저 밴드 지표의 상단 밴드에 도달합니다.
  • 제한 사항: 주어진 바에서 하나의 거래만 실행할 수 있습니다.

전략 В:

  • 매수: 이전 바가 약세(종가 < 시가)이고 매도가가 이전 바의 고점에 도달했습니다.
    결산: 손절매 또는 이익 실현.
  • 매도: 이전 바가 강세(종가 > 시가)이고 입찰가가 이전 바의 최저가에 도달합니다.
    결산: 손절매 또는 이익 실현.
  • 제한 사항: 주어진 바에서 하나의 거래만 실행할 수 있습니다.

Expert Advisor가 테스트되거나 거래될 심볼에 대한 새로운 틱에서 독립하려면 다중 통화 모드에서 거래할 때 OnTimer() 함수를 사용하는 것이 좋습니다.

이를 위해 Expert Advisor를 초기화할 때 EventSetTimer() 함수를 사용하여 프로그램 계산 호출을 위한 이벤트 생성 빈도를 지정하고 초기화 해제 시 EventKillTimer() 이벤트 생성을 중지하도록 터미널에 알리는 기능:

// Include standard libraries
// Create external parameters
// Create arrays, variables, indicator handles, etc.

//--- Initialization of the Expert Advisor
int OnInit()
  {
   //--- Set event generation frequency
   EventSetTimer(1); // 1 second
   // ...
   return(0);
  }
void OnTimer()
  {
   // ...
  }
//--- Deinitialization of the Expert Advisor
void OnDeinit(const int reason)
  {
   //--- Stop event generation
   EventKillTimer();
   // ...
  }

EventSetTimer() 대신 EventSetMillisecondTimer()를 사용할 수도 있습니다. 여기서 주파수는 밀리초로 정확하지만 너무 오용해서는 안 됩니다. 빈번한 프로그램 계산 호출.

계정, 위치 및 기호 설정 및 거래 기능에 대한 액세스를 위해 CAccountInfo, CPositionInfo, CSymbolInfoCTrade를 사용합니다. 클래스. Expert Advisor에 포함시켜 보겠습니다.

//--- Include standard libraries
#include <Trade\AccountInfo.mqh>
#include <Trade\PositionInfo.mqh>
#include <Trade\SymbolInfo.mqh>
#include <Trade\Trade.mqh>

Expert Advisor는 for 루프를 기반으로 하므로 외부 매개변수에 대한 배열을 생성해야 합니다. 먼저 각 전략에 대한 기호 수와 동일한 상수를 생성해 보겠습니다.

//--- Number of traded symbols for each strategy
#define Strategy_A 2
#define Strategy_B 2

그런 다음 외부 매개변수를 만듭니다. 상수를 사용하여 복사할 배열의 크기를 결정합니다. 또한 지표 핸들 및 기타 전역 변수를 생성합니다.

전략 А의 한 기호에 대한 예는 다음과 같습니다.

//------------------- External parameters of strategy A
input string          Data_for_Strategy_A="Strategy A -----------------------";
//--- Symbol 0
input string          Symbol_A0      = "EURUSD";   // Symbol
input bool            IsTrade_A0     = true;       // Permission for trading
//--- Bollinger Bands (BB) parameters
input ENUM_TIMEFRAMES Period_A0      = PERIOD_H1;  // ВВ period
input uint            BBPeriod_A0    = 20;         // Period for calculation of the moving average of BB
input int             BBShift_A0     = 0;          // Horizontal shift of ВВ
input double          BBDeviation_A0 = 2.0;        // Number of standard deviations of BB
//...
//--- General parameters of strategy A
input double          DealOfFreeMargin_A = 1.0;    // Percent of free margin for a deal
input uint            MagicNumber_A      = 555;    // Magic number
input uint            Slippage_A         = 100;    // Permissible slippage for a deal
//...
//------------- Set variables of strategy A -----
//--- Arrays for external parameters
string          Symbol_A[Strategy_A];
bool            IsTrade_A[Strategy_A];
ENUM_TIMEFRAMES Period_A[Strategy_A];
int             BBPeriod_A[Strategy_A];
int             BBShift_A[Strategy_A];
double          BBDeviation_A[Strategy_A];
//--- Arrays for global variables
double          MinLot_A[Strategy_A],MaxLot_A[Strategy_A];
double          Point_A[Strategy_A],ContractSize_A[Strategy_A];
uint            DealNumber_A[Strategy_A];
datetime        Locked_bar_time_A[Strategy_A],time_arr_A[];
//--- Indicator handles
int             BB_handle_high_A[Strategy_A];
int             BB_handle_low_A[Strategy_A];
//--- Arrays for indicator values
double          BB_upper_band_high[],BB_lower_band_high[];
double          BB_upper_band_low[],BB_lower_band_low[];
//--- Class
CTrade          Trade_A;
//...
//--- Set global variables for all strategies
long            Leverage;
//--- Classes
CAccountInfo    AccountInfo;
CPositionInfo   PositionInfo;
CSymbolInfo     SymbolInfo;

특정 기호에 대한 거래를 비활성화할 수 있도록 for 루프의 맨 처음에 배치되는 부울 변수 IsTrade_A0을 만들었습니다.


2. Expert Advisor 초기화

먼저 모든 전략에 필요한 값을 얻습니다. 예를 들어 영향력 같은 것들입니다. 레버리지는 거래 계정에 적용되며 전략이나 기호와 관련이 없으므로 해당 값을 배열에 복사할 필요가 없습니다.

//--- Get the leverage for the account
   Leverage=AccountInfo.Leverage();

그런 다음 외부 변수를 배열에 복사합니다.

//--- Copy external variables to arrays
   Symbol_A[0]     =Symbol_A0;
   IsTrade_A[0]    =IsTrade_A0;
   Period_A[0]     =Period_A0;
   BBPeriod_A[0]   =(int)BBPeriod_A0;
   BBShift_A[0]    =BBShift_A0;
   BBDeviation_A[0]=BBDeviation_A0;

외부 매개변수가 다른 매개변수로 변환해야 하는 유형으로 정의된 경우 배열에 복사할 때 더 편리한 방법으로 수행할 수 있습니다.

이 경우 사용자가 음수 값을 설정하지 못하도록 BBPeriod_A0uint로 생성되었음을 알 수 있습니다. 여기에서 int로 변환하고 int로도 생성된 배열에 복사합니다. 그렇지 않으면 지표 핸들에 uint 유형 매개변수를 삽입하려고 하면 컴파일러에서 경고를 표시합니다.

거래된 기호가 Market Watch에서 사용 가능한지 여부와 한 전략 내에서 두 번 이상 사용되었는지 더 살펴보겠습니다.

//--- Check for the symbol in the Market Watch
   for(int i=0; i<Strategy_A; i++)
     {
      if(IsTrade_A[i]==false) continue;
      if(IsSymbolInMarketWatch(Symbol_A[i])==false)
        {
         Print(Symbol_A[i]," could not be found on the server!");
         ExpertRemove();
        }
     }

//--- Check whether the symbol is used more than once
   if(Strategy_A>1)
     {
      for(int i=0; i<Strategy_A-1; i++)
        {
         if(IsTrade_A[i]==false) continue;
         for(int j=i+1; j<Strategy_A; j++)
           {
            if(IsTrade_A[j]==false) continue;
            if(Symbol_A[i]==Symbol_A[j])
              {
               Print(Symbol_A[i]," is used more than once!");
               ExpertRemove();
              }
           }
        }
     }
//--- The IsSymbolInMarketWatch() function
bool IsSymbolInMarketWatch(string f_Symbol)
  {
   for(int s=0; s<SymbolsTotal(false); s++)
     {
      if(f_Symbol==SymbolName(s,false))
         return(true);
     }
   return(false);
  }

기호가 올바르게 선택되었으면 각 기호에 대한 입력 매개변수의 오류를 확인하고 지표 핸들을 만들고 랏 계산에 필요한 데이터를 가져오고 필요한 경우 주어진 전략에 정의된 대로 다른 작업을 수행합니다.

for 루프 내에서 위에서 언급한 작업을 구현합니다.

//--- General actions
   for(int i=0; i<Strategy_A; i++)
     {
      if(IsTrade_A[i]==false) continue;
      //--- Check for errors in input parameters
      //...
      //--- Set indicator handles
      BB_handle_high_A[i]=iBands(Symbol_A[i],Period_A[i],BBPeriod_A[i],BBShift_A[i],BBDeviation_A[i],
                                 PRICE_HIGH);
      if(BB_handle_high_A[i]<0)
        {
         Print("Failed to create a handle for Bollinger Bands based on High prices for ",Symbol_A[i]," . Handle=",INVALID_HANDLE,
               "\n Error=",GetLastError());
         ExpertRemove();
        }
      //...
      //--- Calculate data for the Lot
      //--- set the name of the symbol for which the information will be obtained
      SymbolInfo.Name(Symbol_A[i]);
      //--- minimum and maximum volume size in trading operations
      MinLot_A[i]=SymbolInfo.LotsMin();
      MaxLot_A[i]=SymbolInfo.LotsMax();
      //--- point value
      Point_A[i]=SymbolInfo.Point();
      //--- contract size
      ContractSize_A[i]=SymbolInfo.ContractSize();

      //--- Set some additional parameters
     }

그런 다음 CTrade 클래스의 Trade_A 개체를 사용하여 전략 A의 거래 작업에 대한 매개변수를 설정합니다.

//--- Set parameters for trading operations
//--- set the magic number
   Trade_A.SetExpertMagicNumber(MagicNumber_A);
//--- set the permissible slippage in points upon deal execution
   Trade_A.SetDeviationInPoints(Slippage_A);
//--- order filling mode, use the mode that is allowed by the server
   Trade_A.SetTypeFilling(ORDER_FILLING_RETURN);
//--- logging mode, it is advisable not to call this method as the class will set the optimal mode by itself
   Trade_A.LogLevel(1);
//--- the function to be used for trading: true - OrderSendAsync(), false - OrderSend().
   Trade_A.SetAsyncMode(true);

각 전략에 대해 동일한 절차가 반복됩니다.

  1. 외부 변수를 배열에 복사합니다.
  2. 기호가 올바르게 선택되었는지 확인하십시오.
  3. 오류를 확인하고, 지표 핸들을 설정하고, 랏 및 주어진 전략에 필요한 모든 데이터를 계산합니다.
  4. 거래 작업에 대한 매개변수를 설정합니다.

마지막으로 여러 전략에서 하나의 동일한 기호가 사용되는지 확인하는 것이 좋습니다(아래에 두 가지 전략의 예가 제공됨).

//--- Check whether one and the same symbol is used in several strategies
   for(int i=0; i<Strategy_A; i++)
     {
      if(IsTrade_A[i]==false) continue;
      for(int j=0; j<Strategy_B; j++)
        {
         if(IsTrade_B[j]==false) continue;
         if(Symbol_A[i]==Symbol_B[j])
           {
            Print(Symbol_A[i]," is used in several strategies!");
            ExpertRemove();
           }
        }
     }

3. "For" 루프 거래

OnTimer() 함수 내 for 루프의 프레임워크는 다음과 같습니다.

void OnTimer()
  {
//--- Check if the terminal is connected to the trade server
   if(TerminalInfoInteger(TERMINAL_CONNECTED)==false) return;

//--- Section A: Main loop of the FOR operator for strategy A -----------
   for(int A=0; A<Strategy_A; A++)
     {
      //--- A.1: Check whether the symbol is allowed to be traded
      if(IsTrade_A[A]==false)
         continue; // terminate the current FOR iteration

     }

//--- Section В: Main loop of the FOR operator for strategy В -----------
   for(int B=0; B<Strategy_B; B++)
     {
      //--- B.1: Check whether the symbol is allowed to be traded
      if(IsTrade_B[B]==false)
         continue; // terminate the current FOR iteration

     }
  }

단일 전략을 기반으로 하는 단일 기호 Expert Advisor에 모든 후속 계산을 중지해야 하는 조건이 있는 경우 return 연산자를 사용합니다. 우리의 경우에는 현재 반복을 종료하고 다음 기호 반복으로 진행하기만 하면 됩니다. 이를 위해서는 continue 연산자를 사용하는 것이 가장 좋습니다.

모든 후속 계산의 종료 조건이 포함된 for 루프가 있는 전략을 추가하여 다중 전략 Expert Advisor를 향상시키려면 다음 패턴을 사용할 수 있습니다.

//--- Section N: Main loop of the FOR operator for strategy N -----------
for(int N=0; N<Strategy_N; N++)
  {

   //...
   bool IsInterrupt=false;
   for(int i=0; i<Number; i++)
     {
      if(...) // terminate all calculations
        {
         IsInterrupt=true;
         break;
        }
     }
   if(IsInterrupt=true)
      continue; // terminate the current FOR iteration
   //...

  }

for 루프의 프레임워크를 만든 후 다른 EA의 코드를 삽입하고 일부 변수를 배열 요소로 대체합니다.

예를 들어 사전 정의된 변수 _SymbolSymbol_A[i]로 변경하거나 _PointPoint_A[i]로 변경합니다. 이러한 변수의 값은 지정된 기호의 전형이므로 초기화 시 배열에 복사되었습니다.

예를 들어 지표 값을 찾아보겠습니다.

 //--- A.3: Lower band of BB calculated based on High prices
 if(CopyBuffer(BB_handle_high_A[A],LOWER_BAND,BBShift_A[A],1,BB_lower_band_high)<=0)
    continue; // terminate the current FOR iteration
 ArraySetAsSeries(BB_lower_band_high,true);

매수 포지션 청산을 구현하기 위해 다음 코드를 작성합니다.

 //--- A.7.1: Calculate the current Ask and Bid prices
 SymbolInfo.Name(Symbol_A[A]);
 SymbolInfo.RefreshRates();
 double Ask_price=SymbolInfo.Ask();
 double Bid_price=SymbolInfo.Bid();

 if(PositionSelect(Symbol_A[A]))
   {
    //--- A.7.2: Closing a BUY position
    if(PositionInfo.PositionType()==POSITION_TYPE_BUY)
      {
       if(Bid_price>=BB_lower_band_high[0] || DealNumber_A[A]==0)
         {
          if(!Trade_A.PositionClose(Symbol_A[A]))
            {
             Print("Failed to close the Buy ",Symbol_A[A]," position. Code=",Trade_A.ResultRetcode(),
                   " (",Trade_A.ResultRetcodeDescription(),")");
             continue; // terminate the current FOR iteration
            }
          else
            {
             Print("The Buy ",Symbol_A[A]," position closed successfully. Code=",Trade_A.ResultRetcode(),
                   " (",Trade_A.ResultRetcodeDescription(),")");
             continue; // terminate the current FOR iteration
            }
         }
      }

    //...
   }

매수 포지션 개설:

 //--- A.9.1: for a Buy
 if(Ask_price<=BB_lower_band_low[0])
   {
    //...

    //--- A.9.1.3: Execute a deal
    if(!Trade_A.Buy(OrderLot,Symbol_A[A]))
      {
       Print("The Buy ",Symbol_A[A]," has been unsuccessful. Code=",Trade_A.ResultRetcode(),
             " (",Trade_A.ResultRetcodeDescription(),")");
       continue; // terminate the current FOR iteration
      }
    else
      {
       Print("The Buy ",Symbol_A[A]," has been successful. Code=",Trade_A.ResultRetcode(),
             " (",Trade_A.ResultRetcodeDescription(),")");
       continue; // terminate the current FOR iteration
      }
   }

타이머 이벤트 생성을 종료하고 초기화 해제 시 지표 핸들을 삭제하는 것을 잊지 마십시오.


4. 시험 결과

Expert Advisor가 준비되면 각 전략과 기호를 별도로 테스트하고 모든 전략과 기호를 동시에 거래할 때 테스트 모드에서 얻은 것과 테스트 결과를 비교합니다.

사용자가 이미 최적의 입력 매개변수 값을 식별했다고 가정합니다.


다음은 전략 테스터의 설정입니다.

그림 2. 전략 테스터 설정

그림 2. 전략 테스터 설정

전략 A, EURUSD에 대한 결과:

그림 3. 전략 A, EURUSD에 대한 테스트 결과

그림 3. 전략 A, EURUSD에 대한 테스트 결과

전략 A, GBPUSD에 대한 결과::

그림 4. 전략 A, GBPUSD에 대한 테스트 결과

그림 4. 전략 A, GBPUSD에 대한 테스트 결과

전략 B, AUDUSD에 대한 결과:

그림 5. 전략 В, AUDUSD에 대한 테스트 결과

그림 5. 전략 В, AUDUSD에 대한 테스트 결과

전략 B에 대한 결과, EURJPY:

그림 6. 전략 В, EURJPY에 대한 테스트 결과

그림 6. 전략 В, EURJPY에 대한 테스트 결과

모든 전략 및 기호에 대한 테스트 결과:

그림 7. 모든 전략 및 기호에 대한 테스트 결과

그림 7. 모든 전략 및 기호에 대한 테스트 결과


결론

결과적으로, 우리는 거의 모든 전략을 배치할 수 있는 다중 통화 다중 시스템 Expert Advisor의 편리하고 간단한 구조를 갖게 되었습니다.

이러한 Expert Advisor를 사용하면 모든 전략을 사용하여 거래의 효율성을 더 잘 평가할 수 있습니다. 특정 계정에서 한 명의 Expert Advisor만 작업할 수 있는 경우에도 유용할 수 있습니다. 위의 정보를 쉽게 공부할 수 있도록 Expert Advisor의 소스 코드를 글에 첨부했습니다.


MetaQuotes 소프트웨어 사를 통해 러시아어가 번역됨.
원본 기고글: https://www.mql5.com/ru/articles/770

파일 첨부됨 |
2multi_en.mq5 (30.27 KB)
Kagi 차트 지표 Kagi 차트 지표
이 글에서는 다양한 차트 옵션과 추가 기능을 갖춘 Kagi 차트 지표를 제안합니다. 또한 지표 차트 작성 원리와 MQL5 구현 기능을 고려합니다. 거래에서 가장 인기 있는 구현 사례가 표시됩니다. 음/양 교환 전략, 추세선에서 멀어지고 지속적으로 "어깨" 증가/"허리" 감소.
MQL5 Coobook: MQL5에서 다중 기호 변동성 지표 개발 MQL5 Coobook: MQL5에서 다중 기호 변동성 지표 개발
이 글에서는 다중 기호 변동성 지표의 개발을 고려해볼 것입니다. 다중 기호 지표의 개발은 이 글에서 명확히 하는 데 도움이 되는 초보 MQL5 개발자에게 몇 가지 어려움을 줄 수 있습니다. 다중 기호 지표 개발 과정에서 발생하는 주요 문제는 현재 기호에 대한 다른 기호 데이터의 동기화, 일부 지표 데이터의 부족 및 주어진 시간 프레임의 '참' 바에 대한 시작 식별과 관련이 있습니다. 이 모든 문제는 글에서 면밀히 고려해보겠습니다.
계량경제학 EURUSD 1단계 예측 계량경제학 EURUSD 1단계 예측
이 글은 EViews 소프트웨어를 사용한 EURUSD에 대한 한 단계 앞선 예측과 EViews의 프로그램을 사용한 예측 결과의 추가 평가에 중점을 둡니다. 예측에는 회귀 모델이 포함되며 MetaTrader 4용으로 개발된 Expert Advisor를 통해 평가됩니다.
MQL5 Coobook: 지표 하위 창 컨트롤 - 스크롤바 MQL5 Coobook: 지표 하위 창 컨트롤 - 스크롤바
계속해서 다양한 컨트롤을 탐색하고 이번에는 스크롤바에 주의를 기울이겠습니다. "MQL5 Cookbook: 지표 하위 창 컨트롤 - 버튼"라는 제목의 이전 글와 마찬가지로 모든 작업은 지표 하위 창에서 수행됩니다. OnChartEvent() 함수의 이벤트 작업에 대한 자세한 설명을 제공하는 위에서 언급한 글을 잠시 읽어보십시오. 설명을 위해 이번에는 MQL5 리소스를 사용하여 얻을 수 있는 모든 금융 상품 속성의 큰 목록에 대한 세로 스크롤 바를 만듭니다.