English Русский 中文 Deutsch 日本語 Português Türkçe
preview
Aproximación por fuerza bruta a la búsqueda de patrones (Parte II): Nuevos horizontes

Aproximación por fuerza bruta a la búsqueda de patrones (Parte II): Nuevos horizontes

MetaTrader 5Probador | 12 abril 2021, 17:11
650 0
Evgeniy Ilin
Evgeniy Ilin

Contenido


Introducción

En artículo anterior mostramos que resulta posible crear asesores rentables usando un mecanismo tan sencillo como la fuerza bruta, en gran parte debido a que este enfoque, como cualquier otro, no es peor que los demás. En realidad, este tema conecta con el del artículo "Enfoque ideal sobre el desarrollo y el análisis de sistemas comerciales", y especialmente con el apartado "Las matemáticas de una búsqueda óptima". Al crear este software, se hizo hincapié en las ideas formuladas en este artículo. En general, el artículo tiene el objeto de continuar modernizando los algoritmos de nuestro programa para obtener indicadores de mayor calidad de las opciones encontradas, y también para investigar el mercado con mayor detalle en diferentes días de la semana y en diferentes corredores temporales.

Varios de nuestros asesores demuestran que este enfoque tiene razón de ser. Existen diferentes patrones en distintas parejas de divisas. Hay estrechos corredores temporales que funcionan en todas las parejas de divisas: lo único que necesitamos es realizar un análisis exhaustivo, cosa que haremos en el presente artículo. No podemos realizar dicho análisis sin usar software adicional. También queremos decir que no consideramos que nuestro software sea el mejor de su tipo, y aún menos lo consideramos el Grial.

Inicialmente, el programa era un programa de investigación y solo resultaba adecuado como un conjunto adicional de herramientas para analizar varios instrumentos, pero ahora sus capacidades han aumentado drásticamente. Y dado que este enfoque funciona, ¿por qué no aprovecharlo al máximo? Creemos que vale la pena intentarlo. En general, y siendo honestos, consideramos enfoques como las redes neuronales, la inteligencia artificial e incluso el propio aumento de gradiente, mucho más progresivos, pero, como ha resultado, este enfoque puede competir con estos métodos de análisis. También debemos considerar que la base sigue partiendo de unas matemáticas demasiado simples. Y esto se encuentra lejos de alcanzar el techo.


Nuevos pensamientos e ideas

El programa se encontraba en la etapa de prototipo, y queríamos exprimirlo al máximo para ver de qué era capaz incluso un método de búsqueda tan sencillo como la enumeración aleatoria de números. El principal problema era que, para lograr una búsqueda fiable de patrones globales, teníamos que tomar grandes secciones de las cotizaciones y, al mismo tiempo, la duración de una pasada a través de la historia era horriblemente baja. Por ejemplo, al analizar las cotizaciones M5 de cualquier pareja de divisas durante 10 años, el programa producía alrededor de 700-2000 variantes por hora en 1 buen núcleo, y eso teniendo en cuenta que los ajustes eran de ahorro.

Si consideramos que tenemos un servidor con 30 núcleos, incluso aquí la velocidad no resultará muy alta y aún tendremos que esperar días. La única solución es reducir la cantidad de datos a analizar; solo podemos hacer esto cortando el intervalo completo en partes iguales y omitiendo periódicamente algunos de ellos sin realizar cálculos. Tenemos intervalos así: días, meses, años, minutos y horas. Además, cada una de estas áreas condicionales caracteriza ciertos parámetros comerciales. En otras palabras, además de la aceleración, también tenemos la posibilidad de analizar con detalle todos los días de la semana, así como las horas y los minutos para detectar la presencia de patrones. Ni siquiera debemos pensar por qué se da dicho patrón.

En general, resulta imposible clasificar todos los patrones, porque puede haber un número infinito de ellos, y el cerebro humano no es capaz de comprenderlos y describirlos todos (tampoco es necesario) cuando hay una fórmula de trabajo. Los matemáticos comprenderán al autor. Podemos investigar tanto un periodo de tiempo fijo como días fijos, o investigar todo al mismo tiempo. Podemos realizar la siguiente comparación: supongamos que tenemos una función de una variable, y luego resulta que se trata de un caso especial de una función con muchas variables, solo que antes no sabíamos esto, y, al mismo tiempo, se ha vuelto aún más simple.


Segmentación de la muestra y previsibilidad de las muestras aleatorias

Consideramos que sería bastante interesante analizar esta cuestión, porque, como ha resultado, los modos de búsqueda de patrones son muy diferentes en sus capacidades superiores precisamente porque se analizan muestras completamente diferentes en términos de duración. Además de acelerar sustancialmente los cálculos (hasta en decenas de veces, en algunos casos), resulta fácil adivinar que, a partir de la muestra (cotización) inicial, podemos obtener una muestra más útil, aunque más pequeña. Una muestra que podemos analizar utilizando algunas fórmulas o polinomios simples. El caso es que el mercado tiene una vinculación muy rígida a la hora mundial.

En gran parte, la actividad comercial se construye sobre la actividad diaria de las personas. Los asesores también pueden incluirse en esta categoría. Podemos considerar que muchos asesores suponen un jugador predecible, no todos, claro, pero sí la mayoría. Muchos desarrolladores crean los llamados "scalpers nocturnos", que operan según la hora. Aquí tenemos algo interesante para pensar. Resulta que la naturaleza del movimiento de los precios viene determinada no solo por los precios pasados, sino también por ciertos días, semanas, meses, y posiblemente años. Cada una de estas magnitudes está cuantificada, es decir, tiene determinados valores fijos.

