Funciones de procesamiento de eventos

En el lenguaje MQL5 está previsto el procesamiento de algunos eventos predefinidos. Las funciones que manejan estos eventos tienen que ser definidos en el programa MQL5; el nombre de la función, el tipo de valor devuelto, composición de parámetros (si éstos existen) y sus tipos tienen que corresponder estrictamente a la descripción de la función de procesamiento de eventos.

El manejador de eventos del terminal de cliente identifica las funciones, que procesan uno u otro evento, precisamente por el tipo de valor devuelto y por los tipos de parámetros. La función no se usa para manejar los eventos, si en ésta están indicados otros parámetros que no corresponden a las descripciones siguientes, o está indicado otro tipo de valor devuelto.

OnStart #

La función OnStart() es manejador de evento Start, que se genera automáticamente sólo para los scripts a ser ejecutados. Esta función debe ser del tipo void, sin tener parámetros:

void OnStart();

Para la función OnStart() se admite especificar el tipo de valor devuelto int.

OnInit #

La función OnInit() es el manejador de evento Init. Puede tener el tipo void o int, no tiene parámetros:

void OnInit();

El evento Init se genera justo después de haberse cargado un Asesor Experto o un indicador; este evento no se genera para los scripts. La función OnInit() se usa para la inicialización. Si OnInit() tiene el valor devuelto del tipo int, entonces el código no nulo de la devolución significa una inicialización fallida y genera el evento Deinit con el código de la causa de deinicialización REASON_INITFAILED.

Si se retorna el valor INIT_FAILED, el asesor será descargado del gráfico forzosamente.

Si se retorna el valor INIT_FAILED, el indicador no será descargado del gráfico. En este caso, además, el asesor que quedará en el gráfico no funcionará: el manejador de eventos en el indicador no será llamado.

Para la optimización de los parámetros de entrada del EA se recomienda utilizar los valores de la enumeración ENUM_INIT_RETCODE como el código de devolución. Estos valores sirven para organizar el control del proceso de optimización, incluyendo la selección de los agentes de pruebas más apropiados. Durante la inicialización del EA, antes de iniciar el mismo proceso de simulación, se puede solicitar la información sobre la configuración y los recursos del agente (número de núcleos, volumen de la memoria libre, etc.) utilizando la función TerminalInfoInteger(). Y basándose en la información recibida permitir el uso de este agente, o bien rechazarlo para la optimización de este EA.

ENUM_INIT_RETCODE

Identificador

Descripción

INIT_SUCCEEDED

La inicialización se ha finalizado con éxito. Se puede seguir con la simulación del EA.

Este código significa lo mismo que el valor nulo - la inicialización del EA en el Probador ha pasado con éxito.

INIT_FAILED

Inicialización fallida. No merece la pena continuar la simulación debido a los errores insuperables. Por ejemplo, no se ha podido crear el indicador necesario para el funcionamiento del EA.

La devolución de este valor significa lo mismo que la devolución de un valor distinto del cero. Significa que la inicialización del EA en el Probador no ha tenido éxito.

INIT_PARAMETERS_INCORRECT

Se utiliza por el programador para marcar un conjunto incorrecto de parámetros de entrada. La cadena del resultado que contiene este código de retorno se colorea con el rojo en la tabla general de optimización.

La simulación para este conjunto de parámetros del EA no va a llevarse a cabo, el agente está disponible para recibir una nueva tarea.

Cuando el Probador de Estrategias recibe este valor, nunca va a pasar esta tarea a otros agentes para que vuelvan a ejecutarlo.

INIT_AGENT_NOT_SUITABLE

Durante la inicialización no ha surgido ningún error en el funcionamiento del programa, pero por alguna razón este agente no vale para hacer la prueba. Por ejemplo, no hay suficiente memoria operativa, no hay soporte OpenCL, etc.

Después de la devolución de este código, el agente ya no va a recibir tareas hasta que se finalice esta optimización.

