English Русский 中文 Español Deutsch 日本語 Português 한국어 Français Italiano
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

MetaTrader 5Örnekler | 13 Ocak 2022, 09:38
79 0
Anatoli Kazharski
Anatoli Kazharski

Giriş

Önceki makalede MQL5 Tarif Defteri: Çok Para Birimli Uzman Danışmanı - Basit, Düzgün ve Hızlı Yaklaşım" değerlendirilen çok para birimli Uzman Danışman, kullanılan sembollerin ve alım satım stratejisi parametrelerinin sayısı küçükse çok yararlı olabilir. Ancak, MQL5'te bir Uzman Danışmanın giriş parametrelerinin sayısına dair bir kısıtlama vardır: Bu sayı 1024'ten fazla olamaz.

Ve bu sayı çoğu zaman yeterli olsa da, bu kadar büyük bir parametre listesi kullanmak çok sakıncalıdır. Belirli bir sembol için her parametre değişikliği veya optimizasyonu gerektiğinde, uzun parametre listesinde bu belirli sembol için parametreleri aramanız gerekir.

Diğer kısıtlamaları, istemci terminali Yardım bölümündeki Girişler bölümünden öğrenebilirsiniz.

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. Sembollerin listesi standart bir metin dosyasında (*.txt) saklanacaktır. Her sembol için giriş parametreleri de dosyalarda saklanacaktır.

Burada, Uzman Danışmanın normal çalışma modunda tek bir sembol üzerinde çalışacağını, ancak bunu Strateji Test Cihazında seçilen çeşitli semboller üzerinde (her bir sembol üzerinde ayrı ayrı) test edebileceğinizi belirtmemiz gerekir.

Aslında, sembol listesini doğrudan Piyasa İzleme penceresinde oluşturmak, bunun hazır sembol setlerini kaydetmeye bile izin verdiği düşünüldüğünde, daha da kullanışlı olacaktır. Uzman Danışmanın, Piyasa İzleme penceresindeki sembol listesini doğrudan Strateji Test Cihazından elde etmesini bile sağlayabiliriz. Ancak, Strateji Test Cihazından Piyasa İzleme penceresine erişmek şu anda maalesef mümkün değil, bu yüzden sembol listesini önceden manuel olarak veya bir betik kullanarak oluşturmamız gerekecek.


Uzman Danışman Geliştirme

Önceki makalede MQL5 Tarif Defteri: Çok Para Birimli Uzman Danışman - Hızlı, Sade ve Hızlı Yaklaşım" makalesinde içerilen çok para birimli Uzman Danışmanı bir şablon olarak alacağız. İlk olarak giriş parametrelerine karar verelim. Yukarıda belirtildiği gibi, sadece parametrelerin bir setini bırakacağız. Uzman Danışmanın giriş parametrelerinin listesi aşağıda yer almaktadır:

//--- Input parameters of the Expert Advisor
sinput long                      MagicNumber          =777;      // Magic number
sinput int                       Deviation            =10;       // Slippage
sinput string                    delimeter_00=""; // --------------------------------
sinput int                       SymbolNumber         =1;        // Number of the tested symbol
sinput bool                      RewriteParameters    =false;    // Rewriting parameters
sinput ENUM_INPUTS_READING_MODE  ParametersReadingMode=FILE;     // Parameter reading mode
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

Sadece giriş değiştiricisine sahip parametreler bir dosyaya yazılacaktır. Ayrıca, daha önce hiç karşılaşmadığımız üç yeni parametreyi de genişletmeliyiz.

  • SymbolNumber - bu parametre sembol listesini içeren dosyadan sembol sayısını belirtir. 0 olarak ayarlanırsa listedeki tüm semboller test edilecektir. Liste dışına çıkarsanız test yapılmayacaktır.
  • RewriteParameters - bu parametre değeri true olarak ayarlanırsa, belirtilen sembolün parametrelerine (SymbolNumber parametresindeki sayı) sahip dosya mevcut giriş parametresi değerleri kullanılarak yeniden yazılacaktır. Alternatif olarak, eğer false olarak ayarlanırsa, parametreler bir dosyadan okunacaktır.
  • ParametersReadingMode - bu parametre, giriş parametrelerine göre okuma modunu gösterir. Parametre türü, iki seçenek sunan ENUM_INPUTS_READING_MODE özel numaralandırmasıdır: bir dosyadan okumak ve mevcut parametreleri kullanmak.

ENUM_INPUTS_READING_MODE numaralandırma kodu:

//+------------------------------------------------------------------+
//| Input parameter reading modes                                    |
//+------------------------------------------------------------------+
enum ENUM_INPUTS_READING_MODE
  {
   FILE             = 0, // File
   INPUT_PARAMETERS = 1  // Input parameters
  };

Sembol sayısı daha önce NUMBER_OF_SYMBOLS sabiti kullanılarak belirlenmiştir. Bu değer şimdi farklı modlara bağlıdır, bu nedenle bunu SYMBOLS_COUNT global değişkeni olarak değiştireceğiz:

//--- Number of traded symbols. It is calculated and depends on the testing mode and the number of symbols in the file
int SYMBOLS_COUNT=0;

