Redes neuronales en el trading: Desentrañando los componentes estructurados (SCNN)
Introducción
La predicción de series temporales multidimensionales es una tarea fundamental en el aprendizaje automático. Desde esta perspectiva puede abordarse una amplia gama de tareas aplicadas: desde la estimación de la demanda y la predicción del tráfico hasta el reconocimiento del comportamiento de los participantes del mercado y el movimiento de las cotizaciones. Esto es especialmente relevante en el ámbito financiero, ya que prácticamente cualquier activo —ya sea una acción, una divisa o una materia prima— constituye una serie temporal compleja en la que intervienen multitud de factores interrelacionados: volúmenes, precios, indicadores, datos macroeconómicos, señales de comportamiento, etcétera.
La principal dificultad de este tipo de predicciones radica en captar los patrones espaciotemporales. Los aspectos espaciales se manifiestan en las características del entorno externo: diferencias en la liquidez, en las sesiones de negociación y en la actividad regional. Por su parte, los patrones temporales están relacionados con los ritmos de los propios mercados: los ciclos de negociación, los impulsos generados por las noticias y la periodicidad de los datos macroeconómicos. En la práctica, las series financieras distan mucho de ser estacionarias. Estas series están sujetas a cambios bruscos, desplazamientos de la distribución y transiciones complejas entre fases: tendencias, mercado lateral, pánico y euforia. Además, las relaciones de autocorrelación son inestables: lo que funciona hoy puede que mañana ya no tenga ninguna validez.
Los métodos modernos basados en redes neuronales, tales como los Transformers, las redes recurrentes y las arquitecturas convolucionales, no requieren el supuesto de estacionariedad y han demostrado su eficacia en tareas de predicción a corto plazo. Sin embargo, en las condiciones del mercado real, suelen mostrar robustez únicamente ante patrones conocidos. Cuando se enfrentan a desplazamientos repentinos —ya sea un colapso de la liquidez o un cambio en el modelo de comportamiento de los participantes—, su precisión cae drásticamente. Además, estos modelos siguen siendo, en esencia, cajas negras con una elevada carga computacional y una interpretabilidad limitada.
En este contexto, cada vez suscita más interés la idea de descomponer las series temporales, es decir, separarlas en tendencia, estacionalidad y fluctuaciones residuales. Este enfoque permite simplificar la estructura del problema, mejorar la adaptabilidad del modelo y ofrecer una comprensión más clara de en qué se basa la predicción. Incluso los modelos lineales más sencillos, que utilizan la descomposición, superan en algunos casos a las redes neuronales complejas en cuanto a precisión y estabilidad.
Sin embargo, hay que reconocer que estos métodos también tienen sus limitaciones. Muchos de ellos se centran exclusivamente en los componentes de largo plazo y estacionales, pasando por alto los fragmentos de corto plazo o volátiles, en los que precisamente residen las señales clave del mercado. Además, el procesamiento por separado de los distintos componentes, sin intercambio de información entre ellos, dificulta la detección de interacciones de alto nivel y no lineales. Por otra parte, el uso de parámetros estáticos resulta ineficaz ante una autocorrelación dinámica, ya que los ajustes óptimos del modelo deben variar de forma flexible en función del estado actual del mercado.
Para superar estas dificultades, en el artículo «Disentangling Structured Components: Towards Adaptive, Interpretable and Scalable Time Series Forecasting» se presentó una nueva arquitectura: la red neuronal de componentes estructurados (SCNN). Se trata de la primera red neuronal de su clase, construida íntegramente sobre la descomposición estructurada de series temporales. La idea principal de la SCNN consiste en descomponer estratégicamente los datos en varios componentes heterogéneos: no solo en tendencias de largo plazo y fluctuaciones estacionales, sino también en fragmentos volátiles que cambian rápidamente. Cada grupo es procesado por una subred especializada, configurada según su propia dinámica. Gracias a este enfoque, el modelo se vuelve más sensible a los cambios en las condiciones del mercado, y su funcionamiento resulta más comprensible y transparente.
Una característica distintiva de la SCNN es que los procesos de descomposición y ensamblaje están integrados en la propia estructura de la red neuronal, y no se limitan únicamente a las etapas de entrada y salida. Esta arquitectura permite no solo descomponer los datos en profundidad, sino también identificar interacciones complejas entre los componentes, incluidas las relaciones cruzadas y las dependencias latentes. Es más, cada módulo de la red está estructurado según un esquema de dos ramas: una rama adapta dinámicamente los parámetros del modelo a las condiciones actuales del mercado, mientras que la segunda utiliza esos parámetros para procesar las características ocultas. En esencia, el modelo se reajusta sobre la marcha, adaptándose a la estructura de autocorrelación actual.
Para mejorar aún más la robustez y la capacidad de generalización de la SCNN, los autores del framework integraron un mecanismo específico de regularización estructural. Esto ayuda al modelo a centrar la atención en aquellos componentes de la serie temporal que están menos sujetos al ruido y a las distorsiones. De este modo, incluso en un entorno de mercado inestable, en el que algunos patrones pierden rápidamente su validez y otros surgen de forma repentina, la SCNN mantiene un alto nivel de precisión y fiabilidad.
Así lo confirman los resultados de una exhaustiva evaluación experimental llevada a cabo por los autores del framework en tres conjuntos de datos independientes. La SCNN demostró de forma constante su superioridad frente a las alternativas, especialmente en condiciones de desplazamientos bruscos de la distribución y anomalías en los datos. Lo que resulta especialmente importante es que todo ello se consigue con un costo computacional moderado, lo que hace que el modelo sea aplicable tanto para cálculos locales como para su integración en sistemas de trading.
Algoritmo SCNN
En su artículo, los autores del framework SCNN parten de la hipótesis de que la serie temporal se forma por etapas: desde perturbaciones aleatorias hasta estructuras de mercado complejas.