La función OnInit() del tipo void siempre indica a una inicialización exitosa.

OnDeinit #

La función OnDeinit() se llama durante la deinicialización y juega papel de manejador de evento Deinit. Tiene que ser declarada con el tipo void y tener un parámetro del tipo const int que contiene el código de la causa de deinicialización. Si está declarado otro tipo, el compilador lanzará un aviso pero la función no será invocada. Para los scripts el evento Deinit no se genera, y por tanto, en éstos no se puede usar la función OnDeinit().

void OnDeinit(const int reason);

El evento Deinit se genera para los Asesores Expertos e indicadores en las siguientes ocasiones:

  • antes de la reinicialización debido al cambio de símbolo o período del gráfico al cual el programa mql5 es atado;
  • antes de la reinicialización debido al cambio de los parámetros de entrada;
  • antes de descargar un programa mql5.
     

OnTick #

El evento NewTick se genera únicamente para los Asesores Expertos cuando se recibe un nuevo tick para el símbolo, al diagrama del cual está atado el Asesor. Es inútil determinar la función OnTick() en un indicador personalizado o en un script, porque para ellos el evento Tick no se genera.

El evento NewTick se genera sólo para los Asesores Expertos pero esto no significa que ellos tienen que tener la función OnTick() de una forma obligatoria, porque para los Asesores se generan no sólo los eventos NewTick, sino también los eventos Timer, BookEvent y ChartEvent. Tiene que ser declarada con el tipo void, no tiene parámetros:

void OnTick();

OnTimer #

La función OnTimer() se llama cuando se inicia el evento Timer que se genera por el temporizador del sistema sólo para los asesores e indicadores; no se puede usarla en los scripts. La frecuencia del inicio de este evento se establece cuando la función EventSetTimer() efectua la suscripción para obtener avisos sobre el evento Timer.

Para dar de baja dicha suscripción a recibir los eventos del temporizador para un Asesor en concreto se utiliza la función EventKillTimer(). La función tiene que ser declarada con el tipo void, no tiene parámetros:

void OnTimer();

Se recomienda llamar a la función EventSetTimer() una sola vez en la función OnInit(), y también una sola vez  EventKillTimer() en OnDeinit().

Cada Asesor Experto y cada indicador trabaja con su propio temporizador y recibe eventos sólo de él. Una vez terminada la sesión del programa mql5, el temporizador se elimina de una manera forzosa, si ha sido creado pero no ha sido desactivado por la función EventKillTimer().

OnTrade #

La función se llama cuando se inicia el evento Trade, que aparece si se cambia la lista de las órdenes presentadas y posiciones abiertas, historial de órdenes y historial de transacciones. Cuando cualquier operación comercial (presentación de orden pendiente, apertura/cierre de posición, establecimiento de stops, accionamiento de órdenes pendientes, etc.) se efectua de una manera correspondiente, el historial de órdenes y transacciones y/o la lista de posiciones y órdenes corrientes se cambian.

void OnTrade();

Al recibir este evento (si esto requieren las condiciones de la estrategia comercial), el mismo usuario debe comprobar en el código el estado de la cuenta. Si la llamada a la función OrderSend() se ha realizado con éxito y ha devuelto el valor true, esto significa que el servidor comercial ha colocado la orden en la cola para ser ejecutado y le ha asignado un número de ticket. En cuanto el servidor procese esta orden, el evento Trade será generado. Y si el usuario ha memorizado el valor del ticket, durante el procesamiento de evento OnTrade() podrá averiguar con su ayuda qué es lo que haya pasado exactamente con la orden.

OnTradeTransaction #

Como resultado de ejecución de ciertas acciones con la cuenta de trading su estado se cambia. A estas acciones les pertenecen:

  • El envío de una solicitud comercial por parte de cualquier aplicación MQL5 en el terminal de cliente utilizando la función OrderSend y OrderSendAsync, con su posterior ejecución;
  • El envío de una solicitud comercial a través de la interfaz gráfica del terminal y su posterior ejecución;
  • El accionamiento de órdenes pendientes y órdenes Stop en el servidor;
  • La ejecución de operaciones en el servidor de trading.

