거래 전략 테스트

거래 로봇이 하루 24시간, 일주일 내내 쉬지 않고 작업을 할 수 있다는 점이 자동 거래의 아이디어로 어필되고 있습니다. 로봇은 지치거나 의심스럽거나 겁먹지 않습니다. 어떤 심리적 문제에서도 완전히 자유롭습니다. 거래 규칙을 명확하게 공식화해 알고리즘으로 구현하면 충분하며, 로봇은 지칠 줄 모르고 일할 준비가 돼 있습니다. 그러나 먼저 다음 두 가지 중요한 조건이 충족되는지 확인해야 합니다:

  • Expert Advisor는 거래 시스템의 규칙에 따라 거래 작업을 수행합니다;
  • EA에서 시행된 거래 전략은 그간의 내역에서 이익을 있음을 보여줍니다.

이러한 질문에 대한 답변을 얻으려면 MetaTrader 5 클라이언트 터미널에 포함된 Strategy Tester로 이동합니다.

이 섹션에서는 전략 테스터의 프로그램 테스트 및 최적화 기능에 대해 설명합니다:

 

MQL5 Cloud Network의 메모리 및 디스크 공간 제한

다음 제한 사항은 MQL5 Cloud Network 최적화 작업 실행시에 적용됩니다.: Expert Advisor는 4GB 이상의 정보를 디스크에 쓰거나 4GB 이상의 RAM을 사용해서는 안 됩니다. 한도를 초과하면 네트워크 에이전트가 계산을 올바르게 완료할 수 없으며 열러분은 결과를 받을 수 없습니다. 그러나 계산에 소요된 모든 시간에 대해 비용이 청구됩니다.

각각의 최적화 단계에서 정보를 가져와야 하는 경우 디스크에 쓰지 말고 프레임을 보내세요 . MQL5 Cloud Network에서 계산하는 동안 Expert Advisors에서 파일 작업을 피하려면 다음과 같은 확인을 사용할 수 있습니다.

   int handle=INVALID_HANDLE;
   bool file_operations_allowed=true;
   if(MQLInfoInteger(MQL_OPTIMIZATION) || MQLInfoInteger(MQL_FORWARD))
      file_operations_allowed=false;
 
   if(file_operations_allowed)
     {
      ...
      handle=FileOpen(...);
      ...
     }

 

전략 테스터의 함수 제한 #

클라이언트 터미널의 Strategy Tester에는 일부 함수에 대한 작동 제한이 있습니다.

Comment(), Print() 및 PrintFormat() 함수 #

퍼포먼스 향상을 위한 Comment(), Print()PrintFormat()함수는 거래 로봇의 매개 변수를 최적화할 때 실행되지 않습니다. OnInit() 핸들러 내부에서 이러한 함수를 사용하는 것은 예외입니다. 이렇게 하면 오류가 발생할 때 쉽게 오류를 찾을 수 있습니다.

Alert(), MessageBox(), PlaySound(), SendFTP, SendMail(), SendNotification(), WebRequest() 함수 #

"외부 세계"와의 상호작용을 위해 설계된 Alert(), MessageBox(), PlaySound(), SendFTP(), SendMail(), SendNotification()WebRequest() 함수는 략 테스터에서 실행되지 않습니다.

 

틱 생성 모드 #

Expert Advisor는 MQL5로 작성된 프로그램으로, 외부 이벤트에 대응하여 매번 실행됩니다. EA에는 사전 정의된 각 이벤트에 해당하는 함수(이벤트 핸들러)가 있습니다.

NewTick 이벤트(가격 변동)는 EA의 주요 이벤트이므로 EA를 테스트하기 위한 틱 시퀀스를 생성해야 합니다. MetaTrader 5 클라이언트 터미널의 Strategy Tester에는 다음과 같은 세 가지 틱 생성 모드가 구현되어 있습니다:

  • Every tick
  • 1분 OHLC(분막대와 OHLC 가격)
  • 시가 전용

기본이자 가장 상세한 모드는 "Every tick" 모드이며, 나머지 두 모드는 "Every tick" 모드와 비교하여 설명됩니다. 세 가지 모드 간의 차이를 이해하기 위해 모두를 고려하십시오.

"Every Tick"

금융상품의 과거 시세 데이터는 거래 서버에서 MetaTrader 5 클라이언트 터미널로 분량 막대 형태로 전송됩니다. 요청의 발생과 필요한 타임프레임 구성에 대한 자세한 정보는 MQL5 참조의 데이터 액세스 구성 장에서 얻을 수 있습니다.

가격 내역의 최소 요소는 분 막대이며, 여기서 다음 네 가지 가격 값에 대한 정보를 얻을 수 있습니다.

  • 시가 - 분 단위 막대가 오픈된 가격;
  • 고가 - 이 분 막대에서 달성한 최대치;
  • 저가 - 이 분 막대에서 달성한 최소값;
  • 종가 - 바의 마감 가격.

새로운 분 막대는 새 분기가 시작되는 순간에 오픈되는 것이 아니라(초 수가 0이 됨), 틱이 발생할 때 - 가격이 최소 1포인트 이상 변경됩니다. 이 수치는 2011.01.10 00:00의 개장 시간을 가진 새로운 거래 주의 첫 번째 분 막대를 보여줍니다. 우리가 차트에서 보는 금요일과 월요일의 가격 차이는 흔히 볼 수 있는데, 이는 들어오는 뉴스에 반응하여 주말에도 환율이 변동하기 때문입니다.

금요일과 월요일 사이의 가격 차이

이 바의 경우 2011년 1월 10일 00시간 00분에 분 막대가 오픈되었다는 것만 알 수 있을 뿐 초는 알 수 없습니다. 00:00:12 또는 00:00:36(다음 날 시작 후 12초 또는 36초) 또는 해당 분 내에 다른 시간에 오픈되었을 수 있습니다. 그러나 우리는 EURUSD의 오픈 가격이 새 분 막대의 오프닝 시간에 1.28940에 있었다는 것을 알 수 있습니다.

또한 고려된 분 막대의 종가에 해당하는 틱을 언제 받았는지 알 수 없습니다. 또한 고려된 분 막대의 종가에 해당하는 틱을 언제 받았는지 알 수 없습니다. 이 분 동안, 가격은 1.28958이었습니다. 고가와 저가의 등장 시점도 알 수 없지만, 최고가와 최저가가 각각 1.28958, 1.28940 수준에 그친 것으로 알 수 있습니다.

거래 전략을 테스트하기 위해서는 Expert Advisor의 작업을 시뮬레이션할 일련의 틱이 필요합니다. 따라서, 매 분마다 가격이 확실히 존재했던 4개의 제어 지점을 알 수 있습니다. 막대에 4개의 틱만 있으면 테스트를 수행하기에 충분한 정보이고, 일반적으로 눈금 볼륨이 4개보다 큽니다.

따라서 시가, 고가, 저가, 및 종가 사이에서 발생한 눈금에 대한 추가 관리 지점을 생성해야 합니다. "Every tick" 생성 모드의 원리는 MetaTrader 5 Terminal의 Strategy Tester에 있는 Ticks 생성 알고리즘에 설명되어 있으며, 아래에 나와 있습니다.

틱 생성 알고리즘

"Every tick" 모드에서 테스트할 때 EA의 OnTick() 함수가 모든 제어 지점에서 호출됩니다. 각 제어점은 생성된 시퀀스의 틱입니다. EA는 온라인 작업 시처럼 시뮬레이션 틱의 시간과 가격을 받게 됩니다.

중요: "Every tick" 테스트 모드가 가장 정확하면서도 동시에 시간이 가장 많이 소요됩니다. 대부분의 거래 전략의 초기 시험의 경우, 보통 나머지 두 가지 시험 모드 중 하나를 사용하는 것으로 충분합니다.

