English Русский 中文 Deutsch 日本語
preview
Características del Wizard MQL5 que debe conocer (Parte 59): Aprendizaje por refuerzo (DDPG) con patrones de media móvil y oscilador estocástico (II)

Características del Wizard MQL5 que debe conocer (Parte 59): Aprendizaje por refuerzo (DDPG) con patrones de media móvil y oscilador estocástico (II)

MetaTrader 5Sistemas comerciales |
39 0
Stephen Njuki
Stephen Njuki

Introducción

En el último artículo habíamos presentado DDPG, un algoritmo de aprendizaje por refuerzo, y habíamos analizado tres de sus clases cruciales tal como se implementan en Python. La clase de búfer de reproducción, la clase de red de actores y la clase de red de críticos. Lo que no se trató fue la clase DDPG-agent; la importación de datos de precios de MetaTrader 5 a Python; funciones para la media móvil y el oscilador estocástico; una función get-pattern para combinar datos de los dos indicadores en un vector de entrada binario para la red de aprendizaje supervisado (implementada en el artículo anterior sobre aprendizaje supervisado a través de MQL5); y, finalmente, un bucle de simulación de entorno para entrenar las redes actor-crítico.

Todo esto forma parte del aprendizaje por refuerzo (RL), que consideramos una transición del aprendizaje supervisado (SL) al aprendizaje por inferencia (IL) (o aprendizaje no supervisado). Cualquiera de estos modos puede utilizarse de forma unilateral para entrenar y usar un modelo; sin embargo, estos artículos intentan demostrar que podrían utilizarse conjuntamente para construir algo más interesante. Así pues, continuamos nuestro análisis del aprendizaje por refuerzo y, en concreto, abordando la importantísima clase DDPG-Agent.



DDPG-Agent

La arquitectura principal y la inicialización de esta clase se pueden definir de la siguiente manera:

def __init__(self, state_dim, action_dim):

    # Actor networks
    self.actor = Actor(state_dim, action_dim, HIDDEN_DIM).to(device)
    self.actor_target = Actor(state_dim, action_dim, HIDDEN_DIM).to(device)
    self.actor_target.load_state_dict(self.actor.state_dict())
    self.actor_optimizer = optim.Adam(self.actor.parameters(), lr=LR_ACTOR)
   
    # Critic networks  
    self.critic = Critic(state_dim, action_dim, HIDDEN_DIM).to(device)
    self.critic_target = Critic(state_dim, action_dim, HIDDEN_DIM).to(device)
    self.critic_target.load_state_dict(self.critic.state_dict())
    self.critic_optimizer = optim.Adam(self.critic.parameters(), lr=LR_CRITIC)

    self.replay_buffer = ReplayBuffer(BUFFER_SIZE)

Los componentes críticos en este caso son la arquitectura de red dual, la configuración del optimizador y la gestión de la experiencia. La arquitectura dual mantiene una política separada (red de actores) y un valor separado (red de críticos) de las dos redes principales de política y valor. Estas implementan redes objetivo para ambos casos, lo cual es importante para la estabilidad durante el entrenamiento. La inicialización de los objetivos respectivos se realiza con los mismos pesos que sus redes principales.

La configuración del optimizador incluye optimizadores Adam independientes para las redes de actores y críticos. Además, como suele ser habitual, utilizamos tasas de aprendizaje diferentes para las redes de políticas y de valores. Por último, para la gestión de la experiencia, nos aseguramos de que el búfer de reproducción almacene las transiciones para el aprendizaje fuera de política y, al fijar el tamaño del búfer, evitamos un uso ilimitado de la memoria. Seleccionamos las acciones incorporando la exploración de la siguiente manera:

def select_action(self, state, noise_scale=0.1):
    state = torch.FloatTensor(state).unsqueeze(0).to(device)
    action = self.actor(state).cpu().data.numpy().flatten()
    action += noise_scale * np.random.randn(self.action_dim)
    return np.clip(action, -1, 1)