Como resultado de estas acciones, para la cuenta se ejecutan las transacciones comerciales:

  • tramitación de la solicitud comercial;
  • cambio de órdenes abiertas;
  • cambio del historial de órdenes;
  • cambio del historial de operaciones;
  • cambio de posiciones.

Por ejemplo, al enviar una orden de compra, ésta se tramita, para la cuenta se crea una orden de compra correspondiente, se realiza la ejecución de la orden, su eliminación de la lista de las abiertas, se agrega al historial de órdenes, luego la operación correspondiente se agrega al historial, y se crea una posición nueva. Pues todas estas acciones son transacciones comerciales. La llegada de cada una de estas transacciones al terminal es el evento TradeTransaction. Este evento llama al manejador OnTradeTransaction

void  OnTradeTransaction(
   const MqlTradeTransaction   trans,        // estructura de transacción comercial
   const MqlTradeRequest&        request,      // estructura de solicitud
   const MqlTradeResult&         result        // estructura de respuesta
   );

El manejador contiene tres parámetros:

  • trans - este parámetro obtiene la estructura MqlTradeTransaction que describe la transacción comercial aplicada a la cuenta de trading;
  • request - este parámetro obtiene la estructura MqlTradeRequest que describe la solicitud comercial;
  • result - este parámetro obtiene la estructura MqlTradeResult que describe el resultado de ejecución de la solicitud comercial.

Los dos últimos parámetros request y result se llenan con los valores sólo para la transacción del tipo TRADE_TRANSACTION_REQUEST, la información sobre el parámetro se puede obtener del parámetro type de la variable trans. Fíjense que en este caso el campo request_id en la variable result contiene el identificador de la solicitud comercial request cuya ejecución ha provocado la aparición de la transacción comercial descrita en la variable trans. La presencia del identificador de la solicitud permite vincular la acción ejecutada (llamada a la función OrderSend o OrderSendAsync) con el resultado de esta acción que se traspasa en OnTradeTransaction().

Una solicitud comercial enviada desde el terminal manualmente o a través de las funciones de trading OrderSend()/OrderSendAsync() puede ocasionar en el servidor de trading varias transacciones consecutivas. Entendiéndose que el orden de llegada de estas transacciones al terminal no se garantiza, por eso no se puede construir su algoritmo de trading esperando la llegada de unas transacciones comerciales tras la llegada de otras.

  • Todos los tipos de transacciones comerciales se describen en la enumeración ENUM_TRADE_TRANSACTION_TYPE.
  • La estructura MqlTradeTransaction que describe la transacción comercial se llena de una manera diferente en función del tipo de transacción. Por ejemplo, para las transacciones del tipo TRADE_TRANSACTION_REQUEST hay que analizar sólo un campo - type (tipo de la transacción comercial). Para obtener la información adicional hay que analizar el segundo y el tercer parámetro de la función OnTradeTransaction (request y result). Más detalles se puede encontrar en el apartado "Estructura de transacción comercial".
  • No toda la información disponible sobre las órdenes, operaciones y posiciones (por ejemplo, un comentario) se pasa en la descripción de una transacción comercial. Para obtener la información más detallada, hay que usar las funciones OrderGet*, HistoryOrderGet*, HistoryDealGet* y PositionGet*.

Una vez aplicadas las transacciones comerciales a la cuenta de cliente, ellas se colocan sucesivamente a la cola de transacciones comerciales del terminal, de donde se pasan sucesivamente al punto de entrada OnTradeTransaction en orden de su llegada al terminal.

