Русский Português
preview
Redes neuronales en el trading: modelo de consultas temporales (TQNet)

Redes neuronales en el trading: modelo de consultas temporales (TQNet)

MetaTrader 5Sistemas comerciales |
40 0
Dmitriy Gizlyk
Dmitriy Gizlyk

Introducción

La predicción de series temporales multidimensionales en el ámbito financiero es un juego de anticipación en el que están en juego la precisión y la rapidez. Los tipos de cambio, los índices, los volúmenes de negociación, los tipos de interés y los indicadores de liquidez: todos estos parámetros interactúan continuamente, formando un sistema complejo y en constante evolución. Los tráders, los gestores de activos y los analistas lo saben: para ir un paso por delante, hay que comprender cómo se influyen entre sí todas las variables en tiempo real. Precisamente en esta capacidad de ver el panorama en su conjunto radica la esencia de la predicción moderna en los mercados financieros.

El problema es que los datos financieros no son mediciones de laboratorio realizadas en condiciones estériles. El mercado tiene vida propia: saltos bruscos de las cotizaciones a raíz de las noticias, periodos de alta y baja volatilidad, y correlaciones inesperadas que aparecen y desaparecen en cuestión de horas. Si a esto añadimos el ruido (errores de medición, retrasos en las cotizaciones, lagunas en los datos), nos encontramos ante un problema clásico: cómo extraer una señal fiable en un mundo lleno de aleatoriedad. La situación se complica especialmente cuando las relaciones locales entre los parámetros en un fragmento temporal concreto contradicen el panorama global a lo largo de todo el historial de observaciones. Es como intentar predecir el tipo de cambio tomando como referencia solo un día, cuando la tendencia general se prolonga durante meses en la dirección opuesta.

Para salvar esta brecha, en el artículo «Temporal Query Network for Efficient Multivariate Time Series Forecasting» se propuso un nuevo enfoque, Temporal Query, una herramienta que permite combinar una visión local y global del mercado. Se basa en vectores entrenables que se desplazan cíclicamente en el tiempo, captando dependencias intermercado estables, verificadas a lo largo de todo el historial de datos. Al mismo tiempo, las propias cotizaciones, los indicadores y otros parámetros de mercado actúan como claves y valores en un mecanismo de atención multi-cabeza, reflejando las características únicas de cada instante concreto. Esto produce un doble efecto: el modelo conserva la capacidad de reaccionar ante cambios instantáneos y, al mismo tiempo, se apoya en relaciones de mercado fundamentales y más estables.

Partiendo de este principio, se desarrolló el framework Temporal Query Network (TQNet), una solución arquitectónica minimalista pero potente, capaz de predecir la evolución de un conjunto de instrumentos financieros interrelacionados. Su estructura es sumamente sencilla: solo una capa de atención multi-cabeza y una red totalmente conectada de poca profundidad. Sin embargo, tras esta sencillez se esconde la capacidad de detectar relaciones sutiles entre activos y reaccionar ante ellas con mayor rapidez que la mayoría de los métodos tradicionales. En los experimentos realizados por los autores del framework, TQNet demostró una precisión comparable a la de las arquitecturas más complejas, pero con una velocidad de cálculo similar a la de los modelos lineales ligeros.

La particularidad de TQNet radica en su capacidad para adaptarse a distintos horizontes de predicción, utilizando el mismo principio de equilibrio entre las dependencias locales y globales. Esto resulta especialmente valioso en los mercados financieros, donde la situación puede cambiar en cuestión de minutos, pero, al mismo tiempo, obedecer a patrones a largo plazo que no se pueden ignorar.

En los mercados financieros actuales, no gana quien solo ve los detalles, ni quien se basa únicamente en la visión general, sino quien sabe combinar estos dos niveles de percepción. Temporal Query y TQNet ofrecen precisamente esa posibilidad y lo hacen con una sencillez elegante, digna de formar parte del arsenal de cualquier analista serio.


El algoritmo TQNet

La tarea de predicción de series temporales multivariantes (Multivariate Time Series Forecasting, MTSF) se basa en el objetivo de predecir el comportamiento futuro de varias variables interrelacionadas a la vez. Formalmente, en el instante t disponemos de una secuencia histórica observada XtRC*L. Aquí, C es el número de variables o canales (pares de divisas, índices bursátiles, volúmenes de negociación y otros indicadores), y L es la longitud de la ventana de observación (cuántos puntos anteriores tenemos en cuenta). El objetivo consiste en construir una predicción para el horizonte de predicción H, obteniendo YtRC*H: una secuencia de valores futuros de las mismas variables.

En el ámbito de los mercados financieros, esto puede significar pronosticar las cotizaciones de los principales pares de divisas en las próximas horas, el comportamiento de los índices clave durante los próximos días de negociación o la dinámica de los tipos de interés en un horizonte de varias semanas, basándose en datos históricos del periodo seleccionado. En este sentido, es importante tener en cuenta no solo los patrones temporales individuales de cada variable, sino también las correlaciones entre ellas, ya que el mercado se mueve como un todo y los cambios en un segmento pueden reflejarse al instante en otro.

Para resolver esta tarea, se propuso el framework Temporal Query Network (TQNet). A pesar de la sencillez de su diseño arquitectónico, el framework combina dos mecanismos clave: la identificación de las dependencias entre las variables y el modelado de la estructura temporal.