Los mecanismos clave en este caso son el procesamiento del estado, la estrategia de exploración y la gestión del dispositivo. El procesamiento de estado supervisa la conversión de la matriz NumPy al formato de tensor adecuado, la adición de una dimensión de lote (mediante la operación unsqueeze) y, finalmente, garantiza que el cálculo se realice en el dispositivo correcto.

La estrategia de exploración añade ruido gaussiano al resultado de la política determinista. La escala de ruido controla la magnitud de la exploración y el recorte mantiene un rango de acción válido. La gestión de dispositivos garantiza una transferencia eficiente entre la GPU y la CPU, cuando corresponda. Además, la función devuelve un resultado final en forma de matriz NumPy para garantizar la compatibilidad con el entorno. El mecanismo de actualización del aprendizaje es el siguiente:

def update(self):

    if len(self.replay_buffer) < BATCH_SIZE:

        return

Esta cláusula condicional sirve como puerta de actualización, donde las actualizaciones se omiten hasta que se recopilen suficientes experiencias, cuyo número coincide con el tamaño del lote. Esto garantiza estadísticas de lotes significativas. La actualización de las dos redes de críticos es la siguiente:

# Sample batch

states, actions, rewards, next_states, dones = self.replay_buffer.sample(BATCH_SIZE)

# Target Q calculation
next_actions = self.actor_target(next_states)
target_q = self.critic_target(next_states, next_actions)
target_q = rewards + (1 - dones) * GAMMA * target_q

# Current Q estimation
current_q = self.critic(states, actions)

# Loss computation and backpropagation
critic_loss = nn.MSELoss()(current_q, target_q.detach())
self.critic_optimizer.zero_grad()
critic_loss.backward()
self.critic_optimizer.step()

Los aspectos clave que aborda este código son el cálculo del valor objetivo, el cálculo de la pérdida y la gestión del gradiente. El cálculo del valor objetivo utiliza redes objetivo para obtener objetivos Q estables. Implementa la ecuación de Bellman con manejo de terminación según lo establecido por el parámetro de experiencia 'dones'. Un factor de descuento de GAMMA controla la importancia de la recompensa futura.

Para el cálculo de la pérdida, se determina el error cuadrático medio entre los valores Q actuales y los valores Q objetivo. El método detach() impide que los gradientes objetivo fluyan (o sean transportados por el tensor para su transferencia). Y se aplica el método estándar de aprendizaje por diferencia temporal. La gestión de gradientes simplemente garantiza que todos los gradientes se restablezcan a cero, y la optimización de la red crítica es un paso aparte. Las actualizaciones de la red de actores también se realizan de la siguiente manera:

actor_loss = -self.critic(states, self.actor(states)).mean()
self.actor_optimizer.zero_grad()
actor_loss.backward()
self.actor_optimizer.step()

Los detalles del gradiente de política que se tratan aquí son la maximización de los valores Q mediante la minimización de Q negativos, la diferenciación a través de las redes del actor y del crítico, así como la aplicación de un enfoque de gradiente de política puro sin probabilidades logarítmicas (siendo determinista). Las actualizaciones de la red objetivo son las siguientes:

for target, param in zip(self.actor_target.parameters(), self.actor.parameters()):

    target.data.copy_(TAU * param.data + (1 - TAU) * target.data)

for target, param in zip(self.critic_target.parameters(), self.critic.parameters()):

    target.data.copy_(TAU * param.data + (1 - TAU) * target.data)

Este mecanismo de actualización suave utiliza un promedio de Polyak con un valor TAU que suele ser inferior a 1. El seguimiento de los pesos de la red se realiza lentamente, ya que esto proporciona una alternativa a las actualizaciones periódicas por completo. En general, este proceso mantiene la estabilidad al tiempo que permite el aprendizaje. Nuestro modelo debe ser persistente. Debería poder cargar los pesos de la red guardados previamente y también guardarlos después del entrenamiento. Lo logramos de la siguiente manera:

def save(self, filename):

    torch.save({
        'actor': self.actor.state_dict(),

        'critic': self.critic.state_dict(),

        'actor_target': self.actor_target.state_dict(),

        'critic_target': self.critic_target.state_dict(),
    }, filename)


