- Recursos
- Símbolos personalizados
- Calendario económico
- Criptografía
- Funciones de red
- Base de datos SQLite
- Desarrollo y conexión de bibliotecas de formatos binarios
- Proyectos
- Compatibilidad nativa con python
- Soporte integrado para computación paralela: OpenCL
Soporte integrado para computación paralela: OpenCL
OpenCL es un estándar abierto de programación paralela que permite crear aplicaciones para su ejecución simultánea en muchos núcleos de procesadores modernos, diferentes en arquitectura, en particular, gráfica (GPU) o central (CPU).
En otras palabras: OpenCL permite utilizar todos los núcleos del procesador central o toda la potencia de cálculo de la tarjeta de vídeo para computar una tarea, lo que en última instancia reduce el tiempo de ejecución del programa. Por lo tanto, OpenCL es muy útil para tareas de cálculo intensivo, pero es importante tener en cuenta que los algoritmos para resolver estas tareas deben ser divisibles en hilos paralelos. Por ejemplo, el entrenamiento de redes neuronales, la transformada de Fourier o la resolución de sistemas de ecuaciones de grandes dimensiones.
Por ejemplo, en relación con los aspectos específicos del trading, se puede lograr un aumento del rendimiento con un script, indicador o Asesor Experto que realice un análisis complejo y prolongado de los datos históricos de varios símbolos y plazos, y cuyo cálculo no dependa de otros.
Al mismo tiempo, los principiantes suelen preguntarse si es posible acelerar las pruebas y la optimización de los Asesores Expertos utilizando OpenCL. La respuesta a ambas preguntas es no. Las pruebas reproducen el proceso real de trading secuencial y, por tanto, cada barra o tick siguiente depende de los resultados de los anteriores, lo que hace imposible paralelizar los cálculos de una pasada. En cuanto a la optimización, los agentes del probador sólo admiten núcleos de CPU. Esto se debe a la complejidad de un análisis completo de las cotizaciones o ticks, el seguimiento de las posiciones y el cálculo del saldo y el valor negociable. Sin embargo, si la complejidad no le asusta, puede implementar su propio motor de optimización en los núcleos de la tarjeta gráfica transfiriendo a OpenCL todos los cálculos que emulan el entorno de trading con la fiabilidad necesaria.
OpenCL significa Open Computing Language, o lenguaje de computación abierto. Es similar a los lenguajes C y C++ y, por tanto, a MQL5. Sin embargo, para preparar («compilar») un programa OpenCL, pasarle datos de entrada, ejecutarlo en paralelo en varios núcleos y obtener resultados de cálculo, se utiliza una interfaz de programación (un conjunto de funciones) especial. Esta API de OpenCL también está disponible para programas MQL que deseen implementar la ejecución en paralelo.
Para utilizar OpenCL no es necesario disponer de una tarjeta de vídeo en el PC, ya que basta con la presencia de un procesador central. En cualquier caso, se necesitan controladores especiales del fabricante (se requiere OpenCL versión 1.1 y superior). Si su ordenador tiene juegos u otros programas (por ejemplo, científicos, de edición de vídeo, etc.) que funcionan directamente con tarjetas de vídeo, lo más probable es que ya disponga de la capa de software necesaria. Esto se puede comprobar probando a ejecutar un programa MQL en el terminal con una llamada a OpenCL (al menos un ejemplo sencillo de la entrega del terminal; véase más adelante).
Si no hay compatibilidad con OpenCL verá un error en el registro.
OpenCL OpenCL not found, please install OpenCL drivers |
Si hay un dispositivo adecuado en su ordenador y se ha habilitado la compatibilidad con OpenCL para él, el terminal mostrará un mensaje con el nombre y el tipo de este dispositivo (puede haber varios dispositivos). Por ejemplo:
OpenCL Device #0: CPU GenuineIntel Intel(R) Core(TM) i7-2700K CPU @ 3.50GHz with OpenCL 1.1 (8 units, 3510 MHz, 16301 Mb, version 2.0, rating 25)
|
El procedimiento de instalación de los controladores de los distintos dispositivos se describe en el artículo en mql5.com. La compatibilidad se extiende a los dispositivos más populares de Intel, AMD, ATI y Nvidia.
En cuanto al número de núcleos y la velocidad de computación distribuida, los procesadores centrales son significativamente inferiores a las tarjetas gráficas, pero un buen procesador central multinúcleo bastará para aumentar considerablemente el rendimiento.
Importante: si su ordenador dispone de una tarjeta de vídeo compatible con OpenCL, no es necesario que instale la emulación de software OpenCL en la CPU.
Los controladores de dispositivos OpenCL automatizan la distribución de los cálculos entre los núcleos. Por ejemplo, si necesita realizar un millón de cálculos del mismo tipo con vectores diferentes y solo tiene mil núcleos a su disposición, los controladores iniciarán automáticamente cada tarea siguiente a medida que las anteriores estén listas y se liberen los núcleos.
Las operaciones preparatorias para configurar el entorno de ejecución OpenCL en un programa MQL se realizan una sola vez utilizando las funciones de la API de OpenCL anterior.
- Crear un contexto para un programa OpenCL (selección de un dispositivo, como una tarjeta de vídeo, una CPU o cualquier otro disponible): CLContextCreate(CL_USE_ANY). La función devolverá un descriptor de contexto (un número entero, denotémoslo condicionalmente ContextHandle).
- Crear un programa OpenCL en el contexto recibido: se compila a partir del código fuente en el lenguaje OpenCL mediante la llamada a la función CLProgramCreate, a la que se pasa el texto del código a través del parámetro Source:CLProgramCreate(ContextHandle, Source, BuildLog). La función devolverá el manejador del programa (número entero ProgramHandle). Es importante señalar aquí que, dentro del código fuente de este programa, debe haber funciones (al menos una) marcadas con una palabra clave especial __kernel (o simplemente kernel): contienen las partes del algoritmo que se van a paralelizar (véase el ejemplo más abajo). Por supuesto, para simplificar (descomponer el código fuente), el programador puede dividir las subtareas lógicas de la función del kernel en otras funciones auxiliares y llamarlas desde el kernel: al mismo tiempo, no es necesario marcar las funciones auxiliares con la palabra kernel.
- Registrar un kernel que se va a ejecutar por el nombre de una de esas funciones que están marcadas en el código del programa OpenCL como formadoras de kernel: CLKernelCreate(ProgramHandle, KernelName). La llamada a esta función devolverá un manejador al kernel (un entero, digamos, KernelHandle). Puede preparar muchas funciones diferentes en código OpenCL y registrarlas como distintos kernels.
- Si es necesario, crear búferes para los arrays de datos pasados por referencia al kernel y para los valores/arrays devueltos: CLBufferCreate(ContextHandle, Size * sizeof(double), CL_MEM_READ_WRITE), etc. Los búferes también se identifican y gestionan con descriptores.
A continuación, una o varias veces, si es necesario, (por ejemplo, en manejadores de eventos de indicadores o Asesores Expertos), los cálculos se realizan directamente según el siguiente esquema:
- Pasar datos de entrada y/o vincular búferes de entrada/salida con CLSetKernelArg(KernelHandle,...) y/o CLSetKernelArgMem(KernelHandle,..., BufferHandle). La primera función permite fijar un valor escalar, y la segunda equivale a pasar o recibir un valor (o un array de valores) por referencia. En esta fase, los datos se trasladan de MQL5 al núcleo de ejecución de OpenCL. CLBufferWrite(BufferHandle,...) escribe datos en el búfer. Los parámetros y búferes estarán disponibles para el programa OpenCL durante la ejecución del kernel.
- Realizar cálculos paralelos llamando a un kernel específico CLExecute(KernelHandle,...). La función del kernel podrá escribir los resultados de su trabajo en el búfer de salida.
- Obtener resultados con CLBufferRead(BufferHandle). En esta fase, los datos vuelven de OpenCL a MQL5.
Una vez finalizados los cálculos, deben liberarse todos los descriptores: CLBufferFree(BufferHandle),CLKernelFree(KernelHandle), CLProgramFree(ProgramHandle) y CLContextFree(ContextHandle).
Esta secuencia se indica convencionalmente en el siguiente diagrama.