"1 분 OHLC"

"Every tick" 모드는 세 가지 모드 중 가장 정확하지만 동시에 가장 느립니다. OnTick() 핸들러는 모든 틱에서 실행되지만 틱 볼륨은 상당히 클 수 있습니다. 막대 전체에 걸친 가격 이동의 틱 순서가 중요하지 않은 전략의 경우, 더 빠르고 대략적인 시뮬레이션 모드인 "1분 OHLC"가 있습니다.

"1분 OHLC" 모드에서 틱 시퀀스는 분봉의 OHLC 가격에 의해서만 생성되며, 생성된 제어 지점의 수는 상당히 감소하므로 테스트 시간도 감소합니다. OnTick() 기능의 시작은 OHLC minute bar의 가격에 의해 구성된 모든 제어 지점에서 수행됩니다.

시가, 고가, 저가, 종가 사이에 추가적인 중간 틱이 생성되지 않는 것은 시가가 결정되는 순간부터 가격 개발에 있어 엄격한 결정론의 출현으로 이어집니다. 이렇게 하면 "Testing Grail"을 만들 수 있으며, 이 그래프는 테스트 밸런스의 좋은 위쪽 그래프를 보여줍니다.

CodeBase에는 이러한 Grail의 예가 나와 있습니다 - Grr-al.

Grr-al Expert Advisor는 OHLC 가격의 특수 기능을 사용합니다

그림은 이 EA 테스트의 매우 매력적인 그래프를 보여줍니다. 어떻게 얻었을까요? 우리는 1분 막대의 4가지 가격을 알고 있으며, 첫 번째는 시가이고 마지막은 종가라는 것도 알고 있습니다. 그것들 사이에 고가와 저가가 있으며, 발생 순서는 알 수 없지만, 고가가 시가보다 높거나 같은 것으로 알려져 있습니다.

공개 가격을 받는 순간을 결정한 뒤 다음 틱 표시를 분석하여 현재 보유하는 가격(높은 가격 또는 낮은 가격)을 결정하기에 충분합니다. 만약 가격이 시가보다 낮고, 저가로 이 틱에서 구매하면, 다음 틱은 고가에 해당할 것이며, 저희가 여기서 구매를 끝내고 판매를 위해 오픈할 것입니다. 다음 틱이 마지막이고, 이것이 종가이며, 판매는 끝납니다.

그 가격 이후에 시가 가격보다 큰 금액의 틱이 나오면 거래 순서가 뒤바뀝니다. 이 "치트" 모드에서 1분 막대를 처리하고 다음 막대를 기다립니다.

그러한 EA를 역사에 대해 시험할 때, 모든 것은 순조롭게 진행되지만, 일단 저희가 그것을 온라인으로 시작하면, '균형선은 흔들리지 않고, 다만 아래로 향한다'는 진실이 밝혀지기 시작합니다. 이 트릭을 노출시키려면 "Every tick" 모드로 EA를 실행하면 됩니다.

참고: 대략적인 테스트 모드("1분 OHLC" 및 "개방 가격 전용")에서 EA의 테스트 결과가 너무 좋은 것 같으면 "Every tick" 모드에서 테스트해야 합니다.

"시가 전용"

이 모드에서는 테스트를 위해 선택한 기간의 OHLC 가격에 따라 틱이 생성됩니다. Expert Advisor의 OnTick() 함수는 바 시작 시 시가에서만 실행됩니다. 이 기능으로 인해 중지 레벨 및 보류는 지정된 가격과 다른 가격으로 트리거될 수 있습니다(특히 더 높은 타임프레임에서 테스트하는 경우). 대신 Expert Advisor의 평가 테스트를 신속하게 실행할 수 있습니다.

W1 및 MN1 기간은 "시가 전용" 틱 생성 모드의 예외입니다. 이러한 기간 동안 타임프레임 틱은 해당 주 또는 달의 OHLC 가격이 아니라 각 요일의 OHLC 가격에 대해 생성됩니다.

EURUSD H1에서 "시가 전용" 모드에서 Expert Advisor를 테스트한다고 가정합니다. 이 경우 총 틱(제어 지점) 수는 검정된 간격 내에 있는 한 시간 막대의 4*개보다 작지 않습니다. 하지만 OnTick() 핸들러는 시봉(1시간 막대)의 시작 시에만 호출됩니다.. 올바른 테스트에 필요한 검사는 나머지 틱(EA로부터 "숨겨진")에서 수행됩니다.

  • 마진 요구사항 계산;
  • 스탑 로스 및 이익 실현 촉발 수준;
  • 보류 주문의 트리거;
  • 만료된 보류 주문 제거.

오픈 포지션나 보류 주문이 없는 경우 숨겨진 틱에 대해 이러한 검사를 수행할 필요가 없으며 속도가 상당히 빨라질 수 있습니다. 이 "시가 전용" 모드는 바 개설 시에만 거래를 처리하고 보류 주문은 사용하지 않는 테스트 전략과 스탑 로스 및 이익 실현 주문에 적합합니다. 이러한 전략의 등급에 필요한 테스트 정확도는 보존됩니다.

모든 모드에서 테스트할 수 있는 EA의 예로 표준 패키지의 이동 평균 Expert Advisor를 사용하겠습니다. 이 EA의 논리는 모든 결정이 막대의 개시에서 이루어지며, 보류 주문을 사용하지 않고 즉시 거래가 진행될 수 있도록 구축됩니다.

2010.09.01에서 2010.12.31까지의 기간에 EURUSD H1에 대한 EA 테스트를 실행하고 그래프를 비교합니다. 그림은 세 가지 모드 모두에 대한 테스트 보고서의 균형 그래프를 보여줍니다.

표준 패키지의 Moving Average.mq5 EA 테스트 그래프는 테스트 모드에 따라 달라지지 않습니다.

보시다시피, 다른 테스트 모드의 그래프는 표준 패키지의 이동 평균 EA와 동일합니다.

"시가 전용" 모드에는 다음과 같은 몇 가지 제한이 있습니다.

  • 다음을 사용할 수 없습니다: 임의 지연 실행 모드.
  • 테스트된 Expert Advisor에서는 테스트/최적화에 사용된 시간보다 낮은 타임프레임의 데이터에 액세스할 수 없습니다. 예를 들어, H1 기간에 테스트/최적화를 실행하면 H2, H3, H4 등의 데이터에 액세스할 수 있지만 M30, M20, M10 등의 데이터는 액세스할 수 없습니다. 또한 액세스되는 더 높은 타임프레임은 테스트 시간의 몇 배여야 합니다. 예를 들어 M20에서 테스트를 실행하면 M30의 데이터에 액세스할 수 없지만 H1에 액세스할 수 있습니다. 이러한 제한은 테스트/최적화 중에 생성된 막대에서 낮거나 다중이 아닌(non-multiple) 타임프레임의 데이터를 얻을 수 없는 것과 관련이 있습니다.
  • 다른 타임프레임의 데이터 액세스에 대한 제한은 Expert Advisor가 데이터를 사용하는 다른 기호에도 적용됩니다. 이 경우 각 심볼에 대한 제한은 테스트/최적화 중에 액세스하는 첫 번째 시간에 따라 달라집니다. EURUSD H1에서 테스트하는 동안 Expert Advisor가 GBPUSD M20의 데이터에 액세스한다고 가정해보십시오. 이 경우 Expert Advisor는 EURUSD H1, H2 등의 데이터와 GBPUSD M20, H1, H2 등의 데이터를 추가로 사용할 수 있습니다.

참고: "시가 전용" 모드는 테스트 시간이 가장 빠르지만 모든 거래 전략에 적합하지 않습니다. 거래 시스템의 특성에 따라 원하는 테스트 모드를 선택하십시오.

