English Русский 中文 Español Deutsch 日本語 Português 한국어 Français Italiano
MQL5 Tarif Defteri: Aşırı Öğrenme Etkisini Azaltma ve Kotasyon Eksikliğini Ele Alma

MQL5 Tarif Defteri: Aşırı Öğrenme Etkisini Azaltma ve Kotasyon Eksikliğini Ele Alma

MetaTrader 5Örnekler | 13 Ocak 2022, 09:40
92 0
Anatoli Kazharski
Anatoli Kazharski

Giriş

Pek çok yatırımcının, alım satım sistemleri için en uygun parametrelere dair defalarca kafasının karıştığına inanıyorum. Gerçekten de, tek başına bir alım satım algoritması yeterli değildir. Bunun nasıl başka şekilde kullanılabileceğini görmek gerekir. Hangi alım satım stratejisini kullanırsanız kullanın, ister basit ister karmaşık olsun, ister tek ister birden fazla enstrümanla olsun, gelecekte kâr sağlamak için hangi parametreleri seçeceğiniz sorusundan kaçamazsınız.

Alım satım sistemlerini, optimizasyon döneminde (geriye dönük test) ve sonraki dönemde (ileriye dönük test) iyi sonuçlar gösteren parametreler ile kontrol etme eğilimindeyiz. İleriye dönük testler aslında çok da gerekli değildir. İlgili sonuçlar geçmiş veriler kullanılarak elde edilebilir.

Bu yöntem, kesin bir cevap verilemeyen devasa bir soruya yol açar: Bir alım satım sistemini optimize etmek için ne kadar geçmiş veri kullanılmalıdır? Mesele şu ki, birçok seçenek var. Her şey, yararlanmayı umduğunuz fiyat dalgalanmalarının aralığına bağlı.

Optimizasyon için gereken geçmiş miktarına geri dönersek, mevcut verilerin saat içi alım satım için yeterli olabileceği sonucuna varıyoruz. Bu, daha uzun zaman aralıkları için her zaman doğru değildir. Tutarlı bir modelin tekrar sayısı ne kadar fazla olursa, yani ne kadar çok alım satımınız olursa, gelecekte görmeyi bekleyebileceğimiz test edilmiş alım satım sisteminin performansı o kadar doğru olur.

Ya belirli bir enstrümanın fiyat verileri yeterli sayıda tekrar elde etmek ve daha emin olabilmek için yeterli değilse? Cevap: Mevcut tüm cihazlardan gelen verileri kullanın.


NeuroShell DayTrader Professional'dan Örnek

MetaTrader 5'te programlamaya geçmeden önce NeuroShell DayTrader Professional'daki bir örneği inceleyelim. Birçok sembol için bir alım satım sisteminin (bir oluşturucu ile derlenmiş) parametrelerini optimize etmek için harika özellikler sunar. Alım satım modülü ayarlarında gerekli parametreleri ayarlayabilir, her bir sembol için parametreleri ayrı ayrı optimize edebilir veya tüm semboller için en uygun parametre setini tek seferde bulabilirsiniz. Bu seçenek Optimizasyon sekmesinde bulunabilir:

NeuroShell DayTrader Professional'daki alım satım modülündeki Optimizasyon sekmesi

Şekil 1. NeuroShell DayTrader Professional'daki alım satım modülündeki Optimizasyon sekmesi

Bizim durumumuzda, sadece iki optimizasyon yönteminin sonuçlarını karşılaştırmamız gerektiğinden herhangi bir basit alım satım sistemi iş görecektir, bu nedenle sistem seçimi şu anda çok az önem taşımaktadır.

NeuroShell DayTrader Professional'da alım satım stratejilerini nasıl derleyebileceğinize dair bilgiyi, blogumun diğer makalelerinde bulabilirsiniz (ilgili bilgiyi bulmak için arama yapabilir veya etiketler kullanabilirsiniz). Ayrıca, NeuroShell DayTrader Professional ile uyumlu biçimde MetaTrader 5'ten kotasyonları bir betik kullanarak nasıl indirebileceğinizi açıklayan ve gösteren "Diğer Uygulamalar için MetaTrader 5 Kotasyonları Nasıl Hazırlanır?" başlıklı makaleyi okumanızı öneririm.

Bu testi yapmak için 2000 yılından Ocak 2013'e kadar sekiz sembol için günlük çubuklardan elde ettiğim verileri hazırladım:

NeuroShell DayTrader Professional'da bir test için semboller listesi