El funcionamiento de TQNet comienza con la entrada de la secuencia analizada Xt en la capa del mecanismo de atención multi-cabeza, reforzada por el componente Temporal Query (TQ-MHA). Esta capa se encarga de identificar e integrar las correlaciones entre variables, tanto las globales y estables en el tiempo como las locales, propias del contexto actual del mercado. A continuación, el resultado se procesa mediante una red multicapa totalmente conectada y poco profunda (MLP), que refina las dependencias temporales y ayuda al modelo a detectar las tendencias y el ritmo de los cambios.

Ambos bloques (TQ-MHA y MLP) se complementan con conexiones residuales, lo que aumenta la estabilidad del entrenamiento y reduce el riesgo de degradación de la calidad en muestras de gran tamaño. La etapa final consiste en una capa lineal con Dropout, que proyecta las representaciones ocultas obtenidas al espacio de datos de salida, generando una predicción ŶtRC*H.

Un elemento clave de la arquitectura de TQNet es el método Temporal Query (TQ), una forma específica de generar consultas (Query) en el mecanismo de atención. Su idea es sencilla y elegante: en lugar de obtener las consultas directamente a partir de los datos originales, como ocurre en el Self-Attention clásico, los autores del framework proponen utilizar un conjunto de vectores entrenables que se desplazan periódicamente en el tiempo. Este método permite identificar correlaciones globales entre variables que son resistentes a las fluctuaciones y al ruido a corto plazo del mercado.

Formalmente, dado el tamaño del periodo W en los datos analizados, inicializamos la matriz de parámetros θTQRC*W. Donde C es el número de variables (canales) y W es la longitud del vector que determina el intervalo de desplazamiento periódico. Estos parámetros se rellenan inicialmente con ceros y, durante el proceso de aprendizaje, se ajustan de forma adaptativa a las dependencias internas de los datos. La elección de W es especialmente importante: en los mercados financieros puede corresponder, por ejemplo, al número de sesiones bursátiles de la semana, a los ciclos recurrentes de liquidez o a otros patrones estacionales estables. Puede determinarse a partir de conocimientos expertos sobre el mercado o mediante métodos estadísticos.

El principio de funcionamiento de TQ es el siguiente: para cada ejemplo analizado en el instante t, extraemos un fragmento de longitud L de la matriz θTQ, comenzando en la posición calculada como t mod W y, si es necesario, tomamos el fragmento de forma circular. Por lo tanto, dos instantes temporales separados exactamente por W pasos tendrán vectores de consulta idénticos. Esto genera un efecto de memoria periódica, lo que permite al modelo reutilizar las dependencias globales aprendidas y reducir el impacto de las perturbaciones aleatorias del mercado.

En el ámbito financiero, esto se puede comparar con un tráder experimentado que recuerda los escenarios típicos del mercado en los mismos días de la semana o en determinadas horas de negociación, y que utiliza ese conocimiento al analizar la situación actual.

En TQNet, este enfoque está integrado en el mecanismo de atención multi-cabeza (TQ-MHA). En este caso, las consultas (Query) no se generan a partir de los datos originales, sino a partir de vectores TQ temporales que reflejan las dependencias globales. Al mismo tiempo, las claves (Key) y los valores (Value) se siguen extrayendo de la secuencia Xt que se está analizando en ese momento, conservando toda la información local y única sobre el mercado en ese instante.

El índice h corresponde al número de la cabeza de atención, mientras que W h Q, W h K y W h V son matrices de proyección entrenables.

A continuación, se calcula la atención para cada cabeza.

De forma análoga a la Multi-Head Self-Attention clásica, los resultados se combinan y pasan por una proyección final.

Esta combinación de Consultas globales y Claves/Valores locales crea un equilibrio entre la robustez frente al ruido y la adaptación al contexto actual. En los datos reales de mercado, donde los periodos de calma pueden dar paso repentinamente a fases de alta turbulencia, este equilibrio es fundamental. El modelo no pierde la capacidad de reaccionar ante acontecimientos únicos —como datos macroeconómicos inesperados o movimientos bruscos provocados por las noticias—, pero, al mismo tiempo, se apoya en un armazón de dependencias globales que se mantienen a lo largo del tiempo.

El objetivo de la técnica propuesta Temporal Query (TQ) es integrar de forma orgánica en el mecanismo de atención tanto las relaciones globales como las locales de una serie temporal. La idea es sencilla, pero eficaz: las consultas (Query) no se generan directamente a partir de los datos originales, sino a partir de vectores entrenables θTQ desplazados periódicamente, mientras que las claves (Key) siguen extrayéndose de la secuencia original. Este enfoque permite encontrar un equilibrio entre la visión global del mercado y las características específicas de cada fragmento concreto de datos.

Para evaluar en la práctica el impacto de las dependencias globales y locales, los autores del framework compararon tres escenarios:

  1. La variante clásica, en la que Query y Key se construyen a partir de datos sin procesar. En este caso, la atención captura únicamente las relaciones particulares entre las observaciones.
  2. El enfoque mixto: este es precisamente el que se implementa en TQNet. Aquí, Consulta (Query) se forma a partir de vectores TQ entrenables, mientras que Clave (Key) se forma a partir de los datos originales. Como resultado, al calcular los coeficientes de atención se tienen en cuenta tanto las dependencias globales como las específicas, lo cual es especialmente importante en los mercados financieros, donde las tendencias generales se entremezclan con fluctuaciones puntuales.
  3. Un esquema puramente global, en el que Consulta (Query) y Clave (Key) se forman a partir de vectores TQ entrenables. Este método ignora por completo las variaciones locales, centrándose en la estructura general de la serie temporal.

