La optimización automática de un Asesor Experto en el trading real

Igor Malcev | 7 marzo, 2016

Introducción

Se supone que un Asesor Experto que tiene las entradas ajustadas al historial resultaría rentable la primera vez (en un tiempo bastante corto). Se puso en evidencia esta hipótesis después de haber observado el Campeonato de Trading Automatizado 2006. Al principio del campeonato, habían Asesores Expertos mucho más, pero más adelante, algunos ya no eran rentables. Por este motivo, supongo que la mayoría de estos Asesores Expertos no habían llegado hasta el final por estar ajustados al historial.

La idea de comprobar esta hipótesis en la práctica surgió en el foro en ruso de este sitio, en el apartado Sistemas ideales de trading automático. El principio de esta idea consiste en iniciar automáticamente la optimización de un Asesor Experto una vez al día y después analizar los resultados de la optimización y almacenarlos en las variables del Asesor Experto.

Para implementar esta idea hemos decidido utilizar el Asesor Experto ya hecho, el MACD Sample, del Terminal de cliente MetaTrader 4 e insertar nuestra propia función de optimización automática en él. Un poco después, ya estaba listo el código del optimizador automático y cargado en el mismo foro, en el apartado Optimizador automático. Después de algún tiempo, comenzó a confirmarse la idea en el apartado Optimizador automatico. Más adelante, se convirtió el optimizador en una librería mqh para una mayor facilidad de uso.


Instalación del optimizador automático

A continuación podemos ver lo que hay que hacer para llevar a cabo esta tarea:

Para mayor comodidad, llamaremos al terminal original "Terminal" y a la copia "Terminal-Tester". Realizaremos una prueba en EURUSD con el período de tiempo H1 mediante el Asesor Experto incluido en el Terminal, pero ligeramente modificado; MACD Sample_1.mq4.

Configuración de Terminal-Tester

No se olvide de compilar MACD Sample_1.mq4 en el Terminal-Tester. Pongamos en marcha primero el terminal de cliente y después la prueba de estrategias y hagamos los ajustes tal y como se muestra en la siguiente captura de pantalla.


Se llevará a cabo la optimización durante tres días. Esto es más que suficiente para probar el optimizador automático. Seleccionaremos la fecha de optimización "De" según la siguiente fórmula: la fecha actual menos tres días. Durante la optimización, hay que descargar el historial del símbolo (en nuestro caso, es el EURUSD) seleccionado.

Aquellos que realizan la optimización por primara vez pueden encontrar la descripción de los procedimientos necesarios en el menú Ayuda del Terminal de cliente MetaTrader 4: <Ayuda - Temas de ayuda F1 - Auto Trading - Expert Optimization - Setup>. O pueden leer el artículo Prueba de Asesores Expertos en el Terminal de cliente MetaTrader 4: Un vistazo desde fuera.

A continuación vamos a marcar las variables a optimizar tal y como se muestra en la siguiente captura de pantalla.


La optimización automática está limitada a 4 variables, pero basta con tener sólo tres para conseguir nuestro objetivo y ahorrar tiempo. Una vez seleccionadas las variables almacenamos los ajustes de la optimización en el archivo MACD Sample_1.set. Hay que guardar este archivo en la carpeta "tester" del Terminal-Tester. A continuación ejecutamos la pre-optimización y memorizamos la hora de inicio. Hace falta calcular el período de tiempo que requiere la optimización automática con los parámetros predefinidos. Una vez finalizada la optimización, calculamos el tiempo de espera necesario. A continuación tenemos que cerrar este terminal, de lo contrario no podremos ejecutarlo mediante la programación.

Configuración del Asesor Experto ubicado en el terminal

Para ello, vamos a abrir el Asesor Experto MACD Sample_1.mq4 en MetaEditor y hacer lo siguiente:

- establecer el tiempo de inicio de la optimización automática, por ejemplo, a las 00:01 cada día:

datetime SetHour    = 0;  // Optimization starting hour; 
        datetime SetMinute  = 1;  // Optimization starting minute.

- establecer la duración de la optimización en días (tiene que coincidir con el número de días de la pre-optimización):

int TestDay = 3;

- establecer el tiempo de espera en minutos del fin de la optimización que hemos calculado antes, por ejemplo, 4 minutos:

