English Русский 中文 Deutsch 日本語 Português
preview
Desarrollo de un sistema de repetición (Parte 53): Esto complica las cosas (V)

Desarrollo de un sistema de repetición (Parte 53): Esto complica las cosas (V)

MetaTrader 5Ejemplos | 29 julio 2024, 09:56
153 0
Daniel Jose
Daniel Jose

Introducción

En el artículo anterior Desarrollo de un sistema de repetición (Parte 52): Esto complica las cosas (IV), creamos una nueva estructura de datos para que el indicador de mouse pudiera interactuar con el indicador de control. A pesar de que la interacción pueda suceder perfectamente y de manera bastante estable al principio, tenemos algunos problemas que nos obligan a modificar ligeramente las cosas.

El problema no está en el código, ni en la plataforma, ni en los conceptos utilizados, sino en la intención y la forma en que estamos trabajando. Personalmente, pido disculpas a todos los que han estado siguiendo esta serie de artículos hasta tener un sistema de simulación/repetición. Sinceramente, no esperaba tener que usar algunas técnicas encontradas en sistemas modulares, pero no hay manera de continuar el desarrollo del sistema de repetición/simulación sin usar algunas técnicas desarrolladas hace décadas.

Quizás para muchos de ustedes lo que voy a mostrar aquí les parecerá algo extremadamente extraño o, para otros, algo muy familiar. Sin embargo, independientemente de cómo quieras verlo, el mecanismo que explicaré aquí, y que comenzaremos a usar cada vez más, está presente en MetaTrader 5, y MQL5 nos permite usarlo. Aunque al usar MQL5, estamos limitados a hacerlo solo dentro del gráfico o dentro del propio MetaTrader 5. Esto no es malo, al contrario, es una medida de seguridad impuesta, ya que la plataforma está diseñada para trabajar con dinero, y no querrás que algo extraño te haga perder dinero a diestra y siniestra.

Así que, a pesar de las limitaciones, no te quejes. Piensa muy bien antes de reclamar, porque lo que empezaremos a usar aquí puede hacer que tú, como principiante o aspirante a programador, te sientas perdido por un tiempo. Pero esto es solo porque desconoces el contenido y cómo aprovecharlo. No obstante, durante algún tiempo he estado usando esta técnica, pero no de la misma manera que se hará a partir de ahora. Así que ha llegado el momento de elevar el nivel y aplicar conceptos más complejos en los artículos.


Explicación del concepto

Lo que vamos a empezar a usar intensamente es el intercambio de mensajes entre programas, y es importante que prestes mucha atención si no conoces el tema , ya que daré una breve introducción. Sí, MQL5 nos permite hacer esto. Este tipo de enfoque es extremadamente potente si se usa y diseña adecuadamente. Pero si no comprendes algunos detalles, te sentirás completamente perdido y hará que los programas se comporten mal al ser colocados juntos en un mismo gráfico dentro de MetaTrader 5.

Hasta ahora, los programas que he presentado en esta serie utilizan mensajes, pero no entre ellos. Sino dentro del propio código, de modo que una clase puede comunicarse con otra, incluso si están en niveles diferentes o no están conectadas por herencia. Puedes notar esto al observar mis códigos de clases. Prácticamente todos tienen un procedimiento común: DispatchMessage. Este procedimiento tiene como objetivo principal gestionar los mensajes que se envían a la clase. Aunque existen otras formas de comunicarse con la clase, utilizando otros procedimientos o funciones. DispatchMessage está ahí para gestionar los mensajes dirigidos a la clase.

Esta idea no es original mía, sino que se remonta a mucho tiempo atrás y tiene como objetivo promover una interfaz común entre programas o procedimientos en general. Quienes llevan más tiempo trabajando en el campo de la programación profesional saben de lo que hablo. Así, cuando necesitas enviar datos, valores o solicitudes a otro programa cuyo código desconoces por completo, utilizas este principio. Envías una mensaje a una función muy específica y esta te devolverá algún tipo de información. La forma en que se comunican es precisamente a través de esta única función.

El nombre de esta función varía, pero el conjunto y la secuencia de datos que se le proporcionan son siempre los mismos.