Los resultados agregados, obtenidos a partir de grandes conjuntos de datos multivariantes con más de 100 variables y promediados en cuatro horizontes de previsión, demuestran que fue precisamente el enfoque TQNet el que obtuvo el mejor resultado. En él se combinan ambos tipos de correlaciones. En segundo lugar se sitúa el esquema tradicional con relaciones puramente específicas, y en tercer lugar queda la variante puramente global. La conclusión es clara: la combinación armoniosa de las dependencias globales y locales mejora la precisión de la predicción y la estabilidad del modelo, lo que resulta especialmente valioso al trabajar con series financieras dinámicas.

Una vez que la capa TQ-MHA ha identificado las relaciones estables entre variables y las ha integrado con la información local, entra en acción el perceptrón multicapa (MLP). Su tarea consiste en refinar las características ya extraídas en el plano temporal, captar tendencias, ritmos y desfases en las interrelaciones.

A pesar de su sencillez, el MLP sigue siendo una herramienta sorprendentemente eficaz para identificar patrones temporales. En la arquitectura de TQNet, se implementa en una versión ligera: solo dos capas totalmente conectadas con activación GeLU, la cual proporciona un procesamiento más fluido de las señales en comparación con ReLU, especialmente en condiciones de fluctuaciones complejas del mercado.

Desde el punto de vista financiero, este paso puede compararse con una situación en la que un analista, tras recibir un resumen de las interrelaciones clave del mercado, realiza un análisis adicional: identifica patrones intradía, evalúa las amplitudes de las fluctuaciones y detecta puntos de inercia y de reversión.

A continuación, las representaciones obtenidas se pasan a la capa de proyección de resultados. Aquí se aplica una transformación lineal que adapta las representaciones internas a un horizonte de predicción concreto H. Además, se puede utilizar Dropout para reducir el sobreajuste y mejorar la robustez del modelo.

En TQNet se presta especial atención a la cuestión de la robustez ante los cambios en la distribución de los datos, un fenómeno muy extendido en el ámbito financiero. Los tipos de cambio, los precios de las materias primas y los índices bursátiles pueden experimentar cambios bruscos en sus características estadísticas bajo la influencia de noticias, factores macroeconómicos o decisiones regulatorias. Si el modelo está anclado a una distribución obsoleta, sus predicciones pierden rápidamente su vigencia.

Para evitarlo, en el framework TQNet se utiliza la normalización reversible (RevIN), un método probado en varias arquitecturas modernas. La idea consiste en que, antes del procesamiento, el modelo resta el valor medio y divide los datos entre la desviación estándar, y, tras elaborar la previsión, devuelve los datos a su escala original. En términos de trading, esto se puede comparar con la forma en que un analista experimentado siempre revisa sus puntos de referencia cuando cambian las condiciones del mercado. La normalización elimina las desviaciones a corto plazo en la escala y la volatilidad, lo que permite que el modelo se centre en los patrones y no en los cambios aleatorios de la escala de las cotizaciones.

Así, en TQNet, MLP y la proyección de resultados funcionan como el pulido final del pronóstico. TQ-MHA proporciona la estructura base de las dependencias entre variables, MLP las desarrolla a lo largo del tiempo y la normalización protege frente a sesgos estadísticos. Como resultado, el modelo ofrece una previsión que, al mismo tiempo, tiene en cuenta las particularidades locales del momento actual y mantiene la coherencia global del mercado.

Abajo se muestra una visualización del framework TQNet elaborada por el autor.


Implementación con MQL5

Después de analizar los fundamentos teóricos del framework TQNet y mostrar por qué la combinación de correlaciones globales y locales puede mejorar la precisión de las previsiones, ha llegado el momento de pasar de los conceptos a la práctica. Ahora nos centraremos en una de las variantes de implementación de estas ideas en el entorno MQL5, adaptando la arquitectura a las tareas de análisis y previsión de series temporales en los mercados financieros.

Aquí, cada elemento —desde la formación de Consultas y Claves hasta la normalización de datos y la proyección de resultados— se plasmará en el código. Esto nos permitirá demostrar cómo la teoría se convierte en una herramienta lista para el trading real. Este enfoque permitirá comprobar la eficacia de TQNet en condiciones de cotizaciones en vivo y evaluar su robustez en distintas fases del mercado: desde fases laterales tranquilas hasta tendencias rápidas.

Aprovechando la experiencia acumulada en la construcción de diversos módulos de atención, es posible realizar una comparación en profundidad entre TQNet y el bloque clásico de Cross-Attention. En el esquema tradicional, la atención cruzada opera con tensores de Consultas (Queries), Claves (Keys) y Valores (Values), que se generan a partir de distintas fuentes de datos. Este enfoque permite que una secuencia procese mediante atención la información contenida en otra, identificando las relaciones entre ambas.

