English Русский 中文 Español Deutsch 日本語 Português Français Italiano Türkçe
MQL5 Cookbook: 지표를 사용하여 Expert Advisor의 거래 조건 설정

MQL5 Cookbook: 지표를 사용하여 Expert Advisor의 거래 조건 설정

MetaTrader 5 | 2 9월 2021, 17:07
79 0
Anatoli Kazharski
Anatoli Kazharski

소개

이 글에서 Expert Advisor는 포지션 개방 조건을 확인하는 데 사용할 값의 지표로 향상됩니다. 재미를 더하기 위해 외부 매개변수에 드롭다운 목록을 만들어 세 가지 거래 지표 중 하나를 선택할 수 있습니다.

만일을 대비하여: MQL5 Cookbook 시리즈의 이전 글 전체에서 작업한 Expert Advisor를 계속 수정합니다. Expert Advisor의 마지막 버전은 "MQL5 Cookbook: History of Deals And Function Library for Get Position Properties"라는 제목의 글에서 다운로드할 수 있습니다.

또한 이 글에서는 거래 작업을 수행할 수 있는지 여부를 확인하기 위해 만들 기능을 제공합니다. 포지션 개시 기능은 Expert Advisor가 거래 모드(즉시 실행시장 실행)를 결정할 수 있도록 수정됩니다.

Expert Advisor의 코드는 이전 글의 모든 개선 사항 및 개선 사항에 따라 이미 1,500줄을 초과하므로 새로운 기능이 추가될 때마다 점점 더 편리해집니다. 따라서 논리적 솔루션은 이를 별도의 라이브러리 파일로 여러 범주로 나누는 것입니다. 목표가 설정되었으니 이제 시작하겠습니다.

 

Expert Advisor 개발

이전 글의 Expert Advisor(*.mq5) 소스 코드를 별도의 폴더 TestIndicatorConditions에 넣습니다. 이 폴더에서 Include 하위 폴더를 만들어야 합니다. 이것은 포함 파일(*.mqh)을 생성할 폴더입니다. MQL5 마법사(Ctrl+N)를 사용하여 생성하거나 표준 텍스트 파일(*.txt)로 필요한 디렉토리에 수동으로 생성하고 나중에 *.mqh로 이름을 변경할 수 있습니다.

다음은 생성된 모든 포함 파일의 이름과 주석입니다.

  • Enums.mqh에는 모든 열거가 포함됩니다.
  • InfoPanel.mqh는 정보 패널 설정, 그래픽 개체 생성 및 삭제 기능을 제공합니다.
  • Errors.mqh는 오류 코드 및 초기화 해제 이유를 반환하는 모든 함수를 다룹니다.
  • TradeSignals.mqh는 배열을 가격, 지표 값, 신호 블록으로 채우는 기능을 제공합니다.
  • TradeFunctions.mqh에는 거래 기능이 포함됩니다.
  • ToString.mqh는 숫자 값을 문자열 값으로 변환하는 함수를 다룹니다.
  • Auxiliary.mqh는 다른 보조 기능에 사용됩니다.

이러한 라이브러리를 기본 파일에 포함하려면 #include 지시문을 사용합니다. Expert Advisor의 메인 파일과 포함 파일 폴더(Include)가 같은 폴더에 있기 때문에 파일을 포함하는 코드는 다음과 같습니다.

//--- Include custom libraries
#include "Include\Enums.mqh"
#include "Include\InfoPanel.mqh"
#include "Include\Errors.mqh"
#include "Include\TradeSignals.mqh"
#include "Include\TradeFunctions.mqh"
#include "Include\ToString.mqh"
#include "Include\Auxiliary.mqh"

그런 다음 Expert Advisor의 기본 파일에서 소스 코드의 일부를 열어 수정하고 이동할 수 있습니다.

코드를 올바르게 탐색하기 위해 인접 헤더 파일에 대한 참조와 Expert Advisor의 기본 파일에 대한 참조가 각 헤더 파일에 추가됩니다. 예를 들어, 거래 기능 라이브러리인 TradeFunctions.mqh의 경우 다음과 같습니다.

//--- Connection with the main file of the Expert Advisor
#include "..\TestIndicatorConditions.mq5"
//--- Include custom libraries
#include "Enums.mqh"
#include "InfoPanel.mqh"
#include "Errors.mqh"
#include "TradeSignals.mqh"
#include "ToString.mqh"
#include "Auxiliary.mqh"