Mientras que el EA procese las transacciones comerciales con el manejador OnTradeTransaction, el terminal sigue procesando las transacciones que vayan llegando. De esta manera, el estado de la cuenta de trading ya puede cambiarse durante el proceso de trabajo del OnTradeTransaction. Por ejemplo, mientras que el programa MQL5 esté procesando el evento de agregación de una orden nueva, ésta puede ser ejecutada, eliminada de la lista de las abiertas y pasada al historial. A continuación, el programa será avisado sobre todos estos eventos.

La longitud de la cola de transacciones es de 1024 elementos. Si OnTradeTransaction va a tardar en procesar la transacción de turno, las transacciones antiguas pueden ser expulsadas por las nuevas.

  • Por lo general, no existe la proporción exacta respecto al número de llamadas a OnTrade y a OnTradeTransaction. Una llamada a OnTrade corresponde a una o varias llamadas a OnTradeTransaction.
  • OnTrade se invoca tras las llamadas correspondientes a OnTradeTransaction.

OnTester #

La función OnTester() es el manejador del evento Tester que se genera automáticamente una vez terminado el chequeo histórico del Asesor Experto en el intervalo de datos especificado.  La función tiene que ser declarada con el tipo double, no tiene parámetros:

double OnTester();

La función se invoca justamente antes de la llamada a la función OnDeinit() y tiene el tipo del valor devuelto double. La función OnTester() puede ser usada solamente en los Asesores Expertos durante el chequeo. En primer lugar está destinada para el cálculo de un valor que se usa como criterio Custom max durante la optimización genética de los parámetros de entrada.

Durante  la optimización genética la selección de resultados dentro de una generación se realiza en orden descendiente. Es decir, desde el punto de vista del criterio de optimización, los mejores resultados son los que tienen el mayor valor (para el criterio de optimización Custom max se toman en cuenta los valores devueltos por la función OnTester). Con este tipo de selección los peores valores se colocan al final, y luego no toman parte en la formación de la siguiente generación.

OnTesterInit #

La función OnTesterInit() es el manejador del evento TesterInit que se genera automáticamente antes de iniciar la optimización del EA en el Probador de Estrategias. La función tiene que ser definida con el tipo void. No tiene parámetros:

void OnTesterInit();

El EA que cuenta con el manejador OnTesterDeinit() o OnTesterPass(), al iniciarse la optimización, se carga automáticamente en un gráfico separado con el símbolo y período especificados en el Probador y recibe el evento TesterInit. Esta función se utiliza para inicializar el EA antes del inicio de la optimización para el posterior procesamiento de los resultados de la optimización.

OnTesterPass #

La función OnTesterPass() es el manejador del evento TesterPass que se genera automáticamente cuando llega un frame durante la optimización del EA en el Probador de Estrategias. La función tiene que ser definida con el tipo void. No tiene parámetros:

void OnTesterPass();

El EA con el manejador OnTesterPass() se carga automáticamente en un gráfico nuevo del terminal con el símbolo/período especificados para la simulación, y recibe durante la optimización los eventos TesterPass cuando llegue un frame. La función está destinada para el procesamiento dinámico de los resultados de la optimización directamente "al vuelo", sin esperar su finalización. La agregación de los frames se realiza por la función FrameAdd(), que puede ser invocada cuando se finaliza el repaso único en el manejador OnTester().

OnTesterDeinit #

La función OnTesterDeinit() es el manejador del evento TesterDeinit que se genera automáticamente tras finalizarse la optimización del EA en el Probador de Estrategias. La función tiene que ser definida con el tipo void. No tiene parámetros:

void OnTesterDeinit();

El EA con el manejador TesterDeinit() se carga automáticamente en el gráfico al iniciarse la optimización, y recibe el evento TesterDeinit tras su finalización. Esta función está destinada para el procesamiento final de todos los resultados de la optimización.

OnBookEvent #

La función OnBookEvent() es manejador de evento BookEvent. El evento BookEvent se genera sólo para los Asesores e indicadores si se cambia el estado de la profundidad de mercado (Depth of Market).  Debe tener el tipo void y un parámetro del tipo string:

void OnBookEvent (const stringsymbol);

Para recibir los eventos BookEvent por cualquier símbolo, es suficiente suscribirse previamente a la recepción de estos eventos para este símbolo mediante la función MarketBookAdd(). Para dar de baja la recepción del evento BookEvent por un símbolo concreto, es necesario llamar a la función MarketBookRelease().

A diferencia de otros eventos, el evento BookEvent es de difusión. Eso significa que si un Asesor Experto se suscribe a la recepción del evento BookEvent a través de la función MarketBookAdd, todos los demás Asesores que tienen el manejador OnBookEvent() van a recibir este evento. Por eso es necesario analizar el nombre del símbolo que se traspasa al manejador en calidad del parámetro const string& symbol.

OnChartEvent #

OnChartEvent() es manejador del grupo de eventos ChartEvent:

  • CHARTEVENT_KEYDOWN – evento de pulsación de teclas del teclado cuando la ventana del gráfico está en el foco;
  • CHARTEVENT_MOUSE_MOVE – eventos de mover el ratón y pulsar botones del ratón (si para el gráfico está establecida la propiedad CHART_EVENT_MOUSE_MOVE=true);
  • CHARTEVENT_OBJECT_CREATE – evento de creación de un objeto gráfico (si para el gráfico está establecida la propiedad CHART_EVENT_OBJECT_CREATE=true);
  • CHARTEVENT_OBJECT_CHANGE – evento de cambio de propiedades de un objeto a través del diálogo de propiedades;
  • CHARTEVENT_OBJECT_DELETE – evento de eliminación de un objeto gráfico (si para el gráfico está establecida la propiedad CHART_EVENT_OBJECT_DELETE=true);
  • CHARTEVENT_OBJECT_CLICK – evento de cliqueo con el ratón sobre el gráfico;
  • CHARTEVENT_OBJECT_DRAG – evento de movimiento de un objeto gráfico mediante el ratón;
  • CHARTEVENT_OBJECT_ENDEDIT – evento del fin de edición de texto en el campo de introducción de un objeto gráfico LabelEdit;
  • CHARTEVENT_CHART_CHANGE  – evento de modificación del gráfico;
  • CHARTEVENT_CUSTOM+n – identificador del evento de usuario donde la n se encuentra en el rango de 0 a 65535.
  • CHARTEVENT_CUSTOM_LAST – el último identificador aceptable del evento de usuario (CHARTEVENT_CUSTOM+65535).

La función puede invocarse sólo en los Asesores e indicadores. Tiene que poseer el tipo void y 4 parámetros:

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

Para cada tipo de evento, los parámetros de entrada de la función OnChartEvent() tienen los determinados valores que son necesarios para procesar este evento. En la tabla de abajo se enumeran los eventos y valores pasados como parámetros.

Evento

Valor del parámetro id

Valor del parámetro lparam

Valor del parámetro dparam

Valor del parámetro sparam

Evento de un teclazo

CHARTEVENT_KEYDOWN

código de la tecla pulsada

Número de pulsaciones de la tecla generadas mientras ésta se mantenía en estado pulsado

Valor literal de la máscara de bits que describe el estatus de las teclas del teclado

Eventos del ratón (si para el gráfico está establecida la propiedad CHART_EVENT_MOUSE_MOVE=true)

CHARTEVENT_MOUSE_MOVE

coordinada X

coordinada Y

Valor literal de la máscara de bits que describe el estatus de los botones del ratón

Evento de creación de un objeto gráfico  (si para el gráfico está establecida la propiedad CHART_EVENT_OBJECT_CREATE=true)

CHARTEVENT_OBJECT_CREATE

Nombre del objeto gráfico creado

Evento de cambio de propiedades de un objeto a través del diálogo de propiedades