int TimeOut = 4;

- introducir el nombre del Asesor Experto:

string NameMTS = "MACD Sample_1";  // EA's name

- introducir el nombre del archivo con los ajustes:

// Set-file name with the settings
        string NameFileSet = "MACD Sample_1.set"; 

- introducir el nombre de la ruta hacia la carpeta que contiene el Terminal-Tester instalado, por ejemplo:

        // Path to the tester        
        string PuthTester = "D:\Program Files\Forex Best Trade Station";

- establecer la prioridad del filtrado:

// Sorting by Maximal profit
        int Gross_Profit = 1;                      
        // Sorting by Maximal profit factor        
        int Profit_Factor = 2;     
        // Sorting by Maximal expected payoff
        int Expected_Payoff = 3;

- escribir los nombres de las variables a optimizar:

string Per1 = "FastEMA";
        string Per2 = "SlowEMA";
        string Per3 = "SignalSMA";
        string Per4 = "";

- copiar el archivo adjunto auto_optimization.mqh en la carpeta "include";

- incluir el archivo de la librería en el Asesor Experto:

//--- Including the auto optimizer's library
#include <auto_optimization.mqh>

- sólo falta copiar el siguiente código debajo del inicio de la función start() en su Asesor Experto. Ya está incluido en MACD Sample_1.mq4.

// Not to be launched at testing and optimizing   
  if(!IsTesting() && !IsOptimization())
    {                
      // Compare the current hour with that preset for launching
      if(TimeHour(TimeLocal()) == SetHour)
        {
          // Protection against restarting
          if(!StartTest)
            {
              // Compare the minute range to the minute
              // preset for launching
              if(TimeMinute(TimeLocal()) > SetMinute - 1)
                {     
                  // the range is necessary, in case that for some reasons 
                  // no new tick is available for a long time
                  if(TimeMinute(TimeLocal()) < SetMinute + 1)
                    {  
                      // Flag of tester launching
                      StartTest    = true;
                      TimeStart    = TimeLocal();
                      Tester(TestDay, NameMTS, NameFileSet, PuthTester, 
                             TimeOut, Gross_Profit, Profit_Factor, 
                             Expected_Payoff, Per1, Per2, Per3, Per4);
                    
                    }
                }
            }
        }
    }
    
                        
   FastEMA      = GlobalVariableGet(Per1);
   SlowEMA      = GlobalVariableGet(Per2);
   SignalSMA    = GlobalVariableGet(Per3);
   TrailingStop = GlobalVariableGet(Per4);  
// If the tester launching is flagged  
  if(StartTest)
    {                                        
      // If more time has elapsed the launching than it was set 
      // to be the test waiting time
      if(TimeLocal() - TimeStart > TimeOut*60)
        {            
          // Zeroize the flag
          StartTest = false;                              
        }
    }

Eso es todo. Se puede ejecutar el optimizador automático después de volver a compilarlo, pero con el mismo símbolo y período de tiempo utilizados en la pre-optimización. En nuestro caso, es EURUSD en H1. Para probar el optimizador automático, puede insertar el siguiente código en la función init (), de modo que se ejecutará el optimizador nada más iniciar el Asesor Experto.

Tester(TestDay,NameMTS,NameFileSet,PuthTester,TimeOut, Gross_Profit,Profit_Factor, 
       Expected_Payoff, Per1,Per2,Per3,Per4);


Cómo funciona el optimizador automático

El funcionamiento del optimizador automático se basa en el uso del Terminal-Tester para optimizar los parámetros del Asesor Experto adjunto al gráfico en el Terminal. Para ello, el programa envía al Terminal-Tester un archivo que contiene los parámetros de optimización (optimise.ini) y ejecuta el Terminal-Tester en el modo optimización. A continuación copia los resultados obtenidos de "FileReport........htm" en el Terminal y selecciona los mejores valores a partir de los mismos.


Más detalles acerca del funcionamiento del optimizador automático

A la hora predefinida, por ejemplo, a las 00:01, debe ponerse en marcha el optimizador automático. Hay que rellenar las variables con sus valores.