Tal vez pueda parecer muy superficial y totalmente sin sentido. Pero si estás estudiando programación, en este caso MQL5, ya debes haber visto esta función no solo una vez, sino varias veces, y casi todo el código de indicadores o Expert Advisors contiene esta función. Esta función, o mejor dicho, procedimiento, se llama: OnChartEvent, esto en MQL5.

Quizás pienses: "¿Cómo es posible?" "¿Quiere decir que MetaTrader 5 se comunica con mi programa mediante el intercambio de mensajes?" La respuesta es "sí". Y, al analizar el valor indicado en la constante entera ID, presente en esta llamada, podrás filtrar e identificar cuál fue el mensaje que MetaTrader 5 te envió.

Esto te sorprenderá, y mucho. Pero la cosa se complica aún más para los principiantes. Sin embargo, para no complicar demasiado las cosas, mantendré la explicación dentro de MetaTrader 5, aunque no se limita solo a él. Todo es mucho más amplio y complejo. Entonces, debes comprender muy bien este punto: MetaTrader 5 envía mensajes a tu programa. Estos mensajes son capturados y gestionados por algunos procedimientos presentes en tu programa. Entre estos procedimientos, hay uno que es más genérico y permite enviar cosas mucho más complejas, y usa una interfaz común y bien definida. El nombre de este procedimiento es OnChartEvent. Punto y aparte. Ahora viene la parte complicada.

MQL5, y me mantendré solo en él para no complicar aún más las cosas, permite que tú, como programador, definas eventos personalizados. Estos eventos se identifican por una constante sumada a un valor. El nombre de esta constante es: CHARTEVENT_CUSTOM. Así, al utilizar esta constante, puedes enviar desde cualquier parte de tu programa un mensaje al gestor de mensajes, lo que te permite concentrar en un único punto el tratamiento tanto de los eventos específicos como de los comunes. Pero no llamas al gestor de mensajes de cualquier manera. Debes hacerlo del modo adecuado y, para simplificar las cosas, MQL5 nos proporciona una función para este propósito: EventChartCustom. Al usar esta función, puedes enviar mensajes al gestor de mensajes estándar, la mencionada OnChartEvent, que, en mi caso, llama a DispatchMessage.

Todo esto es maravilloso de ver y funciona a la perfección, lo que te permite hacer muchas cosas. Sin embargo, existe un peligro. El peligro se esconde precisamente en los CHARTEVENT_CUSTOM. El mayor peligro de estas llamadas personalizadas no está en mi programa, en el tuyo ni en el de cualquier otro buen programador. El peligro real está en el hecho de que el usuario no sabe lo que hace cada programa. No juzgues mal al pobre usuario. Muchas veces ni siquiera tiene idea de lo que realmente sucede. Por eso es importante que NUNCA, JAMÁS uses algo sin saber realmente qué es. Pues el programa puede funcionar perfectamente bien en varios escenarios, pero habrá uno, y solo uno, en el que la interacción entre programas se convierta en una pesadilla completa. Esto puede hacer que la plataforma se bloquee, que cosas desaparezcan o que otras aparezcan de la nada, y tú te quedes sin entender absolutamente nada de lo que está pasando. Está bien cuando los efectos son perceptibles, pero ¿y cuando simplemente ocurren en absoluto silencio? Puedes pensar que todo está funcionando perfectamente bien cuando, en realidad, la situación puede estar al borde del precipicio.

Si eres un programador profesional y te dedicas a desarrollar y vender soluciones, no me malinterpretes. Pero deberías explicar a tu cliente que tu programa puede interactuar de forma que cause problemas a otros programas, o que otros programas pueden causar problemas en el tuyo. Y tú, usuario, deberías tener cuidado de no mezclar el código de un programador con el de otro. Por esta razón, hace algún tiempo, Windows solía bloquearse sin motivo aparente y la gente simplemente culpaba al programa, cuando en realidad los bloqueos normalmente ocurrían cuando ciertos programas se estaban ejecutando al mismo tiempo en el mismo entorno.

