- Principios de las operaciones de base de datos en MQL5
- Conceptos básicos de SQL
- Estructura de las tablas: tipos de datos y restricciones
- POO (MQL5) e integración SQL: concepto de ORM
- Crear, abrir y cerrar bases de datos
- Ejecutar consultas sin enlace de datos MQL5
- Comprobar si una tabla existe en la base de datos
- Preparar consultas vinculadas: DatabasePrepare
- Borrar y reiniciar consultas preparadas
- Vincular datos a parámetros de consulta: DatabaseBind/Array
- Ejecutar consultas preparadas: DatabaseRead/Bind
- Leer campos por separado: funciones DatabaseColumn
- Ejemplos de operaciones CRUD en SQLite mediante objetos ORM
- Transacciones
- Importar y exportar tablas de bases de datos
- Imprimir tablas y consultas SQL en registros
- Ejemplo de búsqueda de una estrategia de trading mediante SQLite
Principios de las operaciones de base de datos en MQL5
Las bases de datos almacenan información en forma de tablas. La obtención, modificación y adición de nuevos datos se realiza mediante consultas en lenguaje SQL. Describiremos sus particularidades en las secciones siguientes. Mientras tanto, utilicemos el script DatabaseRead.mq5, que no tiene nada que ver con el trading, y veamos cómo crear una base de datos sencilla y obtener información de ella. Todas las funciones mencionadas aquí se describirán en detalle más adelante. Ahora es importante imaginar los principios generales.
La creación y cierre de una base de datos incorporada mediante funciones DatabaseOpen/DatabaseClose integradas se realiza de forma similar a como se hace con los archivos, ya que también creamos un descriptor para la base de datos, lo comprobamos y lo cerramos al final.
void OnStart()
|
Después de abrir la base de datos, nos aseguraremos de que no haya ninguna tabla en ella con el nombre que necesitamos. Si la tabla ya existe, al intentar insertar en ella los mismos datos que en nuestro ejemplo, se producirá un error, por lo que utilizaremos la función DatabaseTableExists.
La eliminación y creación de una tabla se realiza mediante consultas que se envían a la base de datos con dos llamadas a la función DatabaseExecute y acompañadas de una comprobación de errores.
...
|
Vamos a explicar la esencia de las consultas SQL. En la tabla EMPRESA tenemos solo 5 campos: ID de registro, nombre, edad, dirección y salario. Aquí, el campo ID es una clave, es decir, un índice único. Los índices permiten identificar unívocamente cada registro y pueden utilizarse en todas las tablas para vincularlas entre sí. Esto es similar a cómo el ID de posición vincula todas las operaciones y órdenes que pertenecen a una posición en particular.
Ahora necesita llenar la tabla con datos, lo que se hace mediante la consulta «INSERT»:
// insert data into table
|
Aquí se añaden 4 registros a la tabla EMPRESA; para cada registro hay una lista de campos, y se indican los valores que se escribirán en estos campos. Los registros se insertan mediante consultas «INSERT...» separadas, que se combinan en una sola línea, mediante un carácter delimitador especial ';', pero podríamos insertar cada registro en la tabla con una llamada separada a DatabaseExecute.
Como al final del script la base de datos se guardará en el archivo «empresa.sqlite», la próxima vez que se ejecute intentaríamos escribir los mismos datos en la tabla EMPRESA con el mismo ID. Esto provocaría un error, razón por la cual previamente borramos la tabla para empezar de cero cada vez que se ejecutara el script.
Ahora obtenemos todos los registros de la tabla EMPRESA con el campo SALARY > 15000. Para ello se utiliza la función DatabasePrepare, que «compila» el texto de la solicitud y devuelve su controlador para su posterior uso en las funciones DatabaseRead o DatabaseReadBind.
// prepare a request with a descriptor
|
Una vez que la solicitud se ha creado correctamente, necesitamos obtener los resultados de su ejecución. Esto puede hacerse utilizando la función DatabaseRead, que en la primera llamada ejecutará la consulta y saltará al primer registro de los resultados. En cada llamada posterior, leerá el siguiente registro hasta llegar al final. En este caso, devolverá false, lo que significa «no hay más registros».
// printing all records with salary over 15000
|
El resultado de la ejecución será:
Persons with salary > 15000:
|
La función DatabaseRead permite recorrer todos los registros del resultado de la consulta y, a continuación, obtener información completa sobre cada columna de la tabla resultante a través de las funciones DatabaseColumn. Estas funciones están diseñadas para trabajar de forma universal con los resultados de cualquier consulta, pero el coste es un código redundante.
Si se conoce de antemano la estructura de los resultados de la consulta, es mejor utilizar la función DatabaseReadBind, que permite leer todo el registro de una vez en una estructura. Podemos rehacer así el ejemplo anterior y presentarlo con un nuevo nombre DatabaseReadBind.mq5. En primer lugar, declaremos la estructura Person:
struct Person
|
A continuación, restaremos cada registro de los resultados de la consulta con DatabaseReadBind(request, person) en un bucle mientras la función devuelva true:
Person person;
|
De este modo, obtenemos inmediatamente los valores de todos los campos del registro actual y no necesitamos leerlos por separado.
Este ejemplo introductorio se ha extraído del artículo SQLite: trabajo nativo con bases de datos en SQL en MQL5, donde, además, se contemplan varias opciones de aplicación de la base de datos para operadores de trading. En concreto, puede encontrar allí la restauración del historial de posiciones de las operaciones, el análisis de un informe de trading en términos de estrategias, símbolos de trabajo u horas de trading preferidas, así como técnicas para trabajar con los resultados de la optimización.
Para dominar este material pueden ser necesarios algunos conocimientos básicos de SQL, por lo que los trataremos brevemente en las siguientes secciones.