Optimización automática de EAs en MetaTrader 5

28 diciembre 2018, 07:52
BPASoftware Thai Co. Ltd
0
982

Introducción

En nuestro asesor Buddy Ilan se usan 4 parámetros básicos. Queríamos implementar una optimización semanal automática de estos parámetros para que el asesor se correspondiese al máximo con los cambios del mercado.

Los parámetros son:

  • SL - stop-loss
  • TP - take-profit
  • STOFilter - filtro
  • STOTimeFrameFilter - filtro del marco temporal

No es en absoluto realista iniciar manualmente este tipo de proceso cada semana, por eso hemos intentado buscar un mecanismo ya existente para realizar tareas repetitivas. Como no hemos logrado encontrar soluciones preparadas para MetaTrader 5, hemos decidido desarrollar nuestro propio mecanismo.

Querríamos expresar nuestra gratitud a Igor Maltsev, autor de "La optimización automática de un Asesor Experto en el trading real" para el terminal MetaTrader 4.


Principios de funcionamiento


El primer ejemplar del terminal MetaTrader 5 funciona en el modo 24/7, en este terminal ha sido iniciado el asesor Buddy Ilan y el experto sobre el que vamos a trabajar en este artículo (Optimizer EA). Este experto iniciará el proceso de optimización en el segundo ejemplar del terminal MetaTrader 5.

Al finalizar el proceso, el asesor Optimizer EA establecerá los valores optimizados en las variables globales que precisamente va a leer el experto Buddy Ilan.

La optimización se realizará todos los sábados sin ninguna intervención manual.


Copiando los datos

Como se ha dicho más arriba, vamos a necesitar dos ejemplares del terminal MetaTrader 5.

El primer ejemplar será el responsable del copiado de la configuración, los parámetros y los archivos de los informes entre los dos terminales.

Por motivos de seguridad, en MetaTrader 5 no es posible acceder a los archivos fuera del sandbox, por eso, para copiar datos entre los dos entornos, vamos a usar el comando MS-DOS "xcopy".

Para ello, usaremos una DLL basada en las bibliotecas de Windows, que declararemos de la forma siguiente:

#import  "shell32.dll"
int ShellExecuteW(int hwnd,string Operation,string
                  File,string Parameters,string Directory,int ShowCmd);
#import

Aquí tenemos la llamada a estas funciones:

string PathIniFile = sTerminalTesterDataPath + "\\config\\common.ini";
string PathTester=TerminalInfoString(TERMINAL_DATA_PATH)+"\\MQL5\\Files\\Optimiser\\";

int ret=ShellExecuteW(0,"Open","xcopy","\""+PathIniFile+"\" \""+PathTester+"\" /y","",0);

Esta función también se llamará para iniciar las optimizaciones, por ejemplo:

int start = ShellExecuteW(0, "Open", sTerminalTesterPath + "\\terminal64.exe", "/config:" + TerminalInfoString(TERMINAL_DATA_PATH) + "\\MQL5\\Files\\Optimiser\\optimise.ini", "", 0);
if(start<32)
  {
   Print("Error al iniciar el simulador");
   return false;
  }

Para este asesor, será necesario permitir la importación de DLL:

Importación de DLL


Optimización automática

La plataforma MetaTrader 5 se puede iniciar con comandos (ver "Inicio de la plataforma comercial"). Exactamente de la misma forma se pueden iniciar tareas automáticas.

Por ejemplo, es posible añadir el bloque de inicio "[Tester]" al archivo de configuración usado por defecto (common.ini), esto permitirá iniciar la optimización automática al iniciar MetaTrader 5.

Precisamente de ello nos vamos a ocupar.


Implementación

El asesor Optimizer EA deber conocer la ruta del ejemplar de MetaTrader 5 usado en la simulación. Estas rutas se indicarán como parámetros.

input string sTerminalTesterPath = "C:\\Program Files\\ForexTime MT5";
input string sTerminalTesterDataPath="C:\\Users\\BPA\\AppData\\Roaming\\MetaQuotes\\Terminal\\5405B7A2ED87FF45712A041DEF45780";

Hemos definido el catálogo de trabajo en el primer terminal MetaTrader 5: "MQL5\Files\Optimiser".

A continuación, la función "CopyAndMoveCommonIni()" copia el archivo estándar de configuración "common.ini" del ejemplar de MetaTrader 5 para realizar la prueba con el catálogo de trabajo y lo renombra como "optimise.ini".

bool CopyAndMoveCommonIni()
  {
   string PathIniFile= sTerminalTesterDataPath+"\\config\\common.ini";
   string PathTester = TerminalInfoString(TERMINAL_DATA_PATH)+"\\MQL5\\Files\\Optimiser\\";

   int ret=ShellExecuteW(0,"Open","xcopy","\""+PathIniFile+"\" \""+PathTester+"\" /y","",0);

// Esperamos el copiado del archivo
   Sleep(2500);
   if(ret<32)
     {
      Print("Error de copiado del archivo ini");
      return false;
     }

// Ahora trabajamos en el sandbox y podemos usar los comandos de archivo normales de MetaTrader 5
   string IniFileName="Optimiser\\common.ini";
   string CopyTo="Optimiser\\optimise.ini";

   return FileMove( IniFileName, 0, CopyTo, 0 );
  }