틱 생성 모드에 대한 섹션을 마무리하려면 2011.01.11 21:00:00 - 2011.01.11 21:30:00 간격의 두 M15 막대에 대한 EURUSD에 대한 여러 틱 생성 모드의 시각적 비교를 고려해보십시오.

틱들은 WriteTicksFromTester.mq5 EA를 사용하여 다른 파일에 저장되었으며 파일 이름의 끝은 filenameEveryTick, filenameOHLC 및 filenameOpenPrice 입력 매개 변수에 지정되어 있습니다.

WriteTicksFromTester Expert Advisor의 시작일과 종료일(변수 시작 및 종료)을 지정할 수 있습니다.

3개의 틱 시퀀스가 있는 파일 3개를 얻기 위해(다음 모드 각각에 대해 "Every tick", "1분 OHLC", "시가 전용") EA는 해당 모드에서 단일 실행으로 3번 실행되었습니다. 그런 다음 이 세 파일의 데이터가 TicksFromTester.mq5 지표를 사용하여 차트에 표시되었습니다. 이 물품에는 지표 코드가 첨부되어 있습니다.

세 가지 다른 테스트 모드에서의 MetaTrader 5 터미널의 전략 테스터 틱 시퀀스

기본적으로, MQL5 언어의 모든 파일 작업은 "파일 샌드박스" 내에서 이루어지며, 테스트 중에 EA는 자신의 "파일 샌드박스"에만 액세스할 수 있습니다. 테스트 중에 지표와 EA가 한 폴더의 파일로 작동하기 위해 flag FILE_COMMON을 사용했습니다. EA의 코드 예제:

//--- 파일 오픈
   file=FileOpen(filename,FILE_WRITE|FILE_CSV|FILE_COMMON,";");
//--- 파일 핸들 점검
   if(file==INVALID_HANDLE)
     {
      PrintFormat("%s 파일 작성을 위해 여는 중 오류 발생. Error code=%d",filename,GetLastError());
      return;
     }
   else
     {
      PrintFormat("파일이 %s 폴더에 생성됩니다",TerminalInfoString(TERMINAL_COMMONDATA_PATH));
     }

지표의 데이터를 읽기 위해 FILE_COMMON 플래그도 사용했습니다. 이를 통해 필요한 파일을 폴더 간에 수동으로 전송하는 것을 방지할 수 있었습니다.

//--- 파일 오픈
   int file=FileOpen(fname,FILE_READ|FILE_CSV|FILE_COMMON,";");
//--- 파일 핸들 점검
   if(file==INVALID_HANDLE)
     {
      PrintFormat("%s 파일을 읽기 위해 오픈 중 오류 발생. Error code=%d",fname,GetLastError());
      return;
     }
   else
     {
      PrintFormat("파일이 %s 에서 열립니다",TerminalInfoString(TERMINAL_COMMONDATA_PATH));
     }

확산 시뮬레이션 #

입찰 가격과 요청 가격 간의 가격 차이를 스프레드라고 합니다. 시험 중 스프레드는 모델링되지 않지만 과거 데이터에서 추출됩니다. 과거 데이터에서 산포도가 0보다 작거나 같으면 마지막으로 알려진(생성 순간) 산포도가 테스트 에이전트에서 사용됩니다.

Strategy Tester에서 스프레드는 항상 floating으로 간주됩니다. 즉, SymbolInfoInteger(기호, SYMBOL_SPREAD_FLOAT)는 항상 true를 반환합니다.

또한 내역 데이터에는 틱 값과 거래량이 포함됩니다. 데이터의 저장 및 검색을 위해 특별한 MqlRates 구조를 사용합니다:

struct MqlRates
  {
   datetime time;         // 기간 시작 시간
   double   open;         // 시가
   double   high;         // 그 기간의 최고 가격
   double   low;          // 해당 기간의 최저 가격
   double   close;        // 종가
   long     tick_volume;  // 틱 볼륨
   int      spread;       // 스프레드
   long     real_volume;  // 거래량
  };

테스트 중 실제 틱 사용 #

실제 틱에 대한 테스트 및 최적화는 가능한 실제 조건에 가깝습니다. 분 데이터를 기반으로 생성된 틱 대신 브로커가 누적한 실제 틱을 사용할 수 있습니다. 이것들은 거래소와 유동성 제공자들의 틱입니다.

최대 테스트 정확도를 보장하기 위해 실제 틱 모드에서도 분봉이 사용됩니다. 막대는 틱 데이터를 확인하고 수정하는 데 적용됩니다. 또한 테스터와 클라이언트 터미널에서 차트가 분산되는 것을 방지할 수 있습니다.

테스터는 틱 데이터를 분봉 매개변수와 비교합니다. 틱이 막대의 높음/낮음 수준을 초과하면 안 되며, 초기 및 최종 틱이 막대의 시가/종가와 일치해야 합니다. 볼륨도 비교됩니다. 불일치가 탐지되면 이 분봉에 해당하는 모든 틱이 삭제됩니다. 생성된 틱은 대신 사용됩니다(예: "모든 틱" 모드).

심볼 내역에 틱 데이터가 없는 분봉이 있는 경우 테스터는 "Every tick" 모드에서 눈금을 생성합니다. 이렇게 하면 브로커의 틱 데이터가 충분하지 않은 경우 테스터에서 올바른 차트를 플로팅할 수 있습니다.

심볼 내역에 분봉이 없지만 분에 해당하는 틱 데이터가 있는 경우 테스터에서 데이터를 사용할 수 있습니다. 예를 들어, 거래 심볼 페어는 종가를 사용하여 형성됩니다. 종가가 서버에서 도착하지 않은 상태에서 입찰/요청 가격에 대한 틱만 있다면 막대가 생성되지 않습니다. 테스터는 이러한 틱 데이터가 분봉과 모순되지 않으므로 이 틱 데이터를 사용합니다.

소스에서 클라이언트 터미널로 데이터를 전송할 때 연결 끊김 또는 기타 장애로 인해 틱 데이터가 여러 가지 이유로 인해 분봉과 일치하지 않을 수 있습니다. 분당 데이터는 테스트 중에 더 신뢰할 수 있는 것으로 간주됩니다.

실제 틱을 테스트할 때 다음 기능에 유의하십시오:

  • 테스트를 시작할 때 심볼에 있는 분 데이터가 틱 데이터와 동기화됩니다.
  • 틱들은 전략 테스터의 심볼 캐시에 저장됩니다. 캐시 크기가 128000 틱을 초과하지 않습니다. 새 틱이 도착하면 가장 오래된 데이터가 캐시에서 제거됩니다. 그러나, CopyTicks 함수는 캐시 외부에서 틱 수신을 허용합니다(실제 틱에 대해 테스트하는 경우에만). 이 경우 해당 클라이언트 터미널 데이터베이스와 완전히 유사한 테스터 틱 데이터베이스에서 데이터를 요청합니다. 이 베이스에는 분 막대 보정이 구현되지 않습니다. ㅁ따라서, 해당 틱들은 캐시에 저장된 틱들과 다를 수 있습니다.

클라이언트 터미널의 글로벌 변수 #

테스트 과정에서 클라이언트 터미널의 글로벌 변수' 도 에뮬레이션되지만, F3 버튼을 이용해 단말에서 볼 수 있는 현재의 터미널의 글로벌 변수와는 관련이 없습니다. 즉, 테스트 중에 터미널의 전역 변수를 사용하는 모든 작업이 클라이언트 터미널(테스트 에이전트) 외부에서 수행됩니다.

테스트 중 지표 계산 #

실시간 모드에서 지표값은 매 틱마다 계산됩니다.

