Sentencias, bloques de código y funciones

Así, en el script generado por el Asistente, la función OnStart aparece de la siguiente manera:

void OnStart()
{
}

Este es exactamente nuestro primer tema en el contexto de la programación en MQL5. También en este caso nos encontramos de inmediato con conceptos y secuencias de caracteres desconocidos. Para explicarlos, haremos una breve digresión.

Por lo general, un programa debe implementar las siguientes etapas típicas cuando se ejecuta:

  • Definición de variables, es decir, celdas con nombre en la memoria del ordenador en las que almacenar datos;
  • Organización de la entrada de datos de origen;
  • Procesamiento de los datos (un algoritmo aplicado);
  • Organización de la salida de los resultados.

Todas estas etapas no son necesarias en cuanto al mantenimiento de la corrección sintáctica del programa. Por ejemplo, si creamos un programa que calcule el producto de 2*2, obviamente no necesita ningún dato de entrada, ya que los números necesarios para la multiplicación están integrados en el texto del programa. Además, como 2 y 2 son valores constantes en esta expresión, no se necesitan celdas con nombre (variables) en el programa. Como de todos modos sabemos cuál es el doble dos, en realidad no necesitamos comunicar el número resultante. Por supuesto, un programa así carecería de toda función real. Sin embargo, sería absolutamente correcto desde un punto de vista técnico.

Y lo que es más interesante: el programa puede no contener ninguna sentencia sobre el procesamiento. Nuestra plantilla de script representa específicamente un programa 'null' de ejemplo. Pero, ¿qué es el fragmento de texto anterior?

En su día, Niklaus Wirth, uno de los grandes nombres de la programación, dio una sencilla definición generalizada de la programación como simbiosis de algoritmos y estructuras de datos.

Por «algoritmo» se entiende cualquier una secuencia de sentencias de un determinado lenguaje de programación. Una sentencia es un tipo de oración, es decir, un enunciado completo, articulado en un lenguaje de programación según las reglas sintácticas del mismo. El nombre mismo, «sentencia», sugiere que los ordenadores perciben esa oración como una guía para realizar operaciones. En otras palabras: las sentencias describen cuándo y cómo se procesarán las estructuras de datos aplicados requeridas. Ese es exactamente el motivo por el que la interpenetración de algoritmos y estructuras de datos permite poner en práctica las ideas del autor.

Por desgracia, en la mayoría de las tareas prácticas, el número de sentencias es tan grande que deben sistematizarse de alguna manera para que la persona reconozca y controle el comportamiento del programa.

También en este caso resulta útil el algoritmo «divide y vencerás», que se utiliza prácticamente en todos los ámbitos de la programación y bajo distintas formas. Las aprenderemos todas a medida que avancemos en este libro, ahora sólo estamos apuntando lo esencial.

Como es sabido, el algoritmo se reduce a dividir una tarea compleja de gran envergadura en otras más pequeñas y sencillas. Podemos comparar este proceso con la construcción de una casa o el ensamblaje de una nave espacial. Ambos «productos» se componen de múltiples módulos diferentes que, a su vez, constan de componentes, y estos últimos de piezas aún más pequeñas, y así sucesivamente.

Si ampliamos esta similitud a los algoritmos, podemos decir que las sentencias son pequeñas partes, mientras que el programa entero es la casa o la nave espacial. Por lo tanto, necesitamos bloques estructurales de tamaño intermedio.

Esa es la razón por la que es habitual, a la hora de implementar algoritmos, combinar sentencias relacionadas lógicamente en fragmentos más grandes con nombre: las funciones. En los lugares necesarios del programa, podemos dirigirnos a la función por su nombre (llamarla) y, al hacerlo, pedir al ordenador que ejecute todas las sentencias contenidas dentro de la función. El programa entero es, de hecho, el bloque externo más grande y, por lo tanto, también puede ser presentado por la función, desde la que se llama a funciones más pequeñas o se ejecutan sentencias de manera inmediata si no son muchas. Ahora nos acercamos a la función OnStart.

El nombre OnStart se reserva en los scripts para denotar la función última que el propio terminal invoca en respuesta a las acciones del usuario cuando éste lanza el script utilizando el comando del menú contextual o arrastrando el ratón sobre el gráfico. Así, el fragmento de código anterior define la función OnStart que predetermina el comportamiento de todo nuestro script.