Podrá encontrar información más detallada sobre el funcionamiento de ShellExecuteW en la documentación de Microsoft para la función ShellExecuteW. La función no espera a la ejecución del comando MS-DOS, por eso se usa un retraso (Sleep 2500).

Ahora añadimos al archivo el bloque "Tester":

bool AddTesterStanza()
  {
   int filehandle=FileOpen("Optimiser\\Optimise.ini",FILE_READ|FILE_WRITE|FILE_TXT);

   if(filehandle!=INVALID_HANDLE)
     {
      FileSeek(filehandle,0,SEEK_END);

      FileWrite(filehandle,"[Tester]\n",
                "Expert=BuddyIlan\\BuddyIlan\n",
                "ExpertParameters=BuddyIlanTester.set\n",
                "Symbol="+_Symbol+"\n",
                "Period=M15\n",
                "Login=\n",
                "Model=4\n",
                "ExecutionMode=0\n",
                "Optimization=2\n",
                "OptimizationCriterion=0\n",
                "FromDate="+TimeToString(TimeGMT()-InpTesterPeriod*86400,TIME_DATE)+"\n",
                "ToDate="+TimeToString(TimeGMT(),TIME_DATE)+"\n",
                "ForwardMode=0\n",
                "Report=MQL5\\Files\\Reports\\BuddyIlanReport\n",
                "ReplaceReport=1\n",
                "ShutdownTerminal=1\n",
                "Deposit=10000\n",
                "Currency=EURUSD\n",
                "Leverage=1:100\n",
                "UseLocal=1\n",
                "UseRemote=0\n",
                "UseCloud=0\n",
                "Visual=1\n");

      FileClose(filehandle);
     }
   else
     {
      Print("FileOpen, error ",GetLastError());
      return false;
     }
   return true;
  }

Aquí definimos el asesor que vamos a optimizar ("BuddyIlan"), este asesor debe encontrarse necesariamente en el segundo entorno. De la misma manera determinamos el archivo de los parámetros del asesor "BuddyIlanTester.set" (el nombre deberá diferenciarse del nombre del experto), establecemos el intervalo (de FromDate a ToDate) y todos los parámetros necesarios para la optimización.

Establecemos "ShutdownTerminal=1", esto significa que el terminal será cerrado después de finalizar la optimización.

Así se formará también el archivo "Files\Reports\BuddyIlanReport", en este caso, además, la plataforma añadirá la extensión ".xlm".

Si usted inicia los asesores en un terminal que funcione en un servidor virtual con recursos computacionales limitados, podrá utilizar para la optimización tanto agentes de simulación remotos como en la nube ("UseRemote" o "UseCloud").


Archivo de los parámetros

A continuación, deberemos conformar el archivo de parámetros definido más arriba (BuddyIlanTester.set), en este se encontrarán los valores de cada parámetro optimizado del asesor (Buddy Ilan).

El usuario establece los valores de estos parámetros por defecto (se definen como parámetros):

input _TradingMode TradingMode = Dynamic;             // volumen fijo o dinámico
input double  InpIlanFixedVolume = 0.1;               // Tamaño del volumen fijo (si se usa)

input int InpNCurrencies=1;                           // Número de ejemplares del asesor Buddy Ilan en la cuenta

input double  LotExponent = 1.4;
input bool    DynamicPips = true;
input int     DefaultPips = 15;

input int Glubina=24;                                 // Número de últimas barras para el cálculo de la volatilidad
input int DEL=3;

input int TakeProfit = 40.0;                          // Take-profit en puntos
input int Stoploss = 1000.0;                          // Stop-loss en puntos

input bool InpIlanTrailingStop = true;                // Usar trailing-stop
input int InpIlanDistanceTS = 5;                      // Distancia del trailing-stop en puntos

input int MaxTrades=10;
input int InpDeviation=10;                            // Desviación máxima permitida en puntos

input bool bSTOFilter = true;                         // Filtro dinámico de tendencia
input bool bSTOTimeFrameFilter = false;               // Filtro dinámico de marco temporal
input int InpMaxTf = 60;                              // Marco temporal máximo

La función mostrada más abajo aplica 8 argumentos; los 4 primeros se correspoden con los parámetros optimizables (SL, TP, STOFilter y STOTimeFrameFilter). Con el valor true, se añade "Y" al final de la línea de parámetros correspondiente. Los 4 argumentos siguientes corresponden ya a los valores optimizados que deben considerarse en la siguiente optimización.

Como podemos ver por el nombre, la función también copia el archivo de parámetros en el catálogo existente del ejemplar del terminal MetaTrader 5 utilizado para la simulación (MQL5\Profiles\Tester).