Obviamente, estos valores se pueden fraccionar. Por ejemplo, podemos medir la ventana temporal no en horas y minutos, sino, digamos, en segundos transcurridos desde el inicio de un nuevo día. Todo dependerá de lo conveniente que nos resulte medir estos valores. En general, todas estas magnitudes cuantificadas se pueden subdividir hasta el infinito. En nuestro programa, la segmentación ocurre solo en días y semanas. Pensábamos que segmentar en meses y años no resulta tan efectivo, aunque quizá no debiéramos haber descartado los meses: tal vez luego añadamos esta funcionalidad, al igual que hicimos con los días de la semana. Vamos a exponer nuestras reflexiones en forma de diagrama:

Segmenting Diagram

Hemos representado dos opciones aleatorias para segmentar la muestra original y, a continuación, lo que sucedería si nuestra fuerza bruta tuviera lugar de forma indefinida. En el primer caso, vemos lo que sucedería si hubiéramos implementado todas las plantillas matemáticas posibles para la descripción, y en el segundo caso, lo que obtendremos del único método de fuerza bruta implementado (polinomio multidimensional de Taylor). Podemos comprender de inmediato que siempre existe una muestra más predecible y una más impredecible, y que también existe para cada tipo de polinomio una sección segmentada de la forma más óptima posible. Tenemos innumerables segmentos de este tipo, pero podemos encontrarlos con una precisición de hasta un minuto respecto al más cercano. Como estamos analizando barras, no vamos a considerar los segundos aquí.

Usando como base estas conclusiones, podemos adivinar que para cada combinación de parámetros de segmentación, es posible crear una función para cada parámetro comercial que tenga importancia propia en el robot, y que podríamos asimismo obtener al final del ciclo de desarrollo completo. Por ejemplo, la esperanza matemática y el factor de beneficio:

  • Ma=Ma(M,D,Ts,Te)
  • PrF=PrF(M,D,Ts,Te)
  • M - mes del año
  • D - día de la semana
  • Ts - hora de comienzo del pasillo
  • Te - hora de finalización del pasillo ( pueden traspasarse las 0:00 ) 

En general, se trata de funciones discretas. Es decir, los argumentos pueden tomar valores estrictamente fijos. Si registramos las variables asociadas con los meses y los días de la semana, podremos imaginar aproximadamente qué aspecto tendrán estas 2 funciones. Las dimensiones máximas que podemos visualizar son tres, por lo que podremos dibujar el gráfico más informativo con solo dos variables libres. Hemos seleccionado "Ts" y "Te":

3D Graph

Cada fórmula o algoritmo que usaremos para intentar predecir el futuro, dispondrá de gráficos únicos para todas las características cuantitativas del futuro sistema comercial. Hemos mencionado solo dos para mostrar que donde existe el factor de beneficio máximo, no será en absoluto necesaria la esperanza matemática máxima. En la mayoría de los casos, deberemos mantener el equilibrio entre la esperanza matemática y el factor de beneficio, porque los spreads, las comisiones y los swaps obstaculizan nuestro trabajo. El número y la magnitud de estos extremos resultan diferentes para cada fórmula. No podemos realizar una búsqueda multidimensional de extremos manualmente, pero el programa es totalmente capaz de hacerlo, lo cual ya ha demuestrado con éxito.

También nos gustaría señalar que, a la hora de investigar el mercado con nuestro software, detectamos un área muy interesante donde, en la mayoría de los casos, todos las parejas de divisas han sobrestimado los indicadores de previsibilidad. Este intervalo se encuentra aproximadamente entre las 23:30 y las 0:30. Quizás no lo hemos descrito con exactitud, pero definitivamente está relacionado con el cambio de día. Sin embargo, resultó que, al poner a prueba en MetaTrader 5 las mismas estrategias que mostraban excelentes factores de beneficio en MetaTrader 4, toda esta aparente rentabilidad desapareció. La culpa de todo es del spread. Recomendamos a todo el mundo que permanezca muy alerta respecto a que su patrón resulte dentro del spread. La mayor parte de los patrones localizados se hallará dentro del spread.


Modificaciones finales del algoritmo de búsqueda

Las modificaciones finales tenían como objetivo aumentar la velocidad de funcionamiento del programa, y también maximizar la variabilidad y la eficiencia de la búsqueda. Lista de cambios:

  1. Hemos añadido la capacidad de buscar patrones en un intervalo de tiempo fijo.
  2. Hemos añadido la posibilidad de comerciar solo en los días marcados.
  3. Hemos añadido la capacidad de generar conjuntos aleatorios de días para cada nueva opción según los días marcados
  4. Hemos añadido la capacidad de generar ventanas temporales de servidor aleatorias, indicando la posible duración mínima y máxima de la ventana en minutos
  5. Podemos combinar cualquiera de estos ajustes.
  6. La segunda pestaña de optimización ahora puede funcionar en modo multihilo
  7. Hemos mejorado el modo de optimización y este ahora encuentra todo lo que es posible encontrar

El aspecto actual es el siguiente:

Pestaña de fuerza bruta

La segunda pestaña no ha cambiado, pero la mostraremos de todas formas:

Pestaña de optimización

La tercera pestaña tiene el aspecto siguiente:

Pestala de generación del asesor experto

La interfaz, por supuesto, sigue bastante desordenada, y además, los ajustes apenas caben en el formulario. Sin embargo, en la versión que mostraremos en el artículo siguiente, rediseñaremos por completo la interfaz, haciéndola agradable y comprensible para todos. También planeamos grabar un vídeo sobre el proceso completo de creación de un asesor utilizando nuestro programa. Todos podrán ver lo fácil, rápido y agradable que es. Solo necesitamos entender un poco la configuración de la interfaz, bueno, y también practicar.


Optimización de las plantillas y el asesor auxiliar