전략 테스터에서 지표가 계산되는 방식은 데이터 생산을 위해 액세스되는 경우, 즉 지표의 버퍼 값이 요청되는 경우에만 계산됩니다. 유일한 예외는 커스텀 지표#property tester_everytick_calculate로 지정된 경우 뿐입니다. 이 경우 각 틱에 대해 재계산이 수행됩니다.

시각적 테스트 모드에서는 모든 지표는 시각적 테스트 차트에 올바르게 표시되기 위해 새 틱이 도착할 때 무조건 다시 계산됩니다.

지표는 틱당 한 번 계산됩니다. 지표의 데이터에 대한 모든 후속적인 요청은 새 틱이 도착할 때까지 재계산하지 않습니다. 따라서 EA에서 EventSetTimer() 함수를 통해 타이머가 활성화된 경우  지표의 데이터는 OnTimer() 핸들러의 각 호출 이전의 마지막 틱부터 요청됩니다. 지표가 마지막 틱에서 아직 계산되지 않은 경우 지표 값 계산이 시작됩니다. 데이터가 이미 준비된 경우에는 새롭게 재계산 하지 않지 않고 제공됩니다.

따라서 모든 지표의 계산은 가장 리소스를 절약하는 방식으로 수행됩니다. 지표가 지정된 틱에서 이미 계산된 경우에는 해당 데이터는 '있는 그대로' 제공됩니다. 재계산을 하지 않습니다.

테스트 중 내역 로드 #

테스트 프로세스를 시작하기 전에 거래 서버에서 터미널에 의해 테스트될 심볼의 내역이 동기화되고 로드됩니다. 첫 번째 시간 동안 터미널은 나중에 요청하지 않기 위해 사용 가능한 모든 심볼 내역을 로드합니다. 또한 새 데이터만 로드됩니다.

테스트 에이전트는 테스트 시작 직후 클라이언트 터미널에서 테스트할 기호 심볼을 수신합니다. 다른 금융상품의 데이터가 테스트 과정에서 사용되는 경우(예: 다중 통화 Expert Advisor), 테스트 에이전트는 이러한 데이터를 처음 호출하는 동안 클라이언트 터미널에서 필요한 내역을 요청합니다. 터미널에서 사용 가능한 내역 데이터가 있으면 즉시 테스트 에이전트로 전달됩니다. 데이터를 사용할 수 없는 경우 터미널에서 요청하여 서버에서 다운로드한 다음 테스트 에이전트로 전달합니다.

무역업무에 대한 교차요율을 산정하기 위해서는 추가 금융상품의 데이터도 필요합니다. 예를 들어, 첫 번째 거래 작업을 처리하기 전에, USD의 예금 통화로 EURUCHF에 대한 전략을 테스트할 때, 테스트 에이전트는 클라이언트 터미널에서 EURUSD와 USDCHF의 이력 데이터를 요청하지만, 이러한 심볼들의 직접 사용 호출은 포함하지 않습니다.

다중 통화 전략을 테스트하기 전에 필요한 모든 과거 데이터를 클라이언트 터미널로 다운로드하는 것이 좋습니다. 이렇게 하면 필요한 데이터 다운로드와 관련된 테스트/최적화가 지연되는 것을 방지할 수 있습니다. 예를 들어, 적절한 차트를 열고 내역 시작 부분으로 스크롤하여 기록을 다운로드할 수 있습니다. MQL5 레퍼런스의 데이터에 대한 액세스 구성 섹션에서 내역을 터미널에 강제로 로드하는 예를 볼 수 있습니다.

테스트 에이전트는 터미널에서 패킹된 형태로 내역을 수신합니다. 다음 테스트 중에는 테스터가 이전에 테스터를 실행한 이후 필요한 데이터를 사용할 수 있기 때문에 테스터가 터미널에서 이력을 로드하지 않습니다.

  • 터미널은 에이전트가 터미널에서 테스트 할 심볼 내역을 처음 요청할 때 한 번만 트레이드 서버에서 기록을 로드합니다. 내역은 트래픽을 줄이기 위해 꽉 찬 형태로 적재됩니다.
  • 틱은 네트워크를 통해 전송되지 않고 테스트 에이전트에서 생성됩니다.

다중 통화 테스트 #

Strategy Tester를 사용하면 여러 심볼을 사용하여 전략을 테스트할 수 있습니다. 원래 이전 플랫폼에서는 단일 심볼에 대해서만 테스트가 수행되었기 때문에 이러한 EA는 전통적으로 다중 통화 Expert Advisor로 불립니다. MetaTrader 5 터미널의 Strategy Tester에서는 사용 가능한 모든 심볼에 대한 거래를 모델링할 수 있습니다.

테스터는 기호 데이터를 처음 호출하는 동안 클라이언트 터미널(거래 서버가 아님!)에서 사용된 기호 내역을 자동으로 로드합니다.

테스트 에이전트는 테스트 시작 시 지표 계산에 필요한 내역 데이터를 제공하기 위해 적은 여백으로 누락된 기록만 다운로드합니다. D1 이하의 기간 동안 다운로드된 내역의 최소 볼륨은 1년입니다.

따라서 M15 기간(각 막대는 15분)으로 2010.11.01-2010.12.01(1개월 간격 테스트)에 대한 테스트를 실행하면, 2010년 전체 금융상품 이력이 요청됩니다. 주간 타임프레임의 경우 약 2년(연간 52주)에 해당하는 100개의 막대의 이력을 요청할 예정입니다. 월별 타임프레임에 대한 테스트의 경우 에이전트는 8년(12개월 x 8년 = 96개월)의 내역을 요청합니다.

필요한 막대가 없는 경우 테스트 시작 날짜가 자동으로 과거에서 현재로 전환되어 테스트 전에 필요한 막대 예약 기능을 제공합니다.

테스트 중에 "Market Watch"도 에뮬레이션 되어 심볼에 대한 정보를 얻을 수 있습니다.

기본적으로 테스트를 시작할 때 전략 테스터의 "Market Watch"에는 테스트가 실행 중인 심볼인 단 하나의 심볼이 있습니다. 필요한 모든 심볼은 전략 테스터의 "Market Watch"(터미널이 아님)에 자동으로 연결됩니다.

다중 통화 Expert Advisor의 테스트를 시작하기 전에 터미널의 "Market Watch"에서 테스트에 필요한 심볼을 선택하고 필요한 데이터를 로드해야 합니다. "해외" 심볼의 첫 번째 호출 동안, 그것의 내역은 테스트 에이전트와 클라이언트 터미널 간에 자동으로 동기화될 것입니다. "외부" 심볼은 테스트가 실행 중인 심볼 이외의 심볼입니다.

"외부" 심볼에 대한 데이터 참조는 다음과 같은 경우에 발생합니다:

  • 다음 함수를 사용하여 심볼/타임프레임에 대한 시계열 요청:

"다른" 심볼로 처음 호출하는 순간, 테스트 프로세스가 중지되고 터미널에서 테스트 에이전트로 심볼/타임프레임에 대한 내역이 다운로드됩니다. 동시에 이 심볼에 대한 틱 시퀀스가 생성됩니다.

선택한 틱 생성 모드에 따라 각 심볼에 대해 개별 틱 시퀀스가 생성됩니다. OnInit() 핸들러에서 SymbolSelect()를 호출하여 원하는 심볼을 위해 내역을 명시적으로 요청할 수도 있습니다 - 기록 다운로드는 Expert Advisor 테스트 직전에 이루어집니다.

따라서 MetaTrader 5 클라이언트 터미널에서 다중 통화 테스트를 수행하는 데 추가적인 노력이 필요하지 않습니다. 클라이언트 터미널에서 해당 심볼 차트를 열기만 하면 됩니다. 이 데이터가 들어 있는 경우 필요한 모든 심볼에 대한 내역이 거래 서버에서 자동으로 업로드됩니다.