동일한 중첩 수준에 있는 파일의 경우 단순히 이름을 지정하는 것으로 충분합니다. 한 단계 위로 이동하려면 경로에서 백슬래시 앞에 두 개의 점을 넣어야 합니다.

Enums.mqh 파일에 지표에 대한 열거를 추가해 보겠습니다. 설명을 위해 이 Expert Advisor에서는 두 개의 표준 지표(이동 평균상품 채널 지수)와 하나의 맞춤 지표(MultiRange_PCH)를 사용합니다. 열거는 다음과 같습니다.

//--- Indicators
enum ENUM_INDICATORS
  {
   MA       = 0, // Moving Average
   CCI      = 1, // CCI
   PCH      = 2  // Price Channel
  };

외부 매개변수는 다음과 같이 수정됩니다.

//--- External parameters of the Expert Advisor
sinput   long              MagicNumber=777;        // Magic number
sinput   int               Deviation=10;           // Slippage
input    ENUM_INDICATORS   Indicator=MA;           // Indicator
input    int               IndicatorPeriod=5;      // Indicator period
input    int               IndicatorSegments=2;    // Number of one direction indicator segments
input    double            Lot=0.1;                // Lot
input    double            VolumeIncrease=0.1;     // Position volume increase
input    double            VolumeIncreaseStep=10;  // Step for volume increase
input    double            StopLoss=50;            // Stop Loss
input    double            TakeProfit=100;         // Take Profit
input    double            TrailingStop=10;        // Trailing Stop
input    bool              Reverse=true;           // Position reversal
sinput   bool              ShowInfoPanel=true;     // Display of the info panel

위에서 언급했듯이 Indicator 매개변수의 드롭다운 목록에서 세 가지 지표 중 하나를 선택할 수 있습니다.

지표 기간을 설정할 수 있는 모든 지표에 적용할 수 있는 매개변수는 IndicatorPeriod뿐입니다. Expert Advisor 이전 버전의 NumberOfBars 매개변수는 IndicatorSegments로 이름이 바뀌었으며 이제 주어진 지표가 포지션 오픈 조건을 만족하기 위해 위/아래로 움직여야 하는 바 수를 나타냅니다.

또한 포인트의 볼륨 증가 단계를 설정하는 데 사용할 수 있는 다른 외부 매개변수 VolumeIncreaseStep을 추가했습니다.

GetBarsData() 사용자 정의 함수에서 조정되는 데 사용되는 AllowedNumberOfBars 변수(현재 AllowedNumberOfSegments) 값. 이제 별도의 함수에 배치되고 초기화 시에만 호출됩니다.

포지션 오픈 조건은 이제 지표 값을 사용하여 확인되므로 할당되는 값은 항상 2배 커집니다. 즉, IndicatorSegments 외부 변수에 1 값이 할당되면 AllowedNumberOfSegments 변수에는 3 값이 할당됩니다. BUY)의 경우 완료된 바의 지표 값은 이전 바의 지표 값보다 커야 합니다. 이를 위해 마지막 세 개의 지표 값을 가져와야 합니다.

다음은 CorrectInputParameters() 함수 코드입니다.

//+------------------------------------------------------------------+
//| Adjusting input parameters                                       |
//+------------------------------------------------------------------+
void CorrectInputParameters()
  {
//--- Adjust the number of bars for the position opening condition
   if(AllowedNumberOfSegments<=0)
     {
      if(IndicatorSegments<=1)
         AllowedNumberOfSegments=3;                     // At least three bars are required
      if(IndicatorSegments>=5)
         AllowedNumberOfSegments=5;                     // but no more than 7
      else
         AllowedNumberOfSegments=IndicatorSegments+1;   // and always greater by two
     }
  }

지표를 다루기 전에 거래가 허용되는지 확인하는 함수인 CheckTradingPermission()을 만들어 보겠습니다. 함수에 나열된 이유로 거래가 허용되지 않으면 0 값이 반환됩니다. 이것은 다음 시도가 다음 바에서 이루어져야 함을 의미합니다.