bool CreateAndCopyParametersFile( bool SL, bool TP, bool STOFilter, bool STOTimeFrameFilter, int SLValue, int TPValue, bool STOFilterValue, bool STOTimeFrameFilterValue )
  {
   int filehandle=FileOpen("Optimiser\\BuddyIlanTester.set",FILE_WRITE|FILE_TXT);

   if(filehandle!=INVALID_HANDLE)
     {
      FileWrite(filehandle,
                "_EA_IDENTIFIER=Buddy Ilan\n",
                "_EA_MAGIC_NUMBER=1111||0||1||10||N\n",
                StringFormat("TradingMode=%d||0||0||0||N\n",TradingMode),
                StringFormat("InpIlanFixedVolume=%lf||0.0||0.000000||0.000000||N\n",InpIlanFixedVolume),
                StringFormat("InpNCurrencies=%d||0||1||10||N\n",InpNCurrencies),
                StringFormat("LotExponent=%lf||0.0||0.000000||0.000000||N\n",LotExponent),
                StringFormat("DynamicPips=%s||false||0||true||N\n",(DynamicPips==true)?"true":"false"),
                StringFormat("DefaultPips=%d||0||1||10||N\n",DefaultPips),
                StringFormat("Glubina=%d||0||1||10||N\n",Glubina),
                StringFormat("DEL=%d||0||1||10||N\n",DEL),

                StringFormat("TakeProfit=%d||30||10||70||%s\n",(TPValue==0)?30:TPValue,(TP==true)?"Y":"N"),
                StringFormat("Stoploss=%d||500||250||1500||%s\n",(SLValue==0)?1000:SLValue,(SL==true)?"Y":"N"),

                StringFormat("InpIlanTrailingStop=%s||false||0||true||N\n",(InpIlanTrailingStop==true)?"true":"false"),
                StringFormat("InpIlanDistanceTS=%d||0||1||10||N\n",InpIlanDistanceTS),
                StringFormat("MaxTrades=%d||0||1||10||N\n",MaxTrades),
                StringFormat("InpDeviation=%d||0||1||10||N\n",InpDeviation),

                StringFormat("bSTOFilter=%s||false||0||true||%s\n",(STOFilterValue==true)?"true":"false",(STOFilter==true)?"Y":"N"),
                StringFormat("bSTOTimeFrameFilter=%s||false||0||true||%s\n",(STOTimeFrameFilterValue==true)?"true":"false",(STOTimeFrameFilter==true)?"Y":"N"),
                StringFormat("InpMaxTf=%d||0||1||10||N\n",InpMaxTf));

      FileClose(filehandle);
     }
   else
     {
      Print("FileOpen BuddyIlanTester.set, error ",GetLastError());
      return false;
     }

   Sleep(1500);

   string PathTester=TerminalInfoString(TERMINAL_DATA_PATH)+"\\MQL5\\Files\\Optimiser\\BuddyIlanTester.set";
   string PathProfile=sTerminalTesterDataPath+"\\MQL5\\Profiles\\Tester\\";

// Copiamos el archivo ini en el catálogo del simulador 
   int ret=ShellExecuteW(0,"Open","xcopy","\""+PathTester+"\" \""+PathProfile+"\" /y","",0);

// Esperamos el copiado del archivo
   Sleep(2500);
   if(ret<32)
     {
      Print("Error al copiar el archivo de parámetros");
      return false;
     }
   return true;
  }


Iniciando la optimización

La siguiente función inicia el ejemplar de simulación de MetaTrader 5, en este caso, además, la optimización comienza de forma automática con los parámetros que hemos indicado. Este segundo ejemplar formará el archivo con los resultados, después de lo cual el terminal se cerrará.

bool StartOptimizer()
  {
// Eliminando el informe anterior
   FileDelete("Optimiser\\BuddyIlanReport.xml");

// Eliminamos el informe anterior (segundo ejemplar de MetaTrader 5)
   string PathReport=sTerminalTesterDataPath+"\\MQL5\\Files\\Reports\\BuddyIlanReport.xml";

   ShellExecuteW(0,"Open","cmd.exe"," /C del "+PathReport,"",0);

   Sleep(2500);

   string sTerminalPath=TerminalInfoString(TERMINAL_PATH);

// Iniciando el proceso de optimización
   int start=ShellExecuteW(0,"Open",sTerminalTesterPath+"\\terminal64.exe","/config:"+TerminalInfoString(TERMINAL_DATA_PATH)+"\\MQL5\\Files\\Optimiser\\optimise.ini","",0);
   if(start<32)
     {
      Print("Error al iniciar el simulador");
      return false;
     }
   Sleep(15000);
   return true;
  }

El método más sencillo para saber si la optimización del primer terminal ha finalizado es comprobar si existe el archivo del informe.

Después de que el archivo del informe haya sido creado, lo copiamos al catálogo de trabajo.

