English Русский 中文 Español Deutsch 日本語 Português Français Italiano Türkçe
MQL5 Cookbook: 거래의 역사 및 직위 속성 가져오기를 위한 기능 라이브러리

MQL5 Cookbook: 거래의 역사 및 직위 속성 가져오기를 위한 기능 라이브러리

MetaTrader 5 | 2 9월 2021, 17:06
62 0
Anatoli Kazharski
Anatoli Kazharski

소개

포지션 속성에 대한 이전 글에서 제공한 정보를 간략하게 요약할 시간입니다. 이 글에서는 거래 내역에 액세스한 후에만 얻을 수 있는 속성을 가져오는 몇 가지 추가 함수를 만듭니다. 또한 보다 편리한 방법으로 포지션 및 기호 속성에 액세스할 수 있는 데이터 구조에 익숙해질 것입니다.

포지션 볼륨이 존재하는 동안 동일하게 유지되는 거래 시스템은 실제로 이 글에서 제공될 기능의 사용을 필요로 하지 않습니다. 그러나 나중에 자금 관리 시스템을 구현하고 거래 전략에서 포지션 랏 크기를 제어하려는 경우 이러한 기능은 필수 불가결합니다.

시작하기 전에 이 웹 사이트를 처음 방문하거나 MQL5 언어를 막 배우기 시작한 독자들에게 이 글의 링크를 팔로우한 독자들에게 제안하고 싶습니다. "MQL5 Cookbook" 시리즈의 이전 글로 말이죠.


Expert Advisor 개발

"MQL5 Cookbook: 거래 수준을 설정/수정할 때 오류를 방지하는 방법"이라는 이전 글에서 수정된 Expert Advisor의 새 기능 작동을 볼 수 있도록 다음 가능성을 추가합니다. 포지션이 이미 있는 상태에서 열기 신호가 다시 발생하면 포지션 볼륨을 높입니다.

포지션 히스토리에 여러 거래가 있을 수 있으며, 거래 과정에서 포지션 볼륨에 변화가 있었다면 현재 포지션 가격에도 변화가 있었을 것입니다. 첫 번째 진입점의 가격을 알아보려면 해당 특정 포지션과 관련된 거래 내역에 액세스해야 합니다. 아래 그림은 포지션이 하나의 거래(진입점)만 있는 경우를 보여줍니다.

그림 1. 포지션의 첫 번째 거래

그림 1. 포지션에서 첫 번째 거래.

다음 그림은 두 번째 거래에 따른 포지션 가격의 변화를 보여줍니다.

그림 2. 포지션에서 두 번째 거래

그림 2. 포지션에서 두 번째 거래.

이전 글에서 설명한 것처럼 표준 식별자를 사용하면 현재 포지션 가격(POSITION_PRICE_OPEN)과 열린 포지션에 대해 속한 심볼의 현재 가격(POSITION_PRICE_CURRENT)만 얻을 수 있습니다.

그러나 일부 거래 시스템에서는 첫 번째 진입점에서 가격이 적용되는 거리와 마지막 거래의 가격을 알아야 합니다. 이 모든 정보는 계정의 거래/주문 내역에서 확인할 수 있습니다. 아래는 이전 그림과 관련된 거래 목록입니다.

그림 3. 계정 거래 내역

그림 3. 나는 이제 상황이 명확하고 모든 목표가 설정되었다고 믿습니다.

이전 글에서 다룬 Expert Advisor를 계속 수정해 보겠습니다. 먼저 포지션 속성 열거에 0, 6, 9, 12 및 16으로 번호가 매겨진 새 식별자를 추가합니다. 각 속성에 대한 설명은 아래에서 약간 검토할 구조에서 제공됩니다.

//--- Enumeration of position properties
enum ENUM_POSITION_PROPERTIES
  {
   P_TOTAL_DEALS     = 0,
   P_SYMBOL          = 1,
   P_MAGIC           = 2,
   P_COMMENT         = 3,
   P_SWAP            = 4,
   P_COMMISSION      = 5,
   P_PRICE_FIRST_DEAL= 6,
   P_PRICE_OPEN      = 7,
   P_PRICE_CURRENT   = 8,
   P_PRICE_LAST_DEAL = 9,
   P_PROFIT          = 10,
   P_VOLUME          = 11,
   P_INITIAL_VOLUME  = 12,
   P_SL              = 13,
   P_TP              = 14,
   P_TIME            = 15,
   P_DURATION        = 16,
   P_ID              = 17,
   P_TYPE            = 18,
   P_ALL             = 19
  };