//+------------------------------------------------------------------+
//| Checking if trading is allowed                                   |
//+------------------------------------------------------------------+
bool CheckTradingPermission()
  {
//--- For real-time mode
   if(IsRealtime())
     {
      //--- Checking server connection
      if(!TerminalInfoInteger(TERMINAL_CONNECTED))
         return(1);
      //--- Permission to trade at the running program level
      if(!MQL5InfoInteger(MQL5_TRADE_ALLOWED))
         return(2);
      //--- Permission to trade at the terminal level
      if(!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED))
         return(3);
      //--- Permission to trade for the current account
      if(!AccountInfoInteger(ACCOUNT_TRADE_ALLOWED))
         return(4);
      //--- Permission to trade automatically for the current account
      if(!AccountInfoInteger(ACCOUNT_TRADE_EXPERT))
         return(5);
     }
//---
   return(0);
  }

이제 글의 요점으로 내려가 보겠습니다. 지표의 값에 액세스하려면 먼저 핸들을 가져와야 합니다. 이것은 지표의 짧은 이름과 그 앞에 오는 'i' 기호로 이루어진 이름을 가진 특수 기능을 사용하여 수행됩니다.

예를 들어, 이동 평균 표시에는 해당 기능 iMA()이 있습니다. MetaTrader 5 터미널의 모든 표준 지표 핸들은 이 기능을 사용하여 얻을 수 있습니다. 전체 목록은 기술 지표라는 MQL5 참조 섹션에서 확인할 수 있습니다. 사용자 지정 지표의 핸들을 가져와야 하는 경우 iCustom() 함수를 사용하세요.

Indicator 매개변수에서 선택한 지표에 따라 해당 지표의 핸들 값이 indicator_handle 전역 변수에 할당되는 GetIndicatorHandle() 함수를 구현합니다. 기능 코드는 거래 신호 기능 라이브러리(\Include\TradeSignals.mqh 파일)에서 찾을 수 있으며 지표 핸들이 있는 변수는 Expert Advisor의 기본 파일에 있습니다.

//+------------------------------------------------------------------+
//| Getting the indicator handle                                     |
//+------------------------------------------------------------------+
void GetIndicatorHandle()
  {
//--- If the Moving Average indicator is selected
   if(Indicator==MA)
      indicator_handle=iMA(_Symbol,Period(),IndicatorPeriod,0,MODE_SMA,PRICE_CLOSE);
//--- If the CCI indicator is selected
   if(Indicator==CCI)
      indicator_handle=iCCI(_Symbol,Period(),IndicatorPeriod,PRICE_CLOSE);
//--- If the MultiRange_PCH indicator is selected
   if(Indicator==PCH)
      indicator_handle=iCustom(_Symbol,Period(),"MultiRange_PCH",IndicatorPeriod);
//--- If the indicator handle could not be obtained
   if(indicator_handle==INVALID_HANDLE)
      Print("Failed to get the indicator handle!");
  }

또한 얻은 지표 핸들을 사용하여 값을 가져올 수 있는 GetDataIndicators() 함수를 만듭니다. 이는 CopyTime(), CopyClose(), 를 사용하여 바 값을 가져오는 것과 유사한 방식으로 CopyBuffer() 함수를 사용하여 수행됩니다. CopyOpen(), CopyHigh() 및 CopyLow() 함수는 "MQL5 Cookbook: MetaTrader 5 전략 테스터"의 포지션 속성 분석"이라는 글에서 고려됩니다..

지표는 여러 버퍼(값 행)를 가질 수 있으므로 버퍼 인덱스는 두 번째 매개변수로 CopyBuffer() 함수에 전달됩니다. 표준 지표의 버퍼 색인은 MQL5 참조에서 찾을 수 있습니다. 사용자 지정 지표의 경우 소스 코드를 사용할 수 있는 경우 코드에서 버퍼 색인을 찾을 수 있습니다. 코드가 없으면 Strategy Tester의 시각화 모드에서 조건이 어떻게 충족되는지 관찰하여 실험을 통해 인덱스를 찾아야 합니다.

그 전에 Expert Advisor의 기본 파일에서 지표 버퍼 값에 대한 동적 배열을 생성해야 합니다.

//--- Arrays for indicator values
double indicator_buffer1[];
double indicator_buffer2[];

GetIndicatorsData()의 코드는 다음과 같습니다.