En el caso de TQNet, este principio se adapta de forma más precisa y específica a las tareas de predicción de series temporales. Aquí, el papel de las fuentes de datos se distribuye de tal forma que las Consultas puedan contener información global y generalizada, codificada en los vectores entrenables θTQ, mientras que las Claves mantengan la conexión con la estructura local de los datos originales. Esta combinación desempeña un papel fundamental en los mercados financieros, donde los patrones generales —como la estacionalidad o los ciclos macroeconómicos recurrentes— deben integrarse con los cambios locales: saltos bruscos de precios, ruido de mercado y desequilibrios a corto plazo entre la oferta y la demanda.

De este modo, TQNet puede considerarse una especie de híbrido de atención cruzada, en el que la memoria global del modelo y las señales instantáneas del mercado se combinan en un único mecanismo. Esto no solo amplía el abanico de interrelaciones que se tienen en cuenta, sino que también hace que el modelo sea más resistente a los cambios bruscos de modo, lo cual resulta especialmente valioso en un contexto de elevada volatilidad en los mercados de divisas, bursátiles o de materias primas.

En este sentido, se nos plantea una tarea clave: la formación y el entrenamiento del tensor de parámetros de correlación global, que se utilizará como fuente de datos para la generación de Consultas. Es precisamente este tensor, que representa los vectores entrenables θTQ, el que contiene la información sobre las relaciones globales entre las variables y sirve de base para construir correctamente el mecanismo de atención.

El proceso de su entrenamiento requiere un enfoque meticuloso: el tensor debe adaptarse a la estructura de los datos, detectando correlaciones estables, pero sin dejar de ser resistente al ruido y a los valores atípicos locales. En las series financieras, esto es especialmente importante, ya que las series temporales de activos están sujetas a fuertes fluctuaciones, desde picos de liquidez a corto plazo hasta acontecimientos inesperados en el mercado.

Al construir y entrenar este tensor, dotamos al modelo de la capacidad de utilizar patrones globales del mercado al procesar cada nueva secuencia. Las Consultas, formadas a partir de él, actúan como un filtro que dirige la atención del modelo hacia las relaciones más significativas entre las variables, al tiempo que las integra con las características locales del fragmento temporal actual. Esto permite a TQNet alcanzar una alta precisión de predicción, combinando la estabilidad de la memoria global con la adaptabilidad a las condiciones específicas del mercado.

En nuestro arsenal ya contamos con el objeto CParams, en el que se ha implementado el algoritmo para la creación y el mantenimiento de los parámetros entrenables. En teoría, podríamos utilizarlo para construir el tensor de correlaciones globales. Sin embargo, cabe preguntarse por la eficiencia de este enfoque.

La cuestión es que, para las tareas de predicción de series temporales multidimensionales en los mercados financieros, se requiere un tensor de tamaño considerable, capaz de abarcar las correlaciones a lo largo de todo el ciclo de los datos analizados. Por otro lado, un tensor excesivamente grande supondrá unos costes computacionales considerables, lo que afectará negativamente a la velocidad de entrenamiento y al funcionamiento del modelo en tiempo real.

Sobre todo porque la mayor parte de esos recursos computacionales se utilizarán en vano. En cada paso del proceso de entrenamiento o predicción, utilizamos únicamente una pequeña parte del tensor correspondiente a la ventana temporal actual. La parte restante permanece pasiva, y las operaciones sobre ella son en la práctica, vacías.

Al mismo tiempo, el volumen del tensor y el número de operaciones vacías aumentan proporcionalmente al incremento de la longitud del ciclo y al número de variables analizadas. En el caso de los datos financieros, en los que el número de canales puede alcanzar los cientos y los periodos históricos abarcan miles de pasos temporales, esta ineficiencia se convierte rápidamente en un cuello de botella, lo que ralentiza el entrenamiento y reduce el rendimiento general del modelo.

Por eso resulta fundamental buscar soluciones que permitan reducir los cálculos innecesarios, manteniendo al mismo tiempo la capacidad del modelo para captar las correlaciones globales sin perder precisión.

En busca de una solución más eficiente, decidimos replantear en cierta medida el enfoque relativo al almacenamiento y la actualización de los parámetros de correlación. En lugar de utilizar un único objeto CParams estático para generar todo el tensor, hemos creado una versión derivada de dicho objeto, en la que hemos implementado un array de objetos internos de parámetros entrenables.

Cada elemento del array corresponde ahora a un paso temporal independiente, lo que permite utilizar únicamente aquellos datos y parámetros que son relevantes para la ventana de previsión actual. Este enfoque reduce considerablemente los cálculos innecesarios, al tiempo que mantiene la capacidad del modelo para captar las relaciones globales entre las variables a lo largo de todo el periodo de análisis.

En otras palabras, hemos obtenido un tensor dinámico de parámetros, en el que cada elemento corresponde a un momento temporal concreto, y las operaciones innecesarias sobre los demás pasos se han eliminado por completo. Esto hace que nuestra implementación de TQNet sea mucho más eficiente en recursos y escalable para grandes conjuntos de datos financieros.

Una vez que hemos analizado el concepto de tensor dinámico de parámetros y hemos justificado la necesidad de utilizar un array de objetos para cada paso temporal, el siguiente paso lógico es examinar la implementación concreta de este enfoque en el código. En nuestra arquitectura, la clase CCircleParams desempeña un papel fundamental, ya que hereda la funcionalidad básica de la capa neuronal totalmente conectada CNeuronBaseOCL.

