Descargar MetaTrader 5

Recetas de MQL5 - procesamiento de eventos típicos del gráfico

14 octubre 2014, 15:04
Dennis Kirichenko
0
432

Introducción

En este artículo me gustaría describir las posibilidades y el aspecto práctico del manejador OnChartEvent() respecto a los eventos típicos (estándar), ya definidos por el programador del MQL5. Los artículos del foro MQL5 y Code Base ya contienen los ejemplos del uso de este manejador.

Sin embargo, mi objetivo consiste en analizar las posibilidades de esta herramienta de la programación dirigida por eventos (PDE). Supongo que el manejador en cuestión puede ser utilizado tanto para los sistemas de trading totalmente automáticos, como para los semiautomáticos.


1. Evento ChartEvent

Pues bien, para empezar vamos a aclarar qué es lo que representa este tipo de evento.

Según la documentación, el evento ChartEvent puede aparecer durante el trabajo con el gráfico, a saber:

  • teclazo cuando la ventana del gráfico se encuentra enfocada;
  • creación del objeto gráfico;
  • eliminación del objeto gráfico;
  • clic con ratón en un objeto gráfico que pertenece al gráfico;
  • arrastre de un objeto gráfico con ratón;
  • fin de edición del texto en el campo de introducción del objeto gráfico LabelEdit.

De esta manera, este evento introduce la interactividad y permite interactuar con el gráfico. Es más, dicha interacción puede ser resultado tanto del trabajo "con las manos" (trading manual), como de unas acciones algorítmicas (trading automático).

El programador clasifica el evento ChartEvent según los tipos que se establecen por la enumeración ENUM_CHART_EVENT.

Es importante mencionar que en la lista de los tipos existen los que establecen el rango de los eventos personalizados. Dichos eventos representan aquella oculta reserva que el programador puede utilizar a su gusto. Los desarrolladores del MQL5 han previstos 65535 identificadores de eventos personalizados.

En cuanto a los eventos personalizados, el programador cuenta con una función-generador especializada EventChartCustom(). Pero en el presente artículo no vamos a tratar el tema de los eventos personalizados.


2. Manejador y generador del ChartEvent

La función/manejador especial OnChartEvent() se encarga de todo el trabajo de procesamiento del ChartEvent. Y eso cuadra completamente con la concepción del lenguaje MQL5 según la cual, por ejemplo, el evento Trade se procesa por la función OnTrade(), el evento Init se procesa por la función OnInit(), etc.

La función OnChartEvent() tiene el siguiente encabezamiento:

void OnChartEvent(const int id,         // identificador del evento  
                  const long& lparam,   // parámetro del evento del tipo long
                  const double& dparam, // parámetro del evento del tipo double
                  const string& sparam  // parámetro del evento del tipo string
                  )

Todos los parámetros de entrada son constantes y llevan una determinada carga informativa cuando se invoca el manejador.

Así, según el valor del parámetro id se puede identificar el evento que ha llamado al manejador. Los demás pueden poseer los valores de «sus» tipos: long, double y string. Se supone que de esta manera se puede captar algunos datos más sobre el evento.

Más tarde intentaremos crear un ejemplo en el que van a utilizarse los valores de los parámetros mencionados para análizar lo que está pasando.

La parte personalizada del evento ChartEvent de la que se encarga el programador está vinculada con la función EventChartCustom(). Precisamente ella es la que puede generar este evento. El encabezado de la función es el siguiente:

bool  EventChartCustom(long    chart_id,        // identificador del gráfico receptor del evento
                       ushort  custom_event_id, // identificador del evento
                       long    lparam,          // parámetro del tipo long
                       double  dparam,          // parámetro del tipo double
                       string  sparam           // parámetro string del evento
                       )

En realidad, la función-generador es capaz de crear un evento y enviarlo a cualquier gráfico inclusive el actual con cualquier valor de parámetros de entrada. Los últimos pertenecen a los tipos: ushort, long, double, string.

Las funciones OnChartEvent() y EventChartCustom() son una herramienta muy potente que sirve de un brillante ejemplar de ventajas de la programación dirigida por eventos.


3. Plantilla de procesamiento de eventos estándar

Propongo trabajar del siguiente modo. Vamos a analizar los tipos de eventos del gráfico y para cada uno le pondré su ejemplo. Escribiremos para cada evento su versión del Asesor EXperto (EA) EventProcessor.mq5 en cuyo código estará presente el procesamiento del evento del gráfico. En MQL5 hay 10 eventos típicos.