//+------------------------------------------------------------------+
//| Getting indicator values                                         |
//+------------------------------------------------------------------+
bool GetIndicatorsData()
  {
//--- If the indicator handle has been obtained
   if(indicator_handle!=INVALID_HANDLE)
     {
      //--- For the Moving Average or CCI indicator
      if(Indicator==MA || Indicator==CCI)
        {
         //--- Reverse the indexing order (... 3 2 1 0)
         ArraySetAsSeries(indicator_buffer1,true);
         //--- Get indicator values
         if(CopyBuffer(indicator_handle,0,0,AllowedNumberOfSegments,indicator_buffer1)<AllowedNumberOfSegments)
           {
            Print("Failed to copy the values ("+
                  _Symbol+"; "+TimeframeToString(Period())+") to the indicator_buffer1 array! Error ("+
                  IntegerToString(GetLastError())+"): "+ErrorDescription(GetLastError()));
            return(false);
           }
        }
      //--- For the MultiRange_PCH indicator
      if(Indicator==PCH)
        {
         //--- Reverse the indexing order (... 3 2 1 0)
         ArraySetAsSeries(indicator_buffer1,true);
         ArraySetAsSeries(indicator_buffer2,true);
         //--- Get indicator values
         if(CopyBuffer(indicator_handle,0,0,AllowedNumberOfSegments,indicator_buffer1)<AllowedNumberOfSegments || 
            CopyBuffer(indicator_handle,1,0,AllowedNumberOfSegments,indicator_buffer2)<AllowedNumberOfSegments)
           {
            Print("Failed to copy the values ("+
                  _Symbol+"; "+TimeframeToString(Period())+") to the indicator_buffer1 or indicator_buffer2 array! Error ("+
                  IntegerToString(GetLastError())+"): "+ErrorDescription(GetLastError()));
            return(false);
           }
        }
      //---
      return(true);
     }
//--- If the indicator handle has not been obtained, retry
   else
      GetIndicatorHandle();
//---
   return(false);
  }

GetTradingSignal() 함수가 크게 변경되었습니다. 포지션이 없는 경우와 포지션이 있는 경우 조건이 다릅니다. 이동 평균CCI 지표의 조건은 동일합니다. MultiRange_PCH의 경우 별도의 블록에 배열됩니다. 코드를 보다 쉽게 읽을 수 있도록 하고 반복을 방지하기 위해 포지션 열기 또는 반전 신호를 반환하는 보조 함수 Get Signal()을 만듭니다. 단, 해당 위치가 존재하고 외부 매개 변수에 의해 관련 작업이 허용됩니다.

다음은 GetSignal() 함수의 코드입니다.

//+------------------------------------------------------------------+
//| Checking the condition and returning a signal                    |
//+------------------------------------------------------------------+
ENUM_ORDER_TYPE GetSignal()
  {
//--- Check conditions for the Moving Average and CCI indicators
   if(Indicator==MA || Indicator==CCI)
     {
      //--- A Sell signal
      if(AllowedNumberOfSegments==3 && 
         indicator_buffer1[1]<indicator_buffer1[2])
         return(ORDER_TYPE_SELL);
      //---
      if(AllowedNumberOfSegments==4 && 
         indicator_buffer1[1]<indicator_buffer1[2] && 
         indicator_buffer1[2]<indicator_buffer1[3])
         return(ORDER_TYPE_SELL);
      //---
      if(AllowedNumberOfSegments==5 && 
         indicator_buffer1[1]<indicator_buffer1[2] && 
         indicator_buffer1[2]<indicator_buffer1[3] && 
         indicator_buffer1[3]<indicator_buffer1[4])
         return(ORDER_TYPE_SELL);
      //---
      if(AllowedNumberOfSegments==6 && 
         indicator_buffer1[1]<indicator_buffer1[2] && 
         indicator_buffer1[2]<indicator_buffer1[3] && 
         indicator_buffer1[3]<indicator_buffer1[4] && 
         indicator_buffer1[4]<indicator_buffer1[5])
         return(ORDER_TYPE_SELL);
      //---
      if(AllowedNumberOfSegments>=7 && 
         indicator_buffer1[1]<indicator_buffer1[2] && 
         indicator_buffer1[2]<indicator_buffer1[3] && 
         indicator_buffer1[3]<indicator_buffer1[4] && 
         indicator_buffer1[4]<indicator_buffer1[5] && 
         indicator_buffer1[5]<indicator_buffer1[6])
         return(ORDER_TYPE_SELL);

      //--- A Buy signal
      if(AllowedNumberOfSegments==3 && 
         indicator_buffer1[1]>indicator_buffer1[2])
         return(ORDER_TYPE_BUY);
      //---
      if(AllowedNumberOfSegments==4 && 
         indicator_buffer1[1]>indicator_buffer1[2] && 
         indicator_buffer1[2]>indicator_buffer1[3])
         return(ORDER_TYPE_BUY);
      //---
      if(AllowedNumberOfSegments==5 && 
         indicator_buffer1[1]>indicator_buffer1[2] && 
         indicator_buffer1[2]>indicator_buffer1[3] && 
         indicator_buffer1[3]>indicator_buffer1[4])
         return(ORDER_TYPE_BUY);
      //---
      if(AllowedNumberOfSegments==6 && 
         indicator_buffer1[1]>indicator_buffer1[2] && 
         indicator_buffer1[2]>indicator_buffer1[3] && 
         indicator_buffer1[3]>indicator_buffer1[4] && 
         indicator_buffer1[4]>indicator_buffer1[5])
         return(ORDER_TYPE_BUY);
      //---
      if(AllowedNumberOfSegments>=7 && 
         indicator_buffer1[1]>indicator_buffer1[2] && 
         indicator_buffer1[2]>indicator_buffer1[3] && 
         indicator_buffer1[3]>indicator_buffer1[4] && 
         indicator_buffer1[4]>indicator_buffer1[5] && 
         indicator_buffer1[5]>indicator_buffer1[6])
         return(ORDER_TYPE_BUY);
     }
//--- Block that checks conditions for the MultiRange_PCH indicator
   if(Indicator==PCH)
     {
      //--- A Sell signal
      if(close_price[1]<indicator_buffer2[1] && 
         open_price[1]>indicator_buffer2[1])
         return(ORDER_TYPE_SELL);
      //--- A Buy signal
      if(close_price[1]>indicator_buffer1[1] && 
         open_price[1]<indicator_buffer1[1])
         return(ORDER_TYPE_BUY);
     }
//--- No signal
   return(WRONG_VALUE);
  }