bool CopyReport()
  {
   int nTry=0;

// Esperamos y copiamos el archivo del informe

   while(nTry++<500) // Timeout: 2 horas
     {
      string PathReport = sTerminalTesterDataPath + "\\MQL5\\Files\\Reports\\BuddyIlanReport.xml";
      string PathTarget = TerminalInfoString(TERMINAL_DATA_PATH) + "\\MQL5\\Files\\Optimiser\\";

      int ret=ShellExecuteW(0,"Open","xcopy","\""+PathReport+"\" \""+PathTarget+"\" /y","",0);

      if(ret<32)
        {
         PrintFormat("Esperando la formación del informe (%d) ...",nTry);
         Sleep(15000);
        }
      else
        {
         if(FileIsExist("Optimiser\\BuddyIlanReport.xml")==true)
           {
            PrintFormat("Informe localizado (ret=%d) ...",ret);
            Sleep(2500);
            return true;
           }
         else
           {
            PrintFormat("Esperando el informe (%d) ...",nTry);
            Sleep(15000);
           }
        }
     }
   return false;
  }


Leyendo los resultados

El archivo del informe se crea en formato XML. Afortunadamente, disponemos de una biblioteca para trabajar con estos datos. Dicha biblioteca fue escrita por Paul van Hemmen, al que agradecemos mucho su trabajo. Podrá descargar la biblioteca aquí: https://www.mql5.com/es/code/1998.

Vamos a añadir esta biblioteca a nuestro asesor:

#include <EasyXML\EasyXml.mqh>

Hemos añadido una función e introducido pequeños cambios en la biblioteca, para adaptarla a nuestros archivos de informes (ver los archivos adjuntos).

//+------------------------------------------------------------------+
//| Load XML by given file                                           |
//+------------------------------------------------------------------+
bool CEasyXml::loadXmlFromFullPathFile(string pFilename)
  {
   string sStream;
   int    iStringSize;

   Print("Loading XML File ",pFilename);
   int hFile=FileOpen(pFilename,FILE_ANSI|FILE_READ,0,CP_UTF8);
   if(hFile==INVALID_HANDLE)
     {
      Err=EASYXML_ERR_CONNECTION_FILEOPEN;
      PrintFormat("[%s] Err=%d",pFilename,GetLastError());
      return(Error());
     }

   while(!FileIsEnding(hFile))
     {
      iStringSize = FileReadInteger(hFile, INT_VALUE);
      sStream    += FileReadString(hFile, iStringSize);
     }

   FileClose(hFile);

   return(loadXmlFromString(sStream));
  }

El acceso a los datos se ha organizado de una forma bastante sencilla: hay varias funciones que nos permiten analizar los resultados y leer los datos que nos interesen.

bool LoadResults( OptimisationType eType )
  {
// Variable Init
   BetterProfit=0.0;

// Cargando resultados
   CEasyXml EasyXmlDocument;
   EasyXmlDocument.setDebugging(false);

   if(EasyXmlDocument.loadXmlFromFullPathFile("Optimiser\\BuddyIlanReport.xml")==true)
     {
      str="";
      CEasyXmlNode *RootNode=EasyXmlDocument.getDocumentRoot();
      for(int j=0; j<RootNode.Children().Total(); j++)
        {
         CEasyXmlNode *ChildNode=RootNode.Children().At(j);
         for(int i=0; i<ChildNode.Children().Total(); i++)
           {
            CEasyXmlNode *cNode=ChildNode.Children().At(i);
            if(cNode.getName() == "Worksheet" )
              {
               switch(eType)
                 {
                  case _SL :
                     DisplayNodesSL(cNode);
                     PrintFormat("-> SL=%d (Profit=%.2lf)",BetterSL,BetterProfit);
                     break;

                  case _TP :
                     DisplayNodesTP(cNode);
                     PrintFormat("-> TP=%d (Profit=%.2lf DD=%lf)",BetterTP,BetterProfit,BetterDD);
                     break;

                  case _STO :
                     DisplayNodesSTO(cNode);
                     PrintFormat("-> STOFilter=%s STOTimeFrameFilter=%s (Profit=%.2lf)",(BetterSTOFilter==true)?"true":"false",(BetterSTOTimeFrameFilter==true)?"true":"false",BetterProfit);
                     break;
                 }
               break;
              }
           }
        }
     }
   else
      PrintFormat("Error");
   return true;
  }

Puesto que debemos optimizar varios parámetros y sus resultados deberán ser analizados de formas distintas, vamos a necesitar una función aparte para cada optimización (para los parámetros SL, TP y STO). Se trata de funciones recursivas.

Aquí tenemos la función para analizar los resultados de optimización del parámetro SL:

void DisplayNodesSL( CEasyXmlNode *Node )
  {
   for(int i=0; i<Node.Children().Total(); i++)
     {
      CEasyXmlNode *ChildNode=Node.Children().At(i);

      if(ChildNode.Children().Total()==0)
        {
         str+=ChildNode.getValue()+",";
        }
      else
        {
         DisplayNodesSL(ChildNode);

         if(Node.getName()=="Table" && ChildNode.getName()=="Row")
           {
            string res[];
            StringSplit(str,',',res);

            // Iterando los encabezados de las columnas
            if(StringCompare(res[0],"Pass",true)!=0)
              {
               double profit=StringToDouble(res[2]);
               int sl=(int) StringToInteger(res[10]);

               PrintFormat("[%s]  Profit=%.2lf StopLoss=%d DD=%s",str,profit,sl,res[8]);

               if(profit>BetterProfit || (profit==BetterProfit && sl<BetterSL))
                 {
                  BetterProfit=profit;
                  BetterSL=sl;
                 }
              }
           }
         if(Node.getName()=="Table")
            str="";
        }
     }
  }

Esta función se llama para cada línea y celda.

Si el nodo no tiene descendientes, esto significa que contiene datos, así que guardamos estos datos como tipo de cadena y dividimos al final de la línea.

if( ChildNode.Children().Total() == 0 )
  {
   str+=ChildNode.getValue()+",";
  }

De esta forma, los valores para cada columna estarán disponibles en la matriz "res[]", y podremos elegir los resultados deseados.


Cuerpo del asesor

Ahora tenemos todo los elementos necesarios para optimizar nuestros cuatro parámetros, buscar los mejores valores de los parámetros y asignar estos valores a las variables globales correspondientes que leerá el asesor Buddy Ilan iniciado.

void OnTimer()
  {
   MqlDateTime dt;

   datetime now=TimeLocal(dt);

// El sábado
   if(dt.day_of_week!=6)
     {
      bOptimisationDone=false;
      return;
     }

// A las 6:00
   if(dt.hour<6)
      return;

// ¿Ya está hecho?
   if(bOptimisationDone==true)
      return;

// Eliminamos el anterior archivo "optimise.ini"
   FileDelete("Optimiser\\Optimise.ini");

// Creamos el archivo de configuración del asesor y lo copiamos en la carpeta \MQL5\Profiles\Test (ejemplar para la simulación)
   if(CreateAndCopyParametersFile(true,false,false,false,0,0,true,false)==false)
      return;

// Copiamos common.ini -> optimise.ini
   if(CopyAndMoveCommonIni()==false)
      return;

// Añadimos el inicio [Tester] a optimise.ini - https://www.metatrader5.com/es/terminal/help/start_advanced/start
   if(AddTesterStanza()==false)
      return;

   Print("=======================\nOptimizando SL-1");

// Iniciando la primera optimización de SL
   StartOptimizer();

// Copiamos el archivo del informe en el catálogo de trabajo
   if(CopyReport()==false)
      return;

// Analizando los informes   
   if(LoadResults(_SL)==false)
      return;

   Print("=======================\nOptimizando STO");

// Creamos el archivo con los parámetros para la optimización de STO (se optimizarán 2 parámetros simultáneamente) 
   if(CreateAndCopyParametersFile(false,false,true,true,BetterSL,0,true,false)==false)
      return;

// Iniciando la optimización de STO
   StartOptimizer();

// Copiamos el archivo del informe en el catálogo de trabajo
   if(CopyReport()==false)
      return;

   if(LoadResults(_STO)==false)
      return;

   Print("=======================\nOptimizando SL-2");

// Creamos el archivo con los parámetros para la optimización de SL (recálculo con los nuevos valores del parámetro STO)
   if(CreateAndCopyParametersFile(true,false,false,false,0,0,BetterSTOFilter,BetterSTOTimeFrameFilter)==false)
      return;

// Iniciando el optimizador   
   StartOptimizer();

   if(CopyReport()==false)
      return;

   if(LoadResults(_SL)==false)
      return;

   Print("=======================\nOptimizando TP");

// Creamos el archivo con los parámetros para optimizar TP
   if(CreateAndCopyParametersFile(false,true,false,false,BetterSL,0,BetterSTOFilter,BetterSTOTimeFrameFilter)==false)
      return;

// Iniciando el optimizador  
   StartOptimizer();

   if(CopyReport()==false)
      return;

   if(LoadResults(_TP)==false)
      return;

// Conclusión

   PrintFormat("=======================\nSL=%d TP=%d STOFilter=%s STOTimeFrameFilter=%s (Profit=%.2lf DD=%lf)\n=======================",
               BetterSL,BetterTP,(BetterSTOFilter==true)?"true":"false",(BetterSTOTimeFrameFilter==true)?"true":"false",BetterProfit,BetterDD);

// Establecemos las variables globales, el asesor de trabajo BuddyIlan leerá y utilizará estos nuevos valores

// Si se detecta una reducción mayor al 50%, el asesor interrumpirá el comercio
   if(BetterDD>50.0 && GlobalVariableSet(gVarStop,1.0)==false)
     {
      PrintFormat("Error al establecer la variable global [%s]",gVarStop);
     }

   if(GlobalVariableSet(gVarSL,BetterSL)==false)
     {
      PrintFormat("Error al establecer la variable global [%s]=%d",gVarSL,BetterSL);
     }

   if(GlobalVariableSet(gVarTP,BetterTP)==false)
     {
      PrintFormat("Error al establecer la variable global [%s]=%d",gVarTP,BetterTP);
     }

   if(GlobalVariableSet(gVarSTOFilter,(BetterSTOFilter==true)?1.0:0.0)==false)
     {
      PrintFormat("Error al establecer la variable global [%s]=%.1lf",gVarSTOFilter,(BetterSTOFilter==true)?1.0:0.0);
     }

   if(GlobalVariableSet(gVarSTOTimeFrameFilter,(BetterSTOTimeFrameFilter==true)?1.0:0.0)==false)
     {
      PrintFormat("Error al establecer la variable global [%s]=%.1lf",gVarSTOTimeFrameFilter,(BetterSTOTimeFrameFilter==true)?1.0:0.0);
     }

   bOptimisationDone=true;
  }