class CCircleParams  :  public CNeuronBaseOCL
  {
protected:
   CLayer            cOnes;
   CNeuronBaseOCL    *cCurrent;
   //---
   virtual bool      feedForward(CNeuronBaseOCL *NeuronOCL) override          { return FeedForward(); }

   ///\ingroup neuron_base_opt
   virtual bool      updateInputWeights(CNeuronBaseOCL *NeuronOCL) override   { return UpdateInputWeights(); }
   virtual bool      calcInputGradients(CNeuronBaseOCL *NeuronOCL) override   { return true; }

public:
                     CCircleParams(void) : cCurrent(NULL) {};
                    ~CCircleParams(void)  {};
   //---
   virtual bool      Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl,
                          uint numNeurons, uint period, 
                          ENUM_OPTIMIZATION optimization_type, uint batch);
   virtual bool      Identity(const int rows, const int cols);
   virtual bool      Zeros(void);
   //---
   virtual bool      FeedForward(void);
   virtual bool      UpdateInputWeights(void);
   virtual bool      SetPosition(int position);
   //---
   virtual bool      Save(const int file_handle) override;
   virtual bool      Load(const int file_handle) override;
   //---
   virtual int       Type(void) override const  {  return defCircleParams; }
   virtual void      SetOpenCL(COpenCLMy *obj) override;
   virtual CBufferFloat   *getWeightsParams(void);
   virtual int       GetPeriod(void) const { return cOnes.Total(); }
   //---
   virtual bool      WeightsUpdate(CNeuronBaseOCL *source, float tau) override;
  };

Esta clase es un contenedor especializado para almacenar y gestionar los parámetros de correlación entrenables, lo que garantiza su correcta actualización y una interacción eficaz con los mecanismos del contexto OpenCL, algo especialmente importante cuando se trabaja con grandes arrays de datos financieros en la GPU.

Dentro de la clase CCircleParams, ocupa un lugar especial el objeto cOnes, que es un array dinámico de tensores entrenables y mantiene la naturaleza periódica del objeto. El parámetro cCurrent actúa como puntero al objeto activo del array y refleja el estado de un paso temporal concreto. Esto permite al modelo cambiar dinámicamente el contexto de trabajo, procesando cada fragmento temporal con la máxima precisión y, al mismo tiempo, conservando las dependencias globales acumuladas a lo largo de todo el periodo de análisis.

La estructura del objeto CCircleParams se crea y se configura en el método de inicialización Init, que se encarga de preparar todos los componentes necesarios para el correcto funcionamiento del tensor de parámetros de correlación.

bool CCircleParams::Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl,
                         uint numNeurons, uint period,
                         ENUM_OPTIMIZATION optimization_type, uint batch)
  {
   if(!CNeuronBaseOCL::Init(numOutputs, myIndex, open_cl, numNeurons, optimization_type, batch))
      return false;

Al invocar el método, primero se inicializan las interfaces heredadas mediante la clase padre CNeuronBaseOCL, lo que establece los parámetros fundamentales del objeto. Si se produce un error en esta etapa, el método devuelve inmediatamente false, evitando que continúe una ejecución incorrecta.

A continuación, preparamos el array dinámico cOnes: lo limpiamos y lo vinculamos al contexto OpenCL, para que todas las operaciones posteriores con tensores puedan ejecutarse de forma eficiente en la GPU.

   cOnes.Clear();
   cOnes.SetOpenCL(OpenCL);
   for(uint i = 0; i < period; i++)
     {
      cCurrent = new CNeuronBaseOCL();
      if(!cCurrent)
         return false;
      if(!cCurrent.Init(Neurons(), i, OpenCL, 1, optimization, iBatch) ||
         !cOnes.Add(cCurrent))
        {
         delete cCurrent;
         return false;
        }
      cCurrent.SetActivationFunction(None);
     }

El bucle principal del método se encarga de crear un array de objetos, cada uno de los cuales corresponde a un paso temporal concreto. Para cada paso se crea una nueva instancia de CNeuronBaseOCL, que se inicializa con parámetros idénticos para cada paso específico. Tras una inicialización correcta, el objeto se añade al contenedor cOnes, que gestiona todos los pasos temporales. En caso de que se produzca cualquier error, el objeto que se está creando se elimina inmediatamente, lo que evita las fugas de memoria y preserva la integridad de la estructura.

Para cada neurona recién creada también se desactiva la función de activación, lo cual es importante para el correcto funcionamiento del tensor de correlaciones, en el que, en la etapa de Feed-Forward, solo se requiere la transmisión de valores sin transformación no lineal.

Una vez creados todos los objetos de los pasos temporales, el método SetPosition establece como activo el primer elemento de nuestro array, lo que garantiza el estado inicial para los cálculos posteriores.

//---
   if(!SetPosition(0))
      return false;
//---
   return true;
  }

De este modo, el método Init no se limita a crear un array de objetos, sino que genera un almacén de parámetros estructurado y gestionable, en el que cada elemento representa un momento temporal concreto. Esto permite que el modelo aproveche eficazmente las correlaciones globales, evitando cálculos innecesarios y dejando el modelo listo para entrenarse y generar predicciones de series temporales financieras multidimensionales.