GetTradingSignal() 함수 코드는 이제 다음과 같습니다.

//+------------------------------------------------------------------+
//| Determining trading signals                                      |
//+------------------------------------------------------------------+
ENUM_ORDER_TYPE GetTradingSignal()
  {
//--- If there is no position
   if(!pos.exists)
     {
      //--- A Sell signal
      if(GetSignal()==ORDER_TYPE_SELL)
         return(ORDER_TYPE_SELL);
      //--- A Buy signal
      if(GetSignal()==ORDER_TYPE_BUY)
         return(ORDER_TYPE_BUY);
     }
//--- If the position exists
   if(pos.exists)
     {
      //--- Get the position type
      GetPositionProperties(P_TYPE);
      //--- Get the last deal price
      GetPositionProperties(P_PRICE_LAST_DEAL);
      //--- Block that checks conditions for the Moving Average and CCI indicators
      if(Indicator==MA || Indicator==CCI)
        {
         //--- A Sell signal
         if(pos.type==POSITION_TYPE_BUY && 
            GetSignal()==ORDER_TYPE_SELL)
            return(ORDER_TYPE_SELL);
         //---
         if(pos.type==POSITION_TYPE_SELL && 
            GetSignal()==ORDER_TYPE_SELL && 
            close_price[1]<pos.last_deal_price-CorrectValueBySymbolDigits(VolumeIncreaseStep*_Point))
            return(ORDER_TYPE_SELL);
         //--- A Buy signal
         if(pos.type==POSITION_TYPE_SELL && 
            GetSignal()==ORDER_TYPE_BUY)
            return(ORDER_TYPE_BUY);
         //---
         if(pos.type==POSITION_TYPE_BUY && 
            GetSignal()==ORDER_TYPE_BUY && 
            close_price[1]>pos.last_deal_price+CorrectValueBySymbolDigits(VolumeIncreaseStep*_Point))
            return(ORDER_TYPE_BUY);
        }
      //--- Block that checks conditions for the MultiRange_PCH indicator
      if(Indicator==PCH)
        {
         //--- A Sell signal
         if(pos.type==POSITION_TYPE_BUY && 
            close_price[1]<indicator_buffer2[1] && 
            open_price[1]>indicator_buffer2[1])
            return(ORDER_TYPE_SELL);
         //---
         if(pos.type==POSITION_TYPE_SELL && 

            close_price[1]<pos.last_deal_price-CorrectValueBySymbolDigits(VolumeIncreaseStep*_Point))
            return(ORDER_TYPE_SELL);
         //--- A Buy signal
         if(pos.type==POSITION_TYPE_SELL && 
            close_price[1]>indicator_buffer1[1] && 
            open_price[1]<indicator_buffer1[1])
            return(ORDER_TYPE_BUY);
         //---
         if(pos.type==POSITION_TYPE_BUY && 
            close_price[1]>pos.last_deal_price+CorrectValueBySymbolDigits(VolumeIncreaseStep*_Point))
            return(ORDER_TYPE_BUY);
        }
     }
//--- No signal
   return(WRONG_VALUE);
  }