전략 테스터의 시간 시뮬레이션 #

테스트 중 현지시간 TimeLocal()는 항상 서버시간 TimeTradeServer()과 같습니다. 차례로, 서버 시간은 항상 GMT 시간 - TimeGMT()에 해당하는 시간과 같습니다. 이렇게 하면 이러한 모든 함수가 테스트 중에 동일한 시간을 표시합니다.

서버에 연결되지 않은 경우 전략 테스터에 GMT, 로컬 및 서버 시간 차이가 없기 때문에 신중히 수행됩니다. 연결 여부에 관계없이 테스트 결과는 항상 동일해야 합니다. 서버 시간에 대한 정보는 로컬에 저장되지 않으며 서버에서 가져옵니다.

테스트의 그래픽 개체 #

테스트/최적화 중에는 그래픽 개체가 표시되지 않습니다. 따라서 테스트/최적화 중 생성된 객체의 속성을 참조할 때 Expert Advisor는 0 값을 받게 됩니다.

비쥬얼 모드에서 테스트하는 경우에는 이 제한이 적용되지 않습니다.

전략 테스터의 OnTimer() 함수 #

MQL5는 타이머 이벤트를 처리할 수 있는 기회를 제공합니다. 테스트 모드에 관계없이 OnTimer() 핸들러의 호출이 수행됩니다. 즉, 테스트가 H4 기간 동안 "시가 전용" 모드에서 실행 중이고 EA가 초당 통화로 설정된 타이머를 가진 경우 각 H4 막대가 열릴 때 OnTick() 핸들러를 한 번 호출하고 OnTimer() 핸들러를 14400회(3600초 * 4시간) 호출합니다. EA의 테스트 시간이 증가하는 양은 EA의 논리에 따라 달라집니다.

타이머의 주파수에 따른 테스트 시간의 의존성을 확인하기 위해 거래 작업 없이 간단한 EA를 만들었습니다.

//--- 입력 매개 변수
input int      timer=1;              // 타이머 값, sec
input bool     timer_switch_on=true; // 타이머 온
//+------------------------------------------------------------------+
//| Expert 초기화 함수                                                |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- run the timer if  timer_switch_on==true
   if(timer_switch_on)
     {
      EventSetTimer(timer);
     }
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert 초기화 취소 함수                                            |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- 타이머 정지
   EventKillTimer();
  }
//+------------------------------------------------------------------+
//| 타이머 함수                                                        |
//+------------------------------------------------------------------+
void OnTimer()
  {
//---
// 핸들러 본문이 비어 있으므로 아무 조치도 취하지 않습니다
  }
//+------------------------------------------------------------------+

테스트 시간 측정은 타이머 파라미터의 다른 값(Timer 이벤트의 주기)에서 수행되었습니다. 얻은 데이터에 대해 타이머 기간의 함수로써 테스트 시간을 플로팅합니다.

타이머 기간의 함수로 시간을 테스트합니다

동일한 다른 조건에서 EventSetTimer(타이머) 함수를 초기화하는 동안, 타이머 매개 변수가 작을수록, OnTimer() 핸들러의 호출 간 주기(주기)가 작을수록, 테스트 시간 T가 더 크다는 것을 명확히 알 수 있습니다.

전략 테스터의 Sleep() 함수 #

Sleep() 함수를 사용하면 그래프 작업 시 EA 또는 스크립트가 mql5 프로그램의 실행을 잠시 중단할 수 있습니다. 이것은 요청 시 준비되지 않아 준비될 때까지 기다려야 하는 데이터를 요청할 때 유용할 수 있습니다. Sleep() 함수의 자세한 사용 예는 데이터 액세스 구성 섹션에서 확인할 수 있습니다.

테스트 프로세스는 Sleep() 호출에 의해 유지되지 않습니다. Sleep()을 호출하면, 생성된 틱이 지정된 지연 시간 내에 "재생"되어 보류 주문, 스탑 등이 트리거 될 수 있습니다. Sleep() 호출 뒤, Strategy Tester의 시뮬레이션 기간은 Sleep 함수의 매개 변수에 지정된 간격만큼 증가합니다.

Sleep() 함수를 실행한 결과, Strategy Tester의 현재 시간이 테스트 기간을 초과한 경우 "테스트 중 무한 절전 루프가 감지됨" 오류가 발생합니다. 이 오류가 발생하면 테스트 결과가 거부되지 않고 모든 계산이 전체 볼륨(거래 수, 감퇴 등)으로 수행되며 테스트 결과가 터미널로 전달됩니다.

호출 후에는 테스트 시간이 테스트 간격 범위를 초과하므로 OnDeinit()에서는 Sleep() 함수가 작동하지 않습니다.

MetaTrader 5 터미널의 Strategy Tester에서 Sleep() 함수를 사용하는 방식

수학 계산에서 최적화 문제를 위한 전략 테스터 사용 #

MetaTrader 5 터미널의 테스터는 거래 전략 테스트뿐만 아니라 수학적 연산에도 사용할 수 있습니다. 이를 사용하려면 "수학 연산" 모드를 선택해야 합니다.

math_calculations

이 경우 다음 세 함수만 호출이 가능합니다: OnInit(), OnTester(), OnDeinit(). "수학 연산" 모드에서는 Strategy Tester가 틱을 생성하거나 내역을 다운로드하지 않습니다.

시작 날짜를 종료 날짜보다 크게 지정한 경우에도 전략 테스터는 "수학 연산" 모드에서 작동합니다.

테스터를 사용하여 수학적 문제를 해결할 때 내역 업로드 및 틱 생성이 수행되지 않습니다.

MetaTrader 5 Strategy Tester에서 풀 수 있는 일반적 수학 문제 - 변수가 많은 함수의 극한값 찾기.

그 문제를 해결하려면 다음을 해야 합니다:

  • 함수 값의 계산은 OnTester() 함수에 위치해야 합니다;
  • 함수의 매개 변수는 Expert Advisor의 입력-변수로 정의해야 합니다;

EA를 컴파일하고 "Strategy Tester" 창을 엽니다. "입력 매개 변수" 탭에서 필요한 입력 변수를 선택하고 각 함수의 변수들의 시작, 중지 및 단계 값을 지정하여 매개 변수 값 집합을 정의합니다.

최적화 유형 선택 - "느리지만 완전한 알고리즘"(매개 변수 공간의 전체 검색) 또는 "빠른 유전자 기반 알고리즘". 함수의 극단을 간단하게 검색하려면 빠른 최적화를 선택하는 것이 좋지만 전체 변수 집합에 대한 값을 계산하려면 느린 최적화를 사용하는 것이 좋습니다.

"수학 연산" 모드를 선택하고 "시작" 버튼을 사용하여 최적화 절차를 실행합니다. 최적화 중 Strategy Tester는 OnTester 함수의 최대값을 검색합니다. 로컬 최소값을 찾으려면 OnTester 함수에서 계산된 함수 값의 역수를 반환합니다.

return(1/function_value);

function_value가 0이 아닌지 점검할 필요가 있습니다. 그렇지 않으면 0으로 나누는 심각한 오류를 얻을 수도 있기 때문입니다.

다른 방법이 있는데, 그것은 더 편리하고 최적화의 결과를 왜곡하지 않았고, 그것은 이 기사의 독자들에 의해 제안되었습니다:

return(-function_value);

이 옵션은 function_value가 0인지 확인할 필요가 없으며 최적화 결과 표면에서 3D-표현은 동일한 형태를 가집니다. 유일한 차이점은 원본과 비교하여 미러링된다는 것입니다.

한 예로, sink() 함수를 보면:

sink_formula

이 함수의 극단을 찾기 위한 EA 코드는 OnTester()에 저장됩니다:

//+------------------------------------------------------------------+
//|                                                         Sink.mq5 |
//|                        Copyright 2011, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2000-2024, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
//--- 입력 매개 변수
input double   x=-3.0; // start=-3, step=0.05, stop=3
input double   y=-3.0; // start=-3, step=0.05, stop=3
//+------------------------------------------------------------------+
//| 테스터 함수                                                       |
//+------------------------------------------------------------------+
double OnTester()
  {
//---
   double sink=MathSin(x*x+y*y);
//---
   return(sink);
  }
//+------------------------------------------------------------------+

최적화를 수행하고 최적화 결과를 2D 그래프 형식으로 확인합니다.

싱크 (x*x+y*y)의 2D-그래프 함수를 완전히 최적화한 결과

지정된 파라미터 쌍(x, y)에 대해 값이 좋을수록 색상이 더 포화됩니다. sink() 함수의 관점에서 예상되었듯이, 그 값은 (0.0)의 중심에 동심원을 형성합니다. 3D 그래프에서 sink() 함수에 단일 글로벌 극단이 없음을 확인할 수 있습니다:

Sink 함수의 3D Graph

"개방 가격 전용" 모드의 막대 동기화 #

MetaTrader 5 클라이언트 터미널의 테스터를 통해 우리는 소위 "다중 통화" EA를 확인할 수 있습니다. 다중 통화 EA - 는 두 개 이상의 심볼을 거래하는 EA입니다.

여러 심볼에 따라 거래되는 전략 테스트는 테스터에게 몇 가지 추가 기술적 사항이 요구됩니다:

  • 이러한 심볼에 대한 틱의 생성;
  • 이러한 심볼에 대한 지표 값 계산;
  • 이러한 심볼에 대한 마진 요구 사항의 계산;
  • 모든 거래 심볼에 대해 생성된 틱 시퀀스의 동기화.

전략 테스터는 선택된 거래 모드에 따라 각 금융상품에 대해 탁 시퀀스를 생성하고 재생합니다. 동시에 다른 심볼에서 막대가 어떻게 오픈됐는지에 관계없이 각 심볼에 대한 새 막대가 오픈됩니다. 즉, 다중-통화 EA를 테스트할 때 한 금융상품의 경우 새 막대가 이미 열려 있고 다른 금융상품의 경우 열려 있지 않은 상황이 발생할 수 있습니다(그리고 자주 발생하고 있음). 따라서, 테스트 중, 모든 것은 실제와 똑같이 일어납니다.

이 테스터의 기록을 실제로 시뮬레이션하는 것은 "Every tick(모든 틱 표시)" 및 "1분 OHLC" 테스트 모드를 사용하는 한 문제를 일으키지 않습니다. 이러한 모드의 경우 다른 심볼에서 막대가 동기화될 때까지 대기할 수 있는 충분한 틱의 캔들스틱이 생성됩니다. 하지만 거래 금융상품 막대의 동기화가 필수적인 경우, 어떻게 "시가 전용" 모드에서 다중-통화 전략을 테스트할 수 있을까요? 이 모드에서 EA는 막대가 오픈된 시간에 해당하는 하나의 틱에서만 호출됩니다.

예를 들어 EA를 EURUSD에서 테스트하고 있으며 새로운 H1 캔들스틱이 EURUSD에서 오픈됐습니다. 이러한 사실을 쉽게 알 수 있습니다 - "시가 전용" 모드에서 테스트하는 동안, NewTick 이벤트는 테스트된 기간에 막대가 오픈되는 순간과 일치합니다. 하지만 EA에서 사용되는 USDJPY 심볼에 새 캔들스틱이 오픈되었다는 보장은 없습니다.

정상적인 상황에서는 OnTick() 함수의 작업을 완료하고 다음 틱에서 USDJPY에 새로운 막대가 나타나는지 확인하는 것으로 충분합니다. 그러나 "시가 전용" 모드에서 테스트할 때는 다른 틱이 없으므로 이 모드는 다중 통화 EA 테스트에는 적합하지 않은 것으로 보일 수 있습니다. 그러나 이는 그렇지 않습니다 - MetaTrader 5의 테스터는 실제와 똑같이 동작한다는 점을 잊지 마십시오. Sleep() 함수를 사용하여 다른 심볼에 새 막대가 오픈될 때까지 기다릴 수 있습니다!

"시가 전용" 모드에서 막대를 동기화하는 예를 보여주는 EA Synchronize_Bars_Use_Sleep.mq5 코드:

//+------------------------------------------------------------------+
//|                                   Synchronize_Bars_Use_Sleep.mq5 |
//|                        Copyright 2011, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2000-2024, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
//--- 입력 매개 변수
input string   other_symbol="USDJPY";
//+------------------------------------------------------------------+
//| Expert 초기화 함수                                                 |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- 심볼 체크
   if(_Symbol==other_symbol)
     {
      PrintFormat("입력 매개 변수에 다른 심볼을 지정하거나 전략 테스터에서 다른 심볼을 선택해야 합니다!");
      //--- 강제 스탑 테스트
      return(INIT_PARAMETERS_INCORRECT);
     }
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert 틱 함수                                                    |
//+------------------------------------------------------------------+
void OnTick()
  {
//--- 정적 변수, 마지막 막대 시간 저장에 사용됨
   static datetime last_bar_time=0;
//--- 싱크 플래그
   static bool synchonized=false;
//--- 정적 변수가 초기화되지 않은 경우
   if(last_bar_time==0)
     {
      //--- 첫 번째 호출, 바 시간 저장 및 종료
      last_bar_time=(datetime)SeriesInfoInteger(_Symbol,Period(),SERIES_LASTBAR_DATE);
      PrintFormat("The last_bar_time variable is initialized with value %s",TimeToString(last_bar_time));
     }
//--- 차트 심볼의 마지막 막대 오픈 시간 가져오기
   datetime curr_time=(datetime)SeriesInfoInteger(Symbol(),Period(),SERIES_LASTBAR_DATE);
//--- 시간이 동일하지 않을 경우
   if(curr_time!=last_bar_time)
     {
      //--- 정적 변수에 대한 바 오픈 시간 저장
      last_bar_time=curr_time;
      //--- 동기화되지 않음
      synchonized=false;
      //--- print message
      PrintFormat("심볼에 새 막대가 표시되었습니다 %s at %s",_Symbol,TimeToString(TimeCurrent()));
     }
//--- 다른 심볼 막대의 오픈 시간
   datetime other_time;
//--- 다른 심볼의 오픈 시간이 curr_time과 같아질 때까지 루프
   while(!(curr_time==(other_time=(datetime)SeriesInfoInteger(other_symbol,Period(),SERIES_LASTBAR_DATE)) && !synchonized))
     {
      PrintFormat("5초 대기중..");
      //--- 5초 동안 대기했다가 SeriesInfoInteger 호출 (other_symbol,Period(),SERIES_LASTBAR_DATE)
      Sleep(5000);
     }
//--- 막대가 동기화되었음
   synchonized=true;
   PrintFormat("차트 심볼의 막대 오픈 시간 %s: is %s",_Symbol,TimeToString(last_bar_time));
   PrintFormat("심볼의 막대 오픈 시간 %s: is %s",other_symbol,TimeToString(other_time));
//--- TimeCurrent()은 유용하지 않으니, TimeTradeServer()를 사용하십시오
   Print("막대가 다음에 동기화되었습니다 ",TimeToString(TimeTradeServer(),TIME_SECONDS));
  }
//+------------------------------------------------------------------+

EA의 마지막 줄에 동기화된 사실이 설정된 현재 시간을 표시합니다:

   Print("막대가 다음에 동기화되었습니다 ",TimeToString(TimeTradeServer(),TIME_SECONDS));