Uzman Danışmanın kodunun başında, giriş parametreleri üzerinde yineleme yapılırken dizi boyutlarını ve döngü yinelemelerinin sayısını belirleyen TESTED_PARAMETERS_COUNT adlı başka bir sabit bildiririz:

//--- Number of tested/optimized parameters
#define TESTED_PARAMETERS_COUNT 8

Sembol listesinin bulunduğu dosyanın yanı sıra her bir sembol için parametreleri içeren dosya klasörü, hem Uzman Danışmanın normal çalışması hem de bunun test edilmesi sırasında program düzeyinde erişilebildiği için terminalin ortak klasörüne yerleştirilmelidir.

Artık, daha sonra çalışmak için diziler hazırlamamız gerekiyor. Değiştireceğimiz önceki makaledeki çok para birimli Uzman Danışmandaki tüm diziler statiktir, yani önceden ayarlanmış bir öğe boyutundadır. Boyut artık dosyada kullanılan sembollerin sayısına ve giriş parametresi okuma moduna bağlı olacağından hepsini dinamik hale getirmeliyiz. Ayrıca dosyalar ile çalışmak için gerekli olan yeni diziler (sarı ile vurgulanmış) ekleyeceğiz:

//--- Arrays of input parameters
string InputSymbols[];            // Symbol names
//---
int    InputIndicatorPeriod[];    // Indicator periods
double InputTakeProfit[];         // Take Profit values
double InputStopLoss[];           // Stop Loss values
double InputTrailingStop[];       // Trailing Stop values
bool   InputReverse[];            // Values of position reversal flags
double InputLot[];                // Lot values
double InputVolumeIncrease[];     // Position volume increases
double InputVolumeIncreaseStep[]; // Volume increase steps
//--- Array of handles for indicator agents
int spy_indicator_handles[];
//--- Array of signal indicator handles
int signal_indicator_handles[];
//--- Data arrays for checking trading conditions
struct PriceData
  {
   double            value[];
  };
PriceData open[];      // Opening price of the bar
PriceData high[];      // High price of the bar
PriceData low[];       // Low price of the bar
PriceData close[];     // Closing price of the bar
PriceData indicator[]; // Array of indicator values
//--- Arrays for getting the opening time of the current bar
struct Datetime
  {
   datetime          time[];
  };
Datetime lastbar_time[];
//--- Array for checking the new bar for each symbol
datetime new_bar[];
//--- Array of input parameter names for writing to the file
string input_parameters[TESTED_PARAMETERS_COUNT]=
  {
   "IndicatorPeriod",   // Indicator period
   "TakeProfit",        // Take Profit
   "StopLoss",          // Stop Loss
   "TrailingStop",      // Trailing Stop
   "Reverse",           // Position reversal
   "Lot",               // Lot
   "VolumeIncrease",    // Position volume increase
   "VolumeIncreaseStep" // Volume increase step
  };
//--- Array for untested symbols
string temporary_symbols[];
//--- Array for storing input parameters from the file of the symbol selected for testing or trading
double tested_parameters_from_file[];
//--- Array of input parameter values for writing to the file
double tested_parameters_values[TESTED_PARAMETERS_COUNT];

Ardından dizi boyutlarını belirlemeli ve bunları değerlere başlatmalıyız.

Yukarıda oluşturulan giriş parametresi değerleri dizisi, InitializeArrays.mqh ​​dosyasında oluşturacağımız InitializeTestedParametersValues() fonksiyonunda başlatılacaktır. Bu dizi, giriş parametresi değerlerinin dosyaya yazılmasında kullanılacaktır.

//+------------------------------------------------------------------+
//| Initializing the array of tested input parameters                |
//+------------------------------------------------------------------+
void InitializeTestedParametersValues()
  {
   tested_parameters_values[0]=IndicatorPeriod;
   tested_parameters_values[1]=TakeProfit;
   tested_parameters_values[2]=StopLoss;
   tested_parameters_values[3]=TrailingStop;
   tested_parameters_values[4]=Reverse;
   tested_parameters_values[5]=Lot;
   tested_parameters_values[6]=VolumeIncrease;
   tested_parameters_values[7]=VolumeIncreaseStep;
  }

Şimdi dosya işlemlerini ele alalım. İlk olarak, Uzman Danışmanın UnlimitedParametersEA\Include klasöründe FileFunctions.mqh adlı başka bir fonksiyon kitaplığı oluşturun. Bu kitaplık, bir dosyada veri okuma ve yazma ile ilgili fonksiyonlar oluşturmak için kullanılacaktır. Bunu Uzman Danışmanın ana dosyasına ve projenin diğer dosyalarına ekleyin.

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

Bir metin dosyasından sembol listesini okumak için bir fonksiyon oluşturarak başlıyoruz: ReadSymbolsFromFile(). Bu dosya (adını TestedSymbols.txt koyalım) MetaTrader 5 istemci terminalinin ortak klasörünün \Files alt klasörüne yerleştirilmelidir. Benim durumumda bu C:\ProgramData\MetaQuotes\Terminal\Common olacaktır, ancak standart TERMINAL_COMMONDATA_PATH sabitini kullanarak yolu dikkatlice kontrol etmelisiniz:

TerminalInfoString(TERMINAL_COMMONDATA_PATH)
Tüm özel dosyalar, istemci terminalinin ortak klasörünün \Files alt klasörüne veya <Terminal Data Folder>\MQL5\Files\ içine yerleştirilmelidir. Dosya fonksiyonları yalnızca bu klasörlerden erişilebilirdir.