Para tres eventos (evento del ratón, evento de creación del objeto gráfico, evento de eliminación del objeto gráfico) hay que preparar su propio gráfico. Esto se hace mediante la función ChartSetInteger(). Ella permite al gráfico reaccionar a los eventos indicados.

Entonces, el bloque de eventos procesados tendrá el siguiente aspecto:

void OnChartEvent(const int id, 
                  const long   &lparam,
                  const double &dparam,
                  const string &sparam)
  {
   string comment="Último evento: ";

//--- selección del evento del gráfico
   switch(id)
     {
      //--- 1
      case CHARTEVENT_KEYDOWN:
        {
         comment+="1) un teclazo";
         break;
        }
      //--- 2
      case CHARTEVENT_MOUSE_MOVE:
        {
         comment+="2) del ratón";
         break;
        }
      //--- 3
      case CHARTEVENT_OBJECT_CREATE:
        {
         comment+="3) creación del objeto gráfico";
         break;
        }
      //--- 4
      case CHARTEVENT_OBJECT_CHANGE:
        {
         comment+="4) cambio de propiedades del objeto mediante el diálogo de propiedades";
         break;
        }
      //--- 5
      case CHARTEVENT_OBJECT_DELETE:
        {
         comment+="5) eliminación del objeto gráfico";
         break;
        }
      //--- 6
      case CHARTEVENT_CLICK:
        {
         comment+="6) clic del ratón en el gráfico";
         break;
        }
      //--- 7
      case CHARTEVENT_OBJECT_CLICK:
        {
         comment+="7) clic del ratón en el objeto gráfico";
         break;
        }
      //--- 8
      case CHARTEVENT_OBJECT_DRAG:
        {
         comment+="8) arrastre del objeto gráfico con el ratón";
         break;
        }
      //--- 9
      case CHARTEVENT_OBJECT_ENDEDIT:
        {
         comment+="9) fin de edición del texto";
         break;
        }
      //--- 10
      case CHARTEVENT_CHART_CHANGE:
        {
         comment+="10) modificación del gráfico";
         break;
        }
     }
//---
   Comment(comment);
  }

He insertado en cada case una línea que describe el evento seleccionado. Finalmente, en la línea del comentario veremos qué tipo de evento ha tenido lugar en el gráfico.

Cuando inicie la ejecución de la plantilla y vaya a realizar diferentes manipulaciones con el gráfico, verá que en la línea del comentario pueden aparecer diferentes textos.

A que la utilidad de este EA que determina el tipo del evento del gráfico no será muy grande, ¿verdad? Vamos a ampliar sus posibilidades y añadiremos en el código nuevos recursos.


4. Ejemplos de procesamiento de eventos estándar

4.1. Evento de un teclazo

Vamos a coger el primer módulo case y trabajaremos con las teclas del teclado, es decir, enseñaremos al EA reaccionar a las señales del teclado.

Que el EA abra la posición de compra cuando se pulse la tecla «flecha arriba» y la posición de venta cuando se pulse «flecha abajo».

Entonces, el código del módulo case puede tener el siguiente aspecto:

//--- 1
      case CHARTEVENT_KEYDOWN:
        {
         //--- flecha arriba
         if(lparam==38)
            TryToBuy();

         //--- flecha abajo
         else if(lparam==40)
            TryToSell();

         comment+="1) un teclazo";
         //---         
         break;
        }

Puede encontrar el código de las funciones TryToBuy() y TryToSell() en el archivo del EA.

Los parámetros del trading (lote, Stop Loss, Take Profit, etc.) se establecen como variables input (InpLot, InpStopLoss, InpTakeProfit, etc).

Señalaría también que el parámetro lparam recibe el código de la tecla pulsada.




Llamaremos la versión renovada del EA EventProcessor1.mq5.


4.2. Evento del ratón

Este tipo del evento será procesado sólo si para el gráfico ha sido establecida la propiedad CHART_EVENT_MOUSE_MOVE.

Para eso en el bloque de inicialización del EA he escrito las siguientes líneas:

//--- mouse move
bool is_mouse=false;
if(InpIsEventMouseMove)
   is_mouse=true;
ChartSetInteger(0,CHART_EVENT_MOUSE_MOVE,is_mouse);

Hay que decir que si Usted trabaja con el ratón, entonces el evento del ratón naturalmente tendrá lugar con muchísima frecuencia. Por eso merece la pena realizar la posibilidad de desactivar el procesamiento de este evento.

Los parámetros del manejador lparam y dparam comunican las coordenadas X y Y, respectivamente.