def load(self, filename):

    checkpoint = torch.load(filename)
    self.actor.load_state_dict(checkpoint['actor'])
    self.critic.load_state_dict(checkpoint['critic'])
    self.actor_target.load_state_dict(checkpoint['actor_target'])
    self.critic_target.load_state_dict(checkpoint['critic_target'])

Las características clave de nuestro producto mencionado anteriormente son: guardamos y cargamos todos los estados de la red; mantenemos la coherencia de la red objetivo; permitimos la continuación del entrenamiento; y admitimos la evaluación del modelo. En resumen, al implementar un agente DDPG, es necesario tomar algunas decisiones de diseño cruciales para la clase de agente. Estas podrían clasificarse en tres categorías principales: elegir componentes específicos de DDPG, aprovechar las fortalezas de la implementación y realizar posibles mejoras.

Los componentes DDPG utilizados son principalmente las redes objetivo, la política determinista y las tasas de aprendizaje independientes. Las redes objetivo son muy importantes para el aprendizaje estable de las recompensas derivadas de las acciones realizadas (aprendizaje Q) cuando se trabaja con espacios de acción continuos. El uso de espacios continuos hace que esto sea primordial. Esta política determinista requiere, por lo tanto, una exploración externa con ruido para lograr mayor robustez. El uso de tasas de aprendizaje separadas es también una aplicación típica en la que la política (red de actores) tiene una tasa de aprendizaje más lenta que la red de valores.

Las decisiones tomadas que hacen de esta una implementación relativamente sólida son la clara "separación de responsabilidades", donde tenemos métodos bien definidos para la selección de acciones y también para las actualizaciones. Además, cuenta con un sistema de reconocimiento de dispositivos que garantiza una gestión coherente de las transiciones entre la GPU y la CPU. También se utiliza el procesamiento por lotes para hacer más eficientes las operaciones con tensores y, finalmente, se comprueba la seguridad de la forma en varios puntos para garantizar una dimensionalidad tensorial consistente.

Sin embargo, algunas mejoras potenciales podrían ser: el recorte de gradientes para evitar gradientes explosivos; el uso de un programa de tasa de aprendizaje para refinar y controlar mejor el proceso de aprendizaje; el uso de una reproducción prioritaria para un muestreo eficiente, aunque esto está relacionado con el búfer de reproducción ya mencionado en el artículo anterior; y, por último, la exploración paralela, donde se pueden usar múltiples instancias del actor para una recopilación de datos más rápida.

También existen algunas dinámicas de entrenamiento que merecen ser destacadas, relacionadas con la secuencia de actualización y las consideraciones sobre los hiperparámetros. La secuencia de actualización consiste en actualizar primero las redes de críticos. Esto se debe a que unos valores Q más precisos sí orientan la mejora de las políticas. Para aportar mayor estabilidad, también se puede implementar el aplazamiento de las actualizaciones de las políticas. Finalmente, se realizan actualizaciones frecuentes de los objetivos para realizar un seguimiento gradual de los parámetros (pesos de la red) que se han aprendido.

Las consideraciones sobre los hiperparámetros deben incluir un enfoque en TAU, ya que controla la velocidad de la red objetivo y, por lo tanto, es un factor clave para la estabilidad del proceso de aprendizaje general. Debería utilizarse una escala de ruido que permita la disminución gradual con el tiempo. El tamaño del búfer también es fundamental, ya que afecta la eficiencia del aprendizaje y el tamaño del lote tiene un impacto en la varianza de las actualizaciones.



MA y funciones estocásticas

Estas dos funciones se han implementado en Python para el aprendizaje por refuerzo (RL), a diferencia del artículo sobre el aprendizaje supervisado, en el que lo hicimos en MQL5 y simplemente exportamos los datos de entrada de la red a Python para el entrenamiento. En nuestra implementación, utilizamos el módulo de Python MetaTrader 5 de MetaTrader para conectarnos a una instancia de terminal en ejecución y, a continuación, recuperar los datos de precios. En la documentación aquí hay guías que explican cómo hacerlo. Las funciones de nuestros indicadores que se muestran a continuación transforman los datos de precios sin procesar en datos de indicadores técnicos que sirvieron como entradas para nuestro modelo de aprendizaje supervisado tras ser convertidos y normalizados en un vector de patrones binarios. 