Fonksiyonelliği kontrol etmek için, oluşturulan metin dosyasına her bir sembolü bir satır sonu ("\r\n") ile ayırarak birkaç sembol ekleyin:

Şekil 1. Terminalin ortak klasöründe yer alan dosyadaki sembol listesi.

Şekil 1. Terminalin ortak klasöründe yer alan dosyadaki sembol listesi.

Ayrıca ReadSymbolsFromFile() fonksiyon koduna bir göz atalım:

//+------------------------------------------------------------------+
//| Returning the number of strings (symbols) in the file and        |
//| filling the temporary array of symbols temporary_symbols[]       |
//+------------------------------------------------------------------+
//--- When preparing the file, symbols in the list should be separated with a line break
int ReadSymbolsFromFile(string file_name)
  {
   int strings_count=0; // String counter
//--- Open the file for reading from the common folder of the terminal
   int file_handle=FileOpen(file_name,FILE_READ|FILE_ANSI|FILE_COMMON);
//--- If the file handle has been obtained
   if(file_handle!=INVALID_HANDLE)
     {
      ulong  offset =0; // Offset for determining the position of the file pointer
      string text ="";  // The read string will be written to this variable
      //--- 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
            text=FileReadString(file_handle);
            //--- Get the position of the pointer
            offset=FileTell(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 the string is not empty
            if(text!="")
              {
               //--- Increase the string counter
               strings_count++;
               //--- Increase the size of the array of strings,
               ArrayResize(temporary_symbols,strings_count);
               //--- Write the read string to the current index
               temporary_symbols[strings_count-1]=text;
              }
            //--- Exit the nested loop
            break;
           }
         //--- If this is the end of the file, terminate the main loop
         if(FileIsEnding(file_handle))
            break;
        }
      //--- Close the file
      FileClose(file_handle);
     }
//--- Return the number of strings in the file
   return(strings_count);
  }

Burada metin dosyası satır satır okunur. Okunan her finansal enstrümanın adı, daha önce oluşturulan geçici temporary_symbols[] dizisine yazılır (sembolün alım satım sunucusundaki gerçek erişilebilirliği daha sonra kontrol edilecektir). Ayrıca, fonksiyon sonunda, okunan dizilerin sayısı, yani Uzman Danışmanımızın test edileceği sembollerin sayısını döndürülür.

Daha önce hiç karşılaşmadığınız fonksiyonlar ve tanımlayıcılar hakkında ayrıntılı bilgi için her zaman MQL5 Referansına bakın. Kodda sağlanan yorumlar öğrenme sürecini kolaylaştıracaktır.

Daha önce bildirilen InputSymbols[] dizisini doldurmak için InitializeInputSymbols() fonksiyonunu oluşturacağımız InitializeArrays.mqh dosyasına geri dönelim. Yeni başlayanlar bunu muhtemelen oldukça karmaşık bulacaklar, bu yüzden kodda ayrıntılı yorumlar sağladım:

//+------------------------------------------------------------------+
//| Filling the InputSymbol[] array of symbols                       |
//+------------------------------------------------------------------+
void InitializeInputSymbols()
  {
   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
//--- Get the number of symbols from the "TestedSymbols.txt" file
   strings_count=ReadSymbolsFromFile("TestedSymbols.txt");
//--- In optimization mode or in one of the two modes (testing or visualization), provided that the symbol NUMBER IS SPECIFIED
   if(IsOptimization() || ((IsTester() || IsVisualMode()) && SymbolNumber>0))
     {
      //--- Determine the symbol to be involved in parameter optimization
      for(int s=0; s<strings_count; s++)
        {
         //--- If the number specified in the parameters and the current loop index match
         if(s==SymbolNumber-1)
           {
            //--- Check whether the symbol is on the trade server
            if((checked_symbol=GetSymbolByName(temporary_symbols[s]))!="")
              {
               //--- Set the number of symbols
               SYMBOLS_COUNT=1;
               //--- Set the size of the array of symbols
               ArrayResize(InputSymbols,SYMBOLS_COUNT);
               //--- Write the symbol name
               InputSymbols[0]=checked_symbol;
              }
            //--- Exit
            return;
           }
        }
     }
//--- In testing or visualization mode, if you need to test ALL symbols from the list in the file
   if((IsTester() || IsVisualMode()) && SymbolNumber==0)
     {
      //--- Parameter reading mode: from the file
      if(ParametersReadingMode==FILE)
        {
         //--- Iterate over all symbols in the file
         for(int s=0; s<strings_count; s++)
           {
            //--- Check if the symbol is on the trade server
            if((checked_symbol=GetSymbolByName(temporary_symbols[s]))!="")
              {
               //--- Increase the symbol counter
               SYMBOLS_COUNT++;
               //--- Set the size of the array of symbols
               ArrayResize(InputSymbols,SYMBOLS_COUNT);
               //--- Write the symbol name
               InputSymbols[SYMBOLS_COUNT-1]=checked_symbol;
              }
           }
         //--- Exit
         return;
        }
      //--- Parameter reading mode: from input parameters of the Expert Advisor
      if(ParametersReadingMode==INPUT_PARAMETERS)
        {
         //--- Set the number of symbols
         SYMBOLS_COUNT=1;
         //--- Set the size of the array of symbols
         ArrayResize(InputSymbols,SYMBOLS_COUNT);
         //--- Write the current symbol name
         InputSymbols[0]=Symbol();
         //--- Exit
         return;
        }
     }
//--- In normal operation mode of the Expert Advisor, use the current chart symbol
   if(IsRealtime())
     {
      //--- Set the number of symbols
      SYMBOLS_COUNT=1;
      //--- Set the size of the array of symbols
      ArrayResize(InputSymbols,SYMBOLS_COUNT);
      //--- Write the symbol name
      InputSymbols[0]=Symbol();
     }
//---
  }