Şekil 2. NeuroShell DayTrader Professional'da bir test için semboller listesi

Aşağıdaki şekil iki optimizasyon sonucunu göstermektedir. Üst kısım, her sembolün kendi parametrelerini elde ettiği optimizasyonun sonucunu gösterirken alt kısım, parametrelerin tüm semboller için ortak olduğu sonucu gösterir.

İki parametre optimizasyon modunun sonuçlarının karşılaştırması

Şekil 3. İki parametre optimizasyon modunun sonuçlarının karşılaştırması

Ortak parametreleri gösteren sonuç, parametrelerin her bir sembol için farklı olduğu sonuç kadar iyi görünmüyor. Yine de, alım satım sistemi tüm semboller için aynı parametreler ile çeşitli fiyat davranış modellerinden (volatilite, trend/flat sayısı) geçtiğinden daha fazla güven uyandırıyor.

Aynı konudan devam edersek, mantıksal olarak daha fazla miktarda veri kullanarak optimizasyon lehine başka bir argüman bulabiliriz. Belli bir döviz çiftinin, örneğin EURUSD, fiyat davranışının daha sonrasında (iki, beş veya on yıl içinde) oldukça farklı olması da mümkündür. Örneğin, GBPUSD fiyat trendleri, EURUSD'nin geçmiş fiyat davranışına benzer olacaktır ve bunun tersi de geçerlidir. Buna hazır olmalısınız, çünkü bu herhangi bir enstrüman için geçerlidir.


MetaTrader 5'ten Bir Örnek

Şimdi MetaTrader 5'te hangi parametre optimizasyon modlarının sunulduğunu görelim. Aşağıda, optimizasyon modlarının açılır listesindeki bir ok ile işaretlenmiş Piyasa İzlemede Seçilen Tüm Semboller optimizasyon modunu görebilirsiniz.

Şekil 4. MetaTrader 5 Strateji Test Cihazında optimizasyon modları.

Şekil 4. MetaTrader 5 Strateji Test Cihazındaki optimizasyon modları

Bu mod, yalnızca bir EA'yı her bir semboldeki mevcut parametrelerle tek tek test etmenize olanak sağlar. Testte kullanılan semboller, Piyasa İzleme penceresinde halihazırda seçili olan sembollerdir. Diğer bir deyişle, parametre optimizasyonu bu durumda gerçekleştirilmez. Ancak, MetaTrader 5 ve MQL5 bu fikri kendi başınıza uygulamanıza olanak sağlar.

Şimdi, böyle bir EA'nın nasıl uygulanacağını görmemiz gerekiyor. Sembol listesi bir metin dosyasında (*.txt) sağlanacaktır. Ayrıca, birkaç sembol listesi setini saklama imkanını uygulayacağız. Her set, bir bölüm numarası içeren kendi başlığına sahip ayrı bir bölümde yer alacaktır. Sayılar, görsel kontrolü kolaylaştırmak için gereklidir.

Uzman Danışmanın sembol dizisini doldururken doğru veri setini almasına olanak sağlamak için sayının önünde # işaretinin bulunmasının önemli olduğunu unutmayın. Genel olarak başlık herhangi bir sembol içerebilir, ancak her defasında # işareti olmalıdır. Sayı işareti, Uzman Danışmanın bölümleri belirleyeceği/sayacağı başka bir sembol ile değiştirilebilir. Bu durumda, değiştirmenin koda yansıtılması gerekecektir.

Aşağıda, test için üç sembol setini içeren SymbolsList.txt dosyasını görebilirsiniz. Gösterilen bu dosya, yöntemi test ederken daha fazla kullanılacaktır.

Şekil 5. Test için bir metin dosyasında sağlanan birkaç sembol seti

Şekil 5. Test için bir metin dosyasında sağlanan birkaç sembol seti

Harici parametrelere, Uzman Danışmanın mevcut testte kullanması gereken sembollerin setini belirtmek için bir başka parametre SectionOfSymbolList ekleyeceğiz. Bu parametre, sembol setini tanımlayan değeri (sıfırdan büyük) alır. Değer mevcut set sayısını aşarsa, Uzman Danışman günlüğe karşılık gelen bir giriş yazar ve test sadece mevcut sembol üzerinde yapılır.