El método SetPosition desempeña un papel fundamental en la gestión del tensor dinámico de parámetros de correlación en CCircleParams. Su función consiste en cambiar el objeto activo a un paso temporal determinado, garantizando así que el modelo funcione con los datos actuales correspondientes a ese momento concreto.

Al llamar al método, el puntero cCurrent se redirige al elemento del array cOnes correspondiente a la posición indicada. Si el objeto seleccionado no existe o no está inicializado, el método devuelve false, lo que indica que hay un problema y evita que se realicen cálculos incorrectos. En caso contrario, cuando el objeto se ha seleccionado correctamente, el método devuelve true, lo que confirma que el modelo está listo para seguir procesando los datos.

bool CCircleParams::SetPosition(int position)
  {
   cCurrent = cOnes[position];
   if(!cCurrent)
      return false;
//---
   return true;
  }

La sencillez de su implementación esconde una funcionalidad importante: es precisamente a través de SetPosition como el modelo TQNet puede trabajar dinámicamente con diferentes pasos temporales, activando los parámetros de correlación correspondientes sin necesidad de volver a crear ni recargar todo el tensor. Esto es especialmente importante en el caso de las series temporales financieras, ya que cada nuevo intervalo temporal requiere tener en cuenta tanto las dependencias locales como las globales, y una gestión eficaz de la posición activa permite que el modelo siga siendo rápido y adaptativo incluso con grandes volúmenes de datos.

Cabe destacar que, con una inicialización estándar, durante la ejecución del método Init todos los tensores de correlaciones globales se rellenan con valores aleatorios. Para la mayoría de los escenarios, este enfoque resulta totalmente aceptable: la inicialización aleatoria garantiza la diversidad de las condiciones iniciales y permite que los parámetros entrenables se adapten progresivamente a la estructura de los datos.

Sin embargo, los autores del framework TQNet recomiendan otro enfoque: inicializar el tensor con valores cero. Este método resulta especialmente adecuado cuando se trabaja con series temporales financieras, en las que es importante iniciar el entrenamiento sin supuestos previos sobre las correlaciones entre las variables, de modo que el modelo pueda identificar gradualmente las relaciones estables basándose exclusivamente en los datos históricos.

Para aplicar este enfoque, se crea en CCircleParams un método Zeros, que pone a cero sucesivamente los parámetros de todos los pasos temporales. Al llamar a este método, se procesa cada elemento del array cOnes y todos los valores del tensor de correlaciones globales se establecen en cero. Esto permite establecer una hoja en blanco para el entrenamiento, garantizando que las predicciones iniciales del modelo no se vean sesgadas por valores iniciales aleatorios y que todo el proceso de adaptación venga determinado estrictamente por los datos analizados y la estructura de TQNet.

bool CCircleParams::Zeros(void)
  {
   matrix<float> zeros = matrix<float>::Zeros(Neurons(), 2);
//---
   CBufferFloat *w = NULL;
   for(int i = 0; i < cOnes.Total(); i++)
     {
      if(!cOnes[i])
         return false;
      w = cOnes[i].getWeights();
      if(!w || !w.AssignArray(zeros))
         return false;
      w.BufferFree();
      if(!w.BufferCreate(OpenCL))
         return false;
     }
//---
   return FeedForward();
  }

De este modo, el método Zeros ofrece una forma cómoda y eficaz de controlar el estado inicial de las correlaciones globales, lo que aumenta la transparencia y la previsibilidad del entrenamiento del modelo a partir de datos financieros.

Como alternativa a la inicialización a cero, implementamos un método que permite inicializar el tensor de correlaciones globales con una matriz identidad. Este enfoque puede resultar útil cuando es necesario definir variables inicialmente independientes, dejando que el modelo identifique gradualmente las dependencias reales entre ellas durante el proceso de entrenamiento.

El método Identity comienza su ejecución comprobando que las dimensiones de la matriz que se va a crear coincidan con el número de neuronas del objeto.

bool CCircleParams::Identity(const int rows, const int cols)
  {
   if(rows * cols != Neurons())
      return false;
   matrix<float> ident = matrix<float>::Identity(rows, cols);
   if(!ident.Reshape(rows * cols, 1))
      return false;
   if(!ident.Resize(rows * cols, 2))
      return false;
   if(!ident.Col(vector<float>::Zeros(rows * cols), 1))
      return false;

A continuación, se genera una matriz identidad de las dimensiones especificadas, que se transforma y se adapta sucesivamente para adaptarse a las estructuras internas de datos de la clase. Se presta especial atención a la preparación y la reasignación de memoria mediante los métodos Reshape y Resize, así como a la puesta a cero de la columna adicional de sesgos para garantizar un funcionamiento correcto al asignar valores.

Una vez preparada la matriz, el método recorre todos los pasos temporales del contenedor cOnes.

   CBufferFloat *w = NULL;
   for(int i = 0; i < cOnes.Total(); i++)
     {
      if(!cOnes[i])
         return false;
      w = cOnes[i].getWeights();
      if(!w || !w.AssignArray(ident))
         return false;
      w.BufferFree();
      if(!w.BufferCreate(OpenCL))
         return false;
     }
//---
   return FeedForward();
  }