외부 매개변수의 수를 늘리자.

이제 다음을 지정할 수 있습니다. 이제 다음을 지정할 수 있습니다.

  • MagicNumber - Expert Advisor의 고유 ID(매직 넘버).
  • 편차 - 슬리피지;
  • VolumeIncrease - 포지션 볼륨이 증가할 값입니다.
  • InfoPanel - 정보 패널의 표시를 활성화/비활성화할 수 있는 매개변수입니다.

구현 방법은 다음과 같습니다.

//--- External parameters of the Expert Advisor
sinput   long        MagicNumber=777;     // Magic number
sinput   int         Deviation=10;        // Slippage
input    int         NumberOfBars=2;      // Number of Bullish/Bearish bars for a Buy/Sell
input    double      Lot=0.1;             // Lot
input    double      VolumeIncrease=0.1;  // Position 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

sinput modifier가 설정된 매개변수에 유의하세요. 이 modifier를 사용하면 전략 테스터에서 최적화를 비활성화할 수 있습니다. 사실, 자신이 사용할 프로그램을 개발할 때 어떤 매개변수가 최종 결과에 영향을 미치는지 완벽하게 이해하고 있으므로 최적화에서 해당 매개변수의 선택을 취소하기만 하면 됩니다. 그러나 매개변수가 매우 많은 경우 이 방법을 사용하면 회색으로 표시될 때 다른 매개변수와 시각적으로 구분할 수 있습니다.

그림 4. 최적화를 위해 비활성화된 매개변수는 회색으로 표시됩니다.

그림 4. 최적화를 위해 비활성화된 매개변수는 회색으로 표시됩니다.

이제 포지션 및 기호 속성 값을 저장한 전역 변수를 데이터 구조(struct)로 교체해 보겠습니다.

//--- Position properties
struct position_properties
  {
   uint              total_deals;      // Number of deals
   bool              exists;           // Flag of presence/absence of an open position
   string            symbol;           // Symbol
   long              magic;            // Magic number
   string            comment;          // Comment
   double            swap;             // Swap
   double            commission;       // Commission   
   double            first_deal_price; // Price of the first deal in the position
   double            price;            // Current position price
   double            current_price;    // Current price of the position symbol      
   double            last_deal_price;  // Price of the last deal in the position
   double            profit;           // Profit/Loss of the position
   double            volume;           // Current position volume
   double            initial_volume;   // Initial position volume
   double            sl;               // Stop Loss of the position
   double            tp;               // Take Profit of the position
   datetime          time;             // Position opening time
   ulong             duration;         // Position duration in seconds
   long              id;               // Position identifier
   ENUM_POSITION_TYPE type;            // Position type
  };
//--- 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
  }

이제 구조의 특정 요소에 액세스하려면 이 구조 유형의 변수를 만들어야 합니다. 절차는 "MQL5 Cookbook: Analyzing Position Properties in the MetaTrader 5 Strategy Tester"라는 글에서 고려한 트레이드 클래스에 대한 개체를 생성하는 것과 유사합니다.

//--- variables for position and symbol properties
position_properties  pos;
symbol_properties    symb;

클래스 메소드를 다룰 때와 같은 방식으로 요소에 접근할 수 있습니다. 즉, 특정 구조에 포함된 요소 목록을 표시하려면 구조 변수 이름 뒤에 점을 추가하면 충분합니다. 이것은 매우 편리합니다. 구조의 필드에 대해 한 줄 주석이 제공되는 경우(이 예와 같이) 오른쪽의 도구 설명에 표시됩니다.

그림 5a. 포지션 속성에 대한 구조 필드 목록 그림 5b. 기호 속성에 대한 구조 필드 목록

그림 5. 구조 필드 목록입니다.

또 다른 중요한 점. Expert Advisor를 수정하면서 많은 기능에서 사용되는 거의 모든 전역 변수를 변경했으므로 이제 심볼 및 포지션 속성에 해당하는 구조 필드로 대체해야 합니다. 예를 들어, 열린 포지션의 존재/부재 플래그를 저장하는 데 사용되었던 pos_open 전역 변수가 position_properties 구조 유형의 exists 필드로 대체되었습니다. 따라서 pos_open 변수가 사용될 때마다 pos.exists로 바꿔야 합니다.