Los resultados del modelo de aprendizaje supervisado son lo que denominamos «estados», ya que, en esencia, predicen cambios en la evolución de los precios. Estos estados se utilizan luego como entradas para el agente de aprendizaje por refuerzo (RL) DDPG. Nuestra función MA toma como entrada un marco de datos pandas con precios del módulo MetaTrader 5 de Python. Este marco de datos debe validarse y prepararse de la siguiente manera:

p = np.asarray(p).flatten()  # Convert to 1D array if not already

if len(p) < window:

    raise ValueError("Window size cannot be larger than the number of prices.")

Lo que estamos haciendo aquí es estandarizar la matriz para garantizar un formato de entrada 1D consistente, independientemente de la forma de entrada. También contamos con un sistema de manejo de errores que evita que tamaños de ventana no válidos provoquen errores de cálculo. La integridad de los datos también garantiza un flujo de datos limpio a lo largo del proceso. El mecanismo de cálculo es el siguiente:

return np.convolve(p, np.ones(window), 'valid') / window

Esta implementación utiliza convolución para un cálculo eficiente del promedio móvil. El uso del parámetro de entrada 'valid' garantiza que solo se devuelvan ventanas completamente calculadas. La normalización también se realiza mediante el tamaño de la ventana para obtener un promedio real. Toda la operación está vectorizada para lograr un rendimiento óptimo. La importancia financiera de esto radica en que suaviza los datos de precios para ayudar a identificar tendencias, y el tamaño de la ventana utilizada (también conocido como período de promediado) determina la sensibilidad a los cambios de precios. La función de oscilador estocástico valida sus entradas de la siguiente manera:

p = np.asarray(p).flatten()

if len(p) < k_window:
    raise ValueError("Window size for %K cannot be larger than the number of prices.")

En este caso, las consideraciones de diseño se centran en un formato de entrada coherente con la función MA. Es necesario realizar una validación independiente para la ventana de cálculo de %K, generando un error como fallo precoz en caso de parámetros no válidos. El cálculo de %K es el siguiente:

for i in range(k_window - 1, len(p)):

    current_close = p[i]
    lowest_low = min(p[i - k_window + 1:i + 1])
    highest_high = max(p[i - k_window + 1:i + 1])
    K = ((current_close - lowest_low) / (highest_high - lowest_low)) * 100
    K_values.append(K)

Los componentes importantes aquí son el análisis de ventana deslizante, el contexto del mercado y la implementación general. El análisis de ventana deslizante necesita examinar el rango de precios durante un período de tiempo determinado. Esto ayuda a identificar la posición relativa del precio de cierre actual, aplicándose una escala estándar de 0 a 100. El contexto del mercado nos ayuda a evaluar las condiciones de sobrecompra/sobreventa. Los valores cercanos a 100 sugieren una posible reversión a la baja, mientras que los valores cercanos a 0 sugerirían un giro al alza. La implementación general utiliza un bucle explícito para mayor claridad, emplea una indexación de ventana adecuada para manejar casos límite y preserva el orden temporal de los resultados. El cálculo del %D es el siguiente:

D_values = MA(K_values, d_window)

Básicamente, se trata de un refinamiento de la señal en el que se utiliza una versión suavizada de la media móvil %K. La asignación típica para este período de promediado es 3, y eso es lo que estamos utilizando. Este búfer adicional proporciona confirmación de las fluctuaciones en %K y, por lo tanto, ayuda a reducir las señales falsas de un %K sin procesar.


Función de generación de patrones

Esta función se utiliza para integrar los datos de nuestros dos búferes de indicadores mencionados anteriormente en el proceso de aprendizaje. Desempeña un papel en la ingeniería de características. Esto se debe a que: ayuda a reducir la dimensionalidad, ya que transforma los precios brutos en señales más significativas; ayuda a mejorar la estacionariedad, puesto que los indicadores suelen ser más estables que los precios brutos; y, por último, permite capturar el contexto temporal, dado que los cálculos con ventanas mantienen dependencias temporales (un vector de entrada generado, por ejemplo, [1,0,0,1], puede asociarse con el momento en que se produce, al igual que cualquier valor de indicador o los precios brutos también se etiquetan con el momento en que se generan).