Esquema de interacción entre un programa MQL y un archivo adjunto OpenCL
Se recomienda escribir el código fuente de OpenCL en archivos de texto separados, que luego se pueden conectar al programa MQL5 utilizando variables de recursos.
La biblioteca de cabecera estándar suministrada con el terminal contiene una clase envoltorio para trabajar con OpenCL: MQL5/Include/OpenCL/OpenCL.mqh.
Encontrará ejemplos de uso de OpenCL en la carpeta MQL5/Scripts/Examples/OpenCL/. En particular, el script MQL5/Scripts/Examples/OpenCL/Double/Wavelet.mq5 produce una transformada de ondícula (wavelet) de las series temporales (puede tomar una curva artificial según el modelo estocástico de Weierstrass o el incremento de los precios del instrumento financiero actual). En cualquier caso, los datos iniciales para el algoritmo son un array que es una imagen bidimensional de una serie.
Cuando se ejecuta este script, igual que cuando se ejecuta cualquier otro programa MQL con código OpenCL, el terminal seleccionará el dispositivo más rápido (si hay varios, y el dispositivo específico no se seleccionó en el propio programa o no estaba ya definido anteriormente). La información al respecto se muestra en la pestaña Journal (registro del terminal, no expertos).
Scripts script Wavelet (EURUSD,H1) loaded successfully
|
Como resultado de la ejecución, el script muestra en la pestaña Experts registros con mediciones de la velocidad de cálculo de la forma habitual (en serie, en la CPU) y en paralelo (en núcleos OpenCL).
OpenCL: GPU device 'Intel(R) UHD Graphics 630' selected
|
La relación de velocidades, dependiendo de las particularidades de la tarea, puede llegar a decenas.
El script muestra en el gráfico la imagen original, su derivada en forma de incrementos y el resultado de la transformada wavelet.