Asimismo, para esta tarea, necesitamos modificar las plantillas de los asesores, y también robots que generan cotizaciones en el formato deseado, fácil de leer por el programa. El código del asesor experto que genera cotizaciones para MetaTrader 5 ahora tiene este aspecto:

string FileNameString;
uint Handle0x;
datetime Time0=0;

double Open[];
double Close[];
double High[];
double Low[];
datetime Time[];


void WriteEnd()
   {
   FileWriteString(Handle0x,"EndBars"+"\r\n");
   MqlDateTime T;
   TimeToStruct(Time[1],T);
   FileWriteString(Handle0x,IntegerToString(int(T.year))+"\r\n");
   FileWriteString(Handle0x,IntegerToString(int(T.mon))+"\r\n");
   FileWriteString(Handle0x,IntegerToString(int(T.day)));
   }

void OpenAndWriteStart()
   {
   FileDelete(FileNameString);
   Handle0x=FileOpen(FileNameString,FILE_WRITE|FILE_TXT|FILE_COMMON|FILE_ANSI,'\t',CP_UTF8);
   FileSeek(Handle0x,0,SEEK_SET);
   FileWriteString(Handle0x,"DataXXX"+" "+Symbol()+" "+IntegerToString(Period())+"\r\n");
   FileWriteString(Handle0x,DoubleToString(_Point,8)+"\r\n");
   MqlDateTime T;
   TimeToStruct(Time[1],T);
   FileWriteString(Handle0x,IntegerToString(int(T.year))+"\r\n");
   FileWriteString(Handle0x,IntegerToString(int(T.mon))+"\r\n");
   FileWriteString(Handle0x,IntegerToString(int(T.day))+"\r\n");             
   }
      
void WriteBar()
   {
   FileWriteString(Handle0x,"\r\n");
   FileWriteString(Handle0x,DoubleToString(Close[1],8)+"\r\n");
   FileWriteString(Handle0x,DoubleToString(Open[1],8)+"\r\n");
   FileWriteString(Handle0x,DoubleToString(High[1],8)+"\r\n");
   FileWriteString(Handle0x,DoubleToString(Low[1],8)+"\r\n");         
   FileWriteString(Handle0x,IntegerToString(int(Time[1]))+"\r\n");
   MqlDateTime T;
   TimeToStruct(Time[1],T);
   FileWriteString(Handle0x,IntegerToString(int(T.hour))+"\r\n");
   FileWriteString(Handle0x,IntegerToString(int(T.min))+"\r\n");
   FileWriteString(Handle0x,IntegerToString(int(T.day_of_week))+"\r\n");         
   //FileClose(Handle0x);
   }      

void CloseFile()
   {
   FileClose(Handle0x);
   }

bool bNewBar()
   {
   ArraySetAsSeries(Close,false);                        
   ArraySetAsSeries(Open,false);                           
   ArraySetAsSeries(High,false);                        
   ArraySetAsSeries(Low,false);                              
   CopyOpen(_Symbol,_Period,0,2,Open);
   CopyClose(_Symbol,_Period,0,2,Close);
   CopyHigh(_Symbol,_Period,0,2,High);
   CopyLow(_Symbol,_Period,0,2,Low);
   ArraySetAsSeries(Close,true);                        
   ArraySetAsSeries(Open,true);                           
   ArraySetAsSeries(High,true);                        
   ArraySetAsSeries(Low,true);                                 
   if ( Time0 < Time[1] )
      {
      if (Time0 != 0)
         {
         Time0=Time[1];
         return true;
         }
      else
         {
         Time0=Time[1];
         return false;
         }
      }
   else return false;
   }

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
  ArrayResize(Close,2,0);
  ArrayResize(Open,2,0);   
  ArrayResize(Time,2,0);
  ArrayResize(High,2,0);
  ArrayResize(Low,2,0);  
  FileNameString="DataHistory"+" "+Symbol()+" "+IntegerToString(Period());
  OpenAndWriteStart();
   return(INIT_SUCCEEDED);
  }

void OnDeinit(const int reason)
  {
  WriteEnd();
  CloseFile();
  }

void OnTick()
  {
  ArraySetAsSeries(Time,false);
  CopyTime(_Symbol,_Period,0,2,Time);
  ArraySetAsSeries(Time,true);
  if ( bNewBar()) WriteBar();
  }

Aquí solo tenemos algunas funciones simples; algunas escriben algo al comienzo de la prueba, otras añaden información sobre la cotización al final, y la principal simplemente escribe información sobre la barra cuando aparece. El asesor experto no dispone de configuraciones de entrada, solo debemos ejecutarlo a través de la historia; luego generará un archivo de cotización en el formato requerido que el programa podrá leer. En esencia, esto supone, obviamente, un parche. Quizás en el futuro nos ocupemos de los formatos de las cotizaciones en los terminales e implementemos la lectura directamente. Pero, por el momento, todo resulta cómodo como está. Al menos, a nosotros no nos molesta.

En lugar de utilizar funciones temporales que conviertan el formato datetime en días de la semana, horas y minutos, simplemente las escribiremos en la cotización como información adicional sobre la barra. Todos estos son valores enteros, excepto ENUM_DAY_OF_WEEK. Todo lo que tuvimos que hacer fue implementar una lista numerada dentro del código C#, que es de lo más sencillo y, por supuesto, asumir en nuestras plantillas que los datos se retornarán con la misma forma. El rechazo de las funciones temporales nos permite evitar cálculos innecesarios en el lado del código C#. Además, podremos descartar las inconsistencias horarias. Resulta mejor evitar cosas tan peligrosas.

El archivo de cotizaciones en la salida se puede abrir con cualquier editor de texto, y veremos una estructura tan simple y comprensible como esta:

History Data File