SymbolsList.txt, Metatrader 5\MQL5\Files konumu altında yerel terminal dizininde yer almalıdır. Ortak klasöre de yerleştirilebilir, ancak bu durumda MQL5 Cloud Network içinde parametre optimizasyonu için kullanılabilir olmayacaktır. Ayrıca, test için dosyaya ve ilgili özel göstergelere erişime olanak sağlamak amacıyla, dosyanın başına aşağıdaki satırları yazmamız gerekir:

//--- Allow access to the external file and indicator for optimization in the cloud
#property tester_file      "SymbolsList.txt"
#property tester_indicator "EventsSpy.ex5"

Uzman Danışmanımız, aşağıdaki makalede içerilen hazır, çok para birimli Uzman Danışman temelli olacaktır: "MQL5 Tarif Defteri: Sınırsız Sayıda Parametre ile Çok Para Birimli bir Uzman Danışman Geliştirme" Temeldeki alım satım stratejisi oldukça basittir, ancak yöntemin etkinliğini test etmek yeterli olacaktır. Gereksiz kısımları çıkartıp ihtiyacımız olanları ekleyeceğiz ve mevcut ilgili kodu düzelteceğiz. Uzman Danışmanımızı aşağıdaki serinin önceki makalesinde kapsamlı olarak açıklanan rapor kaydetme özelliği ile kesin olarak geliştireceğiz: "MQL5 Tarif Defteri: Excel'de Her Sembol için İşlemlerin Geçmişini Bir Dosyaya Yazma ve Denge Grafikleri Oluşturma. Değerlendirilen yöntemin etkinliğini değerlendirmek için tüm semboller için denge grafikleri de gerekecektir.

Uzman Danışmanın harici parametrelerinin ayarları aşağıdaki şekilde değiştirilmelidir:

//--- External parameters of the Expert Advisor
sinput int    SectionOfSymbolList = 1;     // Section number in the symbol lists
sinput bool   UpdateReport        = false; // Report update
sinput string delimeter_00="";   // --------------------------------
sinput long   MagicNumber         = 777;   // Magic number
sinput int    Deviation           = 10;    // Slippage
sinput string delimeter_01="";   // --------------------------------
input  int    IndicatorPeriod     = 5;     // Indicator period
input  double TakeProfit          = 100;   // Take Profit
input  double StopLoss            = 50;    // Stop Loss
input  double TrailingStop        = 10;    // Trailing Stop
input  bool   Reverse             = true;  // Position reversal
input  double Lot                 = 0.1;   // Lot
input  double VolumeIncrease      = 0.1;   // Position volume increase
input  double VolumeIncreaseStep  = 10;    // Volume increase step

Harici parametrelerle ilişkili tüm diziler, ihtiyaç duyulmayacağından silinmeli ve tüm kod boyunca harici değişkenler ile değiştirilmelidir. Yalnızca, boyutu SymbolsList.txt dosyasındaki setlerden birinden kullanılan sembollerin sayısına bağlı olacak olan dinamik sembol dizisini - InputSymbols [] - bırakmalıyız. Uzman Danışman Strateji Test Cihazı dışında kullanılırsa, bu dizinin boyutu, gerçek zamanlı modda Uzman Danışman yalnızca bir sembol ile çalışacağından 1'e eşit olacaktır.

İlgili değişiklikler, dizi başlatma dosyası InitializeArrays.mqh içinde de yapılmalıdır. Yani, harici değişken dizilerinin başlatılmasından sorumlu tüm fonksiyonlar silinmelidir. InitializeArraySymbols() fonksiyonu şimdi aşağıdaki gibi görünür:

//+------------------------------------------------------------------+
//| Filling the array of symbols                                     |
//+------------------------------------------------------------------+
void InitializeArraySymbols()
  {
   int    strings_count  =0;   // Number of strings in the symbol file
   string checked_symbol ="";  // To check the accessibility of the symbol on the trade server
//--- Test mode message
   string message_01="<--- All symbol names in the <- SymbolsList.txt -> file are incorrect ... --->\n"
                     "<--- ... or the value of the \"Section of List Symbols\" parameter is greater, "
                     "than the number of file sections! --->\n"
                     "<--- Therefore we will test only the current symbol. --->";
//--- Real-time mode message
   string message_02="<--- In real-time mode, we only work with the current symbol. --->";
//--- If in real-time mode
   if(!IsRealtime())
     {
      //--- Get the number of strings from the specified symbol set in the file and fill the temporary array of symbols
      strings_count=ReadSymbolsFromFile("SymbolsList.txt");
      //--- Iterate over all symbols from the specified set
      for(int s=0; s<strings_count; s++)
        {
         //--- If the correct string is returned following the symbol check
         if((checked_symbol=GetSymbolByName(temporary_symbols[s]))!="")
           {
            //--- increase the counter
            SYMBOLS_COUNT++;
            //--- set/increase the array size
            ArrayResize(InputSymbols,SYMBOLS_COUNT);
            //--- index with the symbol name
            InputSymbols[SYMBOLS_COUNT-1]=checked_symbol;
           }
        }
     }
//--- If all symbol names were not input correctly or if currently working in real-time mode
   if(SYMBOLS_COUNT==0)
     {
      //--- Real-time mode message
      if(IsRealtime())
         Print(message_02);
      //--- Test mode message
      if(!IsRealtime())
         Print(message_01);
      //--- We will work with the current symbol only
      SYMBOLS_COUNT=1;
      //--- set the array size and
      ArrayResize(InputSymbols,SYMBOLS_COUNT);
      //--- index with the current symbol name
      InputSymbols[0]=_Symbol;
     }
  }