수동으로 하게 되면 길고 힘든 과정이 될 것입니다. 따라서 MetaEditor 기능을 사용하여 이 작업에 대한 솔루션을 자동화하는 것이 좋습니다. 찾기 및 바꾸기 -> 수정 메뉴 또는 바꾸기 Ctrl+H 키 조합:


그림 6. 텍스트 찾기 및 바꾸기

그림 6. 텍스트 찾기 및 바꾸기.

파일을 컴파일한 후 테스트를 추가로 실행하려면 포지션 및 기호 속성에 대한 모든 전역 변수를 찾아서 교체해야 합니다. 오류가 감지되지 않으면 모든 것이 올바르게 수행되었음을 의미합니다. 글이 불필요하게 길어지지 않도록 여기에 코드를 제공하지 않겠습니다. 게다가, 사용할 준비가 된 소스 코드는 다운로드할 글의 끝에서 사용할 수 있습니다.

변수를 정리했으니 이제 기존 함수를 수정하고 새 함수를 생성해 보겠습니다.

이제 외부 매개변수에서 매직 넘버와 슬립을 포인트 단위로 설정할 수 있습니다. 따라서 우리는 또한 Expert Advisor의 코드에서 관련 변경을 수행해야 합니다. 우리는 사용자 정의 보조 함수 OpenPosition()을 만들 것입니다. 여기서 이러한 속성은 포지션 개설 주문을 보내기 전에 CTrade 클래스의 함수를 사용하여 설정됩니다.

//+------------------------------------------------------------------+
//| Opening a position                                               |
//+------------------------------------------------------------------+
void OpenPosition(double lot,
                  ENUM_ORDER_TYPE order_type,
                  double price,
                  double sl,
                  double tp,
                  string comment)
  {
   trade.SetExpertMagicNumber(MagicNumber); // Set the magic number in the trading structure
   trade.SetDeviationInPoints(CorrectValueBySymbolDigits(Deviation)); // Set the slippage in points
//--- 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())); }
  }

Expert Advisor - TradingBlock()의 주요 거래 기능 코드를 약간만 변경하면 됩니다. 다음은 변경된 기능 코드의 일부입니다.

//--- If there is no position
   if(!pos.exists)
     {
      //--- Adjust the volume
      lot=CalculateLot(Lot);
      //--- Open a position
      OpenPosition(lot,order_type,position_open_price,sl,tp,comment);
     }