Sin embargo, se utiliza principalmente para la preparación del aprendizaje supervisado. Las características que genera en un vector binario de 0 y 1 entrenan al modelo para pronosticar los próximos cambios de precio. La media móvil (MA) proporciona información sobre la tendencia, mientras que la función de seguimiento de tendencias (STO) nos brinda información sobre el impulso y los cambios de tendencia. Analizamos los patrones complementarios combinados de ambos indicadores en el artículo 57. Los resultados de la previsión de cambios de precios sirven entonces como representación del estado del aprendizaje por refuerzo.

Esto implica que las predicciones de nuestro modelo de aprendizaje supervisado se convierten en entradas de estado para DDPG. Por lo tanto, los indicadores MA y STO que utilizamos terminan ayudando al agente DDPG al proporcionar contexto de mercado para ayudar a comprender un régimen de mercado determinado. Esto reduce la necesidad de utilizar precios históricos sin procesar al definir el estado.

Entre las ventajas de la implementación se incluyen la robustez, gracias a la validación de las entradas para evitar fallos silenciosos, el manejo de dimensiones para garantizar formas de matriz consistentes y los mensajes de error para una comunicación clara en caso de uso incorrecto. Asimismo, se deben tener en cuenta consideraciones que favorecen el rendimiento, como el uso de operaciones vectorizadas siempre que sea posible, la iteración explícita y la eficiencia de la memoria gracias a un diseño optimizado para el procesamiento en flujo. Sigue siendo relevante para los operadores y no se pierde entre tecnicismos. Esto se debe a que se están utilizando indicadores estándar de la industria para generar los estados. Los indicadores son complementarios, ya que combinan métricas de tendencia y de impulso, y los resultados de estado se encuentran en un rango normalizado, lo cual es importante para la coherencia.

Las posibles mejoras incluyen la optimización de los cálculos mediante la implementación vectorizada del cálculo de %K, el uso de la aceleración de Numba (importada de JIT) para acelerar los bucles en la función STO y el almacenamiento en caché de los cálculos intermedios. Se puede agregar funcionalidad extendida mediante validación adicional para valores NaN/inf. Este código que implementa el aprendizaje por refuerzo con DDPG es extenso y, si bien sería apropiado comentar sus secciones clave, simplemente adjuntaré las partes no cubiertas al final de este artículo. Entre ellas destacará esta función de obtención de patrones.



Pruebas

De los 10 patrones que probamos en el artículo sobre aprendizaje supervisado n.° 57, solo 7 lograron avanzar de forma rentable durante un año, tras haber sido entrenados con ellos el año anterior. Dado que cada patrón constituye su propia red, debemos generar redes y entornos de aprendizaje por refuerzo también para cada patrón. Seguimos una metodología similar en el artículo 57, donde entrenamos con el par EUR/USD para el año 2023 en el marco temporal diario. En este caso, estamos entrenando nuestras redes de aprendizaje por refuerzo simulando el año 2023 como un entorno de "mercado real". Como se argumentó en los dos últimos artículos, el aprendizaje por refuerzo es un sistema establecido para apoyar y proteger un modelo ya establecido y entrenado, que en nuestro caso es la red que entrenamos mediante aprendizaje supervisado en el artículo 57. 

Esto lo hace mediante la retropropagación cuando se encuentra en entornos de producción o en vivo, y no con datos históricos. Dado que no es factible retropropagar una red ONNX desde MQL5, estamos "simulando" un entorno real, que en nuestro caso sigue siendo el año 2023.

En lugar de preguntarnos, como lo hicimos en el aprendizaje supervisado, ¿qué hará el precio a continuación?, nos preguntamos, dados estos cambios de precio entrantes, ¿qué acciones debería tomar el operador? Por lo tanto, realizamos simulacros de entrenamiento como se describió anteriormente para el año 2023 y luego hacemos una proyección hacia el año 2024, donde nuestras condiciones de entrada se modifican ligeramente.