ReadSymbolsFromFile() fonksiyon kodu da değiştirilmelidir. Önceden tüm sembol listesini okuyabilirken, şimdi sadece belirtilen sembol setini okumasını istiyoruz. Aşağıda, değiştirilmiş fonksiyon kodu yer almaktadır:

//+------------------------------------------------------------------+
//| Returning the number of strings (symbols) from the specified     |
//| set in the file and filling the temporary array of symbols       |
//+------------------------------------------------------------------+
//--- When preparing the file, symbols in the list should be separated with a line break
int ReadSymbolsFromFile(string file_name)
  {
   ulong  offset         =0;   // Offset for determining the position of the file pointer
   string delimeter      ="#"; // Identifier of the section start
   string read_line      ="";  // For the check of the read string
   int    limit_count    =0;   // Counter limiting the number of the possibly open charts
   int    strings_count  =0;   // String counter
   int    sections_count =-1;  // Section counter
   
//--- Message 01
   string message_01="<--- The <- "+file_name+" -> file has not been prepared appropriately! --->\n"
                     "<--- The first string does not contain the section number identifier ("+delimeter+")! --->";
//--- Message 02
   string message_02="<--- The <- "+file_name+" -> file has not been prepared appropriately! --->\n"
                     "<--- There is no line break identifier in the last string, --->\n"
                     "<--- so only the current symbol will be involved in testing. --->";
//--- Message 03
   string message_03="<--- The <- "+file_name+" -> file could not be found! --->"
                     "<--- Only the current symbol will be involved in testing. --->";
                     
//--- Open the file (get the handle) for reading in the local directory of the terminal
   int file_handle=FileOpen(file_name,FILE_READ|FILE_ANSI,'\n');
//--- If the file handle has been obtained
   if(file_handle!=INVALID_HANDLE)
     {
      //--- Read until the current position of the file pointer
      //    reaches the end of the file or until the program is deleted
      while(!FileIsEnding(file_handle) || !IsStopped())
        {
         //--- Read until the end of the string or until the program is deleted
         while(!FileIsLineEnding(file_handle) || !IsStopped())
           {
            //--- Read the whole string
            read_line=FileReadString(file_handle);
            //--- If the section number identifier has been found
            if(StringFind(read_line,delimeter,0)>-1)
               //--- Increase the section counter
               sections_count++;
            //--- If the section has been read, exit the function
            if(sections_count>SectionOfSymbolList)
              {
               FileClose(file_handle); // Close the file
               return(strings_count);  // Return the number of strings in the file
              }
            //--- If this is the first iteration and the first string does not contain the section number identifier
            if(limit_count==0 && sections_count==-1)
              {
               PrepareArrayForOneSymbol(strings_count,message_01);
               //--- Close the file
               FileClose(file_handle);
               //--- Return the number of strings in the file
               return(strings_count);
              }
            //--- Increase the counter limiting the number of the possibly open charts
            limit_count++;
            //--- If the limit has been reached
            if(limit_count>=CHARTS_MAX)
              {
               PrepareArrayForOneSymbol(strings_count,message_02);
               //--- Close the file
               FileClose(file_handle);
               //--- Return the number of strings in the file
               return(strings_count);
              }
            //--- Get the position of the pointer
            offset=FileTell(file_handle);
            //--- If this is the end of the string
            if(FileIsLineEnding(file_handle))
              {
               //--- Go to the next string if this is not the end of the file
               //    For this purpose, increase the offset of the file pointer
               if(!FileIsEnding(file_handle))
                  offset++;
               //--- move it to the next string
               FileSeek(file_handle,offset,SEEK_SET);
               //--- If we are not in the specified section of the file, exit the loop
               if(sections_count!=SectionOfSymbolList)
                  break;
               //--- Otherwise,
               else
                 {
                  //--- if the string is not empty
                  if(read_line!="")
                    {
                     //--- increase the string counter
                     strings_count++;
                     //--- increase the size of the array of strings,
                     ArrayResize(temporary_symbols,strings_count);
                     //--- write the string to the current index
                     temporary_symbols[strings_count-1]=read_line;
                    }
                 }
               //--- Exit the loop
               break;
              }
           }
         //--- If this is the end of the file, terminate the entire loop
         if(FileIsEnding(file_handle))
            break;
        }
      //--- Close the file
      FileClose(file_handle);
     }
   else
      PrepareArrayForOneSymbol(strings_count,message_03);
//--- Return the number of strings in the file
   return(strings_count);
  }