이제 심볼 속성의 일부인 Instant ExecutionMarket Execution 모드를 살펴보고 OpenPosition() 코드를 수정하기만 하면 됩니다. 그에 따른 포지션 열기 기능. 이름이 자명한 모드는 MQL5 참조에서도 찾을 수 있습니다.

  • 즉시 실행
  • 시장 실행

시장 실행 모드를 취급할 때 손절매이익 실현 수준으로 포지션을 열 수 없음을 기억하세요. 먼저 위치를 연 다음 레벨을 설정하여 수정합니다.

빌드 803부터 Market Execution 및 Exchange Execution 모드에 대한 포지션을 열 때 손절매와 이익실현을 설정할 수 있습니다.

기호 속성의 구조에 실행 모드를 추가해 보겠습니다.

//--- Symbol properties
struct symbol_properties
  {
   int               digits;           // Number of decimal places in the price
   int               spread;           // Spread in points
   int               stops_level;      // Stops level
   double            point;            // Point value
   double            ask;              // Ask price
   double            bid;              // Bid price
   double            volume_min;       // Minimum volume for a deal
   double            volume_max;       // Maximum volume for a deal
   double            volume_limit;     // Maximum permissible volume for a position and orders in one direction
   double            volume_step;      // Minimum volume change step for a deal
   double            offset;           // Offset from the maximum possible price for a transaction
   double            up_level;         // Upper Stop level price
   double            down_level;       // Lower Stop level price
   ENUM_SYMBOL_TRADE_EXECUTION execution_mode; // Execution mode
  };

따라서 ENUM_SYMBOL_PROPERTIES 열거를 수정해야 합니다.

//--- Enumeration of position properties
enum ENUM_SYMBOL_PROPERTIES
  {
   S_DIGITS          = 0,
   S_SPREAD          = 1,
   S_STOPSLEVEL      = 2,
   S_POINT           = 3,
   S_ASK             = 4,
   S_BID             = 5,
   S_VOLUME_MIN      = 6,
   S_VOLUME_MAX      = 7,
   S_VOLUME_LIMIT    = 8,
   S_VOLUME_STEP     = 9,
   S_FILTER          = 10,
   S_UP_LEVEL        = 11,
   S_DOWN_LEVEL      = 12,
   S_EXECUTION_MODE  = 13,
   S_ALL             = 14
  };

GetSymbolProperties() 함수:

case S_EXECUTION_MODE: symb.execution_mode=(ENUM_SYMBOL_TRADE_EXECUTION)SymbolInfoInteger(_Symbol,SYMBOL_TRADE_EXEMODE);   break;
      //---
      case S_ALL           :
         symb.digits=(int)SymbolInfoInteger(_Symbol,SYMBOL_DIGITS);
         symb.spread=(int)SymbolInfoInteger(_Symbol,SYMBOL_SPREAD);
         symb.stops_level=(int)SymbolInfoInteger(_Symbol,SYMBOL_TRADE_STOPS_LEVEL);
         symb.point=SymbolInfoDouble(_Symbol,SYMBOL_POINT);
         symb.ask=NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_ASK),symb.digits);
         symb.bid=NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_BID),symb.digits);
         symb.volume_min=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MIN);
         symb.volume_max=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MAX);
         symb.volume_limit=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_LIMIT);
         symb.volume_step=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_STEP);
         symb.offset=NormalizeDouble(CorrectValueBySymbolDigits(lot_offset*symb.point),symb.digits);
         symb.up_level=NormalizeDouble(symb.ask+symb.stops_level*symb.point,symb.digits);
         symb.down_level=NormalizeDouble(symb.bid-symb.stops_level*symb.point,symb.digits);
         symb.execution_mode=(ENUM_SYMBOL_TRADE_EXECUTION)SymbolInfoInteger(_Symbol,SYMBOL_TRADE_EXEMODE);                       break;
         //---

결과적으로 OpenPosition() 함수 코드는 이제 다음과 같습니다.