Aquí Z⁰n,t es el valor inicial de la serie temporal observada (por ejemplo, el precio o el volumen de una operación), y Zⁱn,t para i = 1, 2, 3 son representaciones intermedias en distintos niveles de la estructura. Rn,t es la componente residual, que incluye ruido o valores atípicos inesperados. Cada etapa incluye tanto un coeficiente multiplicativo σ, que refleja el efecto de escala, como un desplazamiento aditivo µ, correspondiente a los ajustes absolutos.
Para comprender de forma intuitiva esta construcción, recurriremos a una analogía con el análisis de datos de mercado. Imaginemos la evolución del precio de un activo. La componente de largo plazo refleja los cambios fundamentales. Puede deberse a la influencia de los tipos de interés o a cambios estructurales en la economía. La componente estacional se refiere a patrones recurrentes relacionados con la presentación de resultados trimestrales, los periodos fiscales o los hábitos de los grandes participantes del mercado. La componente de corto plazo capta las fluctuaciones locales provocadas, por ejemplo, por la publicación de noticias, el aumento de la actividad de negociación o una escasez temporal de liquidez. La capa coevolutiva modela eventos de mercado sincrónicos: por ejemplo, cuando varias acciones de un mismo sector reaccionan a la vez ante una noticia macroeconómica común. La componente residual es el ruido blanco o los valores atípicos provocados, por ejemplo, por órdenes puntuales de gran volumen o por errores en las cotizaciones.
Debemos comprender que, en condiciones reales de mercado, los límites entre estas capas son muy fluidos. Por ejemplo, un aumento brusco del volumen de negociación de una acción concreta puede percibirse en un primer momento como un valor atípico, pero si se mantiene, ya se trata de una tendencia a corto plazo. Y si se mantiene durante semanas, con el tiempo pasa a formar parte de una estructura a largo plazo. Esta evolución de los patrones exige que los modelos sean flexibles y tengan capacidad para adaptarse a la estructura cambiante de los datos.
En el marco de esta estructura, cada componente tiene un efecto tanto multiplicador como aditivo. El efecto multiplicador permite modelar cambios proporcionales. El efecto aditivo, por el contrario, refleja desplazamientos constantes, como la influencia sostenida de los dividendos corporativos o de cargos estacionales, que no dependen del nivel actual del precio. Es precisamente la combinación de estos dos tipos de efectos lo que permite modelar los datos de mercado de la forma más realista posible. Y es que, en algunos casos, lo que resulta determinante es la variación relativa, mientras que en otros es el valor absoluto.
La componente a largo plazo sirve para identificar patrones estructurales persistentes en una serie temporal, como el crecimiento estable del volumen de negociación o la expansión de la actividad del mercado en un contexto de auge económico. Por «patrón» no entendemos simplemente una secuencia cronológica, sino concretamente la forma de distribución de los datos agregados, sin vinculación a puntos temporales concretos. De este modo, la estructura a largo plazo queda determinada por el perfil estadístico de los datos recopilados durante un periodo prolongado que abarca varios ciclos de estacionalidad.
La idea es sencilla: si se combinan observaciones de distintas temporadas, se pueden suavizar las fluctuaciones a corto plazo y obtener una estimación más clara y con menos ruido de las tendencias persistentes. Este enfoque permite evitar el sobreajuste a anomalías temporales, como picos puntuales de volumen o correcciones breves, y centrarse en la dinámica fundamental del mercado.
Para aplicar este enfoque se utiliza una ventana deslizante de longitud ∆, que permite seleccionar dinámicamente las observaciones en cada paso temporal. A continuación, se calculan dos parámetros estadísticos clave: la media (o centro de la distribución) y la desviación estándar (que caracteriza la escala de las fluctuaciones). Ambos parámetros se utilizan conjuntamente para formar una representación de la componente a largo plazo. A continuación, cada nuevo fragmento analizado se normaliza: se le resta la media a largo plazo y el resultado se divide entre la desviación estándar. Esto lleva todos los fragmentos a una escala común, elimina los desplazamientos a largo plazo y prepara los datos para la siguiente etapa de descomposición.