Para cada paso, se obtienen los pesos mediante el método getWeights y se les asigna el contenido de la matriz diagonal preparada. A continuación, el búfer del contexto OpenCL se libera y se vuelve a crear con nuevos valores, lo que garantiza una interacción correcta con la GPU durante el entrenamiento posterior del modelo.

El proceso finaliza con la llamada al método FeedForward, que permite comprobar de inmediato que los valores se han propagado correctamente a través de la capa. Este método de inicialización garantiza que, al inicio del entrenamiento, las correlaciones globales entre las variables no estén sesgadas y partan de un estado neutro, al tiempo que se conserva la estructura que permite al modelo acumular y tener en cuenta de forma eficaz las dependencias reales durante el proceso de predicción.

En el contexto financiero, esto reviste especial importancia: la matriz diagonal unitaria establece un punto de partida limpio para cada variable, eliminando cualquier sesgo inicial y permitiendo al mismo tiempo que el modelo identifique gradualmente relaciones de mercado estables, como las correlaciones entre activos.

Después de analizar en detalle los algoritmos de inicialización y los métodos para preparar los parámetros iniciales de correlación, lo lógico es pasar a describir el algoritmo de pasada directa, una de las etapas clave del funcionamiento de la clase CCircleParams.

El método FeedForward se encarga de preparar los parámetros globales de correlación correspondientes al paso temporal actual, lo que permite al modelo actualizar sus estados internos.

bool CCircleParams::FeedForward(void)
  {
   if(!cCurrent)
      if(!SetPosition(0))
         return false;
//---
   return CNeuronBaseOCL::feedForward(cCurrent);
  }

En primer lugar, el método comprueba si hay un paso activo establecido en el puntero cCurrent. Si no se ha especificado el objeto actual, se invoca el método SetPosition para seleccionar automáticamente el primer paso temporal del array cOnes, lo que garantiza que los cálculos comiencen correctamente.

Una vez establecido el paso activo, el control se transfiere al método del mismo nombre de la clase base, lo que permite formar los parámetros necesarios de las correlaciones globales.

De este modo, FeedForward actúa como enlace entre la estructura preparada del tensor de correlaciones globales y el mecanismo de atención de TQNet. El enfoque propuesto aporta flexibilidad y precisión a las predicciones, lo que permite al modelo responder tanto a las fluctuaciones locales del mercado como a las tendencias a largo plazo.

Una vez analizado el mecanismo de pasada directa y comprobado cómo FeedForward garantiza la propagación correcta de los datos a través del paso temporal activo, el siguiente paso lógico es examinar el método UpdateInputWeights, encargado de actualizar los parámetros del modelo.

Este método desempeña un papel fundamental en el entrenamiento: aquí es donde se producen los cambios en los pesos y los parámetros de correlación a partir de los gradientes calculados, lo que permite que el modelo se adapte gradualmente a la estructura de los datos. En CCircleParams, el método se implementa transfiriendo el control al método del mismo nombre de la clase base, indicando el elemento activo del paso temporal.

bool CCircleParams::UpdateInputWeights(void)
  {
   return CNeuronBaseOCL::updateInputWeights(cCurrent);
  }

El puntero al objeto del paso temporal actual que se pasa garantiza que la actualización se realice únicamente en el segmento actual del tensor. Esto aumenta la eficiencia y evita cálculos innecesarios en los demás pasos temporales.

Cabe destacar especialmente que, en esta etapa, no comprobamos deliberadamente la validez del puntero en la variable cCurrent. Esto se ha hecho a propósito. Es de vital importancia que, tanto en la pasada directa como en la pasada inversa, el modelo trabaje con el mismo objeto de paso temporal. Cualquier redefinición del mismo durante el proceso de actualización de los pesos podría alterar la coherencia de los cálculos y provocar errores en la adaptación de los parámetros.

En este caso, el método de la clase padre se encarga de garantizar la corrección del puntero. En caso de que se produzca un error, simplemente devolverá false, evitando así una actualización incorrecta de los pesos. Este enfoque permite centrarse en la esencia del proceso de actualización de los parámetros del paso temporal actual sin una carga innecesaria ni el riesgo de alterar la estructura del tensor de correlaciones globales.

Esto resulta especialmente importante en el caso de las series temporales financieras. El modelo opera de forma fiable con los datos actuales de cada paso y, al mismo tiempo, preserva los patrones globales, lo que asegura la precisión de las predicciones y la estabilidad del entrenamiento, incluso ante cambios de mercado dinámicos y ruidosos.

Creo que habrán notado que hemos omitido la etapa de propagación de los gradientes de error hacia abajo por el modelo. En su lugar, el método calcInputGradients se redefine como implementación vacía (stub) que siempre devuelve un resultado positivo. Este enfoque puede parecer inusual, pero resulta plenamente suficiente para actualizar los parámetros de correlación global. El modelo solo necesita conocer los gradientes de error a nivel de los resultados de la capa para ajustar los pesos del paso temporal actual.

Los datos subyacentes no intervienen en estos cálculos, ya que el objeto CCircleParams, en esencia, no trabaja con entradas externas de datos de origen. No tiene sentido propagar los gradientes a este nivel.