Vamos a inventar un ejemplo. Que en el gráfico haya sangría de la barra cero desde el borde derecho. Al situar el cursor del ratón sobre el área a la derecha del límite de la sangría, aparecerá la ventana con la propuesta de comprar o vender.

Para empezar, hay que determinarse con la sangría. Crearemos la variable input para determinar el tamaño de la sangría de la barra cero desde el borde derecho en por cientos (InpChartShiftSize).

Fig. 1 Ventana de la operación comercial

Fig. 1 Ventana de la operación comercial

Luego usaremos las funciones que activan y fijan el tamaño de la sangría ChartShiftSet() y ChartShiftSizeSet(). A continuación, averiguaremos si la coordenada X del ratón se encontraba antes a la izquierda del límite, y ahora se encuentra a la derecha. Si es así, aparece la ventana con la propuesta de comprar/vender (Fig. 1).

El código que implementa esta tarea es el siguiente:

//--- 2
      case CHARTEVENT_MOUSE_MOVE:
        {
         comment+="2) del ratón";
         //--- si procesar el evento del ratón
         if(InpIsEventMouseMove)
           {
            long static last_mouse_x;

            //--- activar la sangría
            if(ChartShiftSet(true))
               //--- fijar el tamaño de la sangría 
               if(ChartShiftSizeSet(InpChartShiftSize))
                 {
                  //--- ancho del gráfico
                  int chart_width=ChartWidthInPixels();

                  //--- determinar la coordenada X del límite de la sangría
                  int chart_shift_x=(int)(chart_width-chart_width*InpChartShiftSize/100.);

                  //--- condición del cruce del límite
                  if(lparam>chart_shift_x && last_mouse_x<chart_shift_x)
                    {
                     int res=MessageBox("Sí: comprar / No: vender","Operación de trading",MB_YESNO);
                     //--- si comprar
                     if(res==IDYES)
                        TryToBuy();
                     //--- si vender
                     else if(res==IDNO)
                        TryToSell();
                    }

                  //--- recordar la coordenada X del ratón
                  last_mouse_x=lparam;
                 }
           }

         //---
         break;
        }

Las funciones creadas anteriormente se encargan de las compras y las ventas. Llamaremos la versión renovada del EA EventProcessor2.mq5.


4.3. Evento de creación del objeto gráfico

Este tipo del evento surge cuando en el gráfico se crea algún objeto. Igual que el evento del ratón, este tipo debe obtener permiso para el procesamiento mediante la función de la propiedad CHART_EVENT_OBJECT_CREATE.

En el bloque de inicialización se puede indicar una vez si vamos a reaccionar a la aparición de un nuevo objeto gráfico, o no.

//--- object create
bool is_obj_create=false;
if(InpIsEventObjectCreate)
   is_obj_create=true;
ChartSetInteger(0,CHART_EVENT_OBJECT_CREATE,is_obj_create);

Sólo un parámetro del manejador va a contener aquí la información. Es sparam de cadena con el nombre del objeto gráfico creado.

Podremos encontrar este objeto por su nombre y decidir qué es lo que vamos a hacer con él en adelante.

Aquí propongo un simple ejemplo. Colocamos una línea horizontal en el gráfico. Y que nuestro robot la coloque sobre el precio máximo de todas las barras visibles del gráfico y trace otras dos líneas más. La línea inferior estará situada sobre el precio mínimo, y la última será equidistante entre otras dos.

Aquí tiene el código para la solución de la tarea propuesta:

//--- 3
      case CHARTEVENT_OBJECT_CREATE:
        {
         comment+="3) creación del objeto gráfico";
         //--- si procesar el evento de creación del objeto gráfico
         if(InpIsEventObjectCreate)
           {
            //--- "captar" la creación de la horizontal
            int all_hor_lines=ObjectsTotal(0,0,OBJ_HLINE);

            //--- si es la única línea
            if(all_hor_lines==1)
              {
               string hor_line_name1=sparam;

               //--- calcular los niveles
               int visible_bars_num=ChartVisibleBars();

               //--- los arrays high y low
               double highs[],lows[];
               //---
               int copied=CopyHigh(_Symbol,_Period,0,visible_bars_num-1,highs);
               if(copied!=visible_bars_num-1)
                 {
                  Print("Failed to copy highs!");
                  return;
                 }
               copied=CopyLow(_Symbol,_Period,0,visible_bars_num-1,lows);
               if(copied!=visible_bars_num-1)
                 {
                  Print("Failed to copy lows!");
                  return;
                 }
               //--- precios high y low
               double ch_high_pr,ch_low_pr,ch_mid_pr;
               //---
               ch_high_pr=NormalizeDouble(highs[ArrayMaximum(highs)],_Digits);
               ch_low_pr=NormalizeDouble(lows[ArrayMinimum(lows)],_Digits);
               ch_mid_pr=NormalizeDouble((ch_high_pr+ch_low_pr)/2.,_Digits);

               //--- colocar la línea creada en el máximo
               if(ObjectFind(0,hor_line_name1)>-1)
                  if(!ObjectMove(0,hor_line_name1,0,0,ch_high_pr))
                    {
                     Print("Failed to move!");
                     return;
                    }
               //--- crear la línea en el mínimo
               string hor_line_name2="Hor_line_min";
               //---
               if(!ObjectCreate(0,hor_line_name2,OBJ_HLINE,0,0,ch_low_pr))
                 {
                  Print("Failed to create the 2nd horizontal line!");
                  return;
                 }
               //--- crear la línea entre high y low 
               string hor_line_name3="Hor_line_mid";
               //---
               if(!ObjectCreate(0,hor_line_name3,OBJ_HLINE,0,0,ch_mid_pr))
                 {
                  Print("Failed to create the 3rd horizontal line!");
                  return;
                 }
              }
           }
         break;
        }