Giriş parametreleri dizisinin boyutu, kullanılan sembollerin sayısıyla belirlendikten sonra, diğer tüm giriş parametreleri dizilerinin boyutunu ayarlamalısınız. Bunu ayrı bir fonksiyon olarak uygulayalım: ResizeInputParametersArrays():

//+------------------------------------------------------------------+
//| Setting the new size for arrays of input parameters              |
//+------------------------------------------------------------------+
void ResizeInputParametersArrays()
  {
   ArrayResize(InputIndicatorPeriod,SYMBOLS_COUNT);
   ArrayResize(InputTakeProfit,SYMBOLS_COUNT);
   ArrayResize(InputStopLoss,SYMBOLS_COUNT);
   ArrayResize(InputTrailingStop,SYMBOLS_COUNT);
   ArrayResize(InputReverse,SYMBOLS_COUNT);
   ArrayResize(InputLot,SYMBOLS_COUNT);
   ArrayResize(InputVolumeIncrease,SYMBOLS_COUNT);
   ArrayResize(InputVolumeIncreaseStep,SYMBOLS_COUNT);
  }

Şimdi, seçilen giriş moduna ve Uzman Danışman ayarlarına göre, her bir sembol için giriş parametre değerlerini okumamıza ve bu parametre değerlerini ayrı bir dosyaya (her sembol için) yazmamıza olanak sağlayacak fonksiyonelliği oluşturmamız gerekiyor. Bu da, dosyadan sembol listesini okuma şeklimize benzer şekilde yapılacaktır. Bu karmaşık bir görevdir, bu yüzden bunu birkaç prosedüre ayıralım.

İlk olarak, bir dosyadan bir diziye giriş parametre değerlerini okumayı öğrenmeliyiz. Dizi, double türünde değerler içerecektir. Daha sonra bunlardan bazılarını (gösterge dönemi ve pozisyon ters çevirme bayrağı) sırasıyla int ve bool türlerine çevireceğiz. Açık dosya işleyici ve dosyadan parametre değerlerinin saklandığı dizi ReadInputParametersValuesFromFile() fonksiyonuna aktarılır:

//+----------------------------------------------------------------------+
//| Reading parameters from the file and storing them in the passed array|
//| Text file format: key=value
//+----------------------------------------------------------------------+
bool ReadInputParametersValuesFromFile(int handle,double &array[])
  {
   int    delimiter_position  =0;  // Number of the symbol position "=" in the string
   int    strings_count       =0;  // String counter
   string read_string         =""; // The read string
   ulong  offset              =0;  // Position of the pointer (offset in bytes)
//--- Move the file pointer to the beginning of the file
   FileSeek(handle,0,SEEK_SET);
//--- Read until the current position of the file pointer reaches the end of the file
   while(!FileIsEnding(handle))
     {
      //--- If the user deleted the program
      if(IsStopped())
         return(false);
      //--- Read until the end of the string
      while(!FileIsLineEnding(handle))
        {
         //--- If the user deleted the program
         if(IsStopped())
            return(false);
         //--- Read the string
         read_string=FileReadString(handle);
         //--- Get the index of the separator ("=") in the read string
         delimiter_position=StringFind(read_string,"=",0);
         //--- Get everything that follows the separator ("=") until the end of the string
         read_string=StringSubstr(read_string,delimiter_position+1);
         //--- Place the obtained value converted to the double type in the output array
         array[strings_count]=StringToDouble(read_string);
         //--- Get the current position of the file pointer
         offset=FileTell(handle);
         //--- If it's the end of the string
         if(FileIsLineEnding(handle))
           {
            //--- Go to the next string if it's not the end of the file
            if(!FileIsEnding(handle))
               //--- Increase the offset of the file pointer by 1 to go to the next string
               offset++;
            //--- Move the file pointer relative to the beginning of the file
            FileSeek(handle,offset,SEEK_SET);
            //--- Increase the string counter
            strings_count++;
            //--- Exit the nested loop for reading the string
            break;
           }
        }
      //--- If it's the end of the file, exit the main loop
      if(FileIsEnding(handle))
         break;
     }
//--- Return the fact of successful completion
   return(true);
  }

Bu fonksiyona hangi dosya işleyicilerini ve dizilerini aktaracağız? Bu ise, bunları "TestedSymbols.txt" dosyasından okuduktan sonra hangi sembollerle çalışacağımıza bağlı olacaktır. Her sembol, giriş parametresi değerlerini içeren belirli bir metin dosyasına karşılık gelecektir. Göz önünde bulundurulması gereken iki durum senaryosu vardır:

  1. Dosya mevcuttur ve yukarıda açıklanan ReadInputParametersValuesFromFile()fonksiyonunu kullanarak bu dosyadan giriş parametresi değerlerini okuruz.
  2. Dosya mevcut değildir veya mevcut giriş parametresi değerlerini yeniden yazmamız gerekir.