El encabezado de la plantilla donde se registran las variables, antes contenía campos para autocompletar en el momento de la generación, ahora su lista se ha rellanado con variables comerciales temporales, y también con los días comerciales.

La plantilla de ajustes de entrada ahora se ve así:

double C1[] = { %%%CVALUES%%% };//Brutted Values
int CNum=%%%CNUMVALUE%%%;//Bars To Equation
int DeepBruteX=%%%DEEPVALUE%%%;//Max Pow Of Polinom
int DatetimeStart=%%%DATETIMESTART%%%;//Help Datetime
input bool bInvert=%%%INVERT%%%;//Invert Trade(or sign of values as the same)
input int DaysToFuture=%%%DAYSFUTURE%%%;//Days To Future
int DaysToTrade[]={ %%%DAYS%%% };//Days To Trade
input double ValueOpenE=%%%OPTVALUE%%%;//Open Signal
input bool bUseTimeCorridorE=%%%TIMECORRIDORVALUE%%%;//Use Time Corridor
input int TradeHour=%%%HOURSTARTVALUE%%%;//Start Trading Hour
input int TradeMinute=%%%MINUTESTARTVALUE%%%;//Start Trading Minute
input int TradeHourEnd=%%%HOURENDVALUE%%%;//End Trading Hour
input int TradeMinuteEnd=%%%MINUTEENDVALUE%%%;//End Trading Minute

Aquí, el programa rellena todas las magnitudes cuando se crea el robot, para que este funcione inmediatamente con la configuración por defecto y pueda ser compilado al iniciarse el terminal sin tener que entrar en MetaEditor. Todas las configuraciones y matrices están integradas en el propio asesor. Esto resulta bastante cómodo. Imaginemos que tenemos un montón de estos asesores expertos, y que ninguno de ellos debe confundir los ajustes. El prototipo del brutter para MetaTrader 4 nos ha mostrado que incluso el propio desarrollador puede equivocarse y confundirse con la configuración. Por supuesto, perderemos funcionalidad, ya que, obviamente, podríamos escribir la configuración en un archivo de texto simple y leer este, pero, nuevamente, estos archivos podrían confundirse y, de nuevo, tendríamos un problema.

La función principal también ha sufrido una serie de modificaciones:

bool bDay()//Day check
   {
   MqlDateTime T;
   TimeToStruct(Time[0],T);
   for ( int i=0; i<ArraySize(DaysToTrade); i++ )
      {
      if ( T.day_of_week == DaysToTrade[i] ) return true;
      }
   return false;
   }

void Trade()//Trade Function
   {
   double Value;
   Value=PolinomTrade();
   MqlTick LastTick;
   SymbolInfoTick(Symbol(),LastTick);
   MqlDateTime tm;
   TimeToStruct(LastTick.time,tm);
   int MinuteEquivalent=tm.hour*60+tm.min;
   int BorderMinuteStartTrade=HourCorrect(TradeHour)*60+MinuteCorrect(TradeMinute);
   int BorderMinuteEndTrade=HourCorrect(TradeHourEnd)*60+MinuteCorrect(TradeMinuteEnd);
   
   if ( Value > ValueCloseE)
      {
      if ( !bInvert ) CloseBuyF();
      else CloseSellF();
      }
      
   if ( Value < -ValueCloseE)
      {
      if ( !bInvert ) CloseSellF();
      else CloseBuyF();
      }   
   
   if ( !bUseTimeCorridorE )
      {
      if ( double(TimeCurrent()-DatetimeStart)/86400.0 <= DaysToFuture && Value > ValueOpenE && Value <= ValueOpenEMax )
         {
         if ( !bInvert ) SellF();
         else BuyF();
         }
      
      if ( double(TimeCurrent()-DatetimeStart)/86400.0 <= DaysToFuture && Value < -ValueOpenE && Value >= -ValueOpenEMax )
         {
         if ( !bInvert ) BuyF();
         else SellF();
         }      
      }
   else
      {
      if ( BorderMinuteStartTrade > BorderMinuteEndTrade && bDay() )
         {
         if ( !(MinuteEquivalent>=BorderMinuteEndTrade && MinuteEquivalent<= BorderMinuteStartTrade) )
            {
            if ( double(TimeCurrent()-DatetimeStart)/86400.0 <= DaysToFuture && Value > ValueOpenE && Value <= ValueOpenEMax )
               {
               if ( !bInvert ) SellF();
               else BuyF();
               }
      
            if ( double(TimeCurrent()-DatetimeStart)/86400.0 <= DaysToFuture && Value < -ValueOpenE && Value >= -ValueOpenEMax )
               {
               if ( !bInvert ) BuyF();
               else SellF();
               }
            }        
         }
      if ( BorderMinuteStartTrade <= BorderMinuteEndTrade && bDay() )
         {
         if ( MinuteEquivalent>=BorderMinuteStartTrade && MinuteEquivalent<= BorderMinuteEndTrade )
            {
            if ( double(TimeCurrent()-DatetimeStart)/86400.0 <= DaysToFuture && Value > ValueOpenE && Value <= ValueOpenEMax )
               {
               if ( !bInvert ) SellF();
               else BuyF();
               }
      
            if ( double(TimeCurrent()-DatetimeStart)/86400.0 <= DaysToFuture && Value < -ValueOpenE && Value >= -ValueOpenEMax )
               {
               if ( !bInvert ) BuyF();
               else SellF();
               }
            }        
         }      
      }

   if ( bPrintValue ) Print("Value="+DoubleToString(Value));     
   }