Aquí, μˡᵗn,t y σˡᵗn,t son, respectivamente, la media a largo plazo y la escala (desviación estándar), obtenidas a partir de los datos de la ventana ∆. Y Z¹n,t es el valor normalizado, depurado de la componente a largo plazo, que se pasa al siguiente nivel de procesamiento, donde se identificará la estacionalidad.
Esta etapa puede interpretarse como una representación alineada del mercado, en la que se tienen en cuenta las tendencias estructurales persistentes. Esto es especialmente importante en la predicción financiera, donde las estrategias a corto plazo (por ejemplo, intradía) necesitan datos depurados de desplazamientos a largo plazo para identificar oportunidades locales sin distorsiones de las tendencias globales.
La componente estacional se encarga de identificar patrones cíclicos recurrentes en una serie temporal. En el contexto de los mercados financieros, estos patrones pueden ser, por ejemplo, picos intradía de actividad de negociación: repuntes matutinos, calma a la hora del almuerzo y aceleración vespertina antes del cierre de la sesión. También puede tratarse de una ciclicidad semanal: una disminución de la volatilidad los viernes o un aumento de los volúmenes los lunes, así como de efectos estacionales trimestrales y anuales relacionados con la presentación de resultados o con las publicaciones macroeconómicas.
Se supone que la duración del ciclo estacional se mantiene constante a lo largo del tiempo; se trata de una hipótesis simplificada, pero práctica. No obstante, para escenarios con una duración variable del ciclo, los autores del framework proponen integrar una estimación automática de la estacionalidad mediante la FFT (transformada rápida de Fourier).
Técnicamente, la extracción de la componente estacional se organiza de forma similar a la normalización a largo plazo, pero con una diferencia importante: se utiliza una ventana dilatada (dilated window), cuyo paso corresponde a la duración del ciclo. Digamos que τ es el tamaño de la ventana y m el factor de dilatación (en realidad, la longitud del ciclo). Esto permite muestrear los datos a intervalos correspondientes a la estructura estacional.



Aquí, Z²n,t son los datos normalizados y depurados de estacionalidad que se transmiten a la siguiente fase de procesamiento.
La componente de corto plazo se encarga de captar las desviaciones locales e irregulares que no se explican ni por las tendencias a largo plazo ni por los patrones estacionales. En el contexto del mercado financiero, estos efectos pueden deberse a una reacción repentina ante la difusión de una noticia, a fallos técnicos, a picos especulativos de liquidez o a un cambio brusco en el sentimiento de los operadores en un contexto de volatilidad. Se trata de una especie de pulso del mercado que refleja su sensibilidad ante los estímulos externos en intervalos de tiempo muy cortos.
A diferencia de la normalización a largo plazo, aquí se utiliza una ventana de suavizado pequeña para evitar que se difuminen las fluctuaciones a corto plazo. Digamos que δ es la longitud de esta ventana. Sobre esa base se calculan las características estadísticas estándar —el centro y la escala de la muestra— y, a continuación, los datos se normalizan.
El valor obtenido Z³n,t constituye una representación intermedia, libre de fluctuaciones a corto plazo, y se envía a continuación a la etapa final de normalización.
Sin embargo, este componente tiene sus limitaciones. En primer lugar, no puede reaccionar de forma inmediata ante cambios repentinos y bruscos: el modelo muestra inercia. En segundo lugar, si el cambio dura solo dos o tres pasos temporales, puede pasar desapercibido, sobre todo en condiciones de alta varianza. Esto recuerda a una situación del mercado en la que la volatilidad a corto plazo en una acción concreta puede ser ignorada por el sistema global si su valor se pierde en el ruido agregado.
Para suavizar este efecto y aumentar la sensibilidad del modelo ante las señales a corto plazo, en SCNN se prevé el uso de series temporales coevolutivas (co-evolving). Es decir, si se observa una desviación en un instrumento, el modelo comprueba las señales sincrónicas en otros activos, como instrumentos derivados, índices o volúmenes. De este modo, la componente de corto plazo no solo se vuelve reactiva, sino también contextual, lo cual es especialmente importante en el contexto del trading de alta frecuencia y algorítmico.
La componente coevolutiva ocupa un lugar especial en la estructura general del modelo. A diferencia de las tres componentes anteriores, que analizan el comportamiento de cada serie temporal de forma aislada, esta parte del modelo se basa en las correlaciones espaciales y permite detectar cambios instantáneos que se manifiestan de forma sincronizada en varias series temporales. Si dos o más series temporales muestran una dinámica similar en los mismos momentos, esto indica, con gran probabilidad, la existencia de un proceso generativo común. En ese caso, se puede obtener su estimación mediante la agregación de las observaciones correspondientes.
Sin embargo, para poner en práctica este enfoque es necesario resolver una cuestión clave: determinar qué series concretas participan en este proceso conjunto. Esto se reduce a medir la correlación entre series temporales. En este caso, hay dos enfoques posibles: se puede fijar la matriz de correlaciones de antemano, basándose en el conocimiento experto, o bien entrenarla directamente a partir de los datos. Los autores del framework optaron por la segunda vía, más flexible y versátil, sobre todo cuando no se dispone de información a priori sobre la estructura de los datos.
Para cada par de series temporales n y n', se calcula un coeficiente de atención individual, que posteriormente se normaliza mediante la función SoftMax. Esto garantiza que la suma de los pesos de cada serie sea igual a uno.