Los nombres de las variables globales se crearán en la función OnInit():

int OnInit()
  {
//Variables globales

   gVarStop="BuddyIlan."+_Symbol+".Stop";
   gVarSL = "BuddyIlan." + _Symbol + ".SL";
   gVarTP = "BuddyIlan." + _Symbol + ".TP";
   gVarSTOFilter="BuddyIlan."+_Symbol+".STOFilter";
   gVarSTOTimeFrameFilter="BuddyIlan."+_Symbol+".STOTimeFrameFilter";

Más abajo se muestra el proceso de optimización completo:

2018.07.07 13:20:15.978 BuddyIlanOptimizer (EURGBP,M15) TERMINAL_PATH = C:\Program Files\MetaTrader 5 - ActivTrades
2018.07.07 13:20:15.978 BuddyIlanOptimizer (EURGBP,M15) TERMINAL_DATA_PATH = C:\Users\BPA\AppData\Roaming\MetaQuotes\Terminal\FE0E65DDB0B7B40DE125080872C34D61
2018.07.07 13:20:15.978 BuddyIlanOptimizer (EURGBP,M15) TERMINAL_COMMONDATA_PATH = C:\Users\BPA\AppData\Roaming\MetaQuotes\Terminal\Common
2018.07.07 13:20:32.586 BuddyIlanOptimizer (EURGBP,M15) =======================
2018.07.07 13:20:32.586 BuddyIlanOptimizer (EURGBP,M15) Optimization SL-1
2018.07.07 13:20:50.439 BuddyIlanOptimizer (EURGBP,M15) Waiting report (1) ...
2018.07.07 13:21:05.699 BuddyIlanOptimizer (EURGBP,M15) Waiting report (2) ...
2018.07.07 13:21:20.859 BuddyIlanOptimizer (EURGBP,M15) Waiting report (3) ...
2018.07.07 13:21:35.952 BuddyIlanOptimizer (EURGBP,M15) Report found (ret=42) ...
2018.07.07 13:21:38.471 BuddyIlanOptimizer (EURGBP,M15) Loading XML File Optimiser\BuddyIlanReport.xml
2018.07.07 13:21:38.486 BuddyIlanOptimizer (EURGBP,M15) [0,11032.2600,1032.2600,3.3406,1.7096,1.5083,0.1558,0,6.2173,309,500,]  Profit=1032.26 StopLoss=500 DD=6.2173
2018.07.07 13:21:38.487 BuddyIlanOptimizer (EURGBP,M15) [2,11463.8000,1463.8000,4.7837,2.0386,0.8454,0.1540,0,15.4222,306,1000,]  Profit=1463.80 StopLoss=1000 DD=15.4222
2018.07.07 13:21:38.487 BuddyIlanOptimizer (EURGBP,M15) [4,11444.1000,1444.1000,4.7348,2.0340,0.8340,0.1529,0,15.4493,305,1500,]  Profit=1444.10 StopLoss=1500 DD=15.4493
2018.07.07 13:21:38.487 BuddyIlanOptimizer (EURGBP,M15) [1,11297.1900,1297.1900,4.2392,1.8414,0.8180,0.1400,0,14.1420,306,750,]  Profit=1297.19 StopLoss=750 DD=14.1420
2018.07.07 13:21:38.487 BuddyIlanOptimizer (EURGBP,M15) [3,11514.0800,1514.0800,4.9158,2.3170,1.4576,0.2055,0,9.3136,308,1250,]  Profit=1514.08 StopLoss=1250 DD=9.3136
2018.07.07 13:21:38.487 BuddyIlanOptimizer (EURGBP,M15) -> SL=1250 (Profit=1514.08)
2018.07.07 13:21:38.487 BuddyIlanOptimizer (EURGBP,M15) =======================
2018.07.07 13:21:38.487 BuddyIlanOptimizer (EURGBP,M15) Optimization STO
2018.07.07 13:22:02.660 BuddyIlanOptimizer (EURGBP,M15) Waiting report (1) ...
2018.07.07 13:22:17.768 BuddyIlanOptimizer (EURGBP,M15) Waiting report (2) ...
2018.07.07 13:22:32.856 BuddyIlanOptimizer (EURGBP,M15) Waiting report (3) ...
2018.07.07 13:22:47.918 BuddyIlanOptimizer (EURGBP,M15) Waiting report (4) ...
2018.07.07 13:23:02.982 BuddyIlanOptimizer (EURGBP,M15) Report found (ret=42) ...
2018.07.07 13:23:05.485 BuddyIlanOptimizer (EURGBP,M15) Loading XML File Optimiser\BuddyIlanReport.xml
2018.07.07 13:23:05.499 BuddyIlanOptimizer (EURGBP,M15) [0,11463.5000,1463.5000,4.4483,2.0614,0.8452,0.1540,0,15.4267,329,false,false,]  Profit=1463.50 false false  DD=15.4267
2018.07.07 13:23:05.499 BuddyIlanOptimizer (EURGBP,M15) [1,11444.1000,1444.1000,4.7348,2.0340,0.8340,0.1529,0,15.4493,305,true,false,]  Profit=1444.10 true false  DD=15.4493
2018.07.07 13:23:05.499 BuddyIlanOptimizer (EURGBP,M15) [2,11430.5300,1430.5300,5.1090,2.1548,0.8917,0.1717,0,14.4493,280,false,true,]  Profit=1430.53 false true  DD=14.4493
2018.07.07 13:23:05.499 BuddyIlanOptimizer (EURGBP,M15) [3,11470.7100,1470.7100,6.2851,1.8978,0.8146,0.1288,0,17.3805,234,true,true,]  Profit=1470.71 true true  DD=17.3805
2018.07.07 13:23:05.499 BuddyIlanOptimizer (EURGBP,M15) -> STOFilter=true STOTimeFrameFilter=true (Profit=1470.71)
2018.07.07 13:23:05.500 BuddyIlanOptimizer (EURGBP,M15) =======================
2018.07.07 13:23:05.500 BuddyIlanOptimizer (EURGBP,M15) Optimization SL-2
2018.07.07 13:23:29.921 BuddyIlanOptimizer (EURGBP,M15) Waiting report (1) ...
2018.07.07 13:23:45.043 BuddyIlanOptimizer (EURGBP,M15) Waiting report (2) ...
2018.07.07 13:24:00.170 BuddyIlanOptimizer (EURGBP,M15) Waiting report (3) ...
2018.07.07 13:24:15.268 BuddyIlanOptimizer (EURGBP,M15) Waiting report (4) ...
2018.07.07 13:24:30.340 BuddyIlanOptimizer (EURGBP,M15) Report found (ret=42) ...
2018.07.07 13:24:32.854 BuddyIlanOptimizer (EURGBP,M15) Loading XML File Optimiser\BuddyIlanReport.xml
2018.07.07 13:24:32.872 BuddyIlanOptimizer (EURGBP,M15) [0,9269.9000,-730.1000,-2.7760,0.7328,-0.3644,-0.0532,0,19.4241,263,500,]  Profit=-730.10 StopLoss=500 DD=19.4241
2018.07.07 13:24:32.872 BuddyIlanOptimizer (EURGBP,M15) [4,11470.7100,1470.7100,6.2851,1.8978,0.8146,0.1288,0,17.3805,234,1500,]  Profit=1470.71 StopLoss=1500 DD=17.3805
2018.07.07 13:24:32.872 BuddyIlanOptimizer (EURGBP,M15) [3,11475.9500,1475.9500,6.2806,1.8995,0.8175,0.1290,0,17.3718,235,1250,]  Profit=1475.95 StopLoss=1250 DD=17.3718
2018.07.07 13:24:32.872 BuddyIlanOptimizer (EURGBP,M15) [2,11400.7500,1400.7500,5.8609,1.8442,0.7759,0.1292,0,17.3805,239,1000,]  Profit=1400.75 StopLoss=1000 DD=17.3805
2018.07.07 13:24:32.872 BuddyIlanOptimizer (EURGBP,M15) [1,10662.5500,662.5500,2.8807,1.3618,0.3815,0.0862,0,16.7178,230,750,]  Profit=662.55 StopLoss=750 DD=16.7178
2018.07.07 13:24:32.873 BuddyIlanOptimizer (EURGBP,M15) -> SL=1250 (Profit=1475.95)
2018.07.07 13:24:32.873 BuddyIlanOptimizer (EURGBP,M15) =======================
2018.07.07 13:24:32.873 BuddyIlanOptimizer (EURGBP,M15) Optimization TP
2018.07.07 13:24:57.175 BuddyIlanOptimizer (EURGBP,M15) Waiting report (1) ...
2018.07.07 13:25:12.311 BuddyIlanOptimizer (EURGBP,M15) Waiting report (2) ...
2018.07.07 13:25:27.491 BuddyIlanOptimizer (EURGBP,M15) Waiting report (3) ...
2018.07.07 13:25:42.613 BuddyIlanOptimizer (EURGBP,M15) Waiting report (4) ...
2018.07.07 13:25:57.690 BuddyIlanOptimizer (EURGBP,M15) Report found (ret=42) ...
2018.07.07 13:26:00.202 BuddyIlanOptimizer (EURGBP,M15) Loading XML File Optimiser\BuddyIlanReport.xml
2018.07.07 13:26:00.219 BuddyIlanOptimizer (EURGBP,M15) [1,11768.5700,1768.5700,8.2259,2.4484,1.1024,0.2233,0,14.1173,215,40,]  Profit=1768.57 TakeProfit=40 DD=14.117300
2018.07.07 13:26:00.219 BuddyIlanOptimizer (EURGBP,M15) [4,12343.5200,2343.5200,13.5464,2.5709,1.3349,0.2519,0,15.0389,173,70,]  Profit=2343.52 TakeProfit=70 DD=15.038900
2018.07.07 13:26:00.219 BuddyIlanOptimizer (EURGBP,M15) [0,11243.4600,1243.4600,5.2913,1.6399,0.6887,0.1039,0,17.3805,235,30,]  Profit=1243.46 TakeProfit=30 DD=17.380500
2018.07.07 13:26:00.219 BuddyIlanOptimizer (EURGBP,M15) [3,12292.3500,2292.3500,11.8162,2.5837,0.9257,0.2538,0,20.4354,194,60,]  Profit=2292.35 TakeProfit=60 DD=20.435400
2018.07.07 13:26:00.219 BuddyIlanOptimizer (EURGBP,M15) [2,12146.3900,2146.3900,11.0639,2.4416,1.2226,0.2292,0,15.0772,194,50,]  Profit=2146.39 TakeProfit=50 DD=15.077200
2018.07.07 13:26:00.219 BuddyIlanOptimizer (EURGBP,M15) -> TP=70 (Profit=2343.52 DD=15.038900)
2018.07.07 13:26:00.219 BuddyIlanOptimizer (EURGBP,M15) =======================
2018.07.07 13:26:00.219 BuddyIlanOptimizer (EURGBP,M15) SL=1250 TP=70 STOFilter=true STOTimeFrameFilter=true (Profit=2343.52 DD=15.038900)
2018.07.07 13:26:00.219 BuddyIlanOptimizer (EURGBP,M15) =======================


Conclusión

Para implementar este proceso, necesitaremos tener unos conocimientos mínimos del terminal MetaTrader 5 y sus mecanismos, así como de programación.

Hemos adjuntado al artículo los códigos fuente de este asesor, la utilidad XML Parser de Paul van Hemmen y el archivo modificado "EasyXml.mqh".

Esperamos que el artículo les resulte útil.

Traducción del inglés realizada por MetaQuotes Software Corp.
Artículo original: https://www.mql5.com/en/articles/4917

Archivos adjuntos |
Files.zip (14.39 KB)
Métodos de control remoto de EAs Métodos de control remoto de EAs

La principal ventaja de los robots comerciales es su funcionamiento ininterrumpido las 24 horas del día en un servidor VPS remoto. Pero a veces es necesario intervenir en su funcionamiento manualmente, y ahora no disponemos de acceso directo al servidor. ¿Podemos gestionar de forma remota el funcionamiento del asesor? En este artículo se presenta una de las variantes de control de robots a través de comandos externos.

Implementación de Take Profit en forma de órdenes limitadas sin cambiar el código fuente del EA Implementación de Take Profit en forma de órdenes limitadas sin cambiar el código fuente del EA

Desde hace mucho en el foro se discute la cuestión del uso de órdenes limitadas en vez de colocar el Take Profit estándar para la posición. ¿En qué consiste la ventaja de este enfoque y cómo se puede implementarlo en la negociación? En este artículo me gustaría proponerles mi propia visión de las respuestas a estas preguntas.

Gap - ¿una estrategia rentable o 50/50? Gap - ¿una estrategia rentable o 50/50?

La investigación de la aparición de gaps se relaciona con la situación en la que se da una diferencia sustancial entre el precio de cierre del marco temporal anterior y el precio de apertura del siguiente, así como en la dirección en la que irá la barra diaria. Uso de la función DLL GetOpenFileName de sistema.

Patrones de viraje: Poniendo a prueba el patrón "Pico/valle doble" Patrones de viraje: Poniendo a prueba el patrón "Pico/valle doble"

En la práctica del comercio, los tráders buscan con frecuencia los puntos de viraje de tendencia, puesto que precisamente en el momento en el que surge una tendencia, el precio tiene el mayor potencial de movimiento. Precisamente por ello, en la práctica del análisis técnico se analizan diferentes patrones de viraje. Uno de los más famosos y más utilizados en el patrón del pico/valle doble. En este artículo ofrecemos una variante de detección automática del patrón, y también ponemos a prueba su rentabilidad con datos históricos.