Aquí, solo le hemos añadido la lógica necesaria para controlar los días de la semana y el intervalo temporal dentro del día; todo lo demás permane sin cambios. Por cierto, el intervalo temporal no debe encontrarse en el rango de 0-24 horas. El intervalo puede comenzar un día y terminar otro. Es decir, podemos cruzar el punto de cobro del spread. Según la idea, podemos abrir posiciones en los pasillos destacados, pero no podemos cerrarlas en cualquier momento. Podría merecer la pena añadir como una opción aparte el cierre forzoso de posiciones por tiempo. Hasta ahora, parece que el uso de este enfoque debería ofrecer robots más estables, porque estamos haciendo más vago el límite del pasillo temporal. Lo hemos hecho así para reducir la probabilidad de obtener resultados accidentales, logrando la confirmación de que el pasillo localizado y su fórmula no dejan de funcionar abruptamente, sino que desaparecen de forma gradual.


Análisis de patrones globales

Al igual que en el artículo anterior, todos los resultados presentados aquí se han obtenido usando como base el entrenamiento en el segmento temporal 2010.01.01-2020.01.01. Lo hemos hecho así de forma intencional, para dejar el año en curso como un periodo forward y verificar los resultados de las cotizaciones del futuro. Hemos seleccionado el periodo forward desde 2020.01 hasta 2020.12.01.

Querríamos destacar el aumento significativo en la calidad de los resultados finales; obviamente, este se da en detrimento del número de transacciones, pero, curiosamente, esto solo ha influido de forma positiva en el periodo forward. Como asumimos en el último artículo, un aumento en la calidad de la prueba inicial implica un incremento en la duración del patrón en el periodo forward. Encontraremos las pruebas de ello más abajo.

Vamos a comenzar con la pareja de divisas EURCHF H1. El análisis anterior nos mostró que esta herramienta posee una buena capacidad de predicción, por lo que decidimos comenzar con ella. Logramos crear 3 asesores expertos basados en los resultados de optimización. Vamos a mostrar un par de pruebas de la versión para MetaTrader 4 para mostrar cómo han crecido los indicadores de los patrones encontrados. Veamos la primera variante:

First Bot EURCHF H1 2010.01.01-2020.01.01 MetaTrader 4

Durante la prueba, fijamos el lote en 0,1. Partiendo de la esperanza matemática obtenida durante la prueba, resulta que la esperanza matemática es de 54 dólares contra los 8 dólares que obtuvimos en la anterior versión del programa. El factor de beneficio también ha aumentado significativamente, un mínimo de 0,5, y tal vez incluso más. Recordemos que en el último artículo rondaba el 1,14. Este fue el factor de beneficio máximo que logramos obtener. Esperamos que todos puedan ver la extraordinaria diferencia en los resultados, tan pronto como estructuramos la muestra según el día de la semana y el horario de trabajo.

Querríamos señalar que aún no estamos cerca del mejor resultado, ni mucho menos. Después de todo, hemos realizado las pruebas durante un tiempo muy limitado, dependiendo de las características específicas del problema. Asimismo, hemos tenido que adaptarnos a un marco muy estricto en cuando al tiempo. En total, todas las pruebas ocuparon alrededor de 2-3 días. Realizamos las pruebas en 2 núcleos de un procesador bastante débil para los estándares actuales, ni siquiera en un procesador de servidor. Cada variante ocupó alrededor de 5-6 horas aproximadamente, si miramos más de cerca el proceso de búsqueda de patrones.

Incluso durante el proceso de prueba, encontramos errores en el algoritmo del programa, que con frecuencia arrojaban resultados falsos. Claro está, ya hemos solucionado estos errores, pero estos tuvieron un efecto muy negativo en la cantidad de patrones que detectamos. No obstante, tuvimos tiempo suficiente para encontrar opciones aceptables. Echemos ahora un vistazo a esta prueba en MetaTrader 5:

First Bot EURCHF H1 2010.01.01-2020.01.01 MetaTrader 5

Hay muy pocas operaciones porque limitamos el spread durante las pruebas para conseguir una prueba más o menos estable, en busca de indicadores de mayor rentabilidad. Pero, como ha demostrado la práctica, esto no es necesario en absoluto. Al final del artículo explicaremos por qué. A pesar del escaso número de transacciones que han quedado de la prueba final, todavía podemos confiar en estos datos, ya que tenemos una muestra más larga detrás (la obtuvimos al utilizar los coeficientes de la fórmula en la primera pestaña). De hecho, en la primera pestaña, calculamos todas las barras que se encuentran en el segmento cargado, por lo que se trata de una base ideal para la optimización. Cuando aislamos una parte de los resultados de una muestra grande como una muestra más pequeña, la fuerza de esta muestra resulta mayor cuantos más datos contenga la primera muestra (órdenes).

Ahora podemos echar un vistazo al periodo forward:

Future 1 year

Solo hay 2 transacciones en 1 año; muy pocas, pero el resultado es positivo.

Veamos la siguiente variante, que es del mismo segmento que la anterior:

Second Bot EURCHF H1 2010.01.01-2020.01.01 MetaTrader 4

En MetaTrader 5, sin requisitos para los spreads esta fórmula no resulta rentable, pero si la limitamos según la esperanza matemática obtenida, veremos que entre estas señales hay algunas buenas, aunque el gráfico no tenga un aspecto agradable:

Second Bot EURCHF H1 2010.01.01-2020.01.01 MetaTrader 5

Podríamos decir que el gráfico es realmente feo y no puede ofrecernos gran cosa en el futuro, pero, una vez más, tras él tenemos una enorme muestra base que ofrece un poder tremendo a todas las siguientes, por lo que no debemos temer que la muestra final tenga un aspecto tan impresentable. En nuestro caso, bastará con que ofrezca beneficios. Vamos a echar un vistazo hacia el futuro:

Future 1 year