Usando estos pesos, calculamos los parámetros de la componente coevolutiva. En primer lugar, se calcula el valor medio, que refleja el centrado local considerando las interrelaciones.

A continuación, se estima la escala (desviación estándar) añadiendo la constante estabilizadora ϵ.

Sobre esta base se forma un residuo normalizado.

Este residuo Rn,t corresponde a la parte de la señal que no puede explicarse mediante ninguna de las componentes identificadas anteriormente. Refleja la incertidumbre residual, el ruido estructural o bien las desviaciones únicas y no formalizables de una serie concreta respecto a la dinámica general.
Cuando se trabaja con un gran número de series temporales, es posible mejorar aún más la escalabilidad del modelo. Para ello, se propone utilizar un módulo de aprendizaje de la matriz de adyacencia, que permite ajustar de forma flexible la arquitectura de la atención y optimizar los cálculos.
En la etapa final, todas las representaciones intermedias se combinan en un único vector de características.
![]()
Al mismo tiempo, se genera un vector auxiliar de parámetros de normalización.
![]()
De este modo, la serie temporal deja de ser simplemente un conjunto de números registrados en el tiempo. Se convierte en una representación multicomponente, en la que cada parte responde de un tipo concreto de dinámica: la tendencia estructural, las oscilaciones estacionales recurrentes, las fluctuaciones locales de corto plazo o los cambios colectivos sincronizados. Esto permite analizar los datos con mayor precisión, crear modelos interpretables y desarrollar algoritmos de predicción robustos.
Como cada componente presenta su propia dinámica con distintos grados de previsibilidad, surge de forma natural la necesidad de modelar su comportamiento por separado. Esto resulta especialmente relevante en la predicción de corto plazo, cuando las componentes de largo plazo y estacionales, por lo general, mantienen un carácter estable y varían siguiendo leyes bastante regulares. En tales condiciones, se pueden seguir extrapolando directamente, sin necesidad de introducir parámetros adicionales ni modelos más complejos.
Así, para la componente de largo plazo se aplica el método más sencillo: se supone que sus valores permanecen constantes a lo largo de todo el horizonte de predicción. Es decir, si conocemos las estimaciones actuales de los parámetros de esta componente, simplemente las copiamos hacia el futuro.
La componente estacional, por el contrario, se basa en la periodicidad y requiere un enfoque algo más sutil. Dado que la ciclicidad se mantiene, reutilizamos los valores de los parámetros de puntos temporales anteriores que se encuentran en la misma fase del ciclo que el punto pronosticado. En otras palabras, los valores de la componente estacional para el instante t+i se toman del instante t-m+i, donde m es la longitud del ciclo.
Este método garantiza la conservación del ritmo estacional y permite prolongar con alta precisión el comportamiento de la componente sin añadir carga adicional al modelo.
A diferencia de las componentes de largo plazo y estacionales, la componente de corto plazo, las dependencias coevolutivas y las representaciones residuales presentan una estocasticidad mucho mayor. Su evolución es mucho menos regular, lo que hace imposible utilizar heurísticas fijas o reglas de extrapolación estrictamente definidas. Por ello, para cada una de estas tres componentes, los autores del framework aplican un modelo parametrizado basado en la autorregresión, lo que permite tener en cuenta sus fluctuaciones complejas e impredecibles.
Para cada instante temporal del horizonte de predicción (i), los valores de las componentes correspondientes se calculan a partir de los δ valores anteriores mediante un modelo lineal con pesos entrenables. El procedimiento de extrapolación es el mismo para las componentes de corto plazo, coevolutiva y residual, y se expresa de la siguiente manera:

donde G ∈ {Zˡn,t+i, μstn,t+i, σstn,t+i,μcen,t+i, σcen,t+i} son los parámetros que se extrapolan, correspondientes a las distintas componentes; Ŵji ∈ Rdz · dz son matrices de pesos entrenables que reflejan la contribución de los valores pasados; bi es el sesgo (bias), también entrenable.
Tras la extrapolación, todas las componentes se combinan en dos vectores:
- Ĥn, t+i — conjunto de parámetros estadísticos;
- Źn, t+i — conjunto de representaciones normalizadas.
Para modelar la interacción entre estos dos conjuntos de características, se aplica una operación de multiplicación por pares (producto elemento a elemento) de dos proyecciones lineales, cada una de las cuales se forma a partir de una matriz de parámetros entrenables.
![]()
De este modo, se forma la representación final de la predicción, que sintetiza todos los aspectos estadísticamente significativos del proceso estudiado.
Implementación en MQL5
Tras analizar en detalle los fundamentos teóricos del framework SCNN, pasamos a su implementación práctica. En esta sección se presentará una de las opciones prácticas para trasladar las ideas clave del modelo al ámbito aplicado mediante MQL5. Demostraremos cómo se puede llevar a cabo la descomposición de una serie temporal en componentes estructurados y construir la parte predictiva del modelo, conservando su interpretabilidad y modularidad. Este enfoque abre el camino hacia la creación de estrategias de trading intuitivas, flexibles y adaptativas basadas en arquitecturas complejas de redes neuronales.
En la primera fase de implementación del framework SCNN, nos centraremos en la creación del bloque básico: el algoritmo de extracción de características estadísticas y normalización de los datos de entrada por periodos temporales fijos. Esta etapa desempeña un papel fundamental en la descomposición de la serie temporal, ya que es aquí donde se forman los componentes de largo plazo y de corto plazo, en los que se basará posteriormente todo el proceso de predicción.
El algoritmo se ha implementado como un kernel de OpenCL PeriodNorm, que se encarga de calcular las características estadísticas y normalizar los datos dentro de las ventanas deslizantes de la serie temporal. La implementación se basa en el concepto de procesamiento paralelo, en el que los datos de todas las variables y ventanas temporales se procesan simultáneamente.
__kernel void PeriodNorm(__global const float* inputs, __global float2* mean_stdevs, __global float* outputs, const int total_inputs ) { const size_t i = get_global_id(0); const size_t p = get_local_id(1); const size_t v = get_global_id(2); const size_t windows = get_global_size(0); const size_t period = get_local_size(1); const size_t variable = get_global_size(2);
La función recibe el array de valores de entrada inputs, así como arrays para almacenar los valores normalizados outputs y los parámetros estadísticos calculados (medias y desviaciones estándar) mean_stdevs. También se pasa el parámetro total_inputs, que determina la longitud de la serie temporal por variable.
La organización de los hilos de ejecución es tridimensional: la primera coordenada corresponde al número de la ventana (segmento temporal), la segunda, a la posición dentro de la ventana, y la tercera, al índice de la variable. De este modo, cada flujo se encarga de un elemento concreto de la serie dentro de una ventana concreta y para una variable concreta.
En primer lugar, se calculan los índices necesarios para acceder correctamente a los datos en la memoria. La variable shift_i determina la posición del punto actual con respecto al inicio de la serie temporal; shift_v, el desplazamiento por variables; y shift_ms, la posición en el array de estadísticas.
__local float Temp[LOCAL_ARRAY_SIZE]; const int shift_i = i * period + p; const int shift_v = v * total_inputs; const int shift_ms = v * windows + i;
A continuación, el valor de la serie temporal se extrae del array original tras comprobar si hay valores no válidos: si se detectan NaN o infinitos, se sustituyen por cero.
//--- float val = 0; if((shift_i) < total_inputs) val = IsNaNOrInf(inputs[shift_v + shift_i], 0);
El siguiente paso es calcular el valor medio dentro de la ventana actual. Para ello se utiliza la función auxiliar LocalSum, que permite sumar los valores de los elementos de los flujos del grupo local, lo que mejora considerablemente el rendimiento.
float mean = IsNaNOrInf(LocalSum(val, 1, Temp) / period, 0); val -= mean; BarrierLoc;
A continuación, el valor medio obtenido se resta de la observación actual y, a partir de ahí, se calcula la desviación estándar como la raíz cuadrada de la media de los cuadrados de las desviaciones. Todas las etapas van acompañadas de comprobaciones integradas de estabilidad numérica, con el fin de evitar la división por cero y la acumulación de errores.
float stdev = LocaSum(val * val, 1, Temp) / period; stdev = IsNaNOrInf(sqrt(stdev), 1);
Los resultados se guardan de dos formas: en primer lugar, las estadísticas correspondientes a cada ventana y variable se escriben en el array mean_stdevs; y, en segundo lugar, los valores normalizados se escriben en el array outputs.
mean_stdevs[shift_ms] = (float2)(mean, stdev); if((shift_i) < total_inputs) outputs[shift_v + shift_i] = IsNaNOrInf(val / stdev, 0); }
La normalización se realiza según la fórmula clásica de la normalización Z (puntuación z), utilizando como norma la desviación estándar calculada sobre la marcha.
El kernel está escrito de modo que pueda escalarse fácilmente: se puede modificar el tamaño de la ventana, el número de variables o la profundidad de la serie temporal sin cambiar la lógica. En concreto, al aumentar la longitud de la ventana, la normalización se vuelve sensible a las tendencias de largo plazo y puede utilizarse para extraer la tendencia. Por el contrario, reducir la ventana permite detectar con mayor precisión las desviaciones y anomalías de corto plazo.
Para implementar un modelo con un ciclo completo de entrenamiento que incluya la retropropagación del error, debemos garantizar que el gradiente pueda propagarse desde las salidas de la arquitectura de red neuronal hasta sus entradas. Aunque el kernel PeriodNorm no contiene parámetros entrenables (todos los cálculos son estrictamente estadísticos y se basan en los datos de la serie de entrada), es necesario calcular los gradientes si la normalización se realiza como parte de un grafo computacional. Por eso, ampliamos la arquitectura con un segundo kernel: PeriodNormGrad.
__kernel void PeriodNormGrad(__global const float* inputs, __global float* inputs_gr, __global const float2* mean_stdevs, __global const float2* mean_stdevs_gr, __global const float* outputs, __global const float* outputs_gr, const int total_inputs ) { const size_t i = get_global_id(0); const size_t p = get_local_id(1); const size_t v = get_global_id(2); const size_t windows = get_global_size(0); const size_t period = get_local_size(1); const size_t variable = get_global_size(2);
A diferencia de los bloques clásicos con parámetros entrenables, el algoritmo implementado en el kernel PeriodNormGrad tiene como objetivo la propagación inversa correcta del error a través de una capa que, por sí misma, no contiene neuronas ni pesos. En primer lugar, dentro del kernel se organiza el acceso puntual a cada ventana temporal de la serie para cada variable. Los índices se calculan igual que en la pasada directa:
- i — número de ventana,
- p — posición dentro de la ventana,
- v — número de variable.
Una vez obtenidas así las coordenadas, extraemos todos los datos necesarios: el valor de entrada (inp), su versión normalizada (out), el gradiente del error con respecto al valor normalizado (out_gr), así como la media y la desviación estándar calculadas previamente en la ventana (mean_stdev) y sus gradientes (mean_stdev_gr), que pueden obtenerse adicionalmente cuando los valores se usan varias veces. En concreto, el framework SCNN contempla su uso para la extrapolación de datos. Se comprueba que todos los valores sean correctos: se descartan los valores NaN y los valores infinitos para no alterar los cálculos.
__local float Temp[LOCAL_ARRAY_SIZE]; const int shift_i = i * period + p; const int shift_v = v * total_inputs; const int shift_ms = v * windows + i; //--- float inp = 0; float inp_gr = 0; float out = 0; float out_gr = 0; const float2 mean_stdev = means_stdevs[shift_ms]; const float2 mean_stdev_gr = means_stdevs_gr[shift_ms]; if((shift_i) < total_inputs) { inp = IsNaNOrInf(inputs[shift_v + shift_i], 0); out = IsNaNOrInf(outputs[shift_v + shift_i], 0); out_gr = IsNaNOrInf(outputs_gr[shift_v + shift_i], 0); }
A partir de aquí viene lo más interesante. Para comprender en qué medida cada valor de entrada ha influido en el error final del modelo, debemos calcular cómo variaría el error si modificáramos ligeramente ese valor. En estadística, la normalización se lleva a cabo restando la media y dividiendo por la desviación estándar. Por lo tanto, cualquier variación en la entrada afectará tanto al numerador (desviación respecto a la media) como al denominador (magnitud de la dispersión en la ventana). Por lo tanto, hay que calcular los gradientes para ambos parámetros: tanto para la media como para la desviación estándar.
float mean_gr = LocalSum(out_gr, 1, Temp) / period + IsNaNOrInf(mean_stdev.x, 0); BarrierLoc; float stdev_gr = out * LocalSum(IsNaNOrInf(out * out_gr, 0), 1, Temp) / period + IsNaNOrInf(mean_stdev.y, 0);
Para ello, primero se suman todos los gradientes en el nivel de los resultados de la capa out_gr correspondientes a la ventana actual y se calcula su media; esta es la contribución al gradiente respecto a la media (mean_gr). Tenga en cuenta que aquí no nos limitamos a transmitir el gradiente directamente: tenemos en cuenta cómo la variación de la media afecta a los valores normalizados en toda la ventana.
A continuación, el cálculo del gradiente respecto a la desviación estándar (stdev_gr) es un poco más complejo: aquí utilizamos el producto del valor promediado por su gradiente de error, luego calculamos la media de este resultado y, de este modo, obtenemos la sensibilidad del error a la dispersión de los datos.
Ahora, una vez que disponemos de ambos gradientes, podemos pasar al cálculo del resultado principal: el gradiente respecto a la propia entrada. Combinamos el gradiente de out_gr con las derivadas respecto a la media y la desviación estándar. La fórmula final está equilibrada y permite reflejar con precisión la contribución de cada valor de entrada al error total del modelo, teniendo en cuenta su posición en la ventana y su influencia en las características estadísticas promedio.
inp_gr = (out_gr - mean_gr - stdev_gr) / IsNaNOrInf(mean_stdev.y, 1); //--- if((shift_i) < total_inputs) inpurs_gr[shift_v + shift_i] = IsNaNOrInf(inp_gr, 0); }
Al final, como es habitual, el valor obtenido se vuelve a guardar en el array de gradientes de entrada (inputs_gr). Todo se realiza teniendo en cuenta los límites: si el índice actual queda fuera de los límites del array, no se lleva a cabo ninguna operación.
Por lo tanto, PeriodNormGrad no es solo una implementación formal de los gradientes, sino un importante puente funcional entre la estadística clásica y los métodos modernos de aprendizaje de modelos. Permite que las operaciones estadísticas sean participantes de pleno derecho en el grafo computacional y participen en el entrenamiento, transmitiendo correctamente la información sobre el error al lugar donde se ha producido.
En el código del programa principal, crearemos una clase especializada, CNeuronPeriodNorm, destinada a encapsular la lógica de trabajo con los kernels OpenCL de normalización por periodos, tanto para la pasada directa como para la inversa. Hereda de la clase base CNeuronBaseOCL, lo que indica que pertenece a la jerarquía de componentes del modelo computacional. A continuación se muestra la estructura del nuevo objeto.
class CNeuronPeriodNorm : public CNeuronBaseOCL { protected: uint iPeriod; uint iVariables; uint iCount; CNeuronBaseOCL cMeanSTDevs; //--- virtual bool feedForward(CNeuronBaseOCL *NeuronOCL) override; virtual bool updateInputWeights(CNeuronBaseOCL *NeuronOCL) override { return true; } virtual bool calcInputGradients(CNeuronBaseOCL *NeuronOCL) override; public: CNeuronPeriodNorm(void) : iPeriod(-1), iVariables(1) {}; ~CNeuronPeriodNorm(void) {}; //--- virtual bool Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl, uint units_count, uint period, uint variables, ENUM_OPTIMIZATION optimization_type, uint batch); //--- virtual bool Save(const int file_handle) override; virtual bool Load(const int file_handle) override; //--- virtual int Type(void) override const { return defNeuronPeriodNorm; } virtual void SetOpenCL(COpenCLMy *obj) override; //--- CNeuronBaseOCL* GetMeanSTDevs(void) { return cMeanSTDevs.AsObject(); } virtual uint GetPeriod(void) const { return iPeriod; } virtual uint GetVariables(void) const { return iVariables; } virtual uint GetUnits(void) const { return iCount; } };
Los campos internos de la clase reflejan los parámetros de configuración clave. En concreto, la variable iPeriod define la longitud de la ventana dentro de la cual se realiza el procesamiento estadístico: el cálculo de la media y la desviación estándar. El parámetro iVariables determina el número de variables (o características) que se procesan, mientras que iCount establece el número de ventanas independientes para cada secuencia unitaria.
Además, dentro de la clase hay un objeto cMeanSTDevs, que actúa como búfer intermedio para almacenar los valores de las medias y las desviaciones estándar calculados en la fase de pasada directa. Este búfer también participa en la retropropagación de gradientes, tal y como se ha implementado en el kernel PeriodNormGrad.
El método Init desempeña el papel de constructor de inicialización: recibe todos los parámetros de entrada y, a partir de ellos, prepara las estructuras internas y vincula el objeto con los recursos necesarios de OpenCL.
Los métodos de pasada directa e inversa, en esencia, actúan como envoltorios auxiliares. Su tarea no consiste en recalcular los datos manualmente, sino en preparar todo lo necesario para poner correctamente en la cola de ejecución los kernels de OpenCL correspondientes.
Preste atención a la función GetMeanSTDevs: proporciona acceso a un búfer con las estadísticas calculadas, que otros componentes del modelo pueden utilizar, por ejemplo, para visualización o procesamiento posterior.
De este modo, la clase CNeuronPeriodNorm constituye un componente totalmente autónomo y flexible que no solo realiza la normalización, sino que también garantiza una integración correcta en la estructura del modelo computacional con soporte para el entrenamiento. Todo se ha realizado siguiendo estrictamente los cánones de la arquitectura de los frameworks de redes neuronales, pero manteniendo la lógica clara característica de los sistemas con control manual de los cálculos, como MQL5 + OpenCL.
El código completo de esta clase, incluidos sus métodos, se incluye en el archivo adjunto para su estudio independiente.
Hoy hemos realizado un trabajo importante y productivo. El material ha resultado denso y requiere tiempo para asimilarlo. Es un buen momento para hacer una pequeña pausa, recuperar el aliento y, con nuevas energías, continuar el trabajo en el próximo artículo.
Conclusión
En este artículo hemos conocido los aspectos teóricos del framework SCNN, que propone un enfoque original y conceptualmente coherente para la descomposición de series temporales en componentes interpretables: de largo plazo, estacional, de corto plazo y residual. Esta estructura no solo permite aumentar la precisión de las predicciones, sino que también mejora considerablemente la transparencia del modelo, haciendo que su comportamiento sea más predecible y se adapte mejor a las condiciones cambiantes del mercado.
Se hace especial hincapié en la diferencia en el carácter de la dinámica de cada componente, lo que justifica el uso de métodos especializados de interpolación: para los componentes de largo plazo y estacional se aplican patrones simples y repetitivos, mientras que las fluctuaciones de corto plazo y residuales se modelan mediante estructuras autorregresivas entrenables.
En la parte práctica del artículo hemos comenzado a poner en práctica nuestra propia visión de los enfoques propuestos y hemos desarrollado uno de los elementos básicos del modelo: el algoritmo de normalización de segmentos periódicos de una serie temporal. Hemos analizado los detalles de la ejecución de los cálculos en OpenCL, incluidas las pasadas directa e inversa, lo que permitirá posteriormente integrar este mecanismo en una arquitectura de red neuronal entrenable. Este paso ha supuesto un eslabón fundamental en la adaptación práctica del framework a las tareas de trading en el entorno MQL5.
En el próximo artículo continuaremos desarrollando esta implementación, añadiendo nuevos componentes al modelo y acercándonos poco a poco a un sistema completo de análisis y predicción de series temporales basado en el framework SCNN.
Enlaces
- Desentrelazamiento de componentes estructurados: hacia un pronóstico de series temporales adaptativo, interpretable y escalable
- Otros artículos de la serie
Programas utilizados en el artículo
| # | Nombre | Tipo | Descripción |
|---|---|---|---|
| 1 | Study.mq5 | asesor experto | Asesor experto para el aprendizaje offline de modelos |
| 2 | StudyOnline.mq5 | asesor experto | Asesor experto para el aprendizaje 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/18950
Advertencia: todos los derechos de estos materiales pertenecen a MetaQuotes Ltd. Queda totalmente prohibido el copiado total o parcial.
Este artículo ha sido escrito por un usuario del sitio web y refleja su punto de vista personal. MetaQuotes Ltd. no se responsabiliza de la exactitud de la información ofrecida, ni de las posibles consecuencias del uso de las soluciones, estrategias o recomendaciones descritas.
Optimización por comunidad de científicos — Community of Scientist Optimization (CoSO): Práctica
Automatización de estrategias de trading en MQL5 (Parte 22): Desarrollo de un sistema de recuperación por zonas para trading de tendencia con Envelopes
Particularidades del trabajo con números del tipo double en MQL4
Red neuronal cuántica en MQL5 (Parte II): Entrenamos una red neuronal con retropropagación del error utilizando matrices de Márkov de ALGLIB
- Aplicaciones de trading gratuitas
- 8 000+ señales para copiar
- Noticias económicas para analizar los mercados financieros
Usted acepta la política del sitio web y las condiciones de uso