Llamaremos la versión renovada del EA EventProcessor3.mq5.

Fig. 2. Resultado de procesamiento del evento de creación del objeto gráfico

Fig. 2. Resultado de procesamiento del evento de creación del objeto gráfico

Después de realizar esta operación, me ha salido la siguiente imagen (Fig. 2). De esta manera, cuando creamos un objeto gráfico, podemos enseñar reaccionar a nuestro EA y luego ejecutar alguna acción.


4.4. Evento del cambio de propiedades de un objeto mediante el diálogo de propiedades

Este tipo del evento parece parcialmente al tipo anterior. Se activa cuando alguna propiedad del objeto gráfico se cambia mediante el diálogo de propiedades. Es una herramienta bastante cómoda, por ejemplo, para la sincronización de las propiedades gráficas de los objetos del mismo tipo.

Imagínese que tiene en su gráfico varios objetos. Habitualmente el trader siempre tiene en su gráfico muchas lineas de diferentes tipos. Y necesitamos hacer que estas líneas sean invisibles por algún tiempo sin eliminarlas del gráfico. Intentaremos resolver este problema.

Se puede descolorar la línea modificada y, por lo tanto, hacer lo mismo con otros objetos gráficos.

Entonces, el código puede ser el siguiente:

//--- 4
      case CHARTEVENT_OBJECT_CHANGE:
        {
         comment+="4) cambio de propiedades del objeto mediante el diálogo de propiedades";
         //---
         string curr_obj_name=sparam;
         //--- buscar objeto modificado
         if(ObjectFind(0,curr_obj_name)>-1)
           {
            //--- obtener el color del objeto
            color curr_obj_color=(color)ObjectGetInteger(0,curr_obj_name,OBJPROP_COLOR);
            //--- total de objetos en el gráfico
            int all_other_objects=ObjectsTotal(0);
            //--- buscar otros objetos
            for(int obj_idx=0;obj_idx<all_other_objects;obj_idx++)
              {
               string other_obj_name=ObjectName(0,obj_idx);
               if(StringCompare(curr_obj_name,other_obj_name)!=0)
                  if(!ObjectSetInteger(0,other_obj_name,OBJPROP_COLOR,curr_obj_color))
                    {
                     Print("Failed to change the object color!");
                     return;
                    }
              }
            //--- redibujar el gráfico
            ChartRedraw();
           }
         //---
         break;

Que haya una serie de líneas en el gráfico (Fig. 3).

Fig. 3. Líneas dinámicas de varios colores

Fig. 3. Líneas dinámicas de varios colores

Si intentamos entrar en el diálogo de propiedades y cambiar el color de cualquier línea, es decir, descolorarla (Fig. 4), en el gráfico no se verá ninguna línea. Los objetos gráficos no se eliminan físicamente.

Fig. 4. Cambio del color de la línea

Fig. 4. Cambio del color de la línea

La nueva versión del EA obtiene el nombre EventProcessor4.mq5.


4.5. Evento de eliminación del objeto gráfico

Como se desprende del nombre del tipo del evento del gráfico, este evento aparece cuando un objeto se quita del gráfico.

Se trata del último evento entre los demás que requiere directamente el permiso previo para su procesamiento. Se puede hacerlo a través de la propiedad CHART_EVENT_OBJECT_DELETE.

//--- object delete
   bool is_obj_delete=false;
   if(InpIsEventObjectDelete)
      is_obj_delete=true;
   ChartSetInteger(0,CHART_EVENT_OBJECT_DELETE,is_obj_delete);

Vamos a mostrar el siguiente ejemplo. En el gráfico donde se encuentra nuestro EA hay una serie de objetos gráficos de diferentes tipos. Supongamos que hay que eliminar los objetos de un solo tipo. Que sean las líneas verticales (Fig. 5).

Fig. 5. Cinco verticales y otras líneas

Fig. 5. Cinco verticales y otras líneas

Eliminaremos manualmente una de las líneas verticales, el EA eliminará las cuatro restantes (Fig. 6).

Fig. 6. Líneas restantes

Fig. 6. Líneas restantes

En el diario «Asesores Expertos» aparecerán las siguientes entradas:

NS      0       10:31:17.937    EventProcessor5 (EURUSD.e,W1)   Líneas verticales antes de eliminación: 4
MD      0       10:31:17.937    EventProcessor5 (EURUSD.e,W1)   Número de líneas verticales eliminadas: 4
QJ      0       10:31:18.078    EventProcessor5 (EURUSD.e,W1)   Líneas verticales después de eliminación: 0

Habría que matizar una cosa. Si un objeto ha sido eliminado, ya no se puede acceder a sus propiedades. Eso significa que si no nos hemos preocupado de antemano de obtener los datos necesarios sobre el objeto, tras su eliminación ya no estarán disponibles. Por eso, por ejemplo, para averiguar el tipo del objeto eliminado, hace falta memorizarlo antes de eliminar el objeto. Y se me ha ocurrido una propuesta para el desarrollador de MQL5 que consiste en crear el historial del gráfico abierto en el terminal. Entonces tendremos la posibilidad de dirigirse, por ejemplo, a las propiedades de objetos eliminados.

Nombraremos la última versión del EA EventProcessor5.mq5.


4.6. Evento de un clic del ratón sobre un gráfico

Este evento surge si hacemos un clic del ratón sobre el gráfico. El manejador reaccionará sólo al clic izquierdo. Si hacemos clic con el botón derecho, se abre el menú contextual, si usamos el botón intermedio, aparece el cursor en cruz.

Los parámetros del manejador lparam y dparam comunican las coordenadas X y Y, respectivamente.

Cogemos como ejemplo una tarea no tan complicada. Necesitamos que en el punto del gráfico donde ha sido hecho el clic del ratón se dibuje la flecha buy. El objeto de la flecha tiene sólo un punto de anclaje. Por eso vamos a necesitar una conversión de coordenadas X y Y en el valor del tiempo del punto de anclaje y del precio del punto de anclaje.

Aquí tiene el código para este ejemplo:

//--- 6
      case CHARTEVENT_CLICK:
        {
         comment+="6) clic del ratón en el gráfico";
         //--- contador de objetos
         static uint sign_obj_cnt;
         string buy_sign_name="buy_sign_"+IntegerToString(sign_obj_cnt+1);
         //--- coordenadas 
         int mouse_x=(int)lparam;
         int mouse_y=(int)dparam;
         //--- tiempo y precio
         datetime obj_time;
         double obj_price;
         int sub_window;
         //--- convertir las coordenadas X y Y en los valores de tiempo y precio
         if(ChartXYToTimePrice(0,mouse_x,mouse_y,sub_window,obj_time,obj_price))
           {
            //--- creación del objeto
            if(!ObjectCreate(0,buy_sign_name,OBJ_ARROW_BUY,0,obj_time,obj_price))
              {
               Print("Failed to create buy sign!");
               return(false);
              }
            //--- redibujar el gráfico
            ChartRedraw();
            //--- aumentar el contador de objetos
            sign_obj_cnt++;
           }
         //---
         break;
        }

La versión actual del EA recibe el nombre EventProcessor6.mq5.


4.7. Evento de un clic del ratón sobre un objeto gráfico

Este tipo del evento se diferencia del anterior sólo en que el clic del ratón se hace en un objeto gráfico. El parámetro de cadena sparam indicará el nombre del objeto pulsado.

En el último ejemplo hemos creado las flechas buy. Ahora vamos a hacer que el clic en el objeto de este tipo lo cambie por la flecha sell.

El código del bloque del manejador puede tener aproximadamente el siguiente aspecto:

//--- 7
      case CHARTEVENT_OBJECT_CLICK:
        {
         comment+="7) clic del ratón en el objeto gráfico";
         //---
         string sign_name=sparam;

         //--- eliminar la flecha buy
         if(ObjectDelete(0,sign_name))
           {
            //--- redibujar el gráfico
            ChartRedraw();
            //---
            static uint sign_obj_cnt;
            string sell_sign_name="sell_sign_"+IntegerToString(sign_obj_cnt+1);

            //--- coordenadas 
            int mouse_x=(int)lparam;
            int mouse_y=(int)dparam;
            //--- tiempo y precio
            datetime obj_time;
            double obj_price;
            int sub_window;
            //--- convertir las coordenadas X y Y en los valores de tiempo y precio
            if(ChartXYToTimePrice(0,mouse_x,mouse_y,sub_window,obj_time,obj_price))
              {
               //--- creación del objeto
               if(!ObjectCreate(0,sell_sign_name,OBJ_ARROW_SELL,0,obj_time,obj_price))
                 {
                  Print("Failed to create sell sign!");
                  return;
                 }
               //--- redibujar el gráfico
               ChartRedraw();
               //--- aumentar el contador de objetos
               sign_obj_cnt++;
              }
           }
         //---
         break;
        }

Para los fines del ejemplo he dejado intacto el módulo case del procesamiento del clic del ratón.

Al iniciar el EA, he hecho tres clics izquierdos y he obtenido 3 flechas de compra (Fig. 7). Su ubicación he resaltado con el color amarillo.

Fig. 7. Flechas buy

Fig. 7. Flechas buy

Y si ahora hacemos clic en cada flecha buy, obtendremos la siguiente imagen (Fig. 8).

Fig. 8. Flechas buy y sell

Fig. 8. Flechas buy y sell

Aparecieron las flechas sell tal como habíamos pensado, pero también aparecieron las flechas buy como no habíamos pensado. Muestro intencionadamente la lista de objetos en el gráfico donde he resaltado con amarillo los nombres de las flechas buy.

Es fácil de notar que el EA ha creado la cuarta, la quinta, y la sexta flecha buy. ¿Por qué ha pasado eso? Quizás porque el primer clic en el objeto ha provocado dos eventos: el primero ha sido el clic en el objeto, y el segundo, el clic en el gráfico. Precisamente el último evento genera la creación de la flecha buy. Entonces, surge la necesidad de añadir algún mecanismo que corte el procesamiento del segundo evento- clic en el gráfico. Creo que este mecanismo puede ser el control del tiempo.

Añadiremos la variable global gLastTime. Vamos a usarla para controlar el tiempo de creación de la flecha buy. Si el manejador de un clic habitual se invoca dentro de un período inferior a 250 milisegundos tras la creación de la flecha sell, vamos a considerar que hay que omitir su llamada.

Antes de redibujar el gráfico, hay que insertar la línea en el bloque de procesamiento del clic en el objeto:

//--- recordar el momento de creación
gLastTime=GetTickCount();

Y en el bloque de procesamiento del clic en el gráfico hay que insertar la comprobación por el tiempo:

uint lastTime=GetTickCount();
if((lastTime-gLastTime)>250)
  {
   //--- aquí procesamiento del clic
  }

Volveremos a crear tres flechas del tipo buy (Fig. 9).

Fig. 9. Flechas buy

Fig. 9. Flechas buy

A pesar de su reducido tamaño intentaremos hacer clic sobre ellas. Las flechas han sido cambiadas por las del tipo sell (Fig. 10).

Fig. 10 Flechas sell

Fig. 10 Flechas sell

Siguiendo el costumbre, llamaremos la nueva versión del EA EventProcessor7.mq5.


4.8. Evento de desplazamiento de un objeto gráfico con el ratón

Este evento tiene lugar cuando el objeto se desplaza dentro de los límites del gráfico. El manejador recibe el nombre del objeto en forma del parámetro de cadena sparam.

Vamos a verlo en un ejemplo. El trader intradía opera muy a menudo dentro de un intervalo temporal. Marcaremos sus límites con dos líneas verticales. La imagen será aproximadamente la siguiente (Fig. 11). El período que nos interesa está resaltado con color más claro.

Fig. 11 Límites del intervalo temporal

Fig. 11 Límites del intervalo temporal

Usted puede cambiar el intervalo manualmente. Entonces, nuestro semiautomático debe reaccionar a este cambio.

Crearemos a nivel global dos variables que describen los nombres de dos verticales: gTimeLimit1_name y gTimeLimit2_name. Además, hay que crear dos variables para los nombres de los rectángulos que oscurecen el tiempo fuera del trading en el gráfico. También hay que crear las variables globales para los puntos de anclaje. Como tenemos dos rectángulos, serán cuatro puntos.

Aquí mostraré el código del módulo case del manejador del evento CHARTEVENT_OBJECT_DRAG:

//--- 8
      case CHARTEVENT_OBJECT_DRAG:
        {
         comment+="8) arrastre del objeto gráfico con el ratón";
         string curr_obj_name=sparam;
         //--- si se mueve una de las verticales
         if(!StringCompare(curr_obj_name,gTimeLimit1_name) || 
            !StringCompare(curr_obj_name,gTimeLimit2_name))
           {
            //--- coordenada del tiempo de las verticales
            datetime time_limit1=0;
            datetime time_limit2=0;
            //--- encontrar la primera vertical
            if(ObjectFind(0,gTimeLimit1_name)>-1)
               time_limit1=(datetime)ObjectGetInteger(0,gTimeLimit1_name,OBJPROP_TIME);
            //--- encontrar la segunda vertical
            if(ObjectFind(0,gTimeLimit2_name)>-1)
               time_limit2=(datetime)ObjectGetInteger(0,gTimeLimit2_name,OBJPROP_TIME);

            //--- si las verticales han sido encontradas
            if(time_limit1>0 && time_limit2>0)
               if(time_limit1<time_limit2)
                 {
                  //--- actualizar los parámetros de los rectángulos
                  datetime start_time=time_limit1;
                  datetime finish_time=time_limit2;
                  //---
                  if(RefreshRecPoints(start_time,finish_time))
                    {
                     //---
                     if(!ObjectMove(0,gRectLimit1_name,0,gRec1_time1,gRec1_pr1))
                       {
                        Print("Failed to move the 1st point!");
                        return;
                       }
                     if(!ObjectMove(0,gRectLimit1_name,1,gRec1_time2,gRec1_pr2))
                       {
                        Print("Failed to move the 2nd point!");
                        return;
                       }
                     //---
                     if(!ObjectMove(0,gRectLimit2_name,0,gRec2_time1,gRec2_pr1))
                       {
                        Print("Failed to move the 1st point!");
                        return;
                       }
                     if(!ObjectMove(0,gRectLimit2_name,1,gRec2_time2,gRec2_pr2))
                       {
                        Print("Failed to move the 2nd point!");
                        return;
                       }
                    }
                 }
           }
         //---
         break;
        }

Aquí hay una función personalizada RefreshRecPoints(). Ella se encarga de actualizar los valores de los puntos de anclaje para dos rectángulos. En el bloque de inicialización del EA puede informarse sobre cómo se crean los objetos gráficos. Llamaré la nueva versión EventProcessor8.mq5.


4.9. Evento del fin de edición del texto en el campo de introducción

Este tipo de evento es de carácter estrechamente especializado y aparece cuando en el campo de introducción se edita el texto. El parámetro sparam comunicará el nombre del objeto con el que se trabaja.

Vamos a crear un ejemplo. En el campo de introducción vamos a escribir la operación que queremos ejecutar. Que sean 2 operaciones: compra y venta en el mercado. Si introducimos en el campo la palabra «Buy», el EA comprará el activo, si escribimos «Sell», lo venderá. Vamos a arreglar que no dependamos del cambio de minúsculas y mayúsculas. Por eso se puede escribir «buy» y «sell». Además, en caso de la venta el texto y el borde del campo estarán en rojo, y en caso de la compra, en azul (Fig. 12).

Fig. 12 Compra a través del campo de introducción

Fig. 12 Compra a través del campo de introducción

Este es el código en el módulo case CHARTEVENT_OBJECT_ENDEDIT:

//--- 9
      case CHARTEVENT_OBJECT_ENDEDIT:
        {
         comment+="9) fin de edición del texto en el campo de introducción";
         //---
         string curr_obj_name=sparam;
         //--- si se edita el campo establecido
         if(!StringCompare(curr_obj_name,gEdit_name))
           {
            //--- obtener la descripción del objeto
            string obj_text=NULL;
            if(ObjectGetString(0,curr_obj_name,OBJPROP_TEXT,0,obj_text))
              {
               //--- comprobar el valor
               if(!StringCompare(obj_text,"Buy",false))
                 {
                  if(TryToBuy())
                     //--- establecer el color del texto
                     ObjectSetInteger(0,gEdit_name,OBJPROP_COLOR,clrBlue);
                 }
               else if(!StringCompare(obj_text,"Sell",false))
                 {
                  if(TryToSell())
                     //--- establecer el color del texto
                     ObjectSetInteger(0,gEdit_name,OBJPROP_COLOR,clrRed);
                 }
               else
                 {
                   //--- establecer el color del texto
                  ObjectSetInteger(0,gEdit_name,OBJPROP_COLOR,clrGray);
                 }
               //--- redibujar el gráfico
               ChartRedraw();
              }
           }
         //---
         break;
        }

La versión del EA se llama EventProcessor9.mq5. En el archivo fuente se puede ver también el bloque de creación del campo de introducción.


4.10. Evento de modificación del gráfico

Y el último evento del que vamos a tratar en este artículo está relacionado con el cambio de configuraciones del propio gráfico. Este tipo del evento se destaca de los demás ya que no se trata de algún objeto en el gráfico sino del propio gráfico. El programador afirma que el evento se genera cuando se cambia el tamaño del gráfico o algo nuevo aparece en sus ajustes. Vamos a ver el siguiente ejemplo.

Que haya prohibición para cambiar algunos ajustes del gráfico. Entonces todos los intentos de cambiarlos serán ignorados. En realidad, el EA simplemente va a devolver los ajustes anteriores. Vamos a fijar los siguientes parámetros del gráfico:

  • visualización de cuadrícula;
  • tipo de visualización del gráfico;
  • color del fondo.

Aquí tenemos el código para este módulo case:

//--- 10
      case CHARTEVENT_CHART_CHANGE:
        {
         //--- alto y ancho actuales del gráfico         
         int curr_ch_height=ChartHeightInPixelsGet();
         int curr_ch_width=ChartWidthInPixels();
         //--- si el alto y el ancho no se han cambiado
         if(gChartHeight==curr_ch_height && gChartWidth==curr_ch_width)
           {
            //--- fijar la propiedad:
            //--- visualización de cuadrícula
            if(!ChartShowGridSet(InpToShowGrid))
              {
               Print("Failed to show grid!");
               return(false);
              }
            //--- tipo de visualización del gráfico
            if(!ChartModeSet(InpMode))
              {
               Print("Failed to set mode!");
               return(false);
              }
            //--- color del fondo
            if(!ChartBackColorSet(InpBackColor))
              {
               Print("Failed to set background сolor!");
               return(false);
              }
           }
         //--- recordar las dimensiones de la ventana
         else
           {
            gChartHeight=curr_ch_height;
            gChartWidth=curr_ch_width;
           }
         //---
         comment+="10) modificación del gráfico";
         //---
         break;
        }

El nombre de la última versión será EventProcessor10.mq5.


Conclusión

En este artículo he intentado demostrar la variedad de los eventos típicos del gráfico en MetaTrader 5. Espero que el material con los ejemplos de procesamiento de eventos sea útil para los que se inician en el lenguaje MQL5.

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

Archivos adjuntos |
code_en.zip (19.59 KB)
Los bosques aleatorios predicen las tendencias Los bosques aleatorios predicen las tendencias

En el artículo se describe el uso del paquete Rattle para la búsqueda automática de patrones capaces de predecir "longs" y "shorts" para las parejas de divisas del mercado Fórex. El artículo será de utilidad tanto a los principiantes, como a los traders experimentados.

Preparación de la cuenta comercial para la migración al hosting virtual Preparación de la cuenta comercial para la migración al hosting virtual

El terminal de cliente MetaTrader es ideal para realizar la automatización de las estrategias comerciales. Los desarrolladores de robots comerciales encuentran todo lo necesario: un potente lenguaje de programación MQL4/MQL5 en base a C++, el cómodo entorno de desarrollo MetaEditor, el simulador de estrategias multitipo con soporte para los cálculos distributivos MQL5 Cloud Network. En este artículo podrá conocer cómo trasladar su terminal de cliente con todos los desarrollos a un entorno virtual.

Análisis regresivo de la influencia de datos macroeconómicos en el cambio de precio de las divisas Análisis regresivo de la influencia de datos macroeconómicos en el cambio de precio de las divisas

En el artículo estudiaremos la cuestión del uso del análisis regresivo múltiple de datos de la estadística macroeconómica y el análisis de la influencia de estos datos en el curso de las divisas, sobre el ejemplo de la pareja EURUSD. La utilización de tal tipo de análisis permite automatizar la realización del análisis fundamental, que se convertirá en algo accesible para prácticamente cualquiera, incluso para un trader principiante.

Recetas MQL5 - procesamiento del evento BookEvent Recetas MQL5 - procesamiento del evento BookEvent

En el artículo se estudia el evento de la profundidad de mercado BookEvent y su principio de procesamiento. En calidad de ejemplo se crea un programa MQL5, que procesa el estado de la profundidad de mercado. Se usa una aproximación orientada a objetos. Los resultados del procesamiento se muestran en la pantalla en forma de panel y de niveles de profundidad.