No entraré en este tema, ya que se saldría del objetivo principal de esta explicación. Pero es importante que comprendas algo: MetaTrader 5 es similar al sistema operativo Windows. Si utilizas las herramientas adecuadas de la manera correcta, NUNCA tendrás problemas con la plataforma. Pero si empiezas a mezclar las cosas, ten cuidado, ya que podrías enfrentar diversos problemas. Sabiendo que MetaTrader 5 es un entorno gráfico orientado a operaciones en el mercado financiero, surge una pregunta: ¿Qué sucede si dos programas están usando EventChartCustom, ya que esta función hace que MetaTrader 5 transfiera, a pedido del programador, un mensaje?

Bien. La pregunta es simple de formular. Y, de hecho, es una pregunta válida. Pero para entender, comencemos con un caso más sencillo. ¿Qué sucede cuando UN programa utiliza la función EventChartCustom? Básicamente, MetaTrader 5 enviará un evento personalizado para ser tratado por el procedimiento OnChartEvent. Esto parece obvio, ¿verdad? Pero no. No es tan obvio, y ahí radica el peligro.

Un uso típico de EventChartCustom se puede ver en el código del indicador de control, que se muestra en el artículo anterior. En la línea 30 del código del indicador de control, verás el siguiente código:

30.     EventChartCustom(user00, C_Controls::evInit, Info.s_Infos.iPosShift, Info.df_Value, "");

Pues bien. Cuando MetaTrader 5 ejecute esta línea, lanzará un evento ChartEvent, que hará que OnChartEvent sea ejecutado por el código presente en el gráfico. Y el tratamiento sigue hasta encontrar la función DispatchMessage, que se encuentra en la clase C_Control, en la línea 161 del código que se muestra en el artículo anterior, pero para facilitarlo, traigamos el fragmento aquí.