Curiosamente, el resultado es muy bueno, aunque, de nuevo, no tenemos tantas transacciones. De hecho, en los últimos años, hemos podido probar mejor todo esto, porque los brókeres están reduciendo constantemente los spreads con la ayuda de nuevas tecnologías. Ya podemos sacar una conclusión muy buena respecto a las previsiones y su posible comportamiento. Pero, por el momento, disponemos de muy pocos datos para confirmarla, se trata solo de una pista. Para confirmar estas conclusiones, hemos realizado varias pruebas más para diferentes parejas de divisas; veremos todo esto más abajo. Por ahora, vamos a analizar el tercer robot para esta pareja de divisas.

También queremos decir que no habrá más pruebas para MetaTrader 4. Dos opciones completas, en nuestra opinión, bastan de sobra para realizar una comparación. Tampoco vemos ningún sentido en saturar el artículo con datos innecesarios. Tercera opción:

Third Bot EURCHF H1 2010.01.01-2020.01.01 MetaTrader 5

En general, el gráfico parece bastante normal, o al menos no es feo. Miremos ahora hacia el futuro:

Future 1 year

Vemos la misma imagen. Hasta ahora, todos los periodos forward han sido positivos. Obviamente, podríamos pensar que, como tenemos tres robots (con diferentes parámetros, sí, pero de la misma pareja de divisas y entrenados en la misma área), estos tal vez describan el mismo patrón, solo que un poco diferente.

Otro pensamiento que podría surgir es que esta pareja de divisas es muy hermosa y se comporta todo el tiempo de la misma forma. Incluso si fuera así, podemos beneficiarnos de ello. De todas formas, esto se debe a razones mucho más generales. Para demostrar que el asunto no está en la pareja de divisas ni en el hecho de que el área sea la misma, ahora tomaremos una pareja de divisas diferente e incluso un marco temporal distinto.

Pasamos a EURUSD H4

Como ya hemos dicho, no vamos a mostrar más pruebas con MetaTrader 4, pero las pruebas en esta pareja de divisas se ven tan suaves y bonitas como en la última, solo sabemos esto. En este marco temporal, hemos encontrado 2 robots distintos. Empecemos por el primero:

First Bot EURUSD H4 2010.01.01-2020.01.01 MetaTrader 5

El gráfico tiene una pinta horrible, pero si confiamos en nuestras anteriores suposiciones, esto no debería molestarnos, porque también se trata de solo una pequeña parte de una muestra muy grande. Veamos qué hay en el futuro:

Future 1 year

La misma historia, el patrón funciona todo el año. Incluso si eliminamos la primera orden, la más grande, si miramos de cerca el resto, podemos entender que aún así nos habríamos quedado en positivo.

Solo queda reforzar nuestras conclusiones y ver qué nos mostrará el segundo asesor experto:

Second Bot EURUSD H4 2010.01.01-2020.01.01 MetaTrader 5

El gráfico es el más parejo de todos los que hemos visto antes, por eso, podríamos esperar lo mismo en el futuro. Vamos a comprobar nuestras suposiciones:

Future 1 year

Todo ha resultado como esperábamos. Incluso podemos ver una línea recta aquí, aunque haya un gran pico al principio. Hasta ahora, no hemos visto un solo periodo forward con pérdidas de los 5 asesores probados en 2 muestras completamente diferentes. En nuestra opinión, esta ya es una estadística bastante buena. Sin embargo, personalmente, no podemos considerar suficientes incluso estos datos, por lo que cambiaremos a una pareja de divisas completamente distinta y a un marco temporal completamente diferente, y realizaremos una verificación adicional para finalmente consolidar las conclusiones.

Pasamos a EURJPY M5.

EURJPY M5 2010.01.01-2020.01.01 MetaTrader 5

El segmento de entrenamiento se ve extraño: hay un cambio pronunciado en 2015, pero en general, por supuesto, parece que tiene un buen aspecto. Vamos a echar un vistazo al periodo forward:

Future 1 year

Resulta difícil sacar conclusiones del mismo, pero parece claro que este es el primero de los segmentos forward que no está en positivo. Sin embargo, no creemos que este resultado refute la estabilidad de todos los algoritmos generados con este software. Más que nada, porque tenemos un viraje pronunciado en 2015 en el backtest. No queremos que nadie piense que pretendemos ajustar los resultados del artículo a nuestra visión del mercado, pero, personalmente, no podemos calificar esta situación de refutación solo por un viraje pronunciado. Más bien, sacaremos la conclusión de que todo está en orden, porque la situación se desarrolló en 2015, y estamos solo ante una continuación de ese cambio.

Para no descartar los resultados indeseables por alguna causa externa, deberemos realizar ciertas modificaciones en el algoritmo de búsqueda de patrones. En la próxima versión, implementaremos este algoritmo, describiendo a continuación las posibles modificaciones del mismo.


Extrayendo conclusiones

Parece que estas pruebas son suficientes para extraer varias conclusiones importantes respecto a la búsqueda y la puesta a prueba de asesores en los terminales MetaTrader 4 y MetaTrader 5. El caso es que los simuladores de ambos terminales funcionan de forma ligeramente distinta. Las cotizaciones para MetaTrader 4 guardan la historia sin información sobre los spreads, lo cual permite al usuario establecer el spread "1", que es casi igual a "0". Para la inmensa mayoría de los asesores, este margen no importa en absoluto, lo cual permite encontrar el inicio de cualquier patrón y desarrollar este, cosa que MetaTrader 5 no ofrece. No obstante, en las cotizaciones de MetaTrader 5 se almacena el spread, lo que nos permite valorar la rentabilidad real del sistema.