CHARTEVENT_OBJECT_CHANGE

Nombre del objeto gráfico modificado

Evento de eliminación de un objeto gráfico (si para el gráfico está establecida la propiedad CHART_EVENT_OBJECT_DELETE=true)

CHARTEVENT_OBJECT_DELETE

Nombre del objeto gráfico eliminado

Evento de cliquear sobre un gráfico

CHARTEVENT_CLICK

coordenada X

coordenada Y

Evento de cliquear sobre un objeto gráfico

CHARTEVENT_OBJECT_CLICK

coordenada X

coordenada Y

Nombre del objeto gráfico en el que ha ocurrido el evento

Evento de mover un objeto gráfico con el ratón

CHARTEVENT_OBJECT_DRAG

Nombre del objeto gráfico desplazado

Evento del fin de edición del texto en el campo de introducción del objeto gráfico

CHARTEVENT_OBJECT_ENDEDIT

Nombre del objeto gráfico "Campo de texto" donde se ha finalizado la introducción del texto

Evento de modificación del gráfico

CHARTEVENT_CHART_CHANGE

Identificador del evento de usuario

CHARTEVENT_CUSTOM+N

Valor determinado por la función EventChartCustom()

Valor determinado por la función EventChartCustom()

Valor determinado por la función EventChartCustom()

OnCalculate #

La función OnCalculate() se invoca sólo en los indicadores si surge la necesidad de calcular los valores de indicador por evento Calculate. Habitualmente eso ocurre cuando se recibe un nuevo tick por símbolo para el que se calcula el indicador. Además, no es obligatorio que el indicador esté anclado a un gráfico de precio del dicho símbolo.

La función OnCalculate() debe tener el tipo de valor devuelto int. Existen dos posibilidades de definición. No se puede usar las dos opciones de la función dentro un indicador.

La primera forma de la llamada está destinada para los indicadores que pueden ser calculados sobre un buffer de datos. El ejemplo de este indicador es Custom Moving Average.

int OnCalculate (const int rates_total,      // tamaño del array price[]
                 const int prev_calculated,  // cantidad procesada de barras en la anterior llamada
                 const int begin,            // de donde se empiezan los datos significantes
                 const double& price[]       // array a calcular
   );

Como array price[] puede ser pasada una de las series temporales de precios o calculado el búfer de algún indicador. Para determinar la dirección de indexación en el array price[] es necesario invocar la función ArrayGetAsSeries(). Para no depender de los valores predefinidos es necesario invocar incondicionalmente la función ArraySetAsSeries() para los arrays con los que se prevé trabajar.

La elección del indicador o serie temporal apropiados en calidad del array price[] se realiza por el usuario a la hora de iniciar el indicador en la pestaña "Parameters". Para eso se necesita indicar el elemento necesario en la lista desplegable del campo "Apply to".

Selección de una serie temporal para calcular un indicador

Par obtener valores del indicador personalizado desde otros programas mql5, se usa la función iCustom() que devuelve el manejador (handle) del indicador para la siguiente operación. Con eso también se puede indicar el array necesario price[] o manejador (handle) de otro indicador. Este parámetro tiene que ser pasado el último en la lista de las variables de entrada del indicador personalizado.
 
Ejemplo:

void OnStart()
  {
//---
   string terminal_path=TerminalInfoString(STATUS_TERMINAL_PATH);
   int handle_customMA=iCustom(Symbol(),PERIOD_CURRENT"Custom Moving Average",13,0, MODE_EMA,PRICE_TYPICAL);
   if(handle_customMA>0)
      Print("handle_customMA = ",handle_customMA);
   else
      Print("Cannot open or not EX5 file '"+terminal_path+"\\MQL5\\Indicators\\"+"Custom Moving Average.ex5'");
  }