Giriş parametresi değerlerini içeren metin dosyasının (bir .ini dosyası, ancak gerekli olduğunu düşündüğünüz başka bir uzantıyı seçebilirsiniz) biçimi basit olacaktır:

input_parameter_name1=value
input_parameter_name2=value
....
input_parameter_nameN=value

Bu mantığı kodu aşağıda sağlanan tek bir fonksiyonda birleştirelim: ReadWriteInputParameters().

//+------------------------------------------------------------------+
//| Reading/writing input parameters from/to a file for a symbol     |
//+------------------------------------------------------------------+
void ReadWriteInputParameters(int symbol_number,string path)
  {
   string file_name=path+InputSymbols[symbol_number]+".ini"; // File name
//---
   Print("Find the file '"+file_name+"' ...");
//--- Open the file with input parameters of the symbol
   int file_handle_read=FileOpen(file_name,FILE_READ|FILE_ANSI|FILE_COMMON);
   
//--- Scenario #1: the file exists and parameter values do not need to be rewritten
   if(file_handle_read!=INVALID_HANDLE && !RewriteParameters)
     {
      Print("The file '"+InputSymbols[symbol_number]+".ini' exists, reading...");
      //--- Set the array size
      ArrayResize(tested_parameters_from_file,TESTED_PARAMETERS_COUNT);
      //--- Fill the array with file values
      ReadInputParametersValuesFromFile(file_handle_read,tested_parameters_from_file);
      //--- If the array size is correct
      if(ArraySize(tested_parameters_from_file)==TESTED_PARAMETERS_COUNT)
        {
         //--- Write parameter values to arrays
         InputIndicatorPeriod[symbol_number]    =(int)tested_parameters_from_file[0];
         Print("InputIndicatorPeriod[symbol_number] = "+(string)InputIndicatorPeriod[symbol_number]);
         InputTakeProfit[symbol_number]         =tested_parameters_from_file[1];
         InputStopLoss[symbol_number]           =tested_parameters_from_file[2];
         InputTrailingStop[symbol_number]       =tested_parameters_from_file[3];
         InputReverse[symbol_number]            =(bool)tested_parameters_from_file[4];
         InputLot[symbol_number]                =tested_parameters_from_file[5];
         InputVolumeIncrease[symbol_number]     =tested_parameters_from_file[6];
         InputVolumeIncreaseStep[symbol_number] =tested_parameters_from_file[7];
        }
      //--- Close the file and exit
      FileClose(file_handle_read);
      return;
     }
//--- Scenario #2: If the file does not exist or the parameters need to be rewritten
   if(file_handle_read==INVALID_HANDLE || RewriteParameters)
     {
      //--- Close the handle of the file for reading
      FileClose(file_handle_read);
      //--- Get the handle of the file for writing
      int file_handle_write=FileOpen(file_name,FILE_WRITE|FILE_CSV|FILE_ANSI|FILE_COMMON,"");
      //--- If the handle has been obtained
      if(file_handle_write!=INVALID_HANDLE)
        {
         string delimiter="="; // Separator
         //--- Write the parameters
         for(int i=0; i<TESTED_PARAMETERS_COUNT; i++)
           {
            FileWrite(file_handle_write,input_parameters_names[i],delimiter,tested_parameters_values[i]);
            Print(input_parameters_names[i],delimiter,tested_parameters_values[i]);
           }
         //--- Write parameter values to arrays
         InputIndicatorPeriod[symbol_number]    =(int)tested_parameters_values[0];
         InputTakeProfit[symbol_number]         =tested_parameters_values[1];
         InputStopLoss[symbol_number]           =tested_parameters_values[2];
         InputTrailingStop[symbol_number]       =tested_parameters_values[3];
         InputReverse[symbol_number]            =(bool)tested_parameters_values[4];
         InputLot[symbol_number]                =tested_parameters_values[5];
         InputVolumeIncrease[symbol_number]     =tested_parameters_values[6];
         InputVolumeIncreaseStep[symbol_number] =tested_parameters_values[7];
         //--- Depending on the indication, print the relevant message
         if(RewriteParameters)
            Print("The file '"+InputSymbols[symbol_number]+".ini' with parameters of the '"+EXPERT_NAME+".ex5 Expert Advisor has been rewritten'");
         else
            Print("The file '"+InputSymbols[symbol_number]+".ini' with parameters of the '"+EXPERT_NAME+".ex5 Expert Advisor has been created'");
        }
      //--- Close the handle of the file for writing
      FileClose(file_handle_write);
     }
  }

Son dosya fonksiyonu CreateInputParametersFolder(), istemci terminalinin ortak klasöründe Uzman Danışman adında bir klasör oluşturacaktır. Bu, giriş parametre değerlerine sahip metin dosyalarının (bizim durumumuzda .ini dosyaları) okunacağı/yazılacağı klasördür. Tıpkı önceki fonksiyonda olduğu gibi, klasörün mevcut olup olmadığını kontrol edeceğiz. Klasör başarıyla oluşturulduysa veya zaten mevcutsa, bir hata durumunda fonksiyon, yol veya boş bir dize döndürür:

//+----------------------------------------------------------------------------------+
//| Creating a folder for files of input parameters in case the folder does not exist|
//| and returns the path in case of success                                          |
//+----------------------------------------------------------------------------------+
string CreateInputParametersFolder()
  {
   long   search_handle       =INVALID_HANDLE;   // Folder/file search handle
   string EA_root_folder      =EXPERT_NAME+"\\"; // Root folder of the Expert Advisor
   string returned_filename   ="";               // Name of the found object (file/folder)
   string search_path         ="";               // Search path
   string folder_filter       ="*";              // Search filter (* - check all files/folders)
   bool   is_root_folder      =false;            // Flag of existence/absence of the root folder of the Expert Advisor

//--- Find the root folder of the Expert Advisor
   search_path=folder_filter;
//--- Set the search handle in the common folder of the terminal
   search_handle=FileFindFirst(search_path,returned_filename,FILE_COMMON);
//--- If the first folder is the root folder, flag it
   if(returned_filename==EA_root_folder)
      is_root_folder=true;
//--- If the search handle has been obtained
   if(search_handle!=INVALID_HANDLE)
     {
      //--- If the first folder is not the root folder
      if(!is_root_folder)
        {
         //--- Iterate over all files to find the root folder
         while(FileFindNext(search_handle,returned_filename))
           {
            //--- Process terminated by the user
            if(IsStopped())
               return("");
            //--- If it is found, flag it
            if(returned_filename==EA_root_folder)
              {
               is_root_folder=true;
               break;
              }
           }
        }
      //--- Close the root folder search handle
      FileFindClose(search_handle);
      //search_handle=INVALID_HANDLE;
     }
//--- Otherwise print an error message
   else
      Print("Error when getting the search handle or "
            "the folder '"+TerminalInfoString(TERMINAL_COMMONDATA_PATH)+"' is empty: ",ErrorDescription(GetLastError()));

//--- Based on the check results, create the necessary folder
   search_path=EXPERT_NAME+"\\";
//--- If the root folder of the Expert Advisor does not exist
   if(!is_root_folder)
     {
      //--- Create it. 
      if(FolderCreate(EXPERT_NAME,FILE_COMMON))
        {
         //--- If the folder has been created, flag it
         is_root_folder=true;
         Print("The root folder of the '..\\"+EXPERT_NAME+"\\ Expert Advisor has been created'");
        }
      else
        {
         Print("Error when creating "
               "the root folder of the Expert Advisor: ",ErrorDescription(GetLastError()));
         return("");
        }
     }
//--- If the required folder exists
   if(is_root_folder)
      //--- Return the path to create a file for writing parameters of the Expert Advisor
      return(search_path+"\\");
//--- In case of errors, return an empty string
   return("");
  }

Şimdi yukarıdaki fonksiyon çağrılarını tek bir fonksiyona yerleştirelim: InitializeInputParametersArrays(). Bu fonksiyon, Uzman Danışman ile çalışırken 4 giriş parametresi başlatma seçeneğini kapsar:

  1. Mevcut giriş parametre değerlerini kullanarak standart çalışma modu (veya seçilen bir sembol için parametre optimizasyonu)
  2. Test veya optimizasyon sırasında dosyalardaki parametreleri yeniden yazma
  3. Seçilen bir sembolü test etme
  4. Dosyadan listedeki tüm sembolleri test etme

Tüm işlemler kodun ayrıntılı yorumlarında açıklanmıştır:

//+-------------------------------------------------------------------+
//| Initializing arrays of input parameters depending on the mode     |
//+-------------------------------------------------------------------+
void InitializeInputParametersArrays()
  {
   string path=""; // To determine the folder that contains files with input parameters
//--- Mode #1 :
//    - standard operation mode of the Expert Advisor OR
//    - optimization mode OR
//    - reading from input parameters of the Expert Advisor without rewriting the file
   if(IsRealtime() || IsOptimization() || (ParametersReadingMode==INPUT_PARAMETERS && !RewriteParameters))
     {
      //--- Initialize parameter arrays to current values
      InitializeWithCurrentValues();
      return;
     }
//--- Mode #2 :
//    - rewriting parameters in the file for the specified symbol
   if(RewriteParameters)
     {
      //--- Initialize parameter arrays to current values
      InitializeWithCurrentValues();
      //--- If the folder of the Expert Advisor exists or in case no errors occurred when it was being created
      if((path=CreateInputParametersFolder())!="")
         //--- Write/read the file of symbol parameters
         ReadWriteInputParameters(0,path);
      //---
      return;
     }
//--- Mode #3 :
//    - testing (it may be in visualization mode, without optimization) the Expert Advisor on a SELECTED symbol
   if((IsTester() || IsVisualMode()) && !IsOptimization() && SymbolNumber>0)
     {
      //--- If the folder of the Expert Advisor exists or in case no errors occurred when it was being created
      if((path=CreateInputParametersFolder())!="")
        {
         //--- Iterate over all symbols (in this case, the number of symbols = 1)
         for(int s=0; s<SYMBOLS_COUNT; s++)
            //--- Write or read the file of symbol parameters
            ReadWriteInputParameters(s,path);
        }
      return;
     }
//--- Mode #4 :
//    - testing (it may be in visualization mode, without optimization) the Expert Advisor on ALL symbols
   if((IsTester() || IsVisualMode()) && !IsOptimization() && SymbolNumber==0)
     {
      //--- If the folder of the Expert Advisor exists and
      //    no errors occurred when it was being created
      if((path=CreateInputParametersFolder())!="")
        {
         //--- Iterate over all symbols
         for(int s=0; s<SYMBOLS_COUNT; s++)
            //--- Write or read the file of symbol parameters
            ReadWriteInputParameters(s,path);
        }
      return;
     }
  }