La serie simulada original, sus incrementos y la transformada wavelet
Tenga en cuenta que los objetos gráficos permanecen en el gráfico después de que el script haya terminado de funcionar. Deberán eliminarse manualmente.
Este es el aspecto del código fuente de OpenCL de la transformada wavelet, implementado en un archivo independiente MQL5/Scripts/Examples/OpenCL/Double/Kernels/wavelet.cl.
// increased calculation accuracy double is required
|
Encontrará información completa sobre la sintaxis, las funciones integradas y los principios de funcionamiento de OpenCL en el sitio web oficial de Khronos Group.
En particular, es interesante observar que OpenCL admite no solo los tipos de datos numéricos escalares habituales (empezando por char y terminando por double), sino también el vector (u)charN, (u)shortN, (u)intN, (u)longN, floatN, doubleN, donde N = {2|3|4|8|16} y denota la longitud del vector. En este ejemplo no se utiliza.
Además de la mencionada palabra clave kernel, un papel importante en la organización de la computación paralela lo desempeña la función get_global_id: permite encontrar en el código el número de la subtarea computacional que se está ejecutando en ese momento. Obviamente, los cálculos en diferentes subtareas deben ser diferentes (de lo contrario, no tendría sentido utilizar muchos núcleos). En este ejemplo, dado que la tarea implica el análisis de una imagen bidimensional, es más conveniente identificar sus fragmentos utilizando dos coordenadas ortogonales. En el código anterior, los obtenemos mediante dos llamadas, get_global_id(0) y get_global_id(1).
De hecho, nosotros mismos establecemos la dimensión de los datos para la tarea cuando llamamos a la función MQL5 CLExecute (véase más adelante).
En el archivo Wavelet.mq5 se incluye el código fuente OpenCL utilizando la directiva:
#resource "Kernels/wavelet.cl" as string cl_program |
El tamaño de la imagen se establece mediante macros:
#define SIZE_X 600
|
Para gestionar OpenCL se utiliza la biblioteca estándar con la clase COpenCL. Sus métodos tienen nombres similares y utilizan internamente las correspondientes funciones OpenCL integradas de la API de MQL5. Le sugerimos que se familiarice con ella.
#include <OpenCL/OpenCL.mqh> |
De forma simplificada (sin comprobación de errores ni visualización) se muestra a continuación el código MQL que lanza la transformación. Las acciones relacionadas con la transformada wavelet se resumen en la clase CWavelet.
class CWavelet
|
La computación paralela principal está organizada por su método CalculateWavelet_GPU.
bool CWavelet::CalculateWavelet_GPU(double &data[], uint &time)
|
En el código fuente del ejemplo hay una línea comentada que llama a PreparePriceData para preparar un array de entrada basado en precios reales: puede activarlo en lugar de la línea anterior con la llamada a PrepareModelData (que genera un número artificial).
void OnStart()
|
Se ha asignado un conjunto especial de códigos de error (con el prefijo ERR_OPENCL_, empezando por el código 5100, ERR_OPENCL_NOT_SUPPORTED) para las operaciones con OpenCL. Los códigos se describen en la ayuda. Si hay problemas con la ejecución de programas OpenCL, el terminal emite diagnósticos detallados en el registro, indicando los códigos de error.