161.            void DispatchMessage(const int id, const long &lparam, const double &dparam, const string &sparam)
162.                    {
163.                            u_Interprocess Info;
164.                            
165.                            switch (id)
166.                            {
167.                                    case CHARTEVENT_CUSTOM + C_Controls::evInit:
168.                                            Info.df_Value = dparam;
169.                                            m_Slider.Minimal = Info.s_Infos.iPosShift;
170.                                            SetPlay(Info.s_Infos.isPlay);
171.                                            if (!Info.s_Infos.isPlay) CreateCtrlSlider();
172.                                            break;

Fragmento del código presente en la clase C_Control

Ahora, debido a que el evento es personalizado, MetaTrader 5 configurará el valor de la ID en la llamada del procedimiento OnChartEvent, de manera que esta ID sea un valor correspondiente a CHARTEVENT_CUSTOM sumado a otro valor. En el caso mostrado, el valor será el de C_Control:evInit. Pero, ¿cuál es el valor de C_Control:evInit? Para saber esto, deberás ir a la línea 35 del código de la clase C_Control y verificar el valor.

035.            enum EventCustom {evInit};

Este valor forma parte de una enumeración. Y ya que la enumeración cuenta solo con este valor y no está siendo inicializada con un valor, comenzará con el valor predeterminado, es decir, CERO. Entonces, la misma línea 30 presente en el indicador de control, en realidad, sería interpretada por MetaTrader 5 como:

30.     EventChartCustom(user00, CHARTEVENT_CUSTOM + 0, Info.s_Infos.iPosShift, Info.df_Value, "");

Este código funcionará perfectamente y de manera segura, permitiéndote, como programador, hacer una llamada personalizada en cualquier momento, con el fin de que el procedimiento DispatchMessage, presente dentro de la clase C_Control, inicialice algunos valores que no fueron ajustados en el constructor de la clase. Este tipo de cosas es muy común y es una forma perfectamente adecuada de programar, siendo bastante útil en diversas situaciones.

Lo mismo sucede en el indicador de mouse. Entonces, vamos a echar un vistazo a él para entender otra cosa, pero aún dentro del uso de UN programa que hace uso de eventos personalizados en MetaTrader 5.

En todo el código del indicador de mouse, no ves ninguna llamada a EventChartCustom. Sin embargo, existe un código en el manejador de mensajes para responder a un evento personalizado. Este código ha estado allí durante bastante tiempo, previendo su uso futuro casi sin querer queriendo. Puedes ver este código de tratamiento en las líneas 196 y 199 de la clase C_Mouse. Si observas atentamente, notarás algunas cosas. Traigamos el fragmento para este artículo, para que comprendas mejor lo que quiero explicar.

189. virtual void DispatchMessage(const int id, const long &lparam, const double &dparam, const string &sparam)
190.                    {
191.                            int w = 0;
192.                            static double memPrice = 0;
193.                            
194.                            if (m_Mem.szShortName == NULL) switch (id)
195.                            {
196.                                    case (CHARTEVENT_CUSTOM + ev_HideMouse):
197.                                            if (m_Mem.IsFull) ObjectSetInteger(GetInfoTerminal().ID, def_NameObjectLineH, OBJPROP_COLOR, clrNONE);
198.                                            break;
199.                                    case (CHARTEVENT_CUSTOM + ev_ShowMouse):
200.                                            if (m_Mem.IsFull) ObjectSetInteger(GetInfoTerminal().ID, def_NameObjectLineH, OBJPROP_COLOR, m_Info.corLineH);
201.                                            break;

Fragmento del código presente en la clase C_Mouse

Observa que en este fragmento estamos usando ev_HideMouse y ev_ShowMouse. Si algún programa desea ocultar la línea del indicador de mouse, bastará con que solicite a MetaTrader 5 enviar un evento personalizado al indicador de mouse. Así podrás ocultar o mostrar la línea del mouse. Nota que no destruimos el objeto, solo cambiamos la propiedad de color.

Pero estos valores ev_HideMouse y ev_ShowMouse son enumeraciones. ¿De dónde provienen? Bien, puedes verlos en la línea 34 de la clase C_Mouse. Una vez más, para facilitar la explicación, traigamos esa línea a este artículo.

034.            enum eEventsMouse {ev_HideMouse, ev_ShowMouse};

Quizás aún no hayas comprendido lo que trato de explicar. Para simplificar las cosas, mira el video 01, donde podrás ver cómo funciona este sistema.


Video 01 - Demostración.

Nota que trabajan en perfecta armonía, sin causar ningún tipo de problema. Durante la inicialización, el indicador de control le dice a MetaTrader 5 que es necesario tratar un evento personalizado, y el indicador de mouse espera recibir un evento personalizado de algún programa para ocultar o mostrar la línea del mouse. Cuando están separados, ambos indicadores no generan ningún tipo de problema o conflicto entre sí. Sin embargo, cuando se colocan juntos, la situación comienza a complicarse. Puedes verlo en el video 02.


Video 02 - Conflictos.

¿Por qué sucede esto? ¿Por qué no generan ningún tipo de problema cuando están separados, pero entran en conflicto cuando se colocan juntos? Esta es la gran cuestión y es donde muchos desisten en su intento de convertirse en programadores profesionales. Un principiante que no está realmente motivado para aprender programación abandona en este punto. Sin embargo, un programador profesional, o alguien motivado a serlo, ve en esto una oportunidad de aprendizaje y busca más conocimiento para resolver este conflicto. Este es precisamente el problema de usar programas de diferentes programadores, o incluso del mismo programador, que no se preocupa por probar sus programas de manera un poco más creativa e intentar hacer algo para lo que no fueron diseñados inicialmente. Pero dejemos un poco de lado esta cuestión y centrémonos en el conflicto visto en el video 02.

¿Por qué dos indicadores que funcionan aparentemente bien de forma independiente tienen un funcionamiento completamente extraño cuando se colocan juntos?


Entender el concepto de entorno de trabajo

Si eres un usuario más experimentado, es muy probable que ya hayas oído hablar de los entornos de trabajo o que incluso los hayas utilizado. El concepto se basa en la separación de elementos para que puedan coexistir de forma independiente dentro de un mismo ecosistema.

En MetaTrader 5, esta cuestión sobre el entorno se toma muy en serio. Si no comprendes esta idea de entorno de trabajo, no entenderás el motivo del conflicto mostrado en el video 02. Y, principalmente, no podrás resolver este mismo conflicto. Recuerda: Queremos que el indicador de mouse funcione en perfecta armonía con cualquier otro. De esta forma, se eliminan una serie de problemas y se convierte en un módulo de un sistema aún mayor.

Muchos simplemente desistirían. Pero desistir no es una opción. Queremos y haremos que el sistema sea modular, y para ello, necesitamos que el indicador de mouse funcione conjuntamente con el indicador de control.

Al observar el video 01, vemos que los indicadores no entran en conflicto; sin embargo, en el video 02, al colocarlos juntos, ocurren cosas extrañas con el indicador de mouse en el mismo gráfico que el indicador de control. Se puede ver claramente que MetaTrader 5 trata cada gráfico como un entorno totalmente aislado del resto.

Este tipo de observación es importante y la utilizaremos más adelante. Pero hay otra igual de importante en el video 02. Cuando MetaTrader 5 actualiza el gráfico en respuesta a un evento del usuario para cambiar el marco temporal, ocurre una serie de cosas. Para comprenderlo, es necesario saber cómo funciona MetaTrader 5.

Cuando solicitamos un cambio de marco temporal, como se vio en el video, MetaTrader 5 elimina temporalmente todo lo que está en el gráfico y luego repone lo que realmente es necesario. Por esta razón, en el gráfico solo se reemplazan los indicadores y el EA. Si el programador no lo tiene en cuenta, todos los programas entrarán en conflicto. Esto se debe a que el orden en que MetaTrader 5 repone las cosas probablemente no será el mismo en que el usuario las colocó en el gráfico. Puede ser que el usuario coloque las cosas en el gráfico en un orden en el que nada falla. Pero en cuanto sucede algo y MetaTrader 5 recrea el gráfico, el orden puede ser diferente y, en ese momento, empezarán a aparecer problemas. Muchos culparán a la plataforma, otros al sistema operativo, otros culparán a Dios o al Diablo. Pero, en realidad, el problema es que el programa realizado por ti o por alguien que hayas contratado no prevé el uso conjunto de varios elementos. Y el hecho de que muchos códigos estén cerrados dificulta aún más entender por qué las cosas entran en conflicto.

Volvamos a la cuestión principal. En este artículo, mencioné que el indicador de mouse no hace uso interno de ningún evento personalizado. Sin embargo, responde a dos eventos personalizados: uno para ocultar el mouse y otro para mostrar la línea del mouse. Por otro lado, el indicador de control utiliza y responde a un evento personalizado que sirve, precisamente, para inicializar algunas cosas en la clase de control.

Bien, volvamos a revisar el código. Ahora quiero que presten mucha, pero mucha atención a lo que voy a explicar. Si logras entenderlo, darás un gran salto en tu comprensión de cómo funciona MetaTrader 5.

Ambos indicadores, tanto el de control como el de mouse, se compilan por separado. En el código, usamos enumeraciones que deberían estar de alguna forma ligadas a la clase que responderá a los mensajes. Sí, pero, al pensar de esta forma, estás suponiendo algo. Y en programación no hacemos suposiciones. Para el compilador, ese código de evento personalizado será siempre un valor desplazado a partir de una constante. La constante es CHARTEVENT_CUSTOM y, como las enumeraciones comienzan con el valor predeterminado (cero), tanto el código de manejo de mensajes del indicador de mouse como el del indicador de control comienzan en el mismo índice, CHARTEVENT_CUSTOM más cero.

Puede que pienses que esto no explica la causa del conflicto. Pero estás equivocado. Esto sí que lo hace. Y también otras cosas. También explica cómo se organiza MetaTrader 5 en términos de entorno de trabajo.

Cada gráfico es un entorno de trabajo en MetaTrader 5. Cuando un programa envía un evento personalizado a MetaTrader 5, y sí, el evento no se envía al programa ni a ningún otro programa específico, se envía a MetaTrader 5. La plataforma lanzará este evento a cualquier programa presente en el entorno de trabajo, es decir, al gráfico. Por esta razón, en el video 02 puedes ver el comportamiento que se presenta. Esto se debe precisamente al hecho de que todos los programas dentro del gráfico recibirán la misma notificación de MetaTrader 5, en cuanto se dispare un evento personalizado. Ahora, piensa en un Expert Advisor que utiliza un evento personalizado para abrir y cerrar una posición. Si este mismo evento tiene como índice un evento de enviar una señal dentro de un indicador, que está en el mismo gráfico que el Expert Advisor, ¿qué pasará cuando el Expert Advisor o el indicador dispare el evento personalizado? Tendrás un gran problema. Así es. 

Y recuerda que aún estoy siendo moderado en esta cuestión. El asunto es mucho más complicado de lo que puede parecer, y usaremos este mismo sistema para hacer otras cosas. Por esta razón, es necesario que comprendas lo que está sucediendo y estudies con calma lo que te muestro. Si no lo haces, acabarás en un callejón sin salida con un precipicio justo enfrente.

Entonces, es posible que te preguntes: ¿No existe una forma de resolver esto? Sí, y es bastante simple, aunque se necesita tener ciertos conocimientos. Sin embargo, no entraré en detalles sobre esto en este artículo. Ya que será necesario hacer algunos cambios y explicar algunas cosas que, si se hacen en este momento, muy probablemente confundirán más que aclarar.


Conclusión

En este artículo, he comenzado a presentar el contenido de los próximos artículos. Sé que para muchos de ustedes este contenido es extremadamente complicado y difícil de entender de un momento a otro. Pero es importante que empieces a prepararte y a estudiar este tema que mostré en este artículo. La cuestión principal se tratará en los próximos artículos.

Para comprender y asimilar mejor lo que se ha explicado aquí, crea pequeños programas que puedan ser simples indicadores cuyo único propósito sea generar y responder a eventos personalizados. Colócalos en un mismo gráfico y en gráficos separados. Observa cómo se comportan cuando están juntos y cuando están separados. Pero, sobre todo, esta es la clave de oro de este artículo: intenta hacer que un indicador cambie algo en otro indicador, tanto cuando están en el mismo gráfico como cuando están en gráficos separados.

Si no logras que se comuniquen a través de eventos personalizados cuando están en gráficos separados, no te preocupes. No pienses que eres un mal profesional. Probablemente lo que ocurre es que aún no tienes los conocimientos adecuados sobre cómo hacerlo. Pero aquí no solo te mostraré cómo se hace, sino que también llevaremos las cosas a otro nivel de entendimiento, ya que, como habrás notado, querido lector, estoy evitando al máximo usar algunas cosas, como el uso de DLL externas para cubrir alguna deficiencia en MQL5, ya que hasta ahora ha podido satisfacer perfectamente lo que estamos haciendo, sin necesidad de soluciones extravagantes o cosas por el estilo.

Así que, buenos estudios y nos vemos en el próximo artículo. Prepárense, porque se avecinan retos importantes.

Traducción del portugués realizada por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/pt/articles/11932

Archivos adjuntos |
Anexo.zip (420.65 KB)
Desarrollo de un sistema de repetición (Parte 54): El nacimiento del primer módulo Desarrollo de un sistema de repetición (Parte 54): El nacimiento del primer módulo
En este artículo, veremos cómo construir el primero de los módulos, realmente funcional, para ser utilizado en el sistema de repetición/simulador. Además de tener como propósito general servir para otras cosas también. El módulo que se construirá aquí será el del indicador de mouse.
Redes neuronales: así de sencillo (Parte 73): AutoBots para predecir la evolución de los precios Redes neuronales: así de sencillo (Parte 73): AutoBots para predecir la evolución de los precios
Seguimos hablando de algoritmos para entrenar modelos de predicción de trayectorias. En este artículo nos familiarizaremos con un método llamado "AutoBots".
Desarrollo de un sistema de repetición (Parte 55): Módulo de control Desarrollo de un sistema de repetición (Parte 55): Módulo de control
En este artículo, implementaremos el indicador de control de manera que pueda integrarse en el sistema de mensajes que está en desarrollo. Aunque no es algo muy complejo de hacer, es necesario entender algunos detalles sobre cómo inicializar este módulo. El contenido expuesto aquí tiene como objetivo, pura y simplemente, la didáctica. En ningún caso debe considerarse como una aplicación cuya finalidad no sea el aprendizaje y el estudio de los conceptos mostrados.
Equilibrio de riesgos en la negociación simultánea de varios instrumentos comerciales Equilibrio de riesgos en la negociación simultánea de varios instrumentos comerciales
Este artículo permitirá a los principiantes escribir desde cero la implementación de un script para el equilibrio de riesgos en la negociación simultánea de varios instrumentos comerciales, mientras que los usuarios experimentados podrán obtener nuevas ideas para la implementación de sus soluciones en cuanto a las opciones propuestas en este artículo.