#1 ve #2 modlarında InitializeWithCurrentValues() fonksiyonunu kullanırız. Bu, mevcut giriş parametresi değerlerine sıfır (tek) indisini başlatır. Diğer bir deyişle, bu fonksiyon yalnızca bir sembol gerektiğinde kullanılır:

//+------------------------------------------------------------------+
//| Initializing arrays of input parameters to current values        |
//+------------------------------------------------------------------+
void InitializeWithCurrentValues()
  {
   InputIndicatorPeriod[0]=IndicatorPeriod;
   InputTakeProfit[0]=TakeProfit;
   InputStopLoss[0]=StopLoss;
   InputTrailingStop[0]=TrailingStop;
   InputReverse[0]=Reverse;
   InputLot[0]=Lot;
   InputVolumeIncrease[0]=VolumeIncrease;
   InputVolumeIncreaseStep[0]=VolumeIncreaseStep;
  }

Şimdi en basit ama en önemli şeyi yapmamız gerekiyor: Giriş noktasından yukarıdaki fonksiyonların ardışık çağrılarını uygulamak için OnInit() fonksiyonu:

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
void OnInit()
  {
//--- Initialize the array of tested input parameters for writing to the file
   InitializeTestedParametersValues();
//--- Fill the array of symbol names
   InitializeInputSymbols();
//--- Set the size of arrays of input parameters
   ResizeInputParametersArrays();
//--- Initialize arrays of indicator handles
   InitializeIndicatorHandlesArrays();
//--- Initialize arrays of input parameters depending on the operation mode of the Expert Advisor
   InitializeInputParametersArrays();
//--- Get agent handles from the "EventsSpy.ex5" indicator
   GetSpyHandles();
//--- Get indicator handles
   GetIndicatorHandles();
//--- Initialize the new bar
   InitializeNewBarArray();
//--- Initialize price arrays and indicator buffers
   ResizeDataArrays();
  }

Yani kodla işimiz bitti. Makaleye ekli dosyaları kullanarak açıklanan fonksiyonları tanıyabilirsiniz, içlerinde karmaşık bir şey yoktur. Şimdi sonuç olarak ne elde ettiğimizi ve bunu nasıl kullanılabileceğini görmek için biraz daha ilerleyelim.


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

Daha önce bahsedildiği gibi, sembol listesine sahip TestedSymbols.txt dosyanız istemci terminalinin ortak klasöründe olmalıdır. Örnek olarak/test amacıyla, üç sembolden oluşan bir liste oluşturacağız: AUDUSD, EURUSD ve NZDUSD. Şimdi her bir sembol için ayrı ayrı giriş parametrelerini ardışık olarak optimize edeceğiz. Strateji Test Cihazı aşağıda gösterildiği gibi ayarlanmalıdır:

Şekil 2. Strateji Test Cihazı ayarları.

Şekil 2. Strateji Test Cihazı ayarları.

Uzman Danışmanı etkilemediği için herhangi bir sembolü (bizim durumumuzda EURUSD) "Ayarlar" sekmesinden ayarlayabilirsiniz. Ardından Uzman Danışmanın optimizasyonu için parametreleri seçiyoruz:

Şekil 3. Uzman Danışmanın giriş parametreleri

Şekil 3. Uzman Danışman için Giriş Parametreleri.