Los que saben programar en otros lenguajes, como C, C++, Rust o Kotlin, pueden notar la similitud de esta función con la función main, el punto clave de acceder al programa.

Cualquier script debe contener la función OnStart. De lo contrario, la compilación puede finalizar con un error.

La función vacía OnStart, como la nuestra, comienza a ser ejecutada por el terminal (tan pronto como se lanza el script de la manera que sea) e inmediatamente termina su operación. En sentido estricto, todavía no se ha aplicado ningún algoritmo en nuestro script, pero ya existe una función stub para añadirlo.

En otros tipos de programas MQL existen también funciones especiales que el programador debe definir en su código. Hablaremos de las características específicas en las partes correspondientes del libro.

Analizaremos la sintaxis de definición de funciones en detalle en la segunda parte de este libro. A los efectos de realizar un análisis práctica de la misma, bastará con mencionar los siguientes elementos básicos para entender la descripción de OnStart.

Dado que las funciones suelen estar destinadas a obtener un resultado aplicable, las características del valor esperado se describen de manera especial en su definición: qué tipos de datos deben obtenerse y si estos son necesarios o no. Algunas funciones pueden realizar acciones que no requieren devolver ningún valor. Por ejemplo, una función puede estar destinada a cambiar la configuración del gráfico actual o a enviar notificaciones push cuando se alcanza el nivel de drawdown o porcentaje de caída predefinido en la cuenta. Todo esto puede programarse con las sentencias en la función, y no crea ningún dato nuevo (que tenga sentido devolver a cualquier otra parte del programa).

En nuestro caso, la situación es similar: como función principal del script, OnStart podría devolver su resultado sólo al entorno externo (directamente al terminal) una vez finalizado, pero esto no afectaría en modo alguno al funcionamiento del script en sí (porque ya ha finalizado).

Precisamente por eso, antes del nombre de la función OnStart aparece la palabra void que informa al compilador de que el resultado no nos importa (void significa vacío). void es una de las muchas palabras de procedimiento reservadas en MQL5. El compilador conoce el significado de todas las palabras reservadas y se guía por ellas a la hora de revisar el código fuente. En particular, un programador puede utilizar palabras reservadas para definir nuevos términos para el compilador, como la propia función OnStart.

Los paréntesis tras el nombre son parte integrante de la descripción de cualquier función: pueden incluir la lista de parámetros de la función. Por ejemplo, si escribiéramos una función que tomara el cuadrado de un número, tendríamos que proporcionarle un parámetro para ese número. A continuación podríamos llamar a esta función desde cualquier parte del programa, habiendo enviado un argumento sobre ella, es decir, el valor específico para el parámetro. Veremos más adelante cómo describir la lista de parámetros; ello no está en este ejemplo actual. Este requisito se plantea en la función OnStart ya que es invocada por el terminal en sí, y nunca envía nada a esta función como parámetros.

Por último, se utilizan llaves para marcar el principio y el final del bloque que contiene las sentencias. Inmediatamente después de la cadena con el nombre de la función, dicho bloque contendrá un conjunto de operaciones realizadas por esta función. Esto se denomina también cuerpo de la función. En este caso, no hay nada dentro de las llaves. Por lo tanto, la plantilla del script no hace nada.

La secuencia anterior de la palabra void, el nombre OnStart, una lista vacía de parámetros y un bloque de código vacío define la implementación mínima y vacía de la función OnStart para el compilador. Más adelante, añadiendo sentencias en el cuerpo de la función, ampliaremos la definición de la función OnStart.

Una vez ejecutado el comando Compilar, nos aseguraremos de que el script puede compilarse con éxito y que el programa terminado aparece en el Navegador del terminal en la carpeta Scripts/MQL5Book/p1. Esto se debe al hecho de que, en la carpeta correspondiente del disco, ahora está el archivo de Hello.ex5, lo que se puede comprobar fácilmente en cualquier administrador de archivos.

Podemos ejecutar el script en un gráfico, pero la única confirmación de su ejecución serán las entradas en el registro del terminal (pestaña Log de la ventana Herramientas; no confundir con la barra de herramientas):

Scripts        script Hello (EURUSD,H1) loaded successfully
Scripts        script Hello (EURUSD,H1) removed

Es decir: se ha cargado el script y se ha enviado el control a la función OnStart, pero se ha devuelto inmediatamente al terminal porque la función no hace nada, y después, el terminal se ha descargado el script del gráfico.