// Path to the terminal 
string PuthTerminal = TerminalPath() + "\experts\files";
// Name of the ini file for the tester
string FileOptim    = "optimise.ini";
string FileOptim1   = "\optimise.ini";                                  
// Calculation of the starting date
datetime DayStart   = TimeLocal()-86400*TestDay;
// Optimization starting date
string DateStart    = TimeToStr(DayStart,TIME_DATE);
// Optimization ending date
string DateStop     = TimeToStr(TimeLocal(),TIME_DATE);
// Tester report file name
string FileReport   = "FileReport_" + Symbol() + "_" + DateStop + ".htm";
string FileReport1  = "\FileReport_" + Symbol() + "_" + DateStop + ".htm";
// Limitation for the minimum amount of trades per day
double MinTr        = TestDay - 2;
// Limitation for maximal amount of trades per day
double MaxTr        = (60 / Period()*TestDay) + 2;
// The amount of attempts to copy the report file
int    KvoPptk      = 10;
// The amount of lines for sorting
int    StepRes      = 12;

A continuación se almacenan los parámetros del archivo ini en una matriz de cadenas:

// Prepare the ini file for optimization
ArrayOpttim[0] = ";optimise strategy tester";             
// Enable/Disable Expert Advisors
ArrayOpttim[1] = "ExpertsEnable = false";
// Name of the EA file
ArrayOpttim[2] = "TestExpert=" + NameMTS;
// Name of the file containing parameters
ArrayOpttim[3] = "TestExpertParameters=" + NameFileSet;
// Symbol
ArrayOpttim[4] = "TestSymbol=" + Symbol();
// Timeframe
ArrayOpttim[5] = "TestPeriod=" + Period();
// Modeling mode
ArrayOpttim[6] = "TestModel=" + 0;
// Recalculate
ArrayOpttim[7] = "TestRecalculate=false";
// Optimization
ArrayOpttim[8] = "TestOptimization=true";
// Use date
ArrayOpttim[9] = "TestDateEnable=true";
// From
ArrayOpttim[10] = "TestFromDate=" + DateStart;
// To
ArrayOpttim[11] = "TestToDate=" + DateStop;
// Report file name
ArrayOpttim[12] = "TestReport=" + FileReport;
// Rewrite the report file
ArrayOpttim[13] = "TestReplaceReport=true";
// Shut down the terminal upon completion
ArrayOpttim[14] = "TestShutdownTerminal=true";

Se almacenan los parámetros desde la matriz en el archivo ini. También puede leer acerca de cómo crear un archivo ini en la ayuda del Terminal de cliente MetaTrader 4: <Ayuda - Temas de ayuda F1 - Tools - Configuration at Startup>.

// Write data into the ini file                
// Find out about the array size
OptimArraySize = ArraySize(ArrayOpttim);
// Open a file to write
opttim = FileOpen(FileOptim, FILE_CSV|FILE_WRITE, 0x7F);
if(opttim > 0)
  {
    for(int i = 0; i < OptimArraySize; i++)
      {
        // from the array into the variable
        ini = ArrayOpttim[i];                                     
        // from the variable into the file
        FileWrite(opttim, ini);
      } 
    // close the file
    FileClose(opttim);
  }
else
  {
    Print("Failed writing data into the ini file. Error No ", 
          GetLastError());
    return(0);
  }

Una vez almacenados los parámetros en el archivo ini, se conecta el archivo shell32.dll que se encuentra en la librería estándar de Windows y se ejecuta la función ShellExecuteA.

#import  "shell32.dll"               //Connect a dll (provided with Windows)       
  int ShellExecuteA(int hwnd,string Operation,string 
                    File,string Parameters,string Directory,int ShowCmd); 
#import

Se enviará el archivo que contiene los parámetros a la carpeta del Terminal-Tester.

// copy the ini file into the tester folder 
copyini = ShellExecuteA(0,"Open","xcopy", "\"" + PuthTerminal + 
                        FileOptim1 + "\" \"" + PuthTester + "\" /y", 
                        "", 3);
// wait until the file is copied
Sleep(1200);                                                    
if(copyini < 0)
  {
    Print("Failed copying ini file");
    return(0);
  }

A continuación se ejecuta el probador y empieza a optimizar las variables predefinidas. El Asesor Experto está en modo de espera durante la optimización.

// Start Tester 
start = ShellExecuteA(0, "Open", "terminal.exe", FileOptim,
                      PuthTester, 3);
if(start < 0)
  {
    Print("Failed starting Tester");
    return(0);
  }