El uso del stub desempeña aquí un papel importante: permite integrar el nuevo objeto en la estructura general del modelo, manteniendo la compatibilidad con los demás componentes de la red y garantizando que los pesos se actualicen correctamente sin una carga innecesaria.

En conjunto, estas capacidades hacen que CCircleParams pase de ser una idea abstracta de tensor dinámico de correlaciones globales a un objeto plenamente controlable, capaz de integrarse eficazmente en TQNet. El modelo es capaz de identificar patrones globales estables y, al mismo tiempo, tener en cuenta las características locales de los datos en cada paso temporal. Esto es especialmente importante para los mercados financieros: el modelo aprende a reconocer ciclos estacionales recurrentes y correlaciones estables entre activos, así como a reaccionar ante las fluctuaciones a corto plazo, el ruido del mercado y los acontecimientos inesperados.

Hemos realizado un trabajo considerable y el artículo ya ha alcanzado un volumen importante. Todo lo expuesto requiere tiempo para que la información se asimile y se asiente en la mente del lector. Es hora de hacer una breve pausa para reflexionar sobre el material acumulado.

En el próximo artículo continuaremos con este trabajo, pasaremos a la construcción de algoritmos de atención y a la integración completa de los componentes de TQNet, mostrando cómo las estructuras y los métodos descritos se convierten en una herramienta eficaz para la predicción de series temporales financieras.


Conclusión

En este artículo hemos conocido el framework TQNet, que combina modularidad, flexibilidad y un alto rendimiento. Esto lo convierte en una herramienta especialmente valiosa para tareas de predicción y análisis de series temporales financieras. La arquitectura del framework está diseñada de tal forma que cada componente desempeñe una función claramente definida, y que la sustitución o actualización de nodos individuales no requiera rehacer todo el sistema.

La parte práctica se centró en la implementación del nuevo objeto CCircleParams, destinado a gestionar los parámetros de las correlaciones globales. Hemos analizado en detalle su proceso de inicialización, la organización de los pasos temporales y también hemos desarrollado algoritmos alternativos para establecer los valores iniciales de los tensores. Se prestó especial atención al diseño de la pasada directa, al mecanismo de actualización de los pesos y a la sincronización de los cálculos entre los pasos temporales.

De este modo, hemos obtenido un elemento flexible y fiable del framework, listo para funcionar plenamente como parte de modelos más complejos. En el próximo artículo nos centraremos en la creación de una cadena computacional unificada y realizaremos pruebas con datos históricos para evaluar la eficacia y la estabilidad del sistema en condiciones reales del mercado financiero.


Referencias


Programas utilizados en el artículo

# Nombre Tipo Descripción
1 Study.mq5 Asesor experto Asesor experto para el entrenamiento offline de modelos
2 StudyOnline.mq5 Asesor experto Asesor experto para el entrenamiento online de modelos
3 Test.mq5 Asesor experto Asesor experto para probar el modelo
4 Trajectory.mqh Biblioteca de clases Estructura para describir el estado del sistema y la arquitectura de los modelos
5 NeuroNet.mqh Biblioteca de clases Biblioteca de clases para crear una red neuronal
6 NeuroNet.cl Biblioteca Biblioteca de código del programa OpenCL

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

Archivos adjuntos |
MQL5.zip (2987.62 KB)
Algoritmo de optimización basado en los sueños — Dream Optimization Algorithm (DOA) Algoritmo de optimización basado en los sueños — Dream Optimization Algorithm (DOA)
Un algoritmo de optimización poblacional inspirado en un fenómeno controvertido y poco estudiado: el fenómeno de los sueños humanos. Grupos de agentes con distintas «memorias», modulación cosenoidal del movimiento y una distribución de fases inusual de 99/1: descubra cómo estas características influyen en la eficacia de la optimización de sus estrategias de trading.
Algoritmo del duelista — Duelist Algorithm Algoritmo del duelista — Duelist Algorithm
¿Y si nuestras estrategias de trading pudieran aprender unas de otras, como auténticos luchadores? Duelist Algorithm es un nuevo método de optimización en el que los parámetros de los sistemas de trading se enfrentan literalmente en duelos por el derecho a ser considerados los mejores.
Características del Wizard MQL5 que debe conocer (Parte 75): Uso del Awesome Oscillator y Envelopes Características del Wizard MQL5 que debe conocer (Parte 75): Uso del Awesome Oscillator y Envelopes
El «Awesome Oscillator» de Bill Williams y el canal de envolventes son una combinación que podría utilizarse de forma complementaria dentro de un asesor experto de MQL5. Utilizamos el Awesome Oscillator por su capacidad para detectar tendencias, mientras que el canal de envolventes se incorpora para definir nuestros niveles de soporte y resistencia. Al explorar esta combinación de indicadores, utilizamos el asistente MQL5 para construir y probar cualquier potencial que estos dos puedan tener.
Implementación de módulos prácticos de otros lenguajes en MQL5 (Parte 02): Desarrollo de la biblioteca REQUESTS inspirada en requests de Python Implementación de módulos prácticos de otros lenguajes en MQL5 (Parte 02): Desarrollo de la biblioteca REQUESTS inspirada en requests de Python
En este artículo, implementamos un un módulo similar a requests, como el que ofrece Python para facilitar el envío y la recepción de solicitudes web en MetaTrader 5 utilizando MQL5.