Yukarıdaki şekil, SymbolNumber parametresinin (Test edilen sembol sayısı 1 olarak ayarlandığını gösterir. Bunun anlamı, optimizasyonu çalıştırırken Uzman Danışmanın TestedSymbols.txt dosyasındaki listedeki ilk sembolü kullanmasıdır. Bizim durumumuzda bu AUDUSD'dir.

Not: Bu Uzman Danışmanın özelliklerinden dolayı (sembol listesi metin dosyasından okunarak ayarlanır), uzak aracılarla optimizasyon mümkün olmayacaktır.

Bu serinin aşağıdaki makalelerinden birinde bu kısıtlamayı aşmaya çalışacağız.

Optimizasyonu tamamladıktan sonra, farklı optimizasyon geçişlerinin sonuçlarını inceleyerek testler yapabilirsiniz. Uzman Danışmanın dosyadan parametreleri okumasını istiyorsanız, ParametersReadingMode parametresinin (Parametre okuma modu) açılır listesinden Dosya seçeneğini seçmelisiniz. Uzman Danışmanın ("Ayarlar" sekmesinde ayarlanır) mevcut parametrelerini kullanabilmek için Giriş parametreleri seçeneğini seçmelisiniz.

Optimizasyon sonuçlarını görüntülerken Giriş parametreleri seçeneği kesinlikle gereklidir. Testi ilk kez çalıştırırken, Uzman Danışman, terminalin ortak klasöründe ilgili ada sahip bir klasör oluşturacaktır. Oluşturulan klasör, test edilen sembolün mevcut parametrelerini içeren bir dosya içerecektir. Bizim durumumuzda bu AUDUSD.ini'dir. Bu dosyanın içeriğini aşağıdaki şekilden görebilirsiniz:

Şekil 4. Sembol dosyasındaki giriş parametrelerinin listesi.

Şekil 4. Sembol dosyasındaki giriş parametrelerinin listesi.

Gerekli parametre kombinasyonu bulunduğunda, RewriteParameters parametresinde (Parametreleri yeniden yaz) true değerini ayarlamalı ve testi tekrar çalıştırmalısınız. Parametre dosyası güncellenecektir. Daha sonra tekrar false ayarını yapabilir ve optimizasyon geçişlerinin diğer sonuçlarını kontrol edebilirsiniz. Ayrıca, yalnızca Parametre okuma modu parametresinin seçenekleri arasında geçiş yaparak, dosyaya yazılan değerlere göre sonuçları giriş parametrelerinde ayarlananlar ile karşılaştırmak da uygundur.

Ardından, optimizasyonu, sembol listesi dosyasından listedeki ikinci sembol olan EURUSD için çalıştırıyoruz. Bunun için, Test edilen sembol sayısı parametresinin değerini 2 değerine eşit ayarlamamız gerekir. Optimizasyonun ardından ve parametreleri belirlenip dosyaya yazılmasının ardından listedeki üçüncü sembol için de aynı işlemin yapılması gerekecektir.

Tüm semboller için parametrelerin dosyaya yazılmasının ardından, sembol sayısını belirterek her bir sembol için sonuçları ayrı ayrı görüntüleyebilir veya Test edilen sembol sayısını 0 olarak ayarlayarak tüm semboller için kümülatif sonucu görüntüleyebilirsiniz. Tüm semboller için aşağıdaki kümülatif sonucu aldım:

Şekil 5. Çok para birimli Uzman Danışmanın kümülatif sonucu.

Şekil 5. Çok para birimli Uzman Danışmanın kümülatif sonucu.


Sonuç

Bunun sonucunda, çok para birimli Uzman Danışmanlar için oldukça uygun bir model elde ettik. Bu model, istenirse daha da geliştirilebilir. Uzman Danışmanın dosyalarını içeren indirilebilir arşiv değerlendirmeniz için makaleye eklenmiştir. Bunları klasöre çıkardıktan sonra, UnlimitedParametersEA klasörünü <MetaTrader 5 terminal klasörü>\MQL5\Experts altına yerleştirin. EventsSpy.mq5 göstergesi <MetaTrader 5 terminal klasörü>\MQL5\Indicators içine yerleştirilmelidir. Bunun yanında, istemci terminalinin ortak klasöründe TestedSymbols.txt metin dosyasını oluşturmayı unutmayın.

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

Ekli dosyalar |
eventsspy.mq5 (7.61 KB)
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.
MQL5 Tarif Defteri: Çok Para Birimli Uzman Danışman - Basit, Sade ve Hızlı Yaklaşım MQL5 Tarif Defteri: Çok Para Birimli Uzman Danışman - Basit, Sade ve Hızlı Yaklaşım
Bu makale, çok para birimli bir Uzman Danışman için uygun olan basit bir yaklaşımın uygulamasını açıklayacaktır. Bu, aynı koşullar altında, ancak her bir sembol için farklı parametreler ile test/alım satım için Uzman Danışmanı kurabileceğiniz anlamına gelir. Örnek olarak, gerekirse kodda küçük değişiklikler yaparak ek semboller eklenebilecek şekilde iki sembol için bir model oluşturacağız.
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
Hangi alım satım stratejisini kullanırsanız kullanın, gelecekteki kârları sağlamak için hangi parametreleri seçeceğinize dair her zaman bir soru olacaktır. Bu makale, aynı anda birçok sembol parametresini optimize etme imkanına sahip bir Uzman Danışman örneği sağlar. Bu yöntemin, aşırı öğrenme parametrelerin etkisini azaltması ve çalışma için tek bir sembolden elde edilen verilerin yeterli olmadığı durumları ele alması amaçlanır.
MQL5 Tarif Defteri: Üçlü Ekran Stratejisine Dayalı Bir Alım Satım Sistemi Çerçevesi Geliştirme MQL5 Tarif Defteri: Üçlü Ekran Stratejisine Dayalı Bir Alım Satım Sistemi Çerçevesi Geliştirme
Bu makalede, MQL5'te Üçlü Ekran stratejisine dayalı bir alım satım sistemi için bir çerçeve geliştireceğiz. Uzman Danışman sıfırdan geliştirilmeyecektir. Bunun yerine, halihazırda büyük ölçüde amacımıza hizmet eden "MQL5 Tarif Defteri: Uzman Danışmanlarda Alım Satım Koşullarını Belirlemek için Göstergeleri Kullanma" önceki makalesinden programı değiştireceğiz. Böylelikle makale aynı zamanda hazır programların modellerini nasıl kolay bir şekilde değiştirebileceğinizi gösterecektir.