Yukarıdaki koddaki bazı dizelerin vurgulandığını görebilirsiniz. Bu dizeler, bir hata durumunda bir (mevcut) sembol için bir dizi hazırlayan PrepareArrayForOneSymbol() fonksiyonunu içerir.

//+------------------------------------------------------------------+
//| Preparing an array for one symbol                                |
//+------------------------------------------------------------------+
void PrepareArrayForOneSymbol(int &strings_count,string message)
  {
//--- Print the message to the log
   Print(message);
//--- Array size
   strings_count=1;
//--- Set the size of the array of symbols
   ArrayResize(temporary_symbols,strings_count);
//--- Write the string with the current symbol name to the current index
   temporary_symbols[0]=_Symbol;
  }

Artık parametre optimizasyon yöntemini test etmek için her şey hazır. Ancak teste geçmeden önce rapora bir veri serisi daha ekleyelim. Daha önce, rapor dosyası, tüm sembollerin dengelerine ek olarak, yüzde olarak ifade edilen yerel maksimum değerlerden tüm düşüşleri içeriyordu. Artık rapor para cinsinden tüm düşüşleri de kapsayacak. Aynı zamanda, raporun oluşturulduğunu CreateSymbolBalanceReport() fonksiyonunu da değiştireceğiz.

CreateSymbolBalanceReport() fonksiyon kodu aşağıda verilmektedir:

//+------------------------------------------------------------------+
//| Creating test report on deals in .csv format                     |
//+------------------------------------------------------------------+
void CreateSymbolBalanceReport()
  {
   int    file_handle =INVALID_HANDLE; // File handle
   string path        ="";             // File path

//--- If an error occurred when creating/getting the folder, exit
   if((path=CreateInputParametersFolder())=="")
      return;
//--- Create a file to write data in the common folder of the terminal
   file_handle=FileOpen(path+"\\LastTest.csv",FILE_CSV|FILE_WRITE|FILE_ANSI|FILE_COMMON);
//--- If the handle is valid (file created/opened)
   if(file_handle>0)
     {
      int           digits           =0;   // Number of decimal places in the price
      int           deals_total      =0;   // Number of deals in the specified history
      ulong         ticket           =0;   // Deal ticket
      double        drawdown_max     =0.0; // Drawdown
      double        balance          =0.0; // Balance
      string        delimeter        =","; // Delimiter
      string        string_to_write  ="";  // To generate the string for writing
      static double percent_drawdown =0.0; // Drawdown expressed as percentage
      static double money_drawdown   =0.0; // Drawdown in monetary terms

      //--- Generate the header string
      string headers="TIME,SYMBOL,DEAL TYPE,ENTRY TYPE,VOLUME,"
                     "PRICE,SWAP($),PROFIT($),DRAWDOWN(%),DRAWDOWN($),BALANCE";
      //--- If more than one symbol is involved, modify the header string
      if(SYMBOLS_COUNT>1)
        {
         for(int s=0; s<SYMBOLS_COUNT; s++)
            StringAdd(headers,","+InputSymbols[s]);
        }
      //--- Write the report headers
      FileWrite(file_handle,headers);
      //--- Get the complete history
      HistorySelect(0,TimeCurrent());
      //--- Get the number of deals
      deals_total=HistoryDealsTotal();
      //--- Resize the array of balances according to the number of symbols
      ArrayResize(symbol_balance,SYMBOLS_COUNT);
      //--- Resize the array of deals for each symbol
      for(int s=0; s<SYMBOLS_COUNT; s++)
         ArrayResize(symbol_balance[s].balance,deals_total);
      //--- Iterate in a loop and write the data
      for(int i=0; i<deals_total; i++)
        {
         //--- Get the deal ticket
         ticket=HistoryDealGetTicket(i);
         //--- Get all the deal properties
         GetHistoryDealProperties(ticket,D_ALL);
         //--- Get the number of digits in the price
         digits=(int)SymbolInfoInteger(deal.symbol,SYMBOL_DIGITS);
         //--- Calculate the overall balance
         balance+=deal.profit+deal.swap+deal.commission;
         //--- Calculate the max drawdown from the local maximum
         TesterDrawdownMaximum(i,balance,percent_drawdown,money_drawdown);
         //--- Generate a string for writing using concatenation
         StringConcatenate(string_to_write,
                           deal.time,delimeter,
                           DealSymbolToString(deal.symbol),delimeter,
                           DealTypeToString(deal.type),delimeter,
                           DealEntryToString(deal.entry),delimeter,
                           DealVolumeToString(deal.volume),delimeter,
                           DealPriceToString(deal.price,digits),delimeter,
                           DealSwapToString(deal.swap),delimeter,
                           DealProfitToString(deal.symbol,deal.profit),delimeter,
                           DrawdownToString(percent_drawdown),delimeter,
                           DrawdownToString(money_drawdown),delimeter,
                           DoubleToString(balance,2));
         //--- If more than one symbol is involved, write their balance values
         if(SYMBOLS_COUNT>1)
           {
            //--- Iterate over all symbols
            for(int s=0; s<SYMBOLS_COUNT; s++)
              {
               //--- If the symbols are equal and the deal result is non-zero
               if(deal.symbol==InputSymbols[s] && deal.profit!=0)
                 {
                  //--- Display the deal in the balance for the corresponding symbol
                  //    Take into consideration swap and commission
                  symbol_balance[s].balance[i]=symbol_balance[s].balance[i-1]+
                                               deal.profit+
                                               deal.swap+
                                               deal.commission;
                  //--- Add to the string
                  StringAdd(string_to_write,","+DoubleToString(symbol_balance[s].balance[i],2));
                 }
               //--- Otherwise write the previous value
               else
                 {
                  //--- If the deal type is "Balance" (the first deal)
                  if(deal.type==DEAL_TYPE_BALANCE)
                    {
                     //--- the balance is the same for all symbols
                     symbol_balance[s].balance[i]=balance;
                     StringAdd(string_to_write,","+DoubleToString(symbol_balance[s].balance[i],2));
                    }
                  //--- Otherwise write the previous value to the current index
                  else
                    {
                     symbol_balance[s].balance[i]=symbol_balance[s].balance[i-1];
                     StringAdd(string_to_write,","+DoubleToString(symbol_balance[s].balance[i],2));
                    }
                 }
              }
           }
         //--- Write the generated string
         FileWrite(file_handle,string_to_write);
         //--- Mandatory zeroing out of the variable for the next string
         string_to_write="";
        }
      //--- Close the file
      FileClose(file_handle);
     }
//--- If the file could not be created/opened, print the appropriate message
   else
      Print("Error creating the file! Error: "+IntegerToString(GetLastError())+"");
  }

DrawdownMaximumToString() fonksiyonunda düşüşleri hesaplıyorduk. Bu işlem artık TesterDrawdownMaximum() fonksiyonu ile gerçekleştirilirken düşüş değeri, temel DrawdownToString() fonksiyonu kullanılarak bir dizeye dönüştürülür.

TesterDrawdownMaximum() fonksiyon kodu aşağıdaki gibidir:

//+------------------------------------------------------------------+
//| Returning the max drawdown from the local maximum                |
//+------------------------------------------------------------------+
void TesterDrawdownMaximum(int deal_number,
                           double balance,
                           double &percent_drawdown,
                           double &money_drawdown)
  {
   ulong         ticket =0;   // Deal ticket
   string        str    ="";  // The string to be displayed in the report
//--- To calculate the local maximum and drawdown
   static double max    =0.0;
   static double min    =0.0;
   
//--- If this is the first deal
   if(deal_number==0)
     {
      //--- There is no drawdown yet
      percent_drawdown =0.0;
      money_drawdown   =0.0;
      //--- Set the initial point as the local maximum
      max=balance;
      min=balance;
     }
   else
     {
      //--- If the current balance is greater than in the memory, then...
      if(balance>max)
        {
         //--- Calculate the drawdown using the previous values:
         //    in monetary terms
         money_drawdown=max-min;
         //    expressed as percentage
         percent_drawdown=100-((min/max)*100);
         //--- Update the local maximum
         max=balance;
         min=balance;
        }
      //--- Otherwise
      else
        {
         //--- Return zero value of the drawdown
         money_drawdown=0.0;
         percent_drawdown=0.0;
         //--- Update the minimum
         min=fmin(min,balance);
         //--- If the deal ticket by its position in the list has been obtained, then...
         if((ticket=HistoryDealGetTicket(deal_number))>0)
           {
            //--- ...get the deal comment
            GetHistoryDealProperties(ticket,D_COMMENT);
            //--- Flag of the last deal
            static bool last_deal=false;
            //--- The last deal in the test can be identified by the "end of test" comment
            if(deal.comment=="end of test" && !last_deal)
              {
               //--- Set the flag
               last_deal=true;
               //--- Update the drawdown values:
               //    in monetary terms
               money_drawdown=max-min;
               //    expressed as percentage
               percent_drawdown+=100-((min/max)*100);
              }
           }
        }
     }
  }

DrawdownToString() fonksiyonu kodu aşağıda verilmektedir:

//+------------------------------------------------------------------+
//| Converting drawdown to a string                                  |
//+------------------------------------------------------------------+
string DrawdownToString(double drawdown)
  {
   return((drawdown<=0) ? "" : DoubleToString(drawdown,2));
  }

Uzman Danışmanın test edilmesi ve sonuçların analizi için artık her şey hazır. Makalenin başlarında hazır dosya örneğini gördük. Aşağıdakileri yapalım: ikinci setteki semboller (üç sembol vardır: EURUSD, AUDUSD ve USDCHF) için parametreleri optimize edelim ve optimizasyonun ardından, verileri parametre optimizasyonunda yer almayan sembollerin sonuçlarını görmek için üçüncü setteki tüm sembolleri (toplamda yedi sembol) kullanarak testi çalıştıralım.


Parametreleri Optimize Etme ve Uzman Danışmanı Test Etme

Strateji Test Cihazı aşağıda gösterildiği gibi ayarlanmalıdır:

Şekil 6. Optimizasyon için Strateji Test Cihazı ayarları

Şekil 6. Optimizasyon için Strateji Test Cihazı ayarları

Parametre optimizasyonu için Uzman Danışman ayarları aşağıda sağlanmaktadır:

Şekil 7. Parametre optimizasyonu için Uzman Danışman ayarları

Şekil 7. Parametre optimizasyonu için Uzman Danışman ayarları

Optimizasyon üç sembol içerdiğinden ve bunlardan her biri için pozisyon hacmi artışı etkinleştirildiğinden, pozisyon açmak ve pozisyon hacmini artırmak amacıyla minimum lotu belirledik. Bizim durumumuzda değer 0,01'dir.

Optimizasyonun ardından, maksimum kurtarma faktörü ile en üstteki sonucu seçiyoruz ve lot için VolumeIncrease parametresini 0,1 olarak ayarlıyoruz. Sonuç aşağıda gösterilmektedir:

Şekil 8. MetaTrader 5'te test sonucu

Şekil 8. MetaTrader 5'te test sonucu

Aşağıda, Excel 2010'da gösterildiği şekliyle sonucu görebilirsiniz:

Excel 2010'da gösterildiği şekliyle üç sembol için test sonuçları

Şekil 9. Excel 2010'da gösterildiği şekliyle üç sembol için test sonuçları

Para cinsinden düşüş, ikinci (yardımcı) ölçek açısından alt grafikte yeşil işaretler olarak görüntülenir.

Excel 2010'daki grafik oluşturma sınırlarının da farkında olmanız gerekir (şartnamelerin ve sınırların tam listesi, Microsoft Office web sitesinin Excel şartnameleri ve sınırları sayfasında bulunabilir).

Şekil 10. Excel 2010'daki grafik oluşturma şartnameleri ve sınırları

Şekil 10. Excel 2010'daki grafik oluşturma şartnameleri ve sınırları

Tablo, testi aynı anda 255 sembol için çalıştırabileceğimizi ve tüm sonuçları grafikte görüntüleyebileceğimizi gösterir. Tek sınırımız bilgisayar kaynaklarıdır.