//+------------------------------------------------------------------+
//| Opening a position                                               |
//+------------------------------------------------------------------+
void OpenPosition(double lot,
                  ENUM_ORDER_TYPE order_type,
                  double price,
                  double sl,
                  double tp,
                  string comment)
  {
//--- Set the magic number in the trading structure
   trade.SetExpertMagicNumber(MagicNumber);
//--- Set the slippage in points
   trade.SetDeviationInPoints(CorrectValueBySymbolDigits(Deviation));
//--- The Instant Execution mode
//    A position can be opened with the Stop Loss and Take Profit levels set
   if(symb.execution_mode==SYMBOL_TRADE_EXECUTION_INSTANT)
     {
      //--- If the position failed to open, print the relevant message
      if(!trade.PositionOpen(_Symbol,order_type,lot,price,sl,tp,comment))
         Print("Error opening the position: ",GetLastError()," - ",ErrorDescription(GetLastError()));
     }
//--- The Market Execution mode 
//    First open a position and only then set the Stop Loss and Take Profit levels
//    *** Starting with build 803, Stop Loss and Take Profit can be set upon position opening ***
   if(symb.execution_mode==SYMBOL_TRADE_EXECUTION_MARKET)
     {
      //--- If there is no position, first open a position and then set Stop Loss and Take Profit
      if(!pos.exists)
        {
         //--- If the position failed to open, print the relevant message
         if(!trade.PositionOpen(_Symbol,order_type,lot,price,0,0,comment))
            Print("Error opening the position: ",GetLastError()," - ",ErrorDescription(GetLastError()));
         //--- Get the flag of presence/absence of the position
         pos.exists=PositionSelect(_Symbol);
         //--- If the position exists
         if(pos.exists)
           {
            //--- Set Stop Loss and Take Profit
            if(!trade.PositionModify(_Symbol,sl,tp))
               Print("Error modifying the position: ",GetLastError()," - ",ErrorDescription(GetLastError()));
           }
        }
      //--- If the position exists, increase its volume and leave the Stop Loss and Take Profit levels unchanged
      else
        {
         //--- If the position failed to open, print the relevant message
         if(!trade.PositionOpen(_Symbol,order_type,lot,price,sl,tp,comment))
            Print("Error opening the position: ",GetLastError()," - ",ErrorDescription(GetLastError()));
        }
     }
  }

이벤트 처리 기능에 마지막으로 매우 중요한 터치를 추가해야 합니다.

  • OnInit
    //+------------------------------------------------------------------+
    //| Expert initialization function                                   |
    //+------------------------------------------------------------------+
    int OnInit()
      {
    //--- Adjust the input parameters
       CorrectInputParameters();
    //--- Get indicator handles
       GetIndicatorHandle();
    //--- Initialize the new bar
       CheckNewBar();
    //--- Get the properties
       GetPositionProperties(P_ALL);
    //--- Set the info panel
       SetInfoPanel();
    //---
       return(0);
      }
  • OnDeinit
    //+------------------------------------------------------------------+
    //| Expert deinitialization function                                 |
    //+------------------------------------------------------------------+
    void OnDeinit(const int reason)
      {
    //--- Print the deinitialization reason to the journal
       Print(GetDeinitReasonText(reason));
    //--- When deleting from the chart
       if(reason==REASON_REMOVE)
         {
          //--- Delete all objects relating to the info panel from the chart
          DeleteInfoPanel();
          //--- Delete the indicator handle
          IndicatorRelease(indicator_handle);
         }
      }
  • OnTick
    //+------------------------------------------------------------------+
    //| Expert tick function                                             |
    //+------------------------------------------------------------------+
    void OnTick()
      {
    //--- If the bar is not new, exit
       if(!CheckNewBar())
         {
          if(IsVisualMode() || IsRealtime())
            {
             //--- Get the properties and update the values on the panel
             GetPositionProperties(P_ALL);
             //--- Set/update the info panel
             SetInfoPanel();
            }
          return;
         }
    
    //--- If there is a new bar
       else
         {
          //--- If trading is allowed
          if(CheckTradingPermission()==0)
            {
             if(!GetIndicatorsData())
                return;
             GetBarsData();          // Get bar data
             TradingBlock();         // Check the conditions and trade
             ModifyTrailingStop();   // Modify the Trailing Stop level
            }
         }
    //--- Get the properties
       GetPositionProperties(P_ALL);
    //--- Update the info panel
       SetInfoPanel();
      }

이제 모든 기능이 준비되었으므로 매개변수를 최적화할 수 있습니다. 메인 프로그램 파일에서 코드를 컴파일해야 한다는 것을 명심하세요.

 

매개변수 최적화 및 Expert Advisor 테스트

Strategy Tester는 아래와 같이 설정해야 합니다.

그림 1. 전략 테스터 설정.

그림 1. 전략 테스터 설정.

또한 최적화를 위해 Expert Advisor의 매개변수를 설정합니다(설정이 포함된 첨부된 *.set 파일 참조).

그림 2. Expert Advisor의 설정.

그림 2. Expert Advisor의 설정.

최적화는 듀얼 코어 프로세서에서 약 40분이 걸렸습니다. 최적화 차트를 사용하면 이익 영역의 결과를 기반으로 거래 시스템의 품질을 부분적으로 평가할 수 있습니다.

그림 3. 최적화 차트.

그림 3. 최적화 차트.

최대 회복 계수 테스트 결과는 다음과 같습니다.

그림 4. 최대 회복 계수 테스트 결과.

그림 4. 최대 회복 계수 테스트 결과.

 

결론

글에 첨부된 것은 Expert Advisor의 소스 코드와 함께 다운로드 가능한 아카이브입니다. 글에 첨부된 것은 Expert Advisor의 소스 코드와 함께 다운로드 가능한 아카이브입니다. Expert Advisor의 올바른 작동을 보장하려면 MultiRange_PCH 지표를 다운로드하여 <Metatrader 5 터미널>\MQL5\Indicators에 배치해야 합니다.

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

지그재그 지표: 신선한 접근 방식과 새로운 솔루션 지그재그 지표: 신선한 접근 방식과 새로운 솔루션
이 글에서는 고급 ZigZag 지표를 만들 가능성을 검토합니다. 노드를 식별하는 아이디어는 Envelopes 지표의 사용을 기반으로 합니다. 우리는 모든 ZigZag 노드가 Envelopes 밴드의 범위 내에 있는 일련의 Envelopes에 대한 입력 매개변수의 특정 조합을 찾을 수 있다고 가정합니다. 결과적으로 우리는 새로운 노드의 좌표를 예측하려고 시도할 수 있습니다.
MQL5 Cookbook: 거래의 역사 및 직위 속성 가져오기를 위한 기능 라이브러리 MQL5 Cookbook: 거래의 역사 및 직위 속성 가져오기를 위한 기능 라이브러리
포지션 속성에 대한 이전 글에서 제공한 정보를 간략하게 요약할 시간입니다. 이 글에서는 거래 내역에 액세스한 후에만 얻을 수 있는 속성을 가져오는 몇 가지 추가 함수를 만듭니다. 또한 보다 편리한 방법으로 포지션 및 기호 속성에 액세스할 수 있는 데이터 구조에 익숙해질 것입니다.
MQL5 Cookbook: 트리플 스크린 전략에 기반한 거래 시스템을 위한 프레임워크 개발 MQL5 Cookbook: 트리플 스크린 전략에 기반한 거래 시스템을 위한 프레임워크 개발
이 글에서는 MQL5의 Triple Screen 전략을 기반으로 하는 거래 시스템의 프레임워크를 개발할 것입니다. Expert Advisor는 처음부터 개발되지 않습니다. 대신에 이미 우리의 목적에 실질적으로 부합하는 이전 글 "MQL5 Cookbook: 지표를 사용하여 Expert Advisors에서 거래 조건 설정"에서 프로그램을 수정하기만 하면 됩니다. 따라서 이 글에서는 기성 프로그램의 패턴을 쉽게 수정할 수 있는 방법도 보여줍니다.
MQL5 Cookbook: 거래 수준을 설정/수정할 때 오류를 피하는 방법 MQL5 Cookbook: 거래 수준을 설정/수정할 때 오류를 피하는 방법
"MQL5 Cookbook: MetaTrader 5 Strategy Tester의 포지션 속성 분석" 시리즈의 이전 글에서 Expert Advisor에 대한 작업을 계속하면서 많은 유용한 기능으로 기존의 기능들과 더불어 이를 개선하고 최적화할 것입니다. Expert Advisor는 이번에 MetaTrader 5 전략 테스터에서 최적화할 수 있는 외부 매개변수를 가지며 어떤 면에서는 단순한 거래 시스템과 유사합니다.