Comment("Wait until optimization is complete");
// wait until optimization is complete
Sleep(60000*TimeOut);

Una vez finalizada la optimización, el probador almacenará automáticamente los resultados en el archivo de registro. Se copia este archivo en la carpeta del terminal.

for(Pptk = 0; Pptk < KvoPptk; Pptk++)
  {                    
    //Start a cycle attempting to compy the resport file
    Comment("Attempt # " + Pptk + " to copy the report file");
    ShellExecuteA(0, "Open", "xcopy", "\"" + PuthTester + FileReport1 + 
                  "\" \"" + PuthTerminal + "\" /y", "", 3);
    // wait until the file is copied
    Sleep(1200);
    // Try to open the report file
    file = FileOpen(FileReport, FILE_READ, 0x7F);
    if(file < 0)
      {
        // if it fails to open, wait some more and try again
        Sleep(60000);
      }                    
    else 
        break;             
  }
if(file < 0)
  {
    Print("Failed copying the report file");
    return(0);
  }

A continuación se colocan los datos del archivo de registro en la matriz de cadenas para su posterior procesamiento.

// Read from file into the array
// Cycle, until the file ends
while(FileIsEnding(file) == false)
  {                 
    // Read a string from the report file
    FileLine = FileReadString(file);
    // Find the necessary string and set the reference point there
    index = StringFind(FileLine, "title", 20);
    if(index > 0)
      {
        // Increase the array in size
        ArrayResize(ArrayStrg, NumStr + 1);
        // Record the strings from the file in the array
        ArrayStrg[NumStr] = FileLine;
        NumStr++;
      }
  }
// Close the file
FileClose(file);
// Delete the file in order not to produce too many copies
FileDelete(FileReport);
// Set the array size by the amount of data read from the file
ArrayResize(ArrayData, NumStr);

Luego se seleccionan los valores relevantes de la matriz:

for(text = 0; text < NumStr; text++)
     {
      select = ArrayStrg[text]; 
    //-------------------------------------------------------------------------
    //   Reporting text processing (These are apples and oranges)              | 
    //-------------------------------------------------------------------------
    // Position Pass 
    ClStep=StringFind(select, "; \">",20)+4;
    // Find the end of position
    ClStepRazm = StringFind(select, "td>", ClStep);
    // Read the value
    CycleStep = StringSubstr(select, ClStep, ClStepRazm - ClStep);
    // Position Profit 
    // Find the beginning of the position
    GrProf = StringFind(select, "", ClStepRazm);
    // Find the end of position
    GrProfRazm = StringFind(select, "td>", GrProf);
    // Read value
    GrossProfit = StringSubstr(select, GrProf+4, GrProfRazm - (GrProf + 4));
    // Position Total Trades
    // Find the beginning of position
    TotTrad = StringFind(select, "", GrProfRazm);
    // Find the end of position
    TotTradRazm = StringFind(select, "td>", TotTrad);
    // Read the value
    TotalTrades = StringSubstr(select, TotTrad+4, TotTradRazm - 
                               (TotTrad + 4));
    // Position Profitability
    // Find the beginning of position
    ProfFact = StringFind(select, "", TotTradRazm);
    // Find the end of position
    ProfFactRazm = StringFind(select, "td>", ProfFact);
    // Read the value
    ProfitFactor = StringSubstr(select, ProfFact + 4, ProfFactRazm - 
                                (ProfFact + 4));
    // Position Expected Payoff 
    // Find the beginning of position
    ExpPay = StringFind(select, "", ProfFactRazm);
    // Find the dn of position
    ExpPayRazm=StringFind(select, "td>", ExpPay);
    // Read the value
    ExpectedPayoff = StringSubstr(select, ExpPay+4, ExpPayRazm - 
                                  (ExpPay + 4));
    // Variables' positions starting with the second one
    // Find the beginning of position
    P1 = StringFind(select, Per1, 20);
    // Find the end of position
    P1k = StringFind(select, ";", P1);
    // Read the Variable
    Perem1 = StringSubstr(select, P1 + StringLen(Per1) + 1, P1k - 
                          (P1 + 1 + StringLen(Per1)));
    // Find the beginning of position
    P2 = StringFind(select, Per2, 20);
    // Find the end of position
    P2k = StringFind(select, ";", P2); 
    // Read the Variable
    Perem2 = StringSubstr(select, P2 + StringLen(Per2) + 1, P2k - 
                          (P2 + 1 + StringLen(Per2)));
    // Find the beginning of position
    P3 = StringFind(select, Per3, 20);
    // Find the end of position
    P3k = StringFind(select, ";", P3);
    // Read the Variable
    Perem3 = StringSubstr(select, P3 + StringLen(Per3) + 1, P3k - 
                          (P3 + 1 + StringLen(Per3)));
    // Find the beginning of position
    P4 = StringFind(select, Per4, 20);
    // Find the end of position
    P4k = StringFind(select, ";", P4);
    // Read the Variable 
    Perem4 = StringSubstr(select, P4 + StringLen(Per4) + 1, P4k - 
                          (P4 + 1 + StringLen(Per4)));
    Comment("The obtained results are being analyzed");

Después de eso, y antes de transformarlos a un formato numérico, se filtran los resultados obtenidos mediante el número mínimo y máximo de operaciones. Se sustituye el valor cero de Profit_Factor por 1000 para corregir la clasificación y la posterior selección.

// Transform into number format
TotalTradesTransit = StrToDouble(TotalTrades);
GrossProfitTransit = StrToDouble(GrossProfit);
ExpectedPayoffTran = StrToDouble(ExpectedPayoff);
nodubl = true;
if(MinTr < TotalTradesTransit && MaxTr > TotalTradesTransit)
  {                    
    // Filter by the amount of trades
    PrFactDouble = StrToDouble(ProfitFactor);
    // Replace 0 in the Profit_Factor for proper analysis
    if(PrFactDouble == 0)
      {
        PrFactDouble = 1000;
      }

A continuación se comprueban las duplicidades y se filtran.

// Filter data having identical values
for(Dubl = 0; Dubl <= ResizeArayNew; Dubl++)
  {                    
    // Start the loop searching for identical values
    if(GrossProfitTransit == ArrayData[Dubl][1])
      {          
        // check whether the results for maximal profit coincide
        if(TotalTradesTransit == ArrayData[Dubl][2])
          {       
            // check whether the results for the amount of trades coincide
            if(PrFactDouble == ArrayData[Dubl][3])
              {          
                // check whether the results for Profit Factor coincide
                if(ExpectedPayoffTran == ArrayData[Dubl][4])
                  { 
                    // check whether the results for expected payoff coincide
                    nodubl=false;                              
                    // If everything coincides, flag it as coincided
                  }
              }
          }
      }
  }

Luego se almacenan los valores que ya están listos para su clasificación en la matriz.

// Write the filtered data in the array
if(nodubl)
  {
    ArrayData[text][1] = GrossProfitTransit;                                
    ArrayData[text][2] = TotalTradesTransit;
    ArrayData[text][3] = PrFactDouble;
    ArrayData[text][4] = ExpectedPayoffTran;
    ArrayData[text][5] = StrToDouble(Perem1);
    ArrayData[text][6] = StrToDouble(Perem2);
    ArrayData[text][7] = StrToDouble(Perem3);
    ArrayData[text][8] = StrToDouble(Perem4);
    ResizeArayNew++; 
  }

Y al final se inicia el análisis de los datos en el orden de prioridad preestablecido. Se lleva a cabo el análisis de la siguiente manera:

// Analyzer
// Analyzing principle is the sequential checking of maximal 
// values according to the predefined filtering priority   
ArrayResize(ArrayTrans, ResizeArayNew - 1);
for(int PrioStep = 1; PrioStep < 4; PrioStep++)
  {
    for(PrCycle = 0; PrCycle < ResizeArayNew; PrCycle++)
      {
        Sort     = ArrayData[PrCycle][0];
        Prior1   = ArrayData[PrCycle][1];             
        transit  = ArrayData[PrCycle][2];
        Prior2   = ArrayData[PrCycle][3];             
        Prior3   = ArrayData[PrCycle][4];             
        transit1 = ArrayData[PrCycle][5];
        transit2 = ArrayData[PrCycle][6];
        transit3 = ArrayData[PrCycle][7];
        transit4 = ArrayData[PrCycle][8]; 
           
        if(PrioStep == 1)
          {
            //Prepare for the 1st sorting
            if(Gross_Profit ==1)
              {
                SortTrans = Prior1;
              }
            if(Profit_Factor == 1)
              {
                SortTrans = Prior2;
              }
            if(Expected_Payoff == 1)
              {
                SortTrans = Prior3;
              }
          }
        if(PrioStep == 2)
          {
            // Restore
            if(Gross_Profit ==1)
              {
                Prior1 = Sort;
              }
            if(Profit_Factor == 1)
              {
                Prior2 = Sort;
              }
            if(Expected_Payoff == 1)
              {
                Prior3 = Sort;
              } 
            //Prepare for the 2nd sorting
            if(Gross_Profit == 2)
              {
                SortTrans = Prior1;
              }
            if(Profit_Factor == 2)
              {
                SortTrans = Prior2;
              }
            if(Expected_Payoff == 2)
              {
                SortTrans = Prior3;
              }
          }
        if(PrioStep == 3)
          {
            // Restore
            if(Gross_Profit == 2)
              {
                Prior1 = Sort;
              }
            if(Profit_Factor == 2)
              {
                Prior2 = Sort;
              }
            if(Expected_Payoff == 2)
              {
                Prior3 = Sort;
              } 
            //Prepare for the 3rd sorting
            if(Gross_Profit ==3)
              {
                SortTrans = Prior1;
              }
            if(Profit_Factor == 3)
              {
                SortTrans = Prior2;
              }
            if(Expected_Payoff == 3)
              {
                SortTrans = Prior3;
              }
          }          
        ArrayTrans[PrCycle][0] = SortTrans;
        ArrayTrans[PrCycle][1] = Prior1;
        ArrayTrans[PrCycle][2] = transit;
        ArrayTrans[PrCycle][3] = Prior2;
        ArrayTrans[PrCycle][4] = Prior3;
        ArrayTrans[PrCycle][5] = transit1;
        ArrayTrans[PrCycle][6] = transit2;
        ArrayTrans[PrCycle][7] = transit3;
        ArrayTrans[PrCycle][8] = transit4;
      }
    ArraySort(ArrayTrans,StepRes, 0, MODE_DESCEND); // Sort the array
    ArrayResize(ArrayTrans, StepRes);               // Cut off the unnecessary things
    for(int CopyAr = 0; CopyAr < StepRes; CopyAr++)
      {
        ArrayData[CopyAr][0] = ArrayTrans[CopyAr][0];
        ArrayData[CopyAr][1] = ArrayTrans[CopyAr][1];
        ArrayData[CopyAr][2] = ArrayTrans[CopyAr][2];
        ArrayData[CopyAr][3] = ArrayTrans[CopyAr][3];
        ArrayData[CopyAr][4] = ArrayTrans[CopyAr][4];             
        // Per1    Variable 1
        ArrayData[CopyAr][5] = ArrayTrans[CopyAr][5];              
        // Per2    Variable 2
        ArrayData[CopyAr][6] = ArrayTrans[CopyAr][6];
        // Per3    Variable 3
        ArrayData[CopyAr][7] = ArrayTrans[CopyAr][7];
        // Per4    Variable 4
        ArrayData[CopyAr][8] = ArrayTrans[CopyAr][8];
      }
   StepRes = StepRes / 2;
  }

Se almacenan los valores filtrados de esta forma en las variables globales. Se sustituyen las variables del Asesor Experto a partir de los valores de las variables globales.

// Write the obtained results in variables
   double Peremen1 = ArrayTrans[0][5];                         
   double Peremen2 = ArrayTrans[0][6];
   double Peremen3 = ArrayTrans[0][7];
   double Peremen4 = ArrayTrans[0][8];
   // If the variable name is specified, write the result in 
   // global variables
   if(Per1 != "")
     {
       GlobalVariableSet(Per1, Peremen1);
     }             
   if(Per2 != "")
     {
       GlobalVariableSet(Per2,Peremen2);
     }
   if(Per3 != "")
     {
       GlobalVariableSet(Per3,Peremen3);
     }
   if(Per4 != "")
     {
       GlobalVariableSet(Per4,Peremen4);
     }
   Comment(Per1, " ", Peremen1, "  | ", Per2, " ", Peremen2, "  | ", Per3, 
           " ", Peremen3, "  | ", Per4, " ", Peremen4);
   Print(Per1, " ", Peremen1, "  | ", Per2, " ", Peremen2, "  | ", Per3, 
         " ", Peremen3,"  | ",Per4," ",Peremen4);
  }  // Function ends. That's all, automated optimization is complete.


Resultados del optimizador automático

Se pueden seguir los resultados del optimizador automático mediante los mensajes que aparecen en la esquina superior izquierda del gráfico, como se muestra en la siguiente captura de pantalla:

Tiempo estimado para finalizar la optimización.

Análisis de los valores obtenidos después de la optimización.

Resultados de las variables.

La aparición de los resultados de la optimización indica que esta última se ha completado y que los datos han sido recibidos.

Para hacer una evaluación del optimizador automático de un modo independiente, se puede echar un vistazo a todos los archivos guardados durante el proceso y que contienen datos intermedios. El probador almacena los datos en un archivo llamado "FileReport_EURUSD_2007.03. 12. htm", donde se sustituye el símbolo y la fecha del nombre del archivo por el símbolo seleccionado y la fecha de optimización. Se puede encontrar este archivo en la carpeta del Terminal-Tester. Estos archivos no se eliminan automáticamente de los registros y se pueden utilizar para realizar el seguimiento de cambio de los parámetros.



El siguiente archivo, FileTest1.csv, se guarda después del filtrado de los valores mediante el número de operaciones y el borrado de las duplicidades. Se guarda el archivo en: D:\Program Files\terminal_folder_ame\experts\files



Se almacenan los archivos obtenidos después de cada pasada en el archivo FileTest2.csv. Se guarda el archivo en esta carpeta también: D:\Program Files\terminal_folder_name\experts\files



Las tablas anteriores muestran cómo se filtran los valores obtenidos. Se ha establecido por defecto este orden de filtrado: 1- Gross_Profit, 2- Profit_Factor, 3- Expected_Payoff.

El optimizador automático incluye comentarios detallados y, si es necesario, se pueden elegir parámetros de variables más convenientes. Por ejemplo, quiere optimizar su Asesor Experto con un período de tiempo distinto a los últimos días, o tiene la intención de aumentar o disminuir el número de operaciones en el período de optimización. Para ello, sólo hay que cambiar las variables correspondientes en el propio auto_optimization.mqh.

// Limitation of minimal amount of trades per day
double MinTr   = TestDay - 2; 
// Limitation on maximal amount of trades per day
double MaxTr   = (60 / Period()*TestDay) + 2;
// The amount of attempts to copy the report file
int    KvoPptk = 10;
// The amount of strings to be sorted
int    StepRes = 12;

Conclusión

Este artículo no está destinado a enseñar los fundamentos de la optimización a los principiantes, por lo que es muy recomendable estudiar la optimización normal antes de configurar la optimización automática de su Asesor Experto. Es mejor utilizar el optimizador automático después de haber elegido las principales variables que afectan a su Asesor Experto de manera distinta y en distintos momentos. Es decir, es mejor utilizar este optimizador automático para ajustar los parámetros de las variables cuyos cambios afectan el funcionamiento del Asesor Experto más que los cambios de otras variables, dependiendo de la volatilidad del mercado.

Además, es mejor no establecer un período de optimización automática muy largo. Supongamos que el Asesor Experto se ha optimizado durante 6-12 horas cada día. Entonces surge la pregunta: ¿Cuándo va a operar? En otras palabras, la optimización no sirve de mucho por sí sola. Se recomienda establecer la periodicidad de la optimización (es decir, la periodicidad de ejecución del optimizador) teniendo en cuenta el período de tiempo en el cual se supone que está operando el Asesor Experto. Esto quiere decir que hay que tener en cuenta que los datos del historial serán transmitidos al iniciar el Terminal-Tester y es posible que el broker no dispone de los datos relevantes del historial para un determinado período de tiempo. Para comprobar la hipótesis descrita al inicio de este artículo, es necesario disponer de una conexión ininterrumpida y estable a Internet.

Los programas de optimización automático que se han desarrollado se encuentran en los archivos adjuntos: auto_optimization.mqh - la misma librería, MACD Sample_1.mq4 - el Asesor Experto incluido en el paquete estándar del Terminal de cliente MetaTrader 4, con una ligera modificación.