현재 시간을 표시하기 위해 TimeTradeServer() 함수를 사용했습니다, TimeCurrent()가 아니라. TimeCurrent() 함수는 마지막 틱의 시간을 반환합니다. 이 시간은 Sleep()을 사용한 후에도 변경되지 않습니다. "시가 전용" 모드에서 EA를 실행하면 막대의 동기화에 대한 메시지가 표시됩니다.

Synchronize_Bars_Use_Sleep_EA

마지막 틱 도착 시간이 아니라 현재 서버 시간을 가져와야 하는 경우 TimeCurrent() 대신 TimeTradeServer() 함수를 사용하십시오.

막대를 동기화하는 또 다른 방법은 타이머를 사용하는 것입니다. 그러한 EA의 예는 본 문서에 첨부되어 있는 Synchronize_Bars_Use_OnTimer.mq5입니다.

테스터의 IndicatorRelease() 함수 #

단일 테스트를 완료하면 완료된 거래와 EA에서 사용된 지표를 표시하는 금융상품 차트가 자동으로 열립니다. 이를 통해 진입점과 종료점을 시각적으로 확인하고 이를 지표 값과 비교할 수 있습니다.  

참고: 차트에 표시되는 지표는 테스트 완료 후 자동으로 오픈됩니다. 비록 이 지표들이 테스트된 EA에서 사용되었다 하더라도 말입니다.

그러나 경우에 따라 프로그래머는 어떤 지표가 거래 알고리즘에 관여했는지에 대한 정보를 숨기고 싶어할 수 있습니다. 예를 들어, EA의 코드는 소스 코드를 제공하지 않고 실행 파일로 대여 또는 판매됩니다. 이러한 목적으로는, IndicatorRelease() 함수가 적합합니다.

터미널이 클라이언트 터미널의 디렉토리/프로파일/템플릿에 tester.tpl이라는 이름의 템플릿을 설정하면 오픈 차트에 적용됩니다. 없으면 기본 템플릿이 적용됩니다. (default.tpl).

IndicatorRelease() 함수는 원래 더 이상 필요하지 않은 지표의 연산 부분을 해제하기 위한 것입니다. 이렇게 하면 각 틱마다 지표 계산이 필요하므로 메모리와 CPU 리소스를 모두 저장할 수 있습니다. 두 번째 목적은 한 번의 테스트 실행 후 테스트 차트에 지표를 표시하는 것을 금지하는 것입니다.

테스트 후 차트에 지표가 표시되지 않도록 하려면 IndicatorRelease() 호출을 핸들러 OnDeinit()의 지표 핸들을 사용해서 해야 합니다. OnDeinit() 함수는 항상 테스트 차트가 표시되기 전에 호출됩니다.

//+------------------------------------------------------------------+
//| Expert 초기화 취소 함수                                            |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
   bool hidden=IndicatorRelease(handle_ind);
   if(hidden) Print("IndicatorRelease() successfully completed");
   else Print("IndicatorRelease() returned false. Error code ",GetLastError());
  }

차트에 지표가 표시되지 않도록 하려면 단일 테스트를 완료한 후 핸들러 OnDeinit()의 IndicatorRelease() 함수를 사용하십시오.

테스터의 이벤트 핸들링 #

EA에 OnTick() 핸들러가 있는 것은 MetaTrader 5 테스터의 기간별 데이터에 대한 테스트를 받기 위한 필수 사항이 아닙니다. EA의 ti가 다음 함수-핸들러 중 하나 이상을 포함하기에 충분합니다:

  • OnTick() - 새 틱 도착의 이벤트 핸들러;
  • OnTrade() - 트레이딩 이벤트 핸들러;
  • OnTimer() - 타이머로부터의 시그널 도착에 대한 이벤트 핸들러;
  • OnChartEvent() - 클라이언트 이벤트에 대한 핸들러.

EA에서 테스트할 때, OnChartEvent() 함수를 사용하여 커스텀 이벤트를 처리할 수 있지만 지표에서는 이 함수를 테스터에서 호출할 수 없습니다. 지표에 OnChartEvent() 이벤트 핸들러가 있고 이 지표가 테스트된 EA에서 사용되는 경우에도 지표 자체는 커스텀 이벤트를 수신하지 않습니다.

테스트 중에 지표는 EventChartCustom() 함수를 사용하여 커스텀 이벤트를 생성할 수 있으며, EA는 OnChartEvent()에서 이 이벤트를 처리할 수 있습니다.

이러한 이벤트 외에도, 테스트 및 최적화 프로세스와 관련된 특수 이벤트가 전략 테스터에서 생성됩니다.

  • 테스터 - 이 이벤트는 Expert Advisor에서 내역 데이터에 대한 테스트를 완료한 후 생성됩니다. 테스터 이벤트는 OnTester() 함수를 사용하여 처리됩니다. 이 함수는 Expert Advisor를 테스트할 때만 사용할 수 있으며, 주로 입력 파라미터의 유전 최적화를 위한 Custom max 기준으로 사용되는 값을 계산하기 위한 것입니다.
  • TesterInit - 이 이벤트는 첫 번째 패스 전에 전략 테스터에서 최적화를 시작할 때 생성됩니다. TesterInit 이벤트는 OnTesterInit() 함수를 사용하여 처리됩니다. 최적화가 시작되는 동안 이 핸들러를 사용하는 Expert Advisor는 테스터에 지정된 심볼과 주기가 있는 별도의 터미널 차트에 자동으로 로드되고 TesterInit 이벤트를 수신합니다. 이 함수는 추가적인 최적화 결과 처리를 위해 최적화를 시작하기 전에 Expert Advisor를 시작하는 데 사용됩니다.
  • TesterPass - 이 이벤트는 새 데이터 프레임이 수신될 때 생성됩니다. TesterPass 이벤트는 OnTesterPass() 함수를 사용하여 처리됩니다. 이 핸들러를 사용하는 Expert Advisor는 테스트를 위해 지정된 심볼/주기가 있는 별도의 터미널 차트에 자동으로 로드되며, 최적화 중에 프레임이 수신되면 TesterPass 이벤트를 수신합니다. 이 함수는 최적화 결과의 완료를 기다리지 않고 "즉각" 동적으로 처리하는 데 사용됩니다. 프레임은 FrameAdd() 함수를 사용하여 추가됩니다 - 이는OnTester() 핸들러에서 단일 패스가 끝난 후 호출할 수 있는 함수입니다.
  • TesterDeinit - 이 이벤트는 Expert Advisor 최적화 종료 후 전략 테스터에서 생성됩니다. TesterDeinit 이벤트는 OnTesterDeinit() 함수를 사용하여 처리합니다. 이 핸들러를 사용하는 Expert Advisor는 최적화가 시작될 때 자동으로 차트에 로드되고 완료되면 TesterDeinit를 받게 됩니다. 이 함수는 모든 최적화 결과의 최종 처리에 사용됩니다.

테스팅 에이전트 #

MetaTrader 5 클라이언트 터미널에서의 테스트는 테스트 에이전트를 사용하여 수행합니다. 로컬 에이전트가 자동으로 생성되고 실행됩니다. 기본 로컬 에이전트 수는 시스템의 코어 수에 해당합니다.

각 테스트 에이전트에는 클라이언트 터미널과 관련이 없는 고유한 글로벌 변수 복사본이 있습니다 터미널 자체는 태스크를 로컬 및 원격 에이전트로 배포하는 발송 관리자입니다. 지정된 매개 변수를 사용하여 EA 테스트에 대한 작업을 실행한 후 에이전트는 결과를 터미널로 반환합니다. 한 번의 테스트에서는 에이전트가 하나만 사용됩니다.