Como nos ha demostrado la práctica, si un sistema escrito para MetaTrader 4 no ha sido transferido también al quinto terminal, dicho sistema tendrá muy pocas posibilidades de mostrar beneficios, porque la mayoría de los patrones que podemos encontrar se encuentran dentro del spread, y no tienen ningún uso práctico. Es cierto que en algunos casos, entre todas las señales, se pueden distinguir aquellas que tenían spreads mínimos, y por ello, al menos quedará una parte de las señales, pero la experiencia demuestra que no siempre es así.

Con mucha frecuencia, disminuyendo el spread requerido, las señales solo empeoran. En este caso, para las pruebas, hemos ajustado manualmente los spreads en MetaTrader 5 para obtener pruebas más o menos aceptables, pero esto lleva mucho tiempo. Estas cosas se pueden hacer automáticamente modificando el programa. Intentaremos representar en la figura cómo se ve ahora el proceso completo de búsqueda de un patrón hasta la última etapa, y cómo podemos automatizar la búsqueda manual del spread:

Development Cycle

El diagrama muestra el ciclo completo de desarrollo de un nuevo asesor experto. En negro, representamos el estado implementado actual de este ciclo utilizando nuestro programa. Las posibles modificaciones, así como la posible automatización, se muestran en gris. Las mejoras que planeamos introducir se dividen en 6 categorías:

  1. Uso de las funciones matemáticas más simples para procesar los datos de barras
  2. Adición de mecanismos de variación de lotes que aumenten el factor de beneficio para los robots que implementan patrones globales
  3. Adición y desarrollo de mecanismos de martingale y martingale inverso para trabajar en áreas extremadamente cortas
  4. Adición de un mecanismo para combinar los robots buenos en un solo robot con la mayor frecuencia de transacciones posible
  5. Inclusión de spreads en las cotizaciones y exclusión de la selección manual para el usuario (automatización completa de todo el ciclo de desarrollo)
  6. Corrección de errores detectados en el optimizador

Querríamos destacar aquí los elementos 1, 5 y 6. La variabilidad de las fórmulas usadas para la fuerza bruta ofrecerá tanto un aumento en el número de diferentes variantes de asesores que se pueden obtener de un ciclo de optimización bruta, como un aumento en la calidad promedio de los resultados. Los miembros del foro habrán notado en artículos anteriores del ciclo que podemos utilizar la serie de Fourier para describir los procesos periódicos del mercado. Siendo honestos, también queríamos implementar esto al principio, pero decidimos que por ahora merece la pena posponer este método debido a su complejidad. Sin embargo, después de pensarlo un poco, llegamos a la conclusión de que no resulta tan difícil. Después de todo, no necesitamos expandir ninguna función en una serie, solo necesitamos buscar los coeficientes de los términos, de la misma forma que sucede en nuestra serie de Taylor. Además, la variabilidad de este método será mucho mayor que la de la serie de Taylor. De todas formas, seguimos usando solo el primer grado, porque a medida que aumentan los grados, la calidad disminuye a causa del aumento desproporcionado en la complejidad del cálculo. Los spreads también son muy importantes. ¿Por qué filtrar las señales manualmente cuando podemos hacerlo automáticamente? También hemos tenido discrepancias en la hora de las barras, pero hemos eliminado estos errores; principalmente, estos se asociaban con diferencias entre la funcionalidad de las plantillas y la funcionalidad del software.

En definitiva, el objetivo de este software es automatizar al completo los procesos de desarrollo, testeo y optimización de los asesores para ambas plataformas, apartándose de la rutina habitual. Las manipulaciones que estamos realizando ahora manualmente las podría hacer fácilmente una máquina y, por supuesto, mucho más rápido que nosotros. Puede ser que nuestra calidad resulte superior a la de una máquina, pero, al final, la máquina seguirá encontrando mejores patrones y a mayor velocidad gracias a su potencia de cálculo, que ninguna otra persona posee. Y, hablando claramente, el ser humano suele ser tan perezoso que ni siquiera le apetece ajustar manualmente cosas tan elementales como el tamaño del spread. Parece una bagatela, pero cada una de esas bagatelas incrementa sustancialmente la duración del ciclo completo de desarrollo del sistema. En sí, el proceso de desarrollo no resulta tan interesante como la cantidad y calidad de los resultados obtenidos por unidad de tiempo, porque de esto dependerá el beneficio si queremos usar estos sistemas para el trading. Además, si invertimos demasiado tiempo configurando un sistema, este podría volverse irrelevante. La mayoría de los asesores verdaderamente operativos funcionarán por un tiempo muy limitado y, en este sentido, deberemos ejecutar todo de forma muy rápida y efectiva. Hay que moldear el metal mientras esté aún caliente. O bien podemos utilizar el optimizador todos los meses, cosa que no recomendaríamos a nuestro peor enemigo.

Puede que si vemos potencial en el desarrollo posterior de la idea, continuemos desarrollando esta dirección. Si la idea tiene éxito, crearemos un programa similar para aumentar el gradiente, o simplemente añadiremos un nuevo modo como tercera etapa del análisis de datos. El hecho es que el método en sí resulta muy bueno como buscador de predictores para el problema del aumento de gradiente. En lugar de inventar predictores y ponerlos a prueba por nosotros mismos, podemos usar con éxito los predictores encontrados por este método. Pero, claro está, eso requeriría ya una modificación mucho más seria y profunda del programa, por lo que es demasiado pronto para hablar de ello. El tiempo dirá. No obstante, ya hemos implementado las modificaciones que hemos enumerado en esta lista; ahora las estamos probando y también guardando los datos para escribir un artículo más detallado con los resultados de los cambios y los ejemplos de aplicación. "CONTINUARÁ", como aquel que dice.