En lugar de basar nuestras posiciones largas o cortas únicamente en lo que el precio va a hacer a continuación, también consideramos qué acciones realmente debemos emprender en función de lo que el precio vaya a hacer después. También tenemos en cuenta si las recompensas serán rentables. De los 7 patrones que avanzaron en el artículo 57, solo 3 avanzan de manera significativa cuando se utiliza el aprendizaje por refuerzo. Utilizando nuestra indexación del 10 que va del 0 al 9, estos patrones son 1, 2 y 5. Sus informes se presentan a continuación:

Para el patrón 1:

r1

c1

Para el patrón 2:

r2

c2

Para el patrón 5:

r5

c5

El Asesor Experto probado, como siempre, está construido con una clase de señal personalizada cuyo código se adjunta a continuación. Realizamos cambios en el archivo de clase de señal que teníamos en el artículo 57, cambiando el nombre de la función 'IsPattern' a 'Supervise'. Además, introducimos una nueva función llamada 'Reinforce'. El código de ambos se comparte a continuación:

//+------------------------------------------------------------------+
//| Supervised Learning Model Forward Pass.                          |
//+------------------------------------------------------------------+
double CSignal_DDPG::Supervise(int Index, ENUM_POSITION_TYPE T)
{  vectorf _x = Get(Index, m_time.GetData(X()), m_close, m_ma, m_ma_lag, m_sto);
   vectorf _y(1);
   _y.Fill(0.0);
   int _i=Index;
   if(_i==8)
   {  _i -= 2;
   }
   ResetLastError();
   if(!OnnxRun(m_handles[_i], ONNX_NO_CONVERSION, _x, _y))
   {  printf(__FUNCSIG__ + " failed to get y forecast, err: %i", GetLastError());
      return(double(_y[0]));
   }
   if(T == POSITION_TYPE_BUY && _y[0] > 0.5f)
   {  _y[0] = 2.0f * (_y[0] - 0.5f);
   }
   else if(T == POSITION_TYPE_SELL && _y[0] < 0.5f)
   {  _y[0] = 2.0f * (0.5f - _y[0]);
   }
   return(double(_y[0]));
}
//+------------------------------------------------------------------+
//| Reinforcement Learning Model Forward Pass.                       |
//+------------------------------------------------------------------+
double CSignal_DDPG::Reinforce(int Index, ENUM_POSITION_TYPE T, double State)
{  vectorf _x(1);
   _x.Fill(float(State));
   vectorf _y(1);
   _y.Fill(0.0);
   vectorf _y_state(1);
   _y_state.Fill(float(State));
   vectorf _y_action(1);
   _y_action.Fill(0.0);
   vectorf _z(1);
   _z.Fill(0.0);
   int _i=Index;
   if(_i==8)
   {  _i -= 2;
   }
   ResetLastError();
   if(!OnnxRun(m_handles_a[_i], ONNX_NO_CONVERSION, _x, _y))
   {  printf(__FUNCSIG__ + " failed to get y action forecast, err: %i", GetLastError());
   }
   _y_action[0] = _y[0];
   ResetLastError();
   if(!OnnxRun(m_handles_c[_i], ONNX_NO_CONVERSION, _y_state, _y_action, _z))
   {  printf(__FUNCSIG__ + " failed to get z reward forecast, err: %i", GetLastError()); 
   }
   //normalize action output & check for state-action alignment
   if(T == POSITION_TYPE_BUY && _y[0] > 0.5f)
   {  _y[0] = 2.0f * (_y[0] - 0.5f);
   }
   else if(T == POSITION_TYPE_SELL && _y[0] < 0.5f)
   {  _y[0] = 2.0f * (0.5f - _y[0]);
   }
   else
   {  _y[0] = 0.0f;
   }
   return(double(_y[0]*_z[0]));
}

Este archivo de clase de señal personalizada está pensado para integrarse en un asesor experto mediante el asistente de MQL5; los lectores que sean nuevos en esto pueden encontrar instrucciones aquí y aquí sobre cómo hacerlo.


Conclusión

Hemos analizado la conveniencia de aplicar el aprendizaje por refuerzo cuando los modelos están en fase de implementación/producción. Nuestro aprendizaje por refuerzo utilizaba el algoritmo de gradiente de política determinista profundo, y esta implementación incluía las clases: búfer de reproducción, actor, crítico y agente, tal como se describe en este artículo y en el anterior. El aprendizaje por refuerzo en la fase de implementación/producción sirve para mantener el modelo enfocado en lo aprendido durante la fase de aprendizaje supervisado (explotación), al tiempo que busca cambios desconocidos en el entorno/condiciones del mercado que deben considerarse al tomar decisiones futuras (explotación). Para hacerlo correctamente, inherentemente tenemos que retropropagar y entrenar un modelo mientras se está utilizando. 

Sin embargo, dado que el entrenamiento de un modelo ONNX en MQL5 no es compatible, optamos por una simulación de las condiciones de negociación en tiempo real con datos históricos. Tras la simulación, probamos los modelos de aprendizaje por refuerzo entrenados en el año siguiente al año de entrenamiento y solo 3 de los 7 fueron capaces de avanzar, aunque con resultados comerciales sesgados, ya que las posiciones se mantenían principalmente en largo o en corto. Como argumentamos en el artículo 57, esto probablemente se deba a un período de prueba reducido, lo que significa que un entrenamiento y pruebas exhaustivas con más datos deberían solucionar este problema. A continuación, analizaremos la inferencia.

Tipo Descripción
Archivos *.onnx Los archivos del modelo ONNX se encuentran en la subcarpeta Python dentro de la ubicación del archivo de clase de señal personalizada.
Archivos *.mqh Archivo de clase de señal personalizada y archivo con función para procesar datos de red de entrada (57_X).
Archivos *.mq5 Asistente Asesor Experto Ensamblado cuyo encabezado muestra los archivos utilizados.

Traducción del inglés realizada por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/en/articles/17684

Archivos adjuntos |
MQL5.zip (1106.07 KB)
Experts.zip (1.67 KB)
Redes neuronales en el trading: Generalización de series temporales sin vinculación a datos (Módulos básicos del modelo) Redes neuronales en el trading: Generalización de series temporales sin vinculación a datos (Módulos básicos del modelo)
Seguimos familiarizándonos con el framework Mamba4Cast. Hoy profundizaremos en la implementación práctica de los enfoques propuestos. Mamba4Cast no ha sido diseñado para un largo periodo de calentamiento en cada nueva serie temporal, sino para un funcionamiento inmediato. Gracias al concepto de pronóstico Zero-Shot, el modelo es capaz de generar inmediatamente pronósticos de alta calidad sobre datos reales sin entrenamiento adicional ni ajuste de hiperparámetros.
Redes neuronales en el trading: Generalización de series temporales sin vinculación a datos (Mamba4Cast) Redes neuronales en el trading: Generalización de series temporales sin vinculación a datos (Mamba4Cast)
En este artículo, presentaremos el framework Mamba4Cast y analizaremos más de cerca uno de sus componentes clave: la codificación posicional basada en marcas temporales. Asimismo, mostraremos cómo se forma la incorporación temporal considerando la estructura de calendario de los datos.
Particularidades del trabajo con números del tipo double en MQL4 Particularidades del trabajo con números del tipo double en MQL4
En estos apuntes hemos reunido consejos para resolver los errores más frecuentes al trabajar con números del tipo double en los programas en MQL4.
Movimiento de precios: Modelos matemáticos y análisis técnico Movimiento de precios: Modelos matemáticos y análisis técnico
Pronosticar los movimientos de los pares de divisas es un factor importante para el éxito en el trading. Este artículo explora varios modelos de movimiento de precios, analiza sus ventajas y desventajas y además explora su aplicación práctica en estrategias comerciales. Asimismo, consideraremos enfoques que nos permitirán identificar patrones ocultos y mejorar la precisión de los pronósticos.