에이전트는 터미널에서 수신한 내역을 기기 이름으로 별도의 폴더에 저장하므로 EURUSD의 기록은 EURUSD라는 폴더에 저장됩니다. 또한 금융상품의 이력은 소스에 따라 구분됩니다. 내역을 저장하는 구조는 다음과 같습니다:

tester_catalog\Agent-IPaddress-Port\bases\name_source\history\symbol_name

예를 들어 MetaQuotes-Demo 서버의 EURUSD 내역은 folder tester_catalog\Agent-127.0.0.1-3000\bases\MetaQuotes-Demo\EURUSD 폴더에 저장할 수 있습니다.

로컬 에이전트는 테스트가 완료된 후 대기 모드로 전환되어 다음 호출을 시작하는 데 시간을 낭비하지 않도록 5분 동안 다음 작업을 대기합니다. 대기 기간이 끝난 후에만 로컬 에이전트가 종료되고 CPU 메모리에서 언로드됩니다.

클라이언트 터미널 종료와 함께 사용자 측에서 테스트를 조기에 완료한 경우, 모든 로컬 에이전트는 즉시 작업을 중지하고 메모리에서 언로드됩니다.

터미널과 에이전트 간의 데이터 교환 #

테스트를 실행하면 클라이언트 터미널은 에이전트에게 다음과 같은 여러 매개 변수 블록을 보낼 준비를 합니다:

  • 테스트를 위한 입력 파라미터(시뮬레이션 모드, 시험 간격, 기구, 최적화 기준 등)
  • "Market Watch"에서 선택한 심볼 목록
  • 테스트 심볼의 명세(계약규모, 스탑로스 및 이익실현 설정의 마켓으로부터의 허용된 마진 등)
  • 테스트할 Expert Advisor와 해당 입력 매개 변수의 값
  • 추가 파일(라이브러리, 지표, 데이터 파일)에 대한 정보 - # property tester_ ...)

tester_indicator

string

"indicator_name.ex5"의 포맷의 커스텀 지표명. 테스트가 필요한 지표는 해당 파라미터가 문자열 상수를 통해 설정된 경우 iCustom() 함수 호출 시 자동으로 정의됩니다. 다른 모든 경우(지표 이름을 설정하는 파라미터에서 IndicatorCreate() 함수 사용 또는 문자열 비상수 사용)에는 이 속성이 필요합니다

tester_file

string

확장명이 표시된 테스터의 파일 이름으로는 큰따옴표로(문자열 상수로써) 표시됩니다. 지정한 파일이 테스터로 전달됩니다. 필요한 경우 테스트할 입력 파일을 항상 지정해야 합니다.

tester_library

string

확장명이 큰따옴표로 표시된 라이브러리 이름. 라이브러리는 dll 또는 ex5 확장자를 가질 수 있습니다. 테스트가 필요한 라이브러리는 자동으로 정의됩니다. 그러나 커스텀 지표에서 라이브러리를 사용하는 경우 이 속성이 필요합니다.

각 매개 변수 블록에 대해 MD5-해시 형식의 디지털 지문이 생성되어 에이전트로 전송됩니다. MD5 해시는 각 세트에 대해 고유하며, MD5 해시의 볼륨은 계산된 정보의 양보다 훨씬 작습니다.

에이전트는 블록 해시를 수신하여 이미 있는 블록과 비교합니다. 지정된 매개 변수 블록의 지문이 에이전트에 없거나 수신된 해시가 기존 해시와 다른 경우 에이전트가 이 매개 변수 블록을 요청합니다. 그러면 터미널과 에이전트 간의 트래픽이 줄어듭니다.

테스트 후 에이전트는 "테스트 결과" 및 "최적화 결과" 탭에 표시된 모든 실행 결과(수령 이익, 거래 수, 샤프 계수, OnTester() 함수 결과 등)를 터미널에 반환합니다.

최적화하는 동안 터미널은 테스트 작업을 작은 패키지로 에이전트에 제공하며, 각 패키지에는 여러 작업이 포함되어 있습니다(각 태스크는 입력 매개 변수 세트를 사용한 단일 테스트를 의미합니다). 그러면 터미널과 에이전트 간의 교환 시간이 줄어듭니다.

에이전트는 보안상의 이유로 터미널(EA, 지표, 라이브러리 등)에서 가져온 EX5 파일을 하드 디스크에 기록하지 않으므로 에이전트가 실행 중인 컴퓨터는 전송된 데이터를 사용할 수 없습니다. DLL을 포함한 다른 모든 파일은 샌드박스에 기록됩니다. 원격 에이전트에서는 DLL을 사용하여 EA를 테스트할 수 없습니다.

테스트 결과는 터미널에 의해 특수 결과 캐시(결과 캐시)에 추가되어 필요할 때 신속하게 액세스할 수 있습니다. 각 매개 변수 세트에 대해 터미널은 재실행을 방지하기 위해 결과 캐시에서 이전 실행의 이미 사용 가능한 결과를 검색합니다. 이러한 매개 변수 집합이 있는 결과를 찾을 수 없는 경우 에이전트에 테스트를 수행하는 작업이 부여됩니다.

터미널과 에이전트 간의 모든 트래픽이 암호화됩니다.

틱은 네트워크를 통해 전송되지 않고 테스트 에이전트에서 생성됩니다.

모든 클라이언트 터미널의 공유 폴더 사용 #

모든 테스트 에이전트는 서로 분리되고 클라이언트 터미널에서 분리됩니다. 각 에이전트에는 로그를 기록하는 고유한 폴더가 있습니다. 또한 에이전트 테스트 중 모든 파일 작업은 agent_name/MQL5/Files폴더에서 수행됩니다. 그러나 파일을 여는 동안 플래그 FILE_COMMON를 지정하는 경우 모든 클라이언트 터미널의 공유 폴더를 통해 로컬 에이전트와 클라이언트 터미널 간의 상호 작용을 구현할 수 있습니다:

//+------------------------------------------------------------------+
//| Expert 초기화 함수                                                |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- 모든 클라이언트 터미널의 공유 폴더
   common_folder=TerminalInfoString(TERMINAL_COMMONDATA_PATH);
//--- 이 폴더의 이름을 빼냅니다
   PrintFormat("클라이언트 터미널의 공유 폴더에 있는 파일 오픈 %s", common_folder);
//--- 공유 폴더에서 파일 오픈 (FILE_COMMON 플래그로 표시됨)
   handle=FileOpen(filename,FILE_WRITE|FILE_READ|FILE_COMMON);
  ... 추가 조치
//---
   return(INIT_SUCCEEDED);
  }

DLLs 사용 #

최적화 속도를 높이기 위해 로컬 에이전트 뿐 아니라 원격 에이전트도 사용할 수 있습니다. 이 경우 원격 에이전트에는 몇 가지 제한이 있습니다. 먼저 원격 에이전트는 로그에서 Print() 함수의 실행 결과, 즉 포지션 오픈 및 클로즈에 대한 메시지를 표시하지 않습니다. 잘못 작성된 EA가 원격 에이전트가 작업 중인 시스템을 메시지와 함께 추적하지 못하도록 로그에 최소한의 정보가 표시됩니다.

두 번째 제한 사항 - EA 테스트 시 DLL 사용 금지. 보안상의 이유로 원격 에이전트에서는 DLL 호출이 절대 금지됩니다. 로컬 에이전트에서 테스트된 EA의 DLL 호출은 적절한 "Allow import DLL" 권한으로만 허용됩니다.

mql5-programs의 "Allow import DLL" 옵션

참고: 허용된 DLL 호출이 필요한 타사 EA(스크립트, 지표)를 사용할 때는 터미널 설정에서 이 옵션을 허용할 때 발생할 수 있는 위험을 알고 있어야 합니다. EA가 사용되는 방법에 관계없이 테스트 또는 차트 실행에 사용됩니다.