Este y todos los artículos anteriores de esta serie se han centrado en MetaTrader 4, pero como ya ha demostrado la práctica, en dicho enfoque, deberíamos hacer hincapié en Meta Trader 5, puesto que la automatización nos permite apartarnos de la búsqueda inicial de rudimentos para los patrones en MetaTrader 4. En el próximo artículo, implementaremos este enfoque al completo, por lo que el programa adquirirá una funcionalidad sin precedentes.

Teniendo en cuenta que MetaTrader 5 es una plataforma mucho más progresiva, y que comenzó a registrar la historia de ticks reales y los spreads (lo cual permite valorar la rentabilidad real de cualquier sistema comercial), deberemos centrarnos en ella, incluso a la hora de realizar la integración con un software similar al nuestro. Para desarrollar sistemas comerciales manualmente, obviamente, continuaremos utilizando ambas plataformas al mismo tiempo; pero para este enfoque, la elección será obvia.

Durante el proceso de prueba, identificamos un factor muy importante que reduce tanto la calidad de los asesores generados como el porcentaje de dichos asesores que puede resistir la selección natural después de poner estos a prueba con datos reales de ticks en el simulador MetaTrader 5. Este factor resulta muy importante no solo para aquellos sistemas que usan cualquier tipo de aprendizaje automático, sino también para cualquier otro asesor experto creado originalmente en MetaTrader 4. Hablamos del spread y sobre cómo afecta este a la muestra final de datos para el entrenamiento. Mucha gente no presta atención al spread; en el mejor de los casos, consideran su tamaño al comerciar, pero este tiene un componente invisible (pero muy importante) que ejerce un efecto muy negativo en el proceso de aprendizaje automático. Revelaremos estos detalles en el próximo artículo.


Conclusión

Lo más importante es que el artículo demuestra que si deseamos aumentar las posibilidades de que nuestro programa rinda adecuadamente, nuestros robots comerciales deberán implementarse en MQL5. Después de todo, esto nos permitirá realizar pruebas en un entorno lo más próximo posible a la realidad. Inicialmente, durante el desarrollo de nuestro software, no apreciábamos especialmente esta plataforma, pero un análisis profundo nos ha mostrado que si no realizamos pruebas en MetaTrader 5, correremos el riesgo de confundir las ilusiones con la realidad.

El artículo muestra que incluso un potencial informático limitado es capaz de dar resultados utilizando las fórmulas matemáticas más simples, concretamente, polinomios lineales y polinomios de grados superiores. Hemos creado una base para usar las funciones matemáticas más simples. Los resultados demuestran que una combinación lineal y de grado de la función más simple puede ofrecer una excelente señal para el comercio.

Los resultados sugieren que cualquier conjunto de condiciones lógicas se puede reducir a un solo indicador cuantitativo en forma de función. En esencia, la fórmula construye un indicador que genera valores simétricos positivos y negativos que podemos utilizar como señales de compra o venta. La fórmula del indicador es siempre diferente y esto asegura la variabilidad del método. En nuestra opinión, muchos tráders sueñan con un indicador que les diga exactamente cuándo comprar y cuándo vender. Este método implementa dicha posibilidad en la medida que el mercado nos lo permite. El próximo artículo promete mostrar resultados mucho mejores; también esperamos poder consolidar todas las conclusiones que hemos extraído a lo largo del ciclo que componen estos artículos. Asimismo, revelaremos nuevos matices que resultarán útiles tanto al crear sistemas comerciales manualmente como en el aprendizaje automático.

Enlaces

  1. Aproximación por fuerza bruta a la búsqueda de patrones
  2. Aproximación por fuerza bruta a la búsqueda de patrones (Parte II): Inmersión


Traducción del ruso hecha por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/ru/articles/8661

Archivos adjuntos |
Bots.zip (880.06 KB)
Trabajando con los precios en la biblioteca DoEasy (Parte 64): Profundidad del mercado, clases del objeto de instantánea y del objeto de serie de instantáneas del DOM Trabajando con los precios en la biblioteca DoEasy (Parte 64): Profundidad del mercado, clases del objeto de instantánea y del objeto de serie de instantáneas del DOM
En este artículo, vamos a crear dos clases: la clase del objeto de instantánea del DOM y la clase del objeto de serie de instantáneas del DOM, además, simularemos la creación de la serie de datos del DOM.
Buscando patrones estacionales en el mercado de divisas con la ayuda del algoritmo CatBoost Buscando patrones estacionales en el mercado de divisas con la ayuda del algoritmo CatBoost
En el presente artículo, mostramos la posibilidad de crear modelos de aprendizaje automático con filtros temporales y también descubrimos la efectividad de este enfoque. Ahora, podremos descartar el factor humano, diciéndole simplemente al modelo: "Quiero que comercies a una hora determinada de un día concreto de la semana". Así, podremos delegar en el algoritmo la búsqueda de patrones.
Redes neuronales: así de sencillo (Parte 10): Multi-Head Attention (atención multi-cabeza) Redes neuronales: así de sencillo (Parte 10): Multi-Head Attention (atención multi-cabeza)
Ya hemos hablado con anterioridad del mecanismo de auto-atención (self-attention) en las redes neuronales. En la práctica, en las arquitecturas de las redes neuronales modernas, se usan varios hilos de auto-atención paralelos para buscar diversas dependencias entre los elementos de la secuencia. Vamos a ver la implementación de este enfoque y evaluar su influencia en el rendimiento general de la red.
Algoritmo de autoadaptación (Parte III): Renunciando a la optimización Algoritmo de autoadaptación (Parte III): Renunciando a la optimización
No podemos obtener un algoritmo verdaderamente estable si para seleccionar los parámetros utilizamos la optimización basada en datos históricos. Un algoritmo estable en sí mismo debe saber qué parámetros se necesitan para trabajar con cualquier instrumento comercial en cualquier momento. El algoritmo no debe suponer ni adivinar: debe saber con certeza.