En este ejemplo el último parámetro pasa el valor PRICE_TYPICAL (desde la enumeración ENUM_APPLIED_PRICE ) que indica que el indicador personalizado va a ser construido por los precios típicos recibidos como (High+Low+Close)/3. Si el parámetro no se indica, el indicador se construye por los valores PRICE_CLOSE, es decir, por los precios de cierre de cada barra.

Otro ejemplo que demuestra el traspaso del manejador (handle) de indicador por el último parámetro para especificar el array price[], se muestra en la descripción de la función iCustom().

La segunda forma de la llamada sirve para todos los demás indicadores en los cuales para el cálculo se utiliza más de una serie temporal.

int OnCalculate (const int rates_total,      // tamaño de series temporales de entrada
                 const int prev_calculated,  // procesado de barras en la anterior llamada
                 const datetime& time[],     // Time
                 const double& open[],       // Open
                 const double& high[],       // High
                 const double& low[],        // Low
                 const double& close[],      // Close
                 const long& tick_volume[],  // Tick Volume
                 const long& volume[],       // Real Volume
                 const int& spread[]         // Spread
   );

Los parámetros open[], high[], low[] y close[] contienen los arrays con los precios de apertura, precio máximo, mínimo y precios de cierre del período en curso. El parámetro time[] contiene el array con valores de apertura, el parámetro spread[] es el array que contiene el historial de spreads (si spread está previsto para este instrumento comercial). Los parámetros volume[] y tick_volume[] contienen respectivamente el historial del volumen comercial y del volumen de tick.

Para determinar la dirección de indexación dentro de los arrays time[], open[], high[], low[], close[], tick_volume[], volume[] y spread[] es necesario llamar a la función ArrayGetAsSeries().  Para no depender de los valores predefinidos es necesario invocar incondicionalmente la función ArraySetAsSeries() para los arrays con los que se prevé trabajar.

El primer parámetro rates_total contiene la cantidad de barras disponibles para el indicador para ser calculados, y corresponde a la cantidad de barras disponibles en el gráfico.

Cabe destacar el vínculo entre el valor de la función devuelta OnCalculate() y el segundo parámetro de entrada prev_calculated. Cuando se invoca la función el parámetro prev_calculated contiene el valor que la función OnCalculate() ha devuelto durante la llamada anterior. Esto permite realizar los algoritmos económicos de cálculo del indicador personalizado con el fin de evitar los cálculos repetidos para las barras que no se hayan cambiado desde el arranque anterior de esta función.

Para eso es suficiente devolver el valor del parámetro rates_total que contiene la cantidad de barras durante la corriente llamada a la función. Si desde la última llamada a la función OnCalculate() los datos de precios han sido cambiados (se ha cargado un historial más profunda o los blancos en el historial han sido llenados), el mismo terminal pondrá el valor cero al parámetro entrante prev_calculated.

Nota: si la función OnCalculate devuelve el valor cero, los valores del indicador no se mostrarán en la ventana DataWindow del terminal de cliente.

Para el mejor entendimiento, será útil iniciar el indicador cuyo código se encuentra más abajo.

Ejemplo de indicador:

#property indicator_chart_window
#property indicator_buffers 1
#property indicator_plots   1
//---- plot Line
#property indicator_label1  "Line"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrDarkBlue
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1
//--- indicator buffers
double         LineBuffer[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   SetIndexBuffer(0,LineBuffer,INDICATOR_DATA);
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime& time[],
                const double& open[],
                const double& high[],
                const double& low[],
                const double& close[],
                const long& tick_volume[],
                const long& volume[],
                const int& spread[])
  {
//--- obtendremos una cantidad de barras disponibles para el símbolo y período actuales en el gráfico
   int bars=Bars(Symbol(),0);
   Print("Bars = ",bars,", rates_total = ",rates_total,", prev_calculated = ",prev_calculated);
   Print("time[0] = ",time[0]," time[rates_total-1] = ",time[rates_total-1]);
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+

Véase también

Ejecución del programa, Eventos del terminal de usuario, Trabajo con eventos