Şimdi mevcut parametrelerl ile üçüncü setten yedi sembol için testi çalıştıralım ve sonucu kontrol edelim:

Excel 2010'da gösterildiği şekliyle yedi sembol için test sonuçları

Şekil 11. Excel 2010'da gösterildiği şekliyle yedi sembol için test sonuçları

Değerlendirilen yedi sembol ile 6901 işlemimiz vardır. Grafikteki veriler Excel 2010'da oldukça hızlı bir şekilde güncellenir.


Sonuç

Uygulanan yöntemin, kullandığımız gibi basit bir alım satım stratejisinin bile iyi sonuçlar vermesi nedeniyle dikkate değer olduğuna inanıyorum. Burada optimizasyonun yedi sembolden sadece üçü için gerçekleştirildiğini unutmamalıyız. Tüm semboller için parametreleri tek seferde optimize ederek sonucu iyileştirmeye çalışabiliriz. Ancak, her şeyden önce, alım satım sistemini iyileştirmeyi ve daha da iyisi, çeşitli alım satım sistemlerinden oluşan bir portföy elde etmeyi hedeflemeliyiz. Bu düşünceye daha sonra döneceğiz.

Neredeyse hepsi bu. Çok para birimli alım satım stratejilerinin sonuçlarını incelemek için oldukça kullanışlı bir aracımız var. Aşağıda, değerlendirmeniz için Uzman Danışmanın dosyalarının bulunduğu indirilebilir zip dosyası yer almaktadır.

Dosyaları çıkardıktan sonra, ReduceOverfittingEA klasörünü MetaTrader 5\MQL5\Experts dizinine yerleştirin. Ayrıca EventsSpy.mq5 göstergesi MetaTrader 5\MQL5\Indicators içine yerleştirilmelidir. SymbolsList.txt MetaTrader 5\MQL5\Files içine yerleştirilmelidir.

MetaQuotes Ltd tarafından Rusçadan çevrilmiştir.
Orijinal makale: https://www.mql5.com/ru/articles/652

Ekli dosyalar |
symbolslist.txt (0.1 KB)
eventsspy__1.mq5 (7.59 KB)
MQL5 Programlarında Hata Ayıklama MQL5 Programlarında Hata Ayıklama
Bu makale öncelikle dili öğrenmiş, ancak henüz program geliştirme konusunda tam olarak uzmanlaşmamış programcılara yöneliktir. Bazı hata ayıklama tekniklerini açıklar ve yazar ile diğer birçok programcının birleşik tecrübesini sunar.
MQL5 Tarif Defteri Excel'de Her Sembol için İşlemlerin Geçmişini Bir Dosyaya Yazma ve Denge Grafikleri Oluşturma MQL5 Tarif Defteri Excel'de Her Sembol için İşlemlerin Geçmişini Bir Dosyaya Yazma ve Denge Grafikleri Oluşturma
Çeşitli forumlarda iletişim kurarken, sık sık Microsoft Excel grafiklerinin ekran görüntüsü olarak görüntülenen test sonuçlarımın örneklerini kullandım. Bu tür grafiklerin nasıl oluşturulabileceğini açıklamam birçok kez istendi. Son olarak, şimdi bu makalede her şeyi açıklamak için biraz zamanım var.
Nokta ve Şekil Grafiği Oluşturma için Gösterge Nokta ve Şekil Grafiği Oluşturma için Gösterge
Mevcut piyasa durumuna dair bilgi sağlayan birçok grafik türü vardır. Nokta ve Şekil grafiği gibi birçoğu uzak geçmişten mirastır. Makale, gerçek zamanlı bir gösterge kullanarak Nokta ve Şekil grafiği oluşturmanın bir örneğini açıklanmaktadır.
MQL5 Tarif Defteri Sınırsız Sayıda Parametreye Sahip Çok Para Birimli Uzman Danışman Geliştirme MQL5 Tarif Defteri Sınırsız Sayıda Parametreye Sahip Çok Para Birimli Uzman Danışman Geliştirme
Bu makalede, sınırsız sayıda parametreye izin verirken, bir alım satım sisteminin optimizasyonu için tek bir parametre seti kullanan bir model oluşturacağız. Sembol listesi, standart bir metin dosyasında (*.txt) oluşturulacaktır. Her sembol için giriş parametreleri de dosyalarda saklanacaktır. Bu şekilde, bir Uzman Danışmanın giriş parametrelerinin sayısı üzerindeki terminal kısıtlamasını aşabileceğiz.