//--- If there is a position
   else
     {
      //--- Get the position type
      GetPositionProperties(P_TYPE);
      //--- If the position is opposite to the signal and the position reversal is enabled
      if(pos.type==opposite_position_type && Reverse)
        {
         //--- Get the position volume
         GetPositionProperties(P_VOLUME);
         //--- Adjust the volume
         lot=pos.volume+CalculateLot(Lot);
         //--- Reverse the position
         OpenPosition(lot,order_type,position_open_price,sl,tp,comment);
         return;
        }
      //--- If the signal is in the direction of the position and the volume increase is enabled, increase the position volume
      if(!(pos.type==opposite_position_type) && VolumeIncrease>0)
        {
         //--- Get the Stop Loss of the current position
         GetPositionProperties(P_SL);
         //--- Get the Take Profit of the current position
         GetPositionProperties(P_TP);
         //--- Adjust the volume
         lot=CalculateLot(Increase);
         //--- Increase the position volume
         OpenPosition(lot,order_type,position_open_price,pos.sl,pos.tp,comment);
         return;
        }

위의 코드는 신호의 방향에 대해 현재 포지션의 방향을 확인하는 블록으로 향상되었습니다. 방향이 일치하고 외부 매개변수에서 포지션 볼륨 증가가 활성화되면(VolumeIncrease 매개변수 값이 0보다 큼) 지정된 랏을 확인/조정하고 관련 주문을 보냅니다. 방향이 일치하고 외부 매개변수에서 포지션 볼륨 증가가 활성화되면(VolumeIncrease 매개변수 값이 0보다 큼) 지정된 랏을 확인/조정하고 관련 주문을 보냅니다.

거래 내역에서 포지션 속성을 가져오는 함수를 만들어 보겠습니다. 현재 포지션의 거래 수를 반환하는 CurrentPositionTotalDeals() 함수로 시작하겠습니다.

//+------------------------------------------------------------------+
//| Returning the number of deals in the current position            |
//+------------------------------------------------------------------+
uint CurrentPositionTotalDeals()
  {
   int    total       =0;  // Total deals in the selected history list
   int    count       =0;  // Counter of deals by the position symbol
   string deal_symbol =""; // symbol of the deal
//--- If the position history is obtained
   if(HistorySelect(pos.time,TimeCurrent()))
     {
      //--- Get the number of deals in the obtained list
      total=HistoryDealsTotal();
      //--- Iterate over all the deals in the obtained list
      for(int i=0; i<total; i++)
        {
            //--- Get the symbol of the deal
            deal_symbol=HistoryDealGetString(HistoryDealGetTicket(i),DEAL_SYMBOL);
            //--- If the symbol of the deal and the current symbol are the same, increase the counter
            if(deal_symbol==_Symbol)
               count++;
        }
     }
//---
   return(count);
  }

위의 코드는 상당히 자세한 설명과 함께 제공됩니다. 그러나 우리는 내역이 어떻게 선택되었는지에 대해 몇 마디 말해야 합니다. 우리의 경우 HistorySelect() 함수를 사용하여 개점 시간으로 결정되는 현재 포지션을 여는 시점부터 현재 시점까지의 목록을 얻었습니다. 히스토리를 선택한 후 HistoryDealsTotal() 함수를 사용하여 목록의 거래 수를 확인할 수 있습니다. 나머지는 주석에서 명확해야 합니다.

특정 포지션의 기록은 HistorySelectByPosition() 함수를 사용하여 식별자로 선택할 수도 있습니다. 여기서 우리의 Expert Advisor에서 때때로 발생하는 것처럼 포지션이 반전될 때 포지션 식별자가 동일하게 유지된다는 점을 고려해야 합니다. 그러나 포지션 개방 시간은 반전 시 변경되므로 이 변형을 구현하는 것이 더 쉽습니다. 하지만 현재 열린 포지션에만 해당되지 않는 거래 내역을 처리해야 하는 경우 식별자를 사용해야 합니다. 우리는 미래 글에서 거래의 내역으로 돌아갈 것입니다.

계속해서 포지션의 첫 번째 거래 가격, 즉 포지션이 열린 거래의 가격을 반환하는 CurrentPositionFirstDealPrice() 함수를 만들어 보겠습니다.

//+------------------------------------------------------------------+
//| Returning the price of the first deal in the current position    |
//+------------------------------------------------------------------+
double CurrentPositionFirstDealPrice()
  {
   int      total       =0;    // Total deals in the selected history list
   string   deal_symbol ="";   // symbol of the deal
   double   deal_price  =0.0;  // Price of the deal
   datetime deal_time   =NULL; // Time of the deal
//--- If the position history is obtained
   if(HistorySelect(pos.time,TimeCurrent()))
     {
      //--- Get the number of deals in the obtained list
      total=HistoryDealsTotal();
      //--- Iterate over all the deals in the obtained list
      for(int i=0; i<total; i++)
        {
         //--- Get the price of the deal
         deal_price=HistoryDealGetDouble(HistoryDealGetTicket(i),DEAL_PRICE);
         //--- Get the symbol of the deal
         deal_symbol=HistoryDealGetString(HistoryDealGetTicket(i),DEAL_SYMBOL);
         //--- Get the time of the deal
         deal_time=(datetime)HistoryDealGetInteger(HistoryDealGetTicket(i),DEAL_TIME);
         //--- If the time of the deal equals the position opening time, 
         //    and if the symbol of the deal and the current symbol are the same, exit the loop
         if(deal_time==pos.time && deal_symbol==_Symbol)
            break;
        }
     }
//---
   return(deal_price);
  }

여기서의 원리는 이전 함수와 동일합니다. 포지션 오픈 시점부터 히스토리를 가져와서 매 반복마다 거래 시간과 포지션 오픈 시간을 확인합니다. 거래 가격과 함께 우리는 기호 이름과 거래 시간을 얻습니다. 첫 번째 거래는 거래 시간이 포지션 개시 시간과 일치할 때 식별됩니다. 해당 변수에 이미 가격이 할당되어 있으므로 값만 반환하면 됩니다.

계속합시다. 때로는 현재 포지션에서 마지막 거래의 가격을 알아야 할 수도 있습니다. 이를 위해 CurrentPositionLastDealPrice() 함수를 생성합니다.

//+------------------------------------------------------------------+
//| Returning the price of the last deal in the current position     |
//+------------------------------------------------------------------+
double CurrentPositionLastDealPrice()
  {
   int    total       =0;   // Total deals in the selected history list
   string deal_symbol ="";  // Symbol of the deal 
   double deal_price  =0.0; // Price
//--- If the position history is obtained
   if(HistorySelect(pos.time,TimeCurrent()))
     {
      //--- Get the number of deals in the obtained list
      total=HistoryDealsTotal();
      //--- Iterate over all the deals in the obtained list from the last deal in the list to the first deal
      for(int i=total-1; i>=0; i--)
        {
         //--- Get the price of the deal
         deal_price=HistoryDealGetDouble(HistoryDealGetTicket(i),DEAL_PRICE);
         //--- Get the symbol of the deal
         deal_symbol=HistoryDealGetString(HistoryDealGetTicket(i),DEAL_SYMBOL);
         //--- If the symbol of the deal and the current symbol are the same, exit the loop
         if(deal_symbol==_Symbol)
            break;
        }
     }
//---
   return(deal_price);
  }

이번에는 목록의 마지막 거래로 루프가 시작되었으며 첫 번째 루프 반복에서 필요한 거래가 식별되는 경우가 종종 있습니다. 그러나 여러 기호를 거래하는 경우 거래 기호가 현재 기호와 일치할 때까지 루프가 계속됩니다.

현재 포지션 볼륨은 POSITION_VOLUME 표준 식별자를 사용하여 얻을 수 있습니다. 초기 포지션 볼륨(첫 번째 거래의 볼륨)을 찾기 위해 CurrentPositionInitialVolume() 함수를 생성합니다.

//+------------------------------------------------------------------+
//| Returning the initial volume of the current position             |
//+------------------------------------------------------------------+
double CurrentPositionInitialVolume()
  {
   int             total       =0;           // Total deals in the selected history list
   ulong           ticket      =0;           // Ticket of the deal
   ENUM_DEAL_ENTRY deal_entry  =WRONG_VALUE; // Position modification method
   bool            inout       =false;       // Flag of position reversal
   double          sum_volume  =0.0;         // Counter of the aggregate volume of all deals, except for the first one
   double          deal_volume =0.0;         // Volume of the deal
   string          deal_symbol ="";          // Symbol of the deal 
   datetime        deal_time   =NULL;        // Deal execution time
//--- If the position history is obtained
   if(HistorySelect(pos.time,TimeCurrent()))
     {
      //--- Get the number of deals in the obtained list
      total=HistoryDealsTotal();
      //--- Iterate over all the deals in the obtained list from the last deal in the list to the first deal
      for(int i=total-1; i>=0; i--)
        {
         //--- If the order ticket by its position is obtained, then...
         if((ticket=HistoryDealGetTicket(i))>0)
           {
            //--- Get the volume of the deal
            deal_volume=HistoryDealGetDouble(ticket,DEAL_VOLUME);
            //--- Get the position modification method
            deal_entry=(ENUM_DEAL_ENTRY)HistoryDealGetInteger(ticket,DEAL_ENTRY);
            //--- Get the deal execution time
            deal_time=(datetime)HistoryDealGetInteger(ticket,DEAL_TIME);
            //--- Get the symbol of the deal
            deal_symbol=HistoryDealGetString(ticket,DEAL_SYMBOL);
            //--- When the deal execution time is less than or equal to the position opening time, exit the loop
            if(deal_time<=pos.time)
               break;
            //--- otherwise calculate the aggregate volume of deals by the position symbol, except for the first one
            if(deal_symbol==_Symbol)
               sum_volume+=deal_volume;
           }
        }
     }
//--- If the position modification method is a reversal
   if(deal_entry==DEAL_ENTRY_INOUT)
     {
      //--- If the position volume has been increased/decreased
      //    I.e. the number of deals is more than one
      if(fabs(sum_volume)>0)
        {
         //--- Current volume minus the volume of all deals except for the first one
         double result=pos.volume-sum_volume;
         //--- If the resulting value is greater than zero, return the result, otherwise return the current position volume         
         deal_volume=result>0 ? result : pos.volume;
        }
      //--- If there are no more deals, other than the entry,
      if(sum_volume==0)
         deal_volume=pos.volume; // return the current position volume
     }
//--- Return the initial position volume
   return(NormalizeDouble(deal_volume,2));
  }

이 기능은 이전 기능보다 더 복잡해졌습니다. 저는 잘못된 값을 초래할 수 있는 모든 가능한 상황을 고려하려고 노력했습니다. 주의 깊게 테스트한 결과 문제가 발견되지 않았습니다. 코드에 제공된 자세한 설명은 요점을 파악하는 데 도움이 됩니다.

포지션 기간을 반환하는 함수를 갖는 것도 유용할 것입니다. 사용자가 반환된 값의 적절한 형식(초, 분, 시간 또는 일)을 선택할 수 있도록 배열합니다. 이를 위해 다른 열거형을 생성해 보겠습니다.

//--- Position duration
enum ENUM_POSITION_DURATION
  {
   DAYS     = 0, // Days
   HOURS    = 1, // Hours
   MINUTES  = 2, // Minutes
   SECONDS  = 3  // Seconds
  };

다음은 모든 관련 계산을 담당하는 CurrentPositionDuration() 함수의 코드입니다.

//+------------------------------------------------------------------+
//| Returning the duration of the current position                   |
//+------------------------------------------------------------------+
ulong CurrentPositionDuration(ENUM_POSITION_DURATION mode)
  {
   ulong     result=0;   // End result
   ulong     seconds=0;  // Number of seconds
//--- Calculate the position duration in seconds
   seconds=TimeCurrent()-pos.time;
//---
   switch(mode)
     {
      case DAYS      : result=seconds/(60*60*24);   break; // Calculate the number of days
      case HOURS     : result=seconds/(60*60);      break; // Calculate the number of hours
      case MINUTES   : result=seconds/60;           break; // Calculate the number of minutes
      case SECONDS   : result=seconds;              break; // No calculations (number of seconds)
      //---
      default        :
         Print(__FUNCTION__,"(): Unknown duration mode passed!");
         return(0);
     }
//--- Return result
   return(result);
  }

포지션 속성이 표시되는 정보 패널에 대한 CurrentPositionDurationToString() 함수를 생성해 보겠습니다. 이 함수는 초 단위의 포지션 지속 시간을 사용자가 쉽게 이해할 수 있는 형식으로 변환합니다. 초 수는 함수에 전달되고 함수는 차례대로 포지션 기간을 일, 시, 분, 초 단위로 포함하는 문자열을 반환합니다.

//+------------------------------------------------------------------+
//| Converting the position duration to a string                     |
//+------------------------------------------------------------------+
string CurrentPositionDurationToString(ulong time)
  {
//--- A dash if there is no position
   string result="-";
//--- If the position exists
   if(pos.exists)
     {
      //--- Variables for calculation results
      ulong days=0;
      ulong hours=0;
      ulong minutes=0;
      ulong seconds=0;
      //--- 
      seconds=time%60;
      time/=60;
      //---
      minutes=time%60;
      time/=60;
      //---
      hours=time%24;
      time/=24;
      //---
      days=time;
      //--- Generate a string in the specified format DD:HH:MM:SS
      result=StringFormat("%02u d: %02u h : %02u m : %02u s",days,hours,minutes,seconds);
     }
//--- Return result
   return(result);
  }

이제 모든 것이 설정되고 준비되었습니다. 위의 모든 변경 사항에 따라 수정해야 하는 GetPositionProperties() 및 GetPropertyValue() 함수 코드는 제공하지 않겠습니다. 이 시리즈의 이전 글을 모두 읽으면 혼자서 하는 데 어려움이 없을 것입니다. 어떤 경우이든 소스 코드 파일은 글에 첨부됩니다.

결과적으로 정보 패널이 아래와 같이 표시되어야 합니다.

그림 7. 정보 패널의 모든 포지션 속성 데모

그림 7. 정보 패널의 모든 포지션 속성 데모.

따라서 우리는 이제 포지션 속성을 가져오기 위한 함수 라이브러리를 갖게 되었으며 필요할 때 향후 글에서 계속 작업할 것입니다.


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

실험으로 Expert Advisor의 매개변수를 최적화해 보겠습니다. 우리가 현재 가지고 있는 것은 아직 완전한 기능을 갖춘 거래 시스템이라고 할 수는 없지만, 우리가 달성하게 될 결과는 몇 가지에 대해 눈을 뜨게 하고 거래 시스템 개발자로서 우리의 경험을 향상시킬 것입니다.

우리는 아래와 같이 전략 테스터 설정을 할 것입니다::

그림 8. 매개변수 최적화를 위한 전략 테스터 설정

그림 8. 매개변수 최적화를 위한 전략 테스터 설정.

Expert Advisor의 외부 매개변수 설정은 다음과 같아야 합니다.

그림 9. 최적화를 위한 Expert Advisor 매개변수 설정

그림 9. 최적화를 위한 Expert Advisor 매개변수 설정.

최적화에 따라 최대 복구 계수를 기준으로 달성된 결과를 정렬합니다.

그림 10. 최대 회복 계수로 정렬된 결과

그림 10. 최대 복구 계수를 기준으로 정렬된 결과입니다.

이제 복구 계수 값이 4.07인 최상위 매개변수 세트를 테스트해 보겠습니다. EURUSD에 대해 최적화가 수행되었다는 사실을 감안하더라도 많은 기호에 대해 긍정적인 결과를 볼 수 있습니다.

EURUSD 결과:

그림 11. EURUSD에 대한 결과

그림 11. EURUSD에 대한 결과입니다.

AUDUSD에 대한 결과:

그림 12. AUDUSD에 대한 결과

그림 12. AUDUSD에 대한 결과입니다.

NZDUSD 결과:

그림 13. NZDUSD에 대한 결과

그림 13. NZDUSD에 대한 결과입니다.


결론

거의 모든 아이디어를 개발하고 향상시킬 수 있습니다. 모든 거래 시스템은 결함이 있는 것으로 거부되기 전에 매우 신중하게 테스트해야 합니다. 향후 글에서 우리는 거의 모든 거래 시스템을 사용자 정의하고 조정하는 데 매우 긍정적인 역할을 할 수 있는 다양한 메커니즘과 계획을 살펴볼 것입니다.

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

MQL5 Cookbook: 지표를 사용하여 Expert Advisor의 거래 조건 설정 MQL5 Cookbook: 지표를 사용하여 Expert Advisor의 거래 조건 설정
이 글에서는 MQL5 Cookbook 시리즈의 이전 글에서 작업한 Expert Advisor를 계속 수정할 것입니다. 이번에는 Expert Advisor가 포지션 개방 조건을 확인하는 데 사용할 값의 지표로 향상됩니다. 재미를 더하기 위해 외부 매개변수에 드롭다운 목록을 만들어 세 가지 거래 지표 중 하나를 선택할 수 있습니다.
MQL5 Cookbook: 거래 수준을 설정/수정할 때 오류를 피하는 방법 MQL5 Cookbook: 거래 수준을 설정/수정할 때 오류를 피하는 방법
"MQL5 Cookbook: MetaTrader 5 Strategy Tester의 포지션 속성 분석" 시리즈의 이전 글에서 Expert Advisor에 대한 작업을 계속하면서 많은 유용한 기능으로 기존의 기능들과 더불어 이를 개선하고 최적화할 것입니다. Expert Advisor는 이번에 MetaTrader 5 전략 테스터에서 최적화할 수 있는 외부 매개변수를 가지며 어떤 면에서는 단순한 거래 시스템과 유사합니다.
지그재그 지표: 신선한 접근 방식과 새로운 솔루션 지그재그 지표: 신선한 접근 방식과 새로운 솔루션
이 글에서는 고급 ZigZag 지표를 만들 가능성을 검토합니다. 노드를 식별하는 아이디어는 Envelopes 지표의 사용을 기반으로 합니다. 우리는 모든 ZigZag 노드가 Envelopes 밴드의 범위 내에 있는 일련의 Envelopes에 대한 입력 매개변수의 특정 조합을 찾을 수 있다고 가정합니다. 결과적으로 우리는 새로운 노드의 좌표를 예측하려고 시도할 수 있습니다.
MQL5 Cookbook: MetaTrader 5 전략 테스터의 포지션 속성 분석 MQL5 Cookbook: MetaTrader 5 전략 테스터의 포지션 속성 분석
이전 글 "MQL5 Cookbook: 사용자 지정 정보 패널의 포지션 속성"에서 수정된 버전의 Expert Advisor를 소개합니다. 우리가 다룰 문제 중 일부는 바에서 데이터 가져오기, 파일에 대한 표준 라이브러리의 거래 클래스를 포함하여 현재 기호에 대한 새로운 바 이벤트 확인, 거래 신호를 검색하는 기능 및 거래 작업을 실행하는 기능 만들기를 포함합니다. OnTrade() 함수에서 거래 이벤트를 결정하는 것 외에도 말이죠.