English Русский Deutsch 日本語 Português
preview
Previsión y apertura de órdenes basadas en aprendizaje profundo (Deep Learning) con el paquete Python MetaTrader 5 y el archivo modelo ONNX

Previsión y apertura de órdenes basadas en aprendizaje profundo (Deep Learning) con el paquete Python MetaTrader 5 y el archivo modelo ONNX

MetaTrader 5Sistemas comerciales | 25 julio 2024, 10:16
64 0
Javier Santiago Gaston De Iriarte Cabrera
Javier Santiago Gaston De Iriarte Cabrera

Introducción

El aprendizaje profundo (Deep learning), es un subcampo del aprendizaje automático que se centra en las redes neuronales artificiales, inspiradas en la estructura y el funcionamiento del cerebro humano. Consiste en entrenar modelos para que realicen tareas sin programación explícita, sino aprendiendo patrones y representaciones a partir de los datos. El aprendizaje profundo ha ganado una atención significativa debido a su capacidad para aprender automáticamente características y representaciones jerárquicas, lo que lo hace eficaz en diversos dominios como el reconocimiento de imágenes y del habla, el procesamiento del lenguaje natural, etc.

Conceptos clave del aprendizaje profundo:

  • Redes neuronales: Unidades básicas del aprendizaje profundo, formadas por nodos o neuronas interconectadas y organizadas en capas.
  • Redes neuronales profundas (DNN, Deep Neural Networks): Redes neuronales con múltiples capas, lo que les permite aprender patrones complejos.
  • Entrenamiento: Proceso de ajuste de los parámetros del modelo utilizando datos etiquetados para minimizar la diferencia entre los resultados previstos y los reales.
  • Funciones de activación: Funciones aplicadas a la salida de las neuronas para introducir no linealidad, lo que permite al modelo aprender relaciones más complejas.
  • Retropropagación: Algoritmo de optimización utilizado para actualizar los pesos del modelo en función del error en sus predicciones.

Python: Python es un lenguaje de programación versátil y de alto nivel conocido por su legibilidad y facilidad de uso. Cuenta con un vasto ecosistema de bibliotecas y frameworks que lo hacen adecuado para diversas aplicaciones, como el desarrollo web, la ciencia de datos, la inteligencia artificial, etc.

Características principales de Python:

  • Lecturabilidad: La sintaxis de Python está diseñada para ser legible y limpia, lo que facilita a los desarrolladores expresar conceptos en menos líneas de código.
  • Bibliotecas extensas: Python cuenta con un rico conjunto de bibliotecas y frameworks para diversas aplicaciones, como NumPy y pandas para la manipulación de datos, TensorFlow y PyTorch para el aprendizaje profundo, Django y Flask para el desarrollo web, y mucho más.
  • Soporte de la comunidad: Python cuenta con una amplia y activa comunidad de desarrolladores, que contribuyen a su mejora continua y a la disponibilidad de numerosos recursos para el aprendizaje.

Uso de Python para el aprendizaje profundo: Python es un lenguaje popular para el aprendizaje profundo debido a sus amplias bibliotecas y frameworks. Dos de las principales bibliotecas de aprendizaje profundo en Python son TensorFlow y PyTorch. Estas bibliotecas proporcionan abstracciones de alto nivel para construir y entrenar redes neuronales, lo que las hace accesibles tanto para principiantes como para profesionales experimentados.

En resumen, el aprendizaje profundo es un potente enfoque dentro del campo más amplio del aprendizaje automático, y Python sirve como un excelente lenguaje de programación para implementar modelos y soluciones de aprendizaje profundo. La combinación de Python y el aprendizaje profundo ha propiciado avances en diversos campos, haciendo que tareas complejas sean más accesibles y automatizables.


Ordenes con Python y el paquete MQL5: Parece que estás interesado en combinar Python con el paquete MQL5 para gestionar órdenes de trading. MQL5 es un lenguaje especializado diseñado para la negociación algorítmica en la plataforma MetaTrader 5 (MT5). He aquí un esquema general de cómo se podría abordar la integración de Python con MQL5 para el comercio:

  • Script Python para aprendizaje profundo: Desarrolle un script Python utilizando una biblioteca de aprendizaje profundo (por ejemplo, TensorFlow, PyTorch) para crear y entrenar un modelo para su estrategia de trading específica. Este script se encargará del análisis y la toma de decisiones basándose en su modelo de aprendizaje profundo.

  • Comunicación entre Python y MQL5: Establezca un puente de comunicación entre su script Python y la plataforma MetaTrader 5. Esto puede hacerse utilizando varios métodos, como sockets, API REST u otros protocolos de comunicación. El objetivo es habilitar su script Python para enviar señales de trading u órdenes al terminal MetaTrader.

  • Ejecución de órdenes en MQL5: En su script MQL5 o asesor experto, implemente la lógica para recibir señales del script Python y ejecutar las órdenes de compra/venta correspondientes en la plataforma MetaTrader 5. Se trata de utilizar las funciones de negociación que ofrece el lenguaje MQL5.


ONNX

(Open Neural Network Exchange), es un formato de código abierto diseñado para facilitar la interoperabilidad de los modelos de inteligencia artificial (IA) en diversos marcos. Desarrollado y respaldado por Microsoft y Facebook, ONNX permite a los usuarios entrenar modelos con un framework y desplegarlos con otro.

La ventaja clave de ONNX es su capacidad para servir como formato intermediario entre diferentes frameworks de aprendizaje profundo como TensorFlow, PyTorch y otros. Esta intercambiabilidad simplifica el proceso de integración de modelos de aprendizaje automático en diferentes aplicaciones, entornos y plataformas.

En el contexto de MQL5 (MetaQuotes Language 5), la integración de modelos ONNX implica convertir un modelo de aprendizaje automático entrenado al formato ONNX. Una vez en el formato ONNX, el modelo se puede cargar en scripts MQL5 o Asesores Expertos, lo que permite la utilización de capacidades avanzadas de aprendizaje automático para estrategias de negociación algorítmica dentro de la plataforma MetaTrader 5.


Breve introducción a lo que se mostrará.

En el próximo artículo, nos adentraremos en el fascinante mundo del aprendizaje profundo aplicado al trading automatizado. El enfoque estará en un programa diseñado para operaciones automáticas, utilizando técnicas avanzadas de aprendizaje profundo. Exploraremos los entresijos de la comprobación del rendimiento del modelo utilizando métricas clave como el error medio absoluto (MAE), el error medio cuadrático (MSE) y R-cuadrado (R2). Esta exploración tiene como objetivo proporcionar información sobre la eficacia del modelo de aprendizaje profundo en el contexto de la negociación algorítmica, arrojando luz sobre su precisión predictiva y robustez general. Acompáñanos en este viaje mientras desentrañamos la intersección entre el aprendizaje profundo, la negociación automatizada y las pruebas de rendimiento exhaustivas.


Además, exploraremos el proceso de convertir el script Python (.py) en un ejecutable, asegurando un paquete completo y fácil de usar. Esta guía paso a paso proporciona información detallada, sin dejar piedra sin remover, para garantizar una comprensión completa de todo el proceso. Al final del artículo, no sólo tendrá una comprensión profunda de la aplicación del aprendizaje profundo en el trading automatizado, sino también el conocimiento práctico de envolver su solución en un formato ejecutable conveniente. Esté atento a un recorrido en profundidad para pasar sin problemas de la codificación a un programa totalmente funcional y ejecutable, haciendo que su experiencia sea tanto educativa como práctica.


Como paso final del artículo, crearé un script para generar la salida en formato ONNX. Este script será fundamental para incorporar el modelo ONNX en MetaTrader 5 (MT5) utilizando un Asesor Experto (EA). Este proceso mejora la adaptabilidad y la integración de las capacidades de aprendizaje automático en la plataforma MT5, facilitando el desarrollo de estrategias de negociación algorítmica más sofisticadas y eficientes.


Antes de empezar a codificar

Lo que pretendemos conseguir es el desarrollo de un bot Python que se someta a un proceso de dos pasos: en primer lugar, realiza un análisis de aprendizaje profundo de los datos disponibles y, posteriormente, ejecuta órdenes de negociación. Dado que MT5 facilita la descarga de una gran cantidad de datos de tick, nuestra estrategia consiste en adquirir estos datos y convertirlos en información sobre precios. La metodología de conversión consistirá en tomar la media entre valores de tick, lo que nos permitirá crear una representación más manejable de los precios de mercado para su posterior análisis y toma de decisiones dentro de nuestro bot.


Pero antes de continuar, necesitamos utilizar Python, y para una configuración conveniente de Python, lo recomendado es descargar e instalar Anaconda. Además, la instalación de Visual Studio Code proporcionará un entorno fácil de usar para la creación de scripts.


Anaconda

VSC

Una vez que tengas Anaconda y Visual Studio Code instalados, el siguiente paso es instalar algunos paquetes usando pip dentro de Visual Studio Code.

Puedes hacer esto abriendo la terminal integrada en Visual Studio Code y usando los siguientes comandos (si estás utilizando Conda/Anaconda, ejecuta estos comandos en el Anaconda Prompt):

pip install [paquete1] [paquete2] ...

Sustituya [paquete1] , [paquete2] , etc., por los nombres de los paquetes específicos de Python que necesite para su proyecto. Esto asegurará que tu entorno está equipado con las herramientas y librerías necesarias para proceder con el desarrollo de tu bot Python.


Paquetes

Necesitas instalar paquetes específicos para un entorno Python, incluyendo MetaTrader 5, TensorFlow, y otras librerías que vienen con Anaconda. He aquí una guía general sobre cómo instalar estas bibliotecas:

  1. MetaTrader 5: MetaTrader 5 (MT5) es una plataforma de trading. Desafortunadamente, a partir de mi última actualización de conocimientos en enero de 2022, MetaTrader 5 no tiene una API Python directa disponible en la distribución oficial. Sin embargo, pueden existir algunas bibliotecas o envoltorios de terceros. Por favor, consulte la documentación oficial de MetaTrader 5 o los foros de la comunidad correspondiente para obtener la información más reciente.   

    pip install MetaTrader5
  2. TensorFlow: TensorFlow es una popular librería de aprendizaje automático. Puede instalarlo utilizando el siguiente comando pip en su terminal o símbolo del sistema:

    pip install tensorflow


Empecemos a codificar

Una vez que hayas instalado correctamente las librerías necesarias, el siguiente paso es empezar a escribir tu código Python. Para ello, debe importar las bibliotecas que ha instalado. En Python, se utiliza la sentencia import para introducir la funcionalidad de una biblioteca en el código.
import MetaTrader5 as mt5
from MetaTrader5 import *
import numpy as np
from sklearn.model_selection import train_test_split, cross_val_score
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
from tensorflow.keras.regularizers import l2
from sklearn.model_selection import KFold


from MetaTrader5 import *

Esta línea importa todas las funciones y clases de la biblioteca MetaTrader 5. El uso de * (comodín) significa que está importando todo, aunque esta práctica generalmente se desaconseja debido a posibles conflictos de espacio de nombres.

import numpy as np

Esta línea importa la biblioteca NumPy y le da el alias np. NumPy es ampliamente utilizado para operaciones numéricas en Python.

from sklearn.model_selection import train_test_split, cross_val_score
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score

Estas líneas importan funciones/clases específicas de la biblioteca Scikit-learn. Incluye utilidades para el preprocesamiento de datos, la evaluación de modelos y la selección de modelos.

from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
from tensorflow.keras.regularizers import l2

Estas líneas importan componentes de la biblioteca TensorFlow, que se utiliza habitualmente para el aprendizaje profundo. Incorpora el modelo secuencial, capas densas y regularización L2.

from sklearn.model_selection import KFold

Esta línea importa la clase KFold de Scikit-learn, que se utiliza a menudo para la validación cruzada en el aprendizaje automático.

En resumen, tu script se está preparando para usar la biblioteca MetaTrader 5 para datos financieros, NumPy para operaciones numéricas, Scikit-learn para utilidades de aprendizaje automático y TensorFlow para aprendizaje profundo. Parece que estás creando un entorno para el análisis de datos financieros y posiblemente construyendo un modelo de aprendizaje automático para predicciones financieras. Asegúrese de tener instaladas estas librerías en su entorno Python utilizando el gestor de paquetes adecuado (por ejemplo, pip o conda)


Descarga de datos

Para descargar ticks, primero, necesitamos conectarnos al proveedor de datos (MT5), y desde ahí, podemos descargar lo que necesitemos. Para ello, utilizaremos lo siguiente:
# You will need to update the values for path, login, pass, and server according to your specific case.
creds = {
    "path": "C:/Program Files/XXX MT5/terminal64.exe",
    "login": account,
    "pass": clave_secreta,
    "server": server_account,
    "timeout": 60000,
    "portable": False
}
# We launch the MT5 platform and connect to the server with our username and password.
if mt5.initialize(path=creds['path'],
                  login=creds['login'],
                  password=creds['pass'],
                  server=creds['server'],
                  timeout=creds['timeout'],
                  portable=creds['portable']):
    
    print("Plataform MT5 launched correctly")
else:
    print(f"There has been a problem with initialization: {mt5.last_error()}")

Una vez hecho esto, procedemos a descargar los datos de interés para el símbolo que nos interesa, en forma de ticks.

rates = rates.drop(index=rates.index)
rates = mt5.copy_ticks_from(symbol, utc_from, 1000000000, mt5.COPY_TICKS_ALL)

Este código primero borra cualquier dato existente en el DataFrame 'rates' y luego obtiene los datos de ticks para un símbolo en particular y un rango de tiempo usando la función copy_ticks_from de la librería de MetaTrader 5.

Como nuestro objetivo es tener los datos en un DataFrame de Pandas (que se usa comúnmente junto con NumPy) para una mejor manipulación en Python, transferiremos los datos a un DataFrame de Pandas.
rates_frame=pd.DataFrame()
# Empty DataFrame
rates_frame = rates_frame.drop(index=rates_frame.index)
rates_frame = pd.DataFrame(rates)

Este código inicializa un DataFrame de Pandas vacío llamado 'rates_frame', elimina cualquier dato existente en él y luego lo llena con los datos de la variable 'rates'.

Para simplificar las cosas, sumemos y dividamos por dos los valores de compra y venta de los datos. De esta forma, obtenemos el valor medio, que será nuestra entrada para el aprendizaje profundo.
rates_frame['time']=pd.to_datetime(rates_frame['time'], unit='s')
rates_frame['close']=(rates_frame['ask']+rates_frame['bid'])/2

Este código convierte la columna 'time' al formato datetime utilizando segundos como unidad y calcula el promedio de los valores 'ask' y 'bid', asignando el resultado a una nueva columna llamada 'close' en el DataFrame `rates_frame`.

La elección de los datos de entrada para el aprendizaje profundo en aplicaciones financieras, como la predicción de los movimientos de precios, depende de varios factores, y no hay una solución única para todos. Sin embargo, hay que tener en cuenta algunas consideraciones y directrices generales:


Datos brutos frente a características derivadas (osciladores e indicadores):

1. Datos en bruto:

  • Ventajas:
    • Retiene toda la información disponible sin suposiciones adicionales.
    • Permite a la red neuronal aprender patrones directamente a partir de la entrada bruta.
  • Consideraciones:
    • Puede contener ruido o información irrelevante.
    • Podría ser necesario un mayor preprocesamiento de los datos.

2. Características derivadas (osciladores e indicadores):

  • Ventajas:
    • La ingeniería de características puede captar dinámicas de mercado específicas.
    • Puede proporcionar una representación más estructurada de los datos.
  • Consideraciones:
    • Introduce suposiciones sobre qué características son relevantes.
    • La eficacia depende de los indicadores elegidos y de sus parámetros.


Buenas prácticas y consideraciones:

1. Normalización de datos:

  • Escala los datos a un rango consistente (por ejemplo, entre 0 y 1) para mejorar la convergencia durante el entrenamiento.

2. Longitud de la secuencia:

  • Para los datos de series temporales, la longitud de la secuencia es importante. Experimente con diferentes longitudes para encontrar el equilibrio óptimo entre la captura de patrones relevantes y la eficiencia computacional.

3. Aspectos temporales:

  • Considere la posibilidad de incorporar aspectos temporales, como valores retardados o ventanas deslizantes, para captar las dependencias temporales.

4. Selección de características:

  • Experimente con diferentes subconjuntos de características para identificar cuáles son las más informativas para su tarea específica.

5. Arquitectura del modelo:

  • Ajuste la arquitectura de la red neuronal en función de la naturaleza de los datos de entrada. Las redes neuronales recurrentes (RNN) y las redes de memoria a largo plazo (LSTM) son eficaces para los datos secuenciales.

6. Regularización:

  • Utilizar técnicas de regularización (por ejemplo, DropOut) para evitar el sobreajuste, especialmente cuando se trata de datos de alta dimensión.

7. Ajuste de hiperparámetros:

  • Experimente con diferentes ajustes de hiperparámetros para encontrar la configuración óptima para su modelo.

En la práctica, suele ser beneficioso comparar empíricamente distintos enfoques. Algunas tareas pueden beneficiarse de la simplicidad de los datos brutos, mientras que otras pueden ganar rendimiento con características derivadas bien elaboradas. Es crucial encontrar un equilibrio entre proporcionar suficiente información para que el modelo aprenda y evitar el ruido o los detalles irrelevantes. Además, reevalúe periódicamente el enfoque elegido, ya que la dinámica del mercado puede cambiar con el tiempo.


Desplazamiento de datos

Ahora tenemos los datos en un DataFrame de Pandas, y podemos enviarlos para que el aprendizaje profundo los procese como entrada. Ya hay muchos artículos interesantes sobre aprendizaje profundo en MQL5, así que no profundizaré mucho en esto. Iré directamente al aspecto práctico en Python. Pero antes de enviar los datos para que TensorFlow haga su magia, necesitamos tener una entrada para el desplazamiento temporal que aplicaremos a los datos para la predicción (el tiempo desplazado será el tiempo que pretendemos predecir). Por eso tenemos el siguiente código.


Desplazar un DataFrame en el contexto del aprendizaje profundo, en particular en la previsión de series temporales, se hace comúnmente para crear secuencias de variables de entrada y de destino. Estas son las razones por las que se utiliza el desplazamiento en el contexto del aprendizaje profundo para la predicción de series temporales:

  1. Dependencias temporales: Los modelos de aprendizaje profundo, como las redes neuronales recurrentes (RNN) o las redes de memoria a corto plazo (LSTM), pueden capturar dependencias temporales en datos secuenciales. El desplazamiento del DataFrame permite crear secuencias en las que cada secuencia de entrada corresponde a un segmento de datos pasados, y la secuencia de destino correspondiente representa los datos futuros.

  2. Aprendizaje secuencial: Los modelos de aprendizaje profundo son eficaces en el aprendizaje de patrones y dependencias en datos secuenciales. Al desplazar el DataFrame, se asegura de que las secuencias de entrada y de destino se alinean temporalmente, lo que permite al modelo aprender del contexto histórico y hacer predicciones basadas en ese contexto.

  3. Entrenamiento de pares de entrada-salida: El desplazamiento ayuda a crear ejemplos de entrenamiento para el modelo de aprendizaje profundo. Cada fila del DataFrame desplazado puede considerarse un par de entrada-salida, donde la entrada es una secuencia de observaciones pasadas y la salida es la variable objetivo que debe predecirse en el futuro.


number_of_rows= seconds
empty_rows = pd.DataFrame(np.nan, index=range(number_of_rows), columns=df.columns)
df = df._append(empty_rows, ignore_index=True)
df['target'] = df['close'].shift(-seconds)
print("df modified",df)
  • number_of_rows es una variable que representa el número de segundos.
  • empty_rows crea un nuevo DataFrame con valores NaN, teniendo las mismas columnas que el DataFrame original (df).
  • df.append(empty_rows, ignore_index=True) añade las filas vacías al DataFrame original (df) ignorando el índice para asegurar un índice continuo.
  • df['target'] = df['close'].shift(-seconds) crea una nueva columna 'target' que contiene los valores 'close' desplazados por un valor negativo del número de segundos especificado. Esto suele hacerse cuando se preparan datos de series temporales para modelos predictivos.

Ahora, todo lo que queda es limpiar los datos para que podamos utilizarlos como entrada con TensorFlow.

# Drop NaN values
df=df.dropna()

El resultado es un DataFrame (df) modificado con filas adicionales rellenas con valores NaN y una nueva columna 'target' para valores 'close' desplazados en el tiempo.


Aprendizaje profundo (Deep learning)

Uso de TensorFlow y Keras para construir y entrenar una red neuronal para la predicción de series temporales.

# Split the data into features (X) and target variable (y)
X=[]
y=[]
X = df2[['close']]
y = df2['target']

# Split the data into training and testing sets
X_train=[]
X_test=[]
y_train=[]
y_test=[]
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, shuffle=False)

# Standardize the features
X_train_scaled=[]
X_test_scaled=[]
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)

# Build a neural network model
model=None
model = Sequential()
model.add(Dense(128, activation='relu', input_shape=(X_train.shape[1],), kernel_regularizer=l2(k_reg)))
model.add(Dense(256, activation='relu', kernel_regularizer=l2(k_reg)))
model.add(Dense(128, activation='relu', kernel_regularizer=l2(k_reg)))
model.add(Dense(64, activation='relu', kernel_regularizer=l2(k_reg)))
model.add(Dense(1, activation='linear'))

# Compile the model[]
model.compile(optimizer='adam', loss='mean_squared_error')

# Train the model
model.fit(X_train_scaled, y_train, epochs=int(epoch), batch_size=256, validation_split=0.2, verbose=1)

# Use the model to predict the next 4 instances
X_predict=[]
X_predict_scaled=[]

predictions = pd.DataFrame()
predictions=[]
# Empty DataFrame
#predictions = predictions.drop(index=predictions.index)
X_predict = df2.tail(segundos)[['close']]
X_predict_scaled = scaler.transform(X_predict)
predictions = model.predict(X_predict_scaled)

# Print actual and predicted values for the next 
    n  instances
print("Actual Value for the Last Instances:")
print(df.tail(1)['close'].values)

print("\nPredicted Value for the Next Instances:")
print(predictions[:, 0])
predictions=pd.DataFrame(predictions)

Preparación y entrenamiento de una red neuronal a partir de datos financieros históricos para predecir valores futuros. Utiliza las bibliotecas TensorFlow y Keras para construir y entrenar el modelo. A continuación, se imprimen las predicciones para las siguientes instancias basándose en el modelo entrenado.

Explicación:

  • El modelo se inicializa como un modelo secuencial, lo que significa que es una pila lineal de capas.

  • Las capas densas representan capas totalmente conectadas en la red neuronal. Los parámetros incluyen el número de neuronas (unidades), la función de activación, la forma de entrada (aplicable sólo para la primera capa) y la regularización del núcleo (en este caso, regularización L2 con una fuerza especificada por k_reg ).

  • activation='relu' implica la función de activación Rectified Linear Unit (ReLU), utilizada habitualmente en las capas ocultas.

  • La última capa tiene una neurona con una función de activación lineal, que indica una salida de regresión. Si se tratara de una tarea de clasificación, se utilizaría una función de activación diferente, como "sigmoid" o "softmax".

Esta arquitectura es una red neuronal con múltiples capas ocultas con fines de regresión. Ajuste los parámetros y las capas en función de su tarea específica y de las características del conjunto de datos.


Predicción

¿Es buena la aproximación de este modelo?

# Calculate and print mean squared error
mse = mean_squared_error(y_test, model.predict(X_test_scaled))
print(f"\nMean Squared Error: {mse}")

# Calculate and print mean absolute error
mae = mean_absolute_error(y_test, model.predict(X_test_scaled))
print(f"\nMean Absolute Error: {mae}")

# Calculate and print R2 Score
r2 = r2_score(y_test, model.predict(X_test_scaled))
print(f"\nR2 Score: {r2}")

El código proporcionado calcula e imprime tres métricas de evaluación para un modelo de regresión entrenado.

Explicación:

  • Mean Squared Error (MSE): Mide la diferencia cuadrática media entre los valores previstos y los reales. Cuanto menor sea el MSE, mejor será el modelo.

  • Mean Absolute Error (MAE): Mide la diferencia absoluta media entre los valores previstos y los reales. Al igual que el MSE, los valores más bajos indican un mejor rendimiento del modelo.

  • Puntuación R2: También conocido como coeficiente de determinación, mide la proporción de la varianza en la variable dependiente que es predecible a partir de la(s) variable(s) independiente(s). Una puntuación R2 de 1 indica un ajuste perfecto, mientras que una puntuación de 0 sugiere que el modelo no es mejor que predecir la media de la variable objetivo. Los valores negativos indican un mal rendimiento del modelo.

Estas métricas proporcionan información sobre el rendimiento del modelo entrenado en el conjunto de pruebas.

En este contexto, hay que experimentar con la cantidad de datos (retardo de entrada) y el número de épocas. Por ejemplo, utilizo 900 días de datos y 1 época para EURUSD para un periodo de tiempo de 2 horas (lo explicaré mejor después). Sin embargo, también obtengo buenos resultados con muchos menos datos y más épocas.


Pedidos

Ahora que tenemos esto, sólo tenemos que medir el tiempo que tarda el script en devolver los datos. Esto nos permite marcar en el gráfico el punto de inicio de la predicción para nosotros (ya que la predicción comienza un tiempo antes, por ejemplo, en mi caso, tarda unos 15-20 minutos). El punto de partida para que abramos órdenes será cuando haya transcurrido ese tiempo. Además, después de usar ampliamente este bot, he notado que las predicciones más precisas se encuentran en el primer cuarto de todo el turno. Para mejorar la precisión, limitaré y marcaré en el gráfico y ejecutaré órdenes durante ese periodo específico. Esto se implementa fácilmente utilizando `time.now()`. Podemos capturar el tiempo en ese momento y convertirlo a segundos, ya que tanto nuestra predicción como la escala del eje X están en segundos. Teniendo en cuenta todo esto, marcaremos dónde empieza nuestra predicción, y las órdenes se lanzarán en función de ese punto inicial.

Esta es una orden Python típica utilizando MetaTrader 5 (MT5). La función `open_trade_sell2` representa una estructura común para colocar una orden de venta en la plataforma MT5. Aprovecha el método `mt5.order_send` para enviar una solicitud de negociación para ejecutar la orden. Los parámetros incluyen la acción de negociación ("comprar" o "vender"), el símbolo, el tamaño del lote, un número entero aleatorio (posiblemente para la identificación del número mágico), el Take Profit (TP), el Stop Loss (SL), y la desviación.

def open_trade_sell2(action, symbol, lot,random_integer, tp, sl, deviation):
        '''https://www.mql5.com/es/docs/integration/python_metatrader5/mt5ordersend_py
        '''
        # prepare the buy request structure
        symbol_info = get_info(symbol)
        
        if action == 'buy':
            trade_type = mt5.ORDER_TYPE_BUY
            price = mt5.symbol_info_tick(symbol).ask
        elif action =='sell':
            trade_type = mt5.ORDER_TYPE_SELL
            price = mt5.symbol_info_tick(symbol).bid
        point = mt5.symbol_info(symbol).point
        print("el precio mt5 es:", price)

        buy_request = {
            "action": mt5.TRADE_ACTION_DEAL,
            "symbol": symbol,
            "volume": lot,
            "type": trade_type,
            "price": price,
            "sl":sl,
            "tp":tp,
            "deviation": deviation,
            "magic": random_integer,
            "comment": "python open",
            "type_time": mt5.ORDER_TIME_GTC, # good till cancelled
            "type_filling": mt5.ORDER_FILLING_IOC,
        }
        # send a trading request
        result = mt5.order_send(buy_request)        
        return result, buy_request

Esta función forma parte de un script que interactúa con la plataforma MT5 para automatizar estrategias de trading. Los pasos clave incluyen determinar el tipo de operación, recuperar el precio actual de compra o venta, preparar una estructura de solicitud de operación y, por último, enviar la solicitud de operación.


Órdenes de cierre

def close_position(position,symbol):
    """This function closes the position it receives as an argument."""
   
    request = {
        'action': mt5.TRADE_ACTION_DEAL,
        'position': position.ticket,
        'magic': position.magic,
        'symbol': symbol,
        'volume': position.volume,
        'deviation': 50,
        'type': mt5.ORDER_TYPE_BUY if position.type == 1 else mt5.ORDER_TYPE_SELL,
        'type_filling': mt5.ORDER_FILLING_FOK,
        'type_time': mt5.ORDER_TIME_GTC,
        'comment': "mi primera orden desde Python"
    }
    return mt5.order_send(request)

# Now, we define a new function that serves to close ALL open positions.
def close_all_positions(symbol):
    """This function closes ALL open positions and handles potential errors."""
   
    positions = mt5.positions_get()
    for position in positions:
        if close_position(position,symbol).retcode == mt5.TRADE_RETCODE_DONE:
            print(f"Position {position.ticket} closed correctly.")
        else:
            print(f"An error occurred while closing the position.{position.ticket}: {mt5.last_error()}")

También podemos cerrar las órdenes utilizando el EA que he modificado para esta ocasión. En este caso, el archivo .py crea un documento y escribe el tiempo en minutos para cerrar órdenes (si estás utilizando esto, recuerda dejar el archivo en la carpeta 'File' de tu MT5).

#Specify the path for the file and open it in write mode
file_path = "C:/XXX/MetaQuotes/Terminal/XXX/MQL5/Files/python_"+symbol+"_file.txt"
try:
    with open(file_path, "w") as file:
        # Write file parameters
        file.write(str(the_value))
    print(f"File '{file_path}' created.")
except Exception as e:
    print(f"Error creating file: {e}")

Y este es el EA modificado que obtuve de este chico (tendréis que añadir las rutas correctas a la carpeta 'File'):

//+------------------------------------------------------------------+
//|                                               Timer_modified.mq5 |
//|                                                                  |
//|                                                                  |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2021, Vladimir Karputov"
#property link      "https://www.mql5.com/ru/market/product/43516"
#property version   "1.000"

//--- display the window of input parameters when launching the script
#property script_show_inputs

//--- parameters for data reading
input string InpFileName="python_file.txt"; // file name
input string InpDirectoryName="Files"; // directory name
//---
#include <Trade\PositionInfo.mqh>
#include <Trade\Trade.mqh>
//#include <File.mqh>
//---
CPositionInfo  m_position;                   // object of CPositionInfo class
CTrade         m_trade;                      // object of CTrade class
//--- input parameters
input uchar    InpAfterHour   = 0; // After: Hour ... (max 255)
input uchar    InpAfterMinutes= 42; // After: Minutes ... (max 255)
input uchar    InpAfterSeconds= 59; // After: Seconds ... (max 255)
//---
int file_handles;
uchar value_uchar;
long     m_after  = 0;
bool         started=false;     // flag of counter relevance
string str1,str2,str3,str4;

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+

int OnInit()
  {
  str1="C:/XXX/MetaQuotes/Terminal/XXXX/MQL5/Files/python_";
  str3="_file.txt";
  str2=Symbol();
  str4=str1+str2+str3;

   // Open file to read
   string file_path = str4;
   file_handles = FileOpen(file_path, FILE_READ|FILE_TXT);
   
   if(file_handles != INVALID_HANDLE)
     {
      PrintFormat("File %s opened correctly", file_path);
      
      // Read uchar value of the file
      if (FileReadInteger(file_handles, INT_VALUE))
        {
         PrintFormat("Uchar value read from file: %u", value_uchar);
         m_after  = 0;
         m_after=value_uchar;
        }
      else
        {
         Print("Error when reading the uchar value from file");
        }

      // Close file after read
      FileClose(file_handles);
     }
   else
     {
      m_after  = 0;
      m_after=InpAfterHour*60*60+InpAfterMinutes*60+InpAfterSeconds;
      PrintFormat("Error when opening file %s, error code = %d", file_path, GetLastError());
     }
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   for(int i=PositionsTotal()-1; i>=0; i--) // returns the number of current positions
      if(m_position.SelectByIndex(i)) // selects the position by index for further access to its properties
        {
         if(TimeCurrent()-m_position.Time()>=m_after)
            m_trade.PositionClose(m_position.Ticket()); // close a position
        }
  }
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| called when a Trade event arrives                                |
//+------------------------------------------------------------------+
void OnTrade()
  {
   if(started) SimpleTradeProcessor();   
  }  
 void SimpleTradeProcessor()
  {
  str1="C:/Users/XXX/MetaQuotes/Terminal/XXX/MQL5/Files/python_";
  str3="_file.txt";
  str2=Symbol();
  str4=str1+str2+str3;
     // Open file to read it
   string file_path = str4;
   file_handles = FileOpen(file_path, FILE_READ|FILE_TXT);
   
   if(file_handles != INVALID_HANDLE)
     {
      PrintFormat("File %s is opened correctly", file_path);
      
      // Reads the uchar value from the file
      if (FileReadInteger(file_handles, INT_VALUE))
        {
         PrintFormat("value_uchar read form file: %u", value_uchar);
         m_after  = 0;
         m_after=value_uchar;
        }
      else
        {
         Print("Error while reading the value uchar from file");
        }

      // Closes the file after reading
      FileClose(file_handles);
     }
   else
     {
      m_after  = 0;
      m_after=InpAfterHour*60*60+InpAfterMinutes*60+InpAfterSeconds;
      PrintFormat("Error when opening the fileo %s, Code error = %d", file_path, GetLastError());
     }    
  }

He presentado dos formas diferentes de cerrar las órdenes. En Python lo único que hago es utilizar `time.sleep(t)`, donde `t` es el número de segundos entre el momento en que se realizó la orden y el momento en que quiero cerrarla. Sin embargo, este enfoque no es muy práctico, ya que implica esperas que consumen tiempo que podría emplearse en otras operaciones de script. Dejo en sus manos la decisión de qué método utilizar para cerrar las órdenes.

Podemos generar más órdenes reduciendo el uso de 'time.sleep()', por ejemplo, entre la colocación de una orden de compra o venta y su cierre. ¿Cómo? Podemos utilizar el Asesor Experto (EA) modificado incorporando el valor del número mágico, permitiéndole cerrar sólo la orden con el número mágico y el símbolo especificados. De esta manera, en lugar de que el script se pause con sleep, puede permanecer activo y seguir funcionando.


Visualización

Para visualizarlo eficazmente trazaremos un gráfico para observar las tendencias. Marcaremos los rangos de las predicciones más fiables e indicaremos los valores máximos y mínimos dentro de esos rangos y, al final, se guardará el gráfico.

plt.axvline(x=pt_division2, color='gray', linestyle='--', label='75 %')
plt.axvline(x=center, color='grey', linestyle='--', label='50 %')
plt.axvline(x=pt_division3, color='blue', linestyle='--', label='33 %')
plt.axvline(x=pt_division1, color='gray', linestyle='--', label='25 %')
plt.axvline(x=pt_division6, color='blue', linestyle='--', label='16 %')
plt.axvline(x=pt_division10, color='yellow', linestyle='--', label='10 %')
plt.axvline(x=pt_division14, color='blue', linestyle='--', label='7 %')
plt.axvline(x=pt_division20, color='yellow', linestyle='--', label='5 %')
plt.axvline(x=entry_point, color='orange', linestyle='--', label='entrada')
plt.axvline(x=value_25, color='orange', linestyle='--', label='salida 20%')
plt.axvline(x=maximal_index, color='red', linestyle='--', label='maximal') ##### ni idea de porqué no pinta correctamente la linea
plt.axvline(x=manimal_index, color='red', linestyle='--', label='minimal')# lo mismo aquí

plt.plot(dff5.iloc[:, 0], linestyle='-', label='Predicted')

plt.xlabel('Instances')
plt.ylabel('Prediction Price')
plt.legend()
plt.title(f'Predicted {symbol} y quedan en minutos: ' + str(MyParameter))
plt.savefig('Predicted_for_'+str(symbol)+'_quedan_'+str(MyParameter)+'_minutos_desde_'+str(formatted_now2)+'_.png')


¿Cómo funciona el script?

Ahora bien, ¿cómo funciona este script? En primer lugar, carga las bibliotecas y, a continuación, anota el momento exacto para seguir la fase actual de la predicción. Después de eso, inicializa MT5, descarga los datos, los procesa y proporciona los resultados. Utilizamos estos resultados para generar un gráfico y ejecutar órdenes en momentos precisos, incluido el momento concreto de cierre de las órdenes. Además, tiene flexibilidad para elegir el método de cierre de las órdenes.

Si desea repetir este proceso para el mismo par de divisas, bastará con un simple bucle, lo que facilitará la ejecución continua del programa. Sólo hay una pega: ¿cómo se determinan las entradas óptimas? Bueno, es sencillo. Un modelo con un R2 cercano a uno, y MSE y MAE cercanos a cero, indica buenas aproximaciones. Sin embargo, hay que tener cuidado con el sobreajuste. Una vez identificados los valores de entrada óptimos, puede prescindir de MSE, MAE y R2, ya que sus cálculos requieren una cantidad de tiempo considerable y, en este contexto, lo que más importa es la rapidez en la obtención de resultados.


Creación de un ejecutable

Puesto que cuando empezamos con un par de divisas, lo primero que necesitamos saber antes de colocar órdenes es si estamos haciendo predicciones precisas. Dado que Python está en continua evolución, y puede que te encuentres con la necesidad de actualizar librerías, no estaría de más envolverlo todo. De este modo, dispondrá de un paquete consolidado listo para probar y experimentar.

Para ello, utilizaremos Tkinter y lo convertiremos en un ejecutable utilizando auto-py-to-exe. De esta forma, no tendremos más problemas a la hora de determinar los datos de entrada, y podremos ser más cautos con el fichero .py encargado de ejecutar las órdenes.

Demostraré cómo crear un ejecutable con fines de prueba, dejando el de ejecución de órdenes para que usted lo personalice.

Para el ejecutable utilizaré Tkinter, que proporciona una interfaz gráfica para introducir los valores. Recuerde que la ruta del archivo debe escribirse con "/" o "\". La interfaz obtendrá los valores de precisión del modelo y mostrará el gráfico.

Aquí está el código para la interfaz gráfica (gui_console)

import tkinter as tk
from program_object import execute_program_with
from program_object_without import execute_program_without
import sys

class Aplication:
    def __init__(self, root):
        self.root = root
        self.root.title("DeepLearning Forecast")
        
        # labels and entries
        label1 = tk.Label(root, text="Input account mt5:")
        label1.pack(pady=5)

        self.value1_entry = tk.Entry(root)
        self.value1_entry.pack(pady=5)

        label2 = tk.Label(root, text="Input password:")
        label2.pack(pady=5)

        self.value2_entry = tk.Entry(root)
        self.value2_entry.pack(pady=5)

        label3 = tk.Label(root, text="Input server of mt5:")
        label3.pack(pady=5)

        self.value3_entry = tk.Entry(root)
        self.value3_entry.pack(pady=5)

        label4 = tk.Label(root, text="Input delay in days (for ticks):")
        label4.pack(pady=5)

        self.value4_entry = tk.Entry(root)
        self.value4_entry.pack(pady=5)

        label5 = tk.Label(root, text="Input timeframe 1 (1h),2,4,1d,1w:")
        label5.pack(pady=5)

        self.value5_entry = tk.Entry(root)
        self.value5_entry.pack(pady=5)

        label6 = tk.Label(root, text="Input epochs:")
        label6.pack(pady=5)

        self.value6_entry = tk.Entry(root)
        self.value6_entry.pack(pady=5)

        label7 = tk.Label(root, text="Input symbol:")
        label7.pack(pady=5)

        self.value7_entry = tk.Entry(root)
        self.value7_entry.pack(pady=5)


        label8 = tk.Label(root, text="Input path for mt5:")
        label8.pack(pady=5)

        self.value8_entry = tk.Entry(root)
        self.value8_entry.pack(pady=5)

        # Radio button to select program to execute
        self.opcion_var = tk.StringVar(value="program_object")
        radio_btn_object = tk.Radiobutton(root, text="With r2 Score, MAE & MSE", variable=self.opcion_var, value="program_object")
        radio_btn_object.pack(pady=5)
        radio_btn_object_without = tk.Radiobutton(root, text="Without", variable=self.opcion_var, value="program_object_without")
        radio_btn_object_without.pack(pady=5)

        # Botón start
        boton_execute = tk.Button(root, text="Run Program", command=self.execute_programa)
        boton_execute.pack(pady=10)

        # Botón close
        boton_quit = tk.Button(root, text="Exit", command=root.destroy)
        boton_quit.pack(pady=10)

    def write(self, text):
        # this method y called when sys.stdout.write is used
        self.salida_text.insert(tk.END, text)
    def flush(self):
        pass
    def execute_program(self):
        # Obteined value of the selected option
        selected_program = self.opcion_var.get()

        # Obteined value of inputs
        value1 = self.value1_entry.get()
        value2 = self.value2_entry.get()
        value3 = self.value3_entry.get()
        value4 = self.value4_entry.get()
        value5 = self.value5_entry.get()
        value6 = self.value6_entry.get()
        value7 = self.value7_entry.get()
        value8 = self.value8_entry.get()

                # Redirects stdout & stderr to the console
        sys.stdout = sys.__stdout__
        sys.stderr = sys.__stderr__

        # Calls the function to execute a selected program and pass values as arguments
        if selected_program == "program_object":
            execute_program_with(value1, value2, value3, value4, value5, value6, value7, value8)
        elif selected_program == "program_object_without":
            execute_program_without(value1, value2, value3, value4, value5, value6, value7, value8)
        # Restores stdout to a predeterminate value to no have conflicts
        sys.stdout = self
        sys.stderr = self

if __name__ == "__main__":
    root = tk.Tk()
    app = Aplication(root)
    root.mainloop()

y este es el código que se llama (donde tienes que pegar tu código):

import sys
import MetaTrader5 as mt5
from MetaTrader5 import *
import matplotlib.pyplot as plt
import seaborn as sns  # Import seaborn for residual plot



def main(value1, value2, value3, value4, value5, value6, value7,value8):
    # Now you can use variables value1, value2, value3, value4, value5, value6, value7 en tu programa
    print("Numero de cuenta mt5 en mt5: ", value1)
    print("Password en mt5: ", value2)
    print("Servidor en mt5: ", value3)
    print("Delay dias ticks: ", value4)
    print("Time frame: ", value5)
    print("Epochs: ", value6)
    print("Symbol: ", value7)
    print("Path a mt5: ", value8)
    

def execute_program_with(value1, value2, value3, value4, value5, value6, value7, value8):
    main(value1, value2, value3, value4, value5, value6, value7, value8)

y termina con esto

if __name__ == "__main__":
    value1, value2, value3, value4, value5, value6, value7 = sys.argv[1:]
    main(value1, value2, value3, value4, value5, value6, value7)

hay dos de esto, uno con las puntuaciones de las predicciones del modelo y el gráfico, y el otro sólo muestra el gráfico.

Para convertir esto en un ejecutable, usaremos auto-py-to-exe. En primer lugar, instala la biblioteca.

pip install auto-py-to-exe

y hacemos que se ejecute, simplemente escribiendo en el terminal auto-py-to-exe

Solo recuerda añadir a la ubicación del script 'gui_console', y añade los archivos 'program_object' y 'program_object_without.py', dale a convertir py a exe, y ya lo tendrás.

auto-py-to-exe

Puede que tengas que utilizar el entorno Conda, para ello sólo tienes que escribir

conda activate XXX

siendo XXX el nombre del entorno.

Podrías tener problemas con Conda. Para solucionarlo, considera desinstalar Anaconda desde el Panel de Control (navega hasta 'Desinstalar un programa') e instala Python directamente desde su web oficial. Puedes descargarlo aquí. Asegúrate de seleccionar tu sistema operativo.

Al instalar Python recuerde añadir la ruta a las variables del sistema. Además, desactiva los límites de longitud.

Además, desactiva los límites de longitud. Para completar la configuración, instale Matplotlib, Seaborn y Scikit-learn ejecutando el siguiente comando en su terminal o símbolo del sistema:

pip install matplotlib
pip install seaborn
pip install scikit-learn


GUI

El término "Tk GUI" se refiere a la interfaz gráfica de usuario (GUI) creada utilizando el conjunto de herramientas Tkinter en Python. Tkinter es un módulo integrado en la biblioteca estándar de Python que facilita el desarrollo de interfaces gráficas de usuario.

Y se ve así:

GUI


Recuerda añadir la ruta para MT5, y cambiar "\" por "/" como aquí:

C:/Program Files/XXX MT5/terminal64.exe


GUI

Esto es más o menos lo que verá en la GUI cuando lo envuelva en un ejecutable y lo ejecute.

001


Los resultados para el probador son los siguientes:

tester001


Así es como se ve el tester, y los valores dentro del rectángulo rojo son los valores importantes. Obviamente, esos valores no son buenos y debería buscar un puntaje R2 cercano a 1 y un MSE y MAE cercanos a 0. Debería intentar usar más datos y/o más épocas, y también cambiar en el script el valor para L2 (te prometo que puedes obtener un buen ajuste y tener tiempo para hacer órdenes ... es como un juego).

Métricas utilizadas:

R2 (R-cuadrado), MSE (error cuadrático medio) y MAE (error absoluto medio) son métricas utilizadas habitualmente en estadística y aprendizaje automático para evaluar el rendimiento de los modelos:

  1. R2 (R-cuadrado):

    • R2 es una medida estadística que representa la proporción de la varianza en la variable dependiente que es predecible a partir de la(s) variable(s) independiente(s).
    • Se trata de una escala de 0 a 1, donde 0 indica que el modelo no explica la variabilidad de la variable dependiente y 1 indica una explicación perfecta.
  2. MSE (error cuadrático medio):

    • El MSE es una métrica que calcula la diferencia cuadrática media entre los valores reales y los predichos.
    • Penaliza más los errores grandes que los pequeños, por lo que es sensible a los valores atípicos.
    • Matemáticamente es la suma de las diferencias al cuadrado dividida por el número de observaciones.
  3. MAE (error medio absoluto):

    • MAE es una métrica que calcula la diferencia absoluta media entre los valores reales y los previstos.
    • A diferencia del MSE, no eleva las diferencias al cuadrado, por lo que es menos sensible a los valores atípicos.
    • Es la suma de las diferencias absolutas dividida por el número de observaciones.

Estas métricas se utilizan habitualmente en el análisis de regresión para evaluar la capacidad de un modelo para predecir la variable de resultado. En general, un valor R2 más alto y unos valores MSE o MAE más bajos indican un modelo con mejores resultados.


Sobreajuste

La sobreadaptación en el aprendizaje profundo para el trading implica el entrenamiento de un modelo que funciona bien con datos históricos, pero que no consigue generalizar eficazmente a datos nuevos no vistos. He aquí algunos peligros asociados al sobreajuste en el contexto del aprendizaje profundo para el trading:

  1. Generalización limitada: Un modelo sobreajustado puede captar ruido o patrones específicos en los datos históricos que no representan la verdadera dinámica del mercado. Como resultado, el modelo puede tener dificultades para generalizarse a las nuevas condiciones del mercado o a datos desconocidos.
  2. Bajo rendimiento con datos reales: Dado que un modelo sobreajustado está esencialmente memorizando los datos históricos, puede funcionar mal cuando se expone a datos de mercado en vivo. El modelo podría hacer predicciones inexactas o no adaptarse a las tendencias cambiantes del mercado.
  3. Cambios en el régimen de mercado: Los mercados financieros son dinámicos, y los distintos regímenes de mercado (alcista, bajista, lateral) pueden presentar características únicas. Un modelo sobreajustado entrenado en un régimen de mercado específico puede fallar cuando el mercado experimenta un cambio de régimen, ya que carece de adaptabilidad.
  4. Señales falsas: Un ajuste excesivo puede hacer que el modelo capte ruido o valores atípicos en los datos históricos, lo que da lugar a señales falsas. Estas señales falsas pueden orientar mal las estrategias de negociación, provocando pérdidas financieras en escenarios de negociación en vivo.
  5. Sesgo de 'Data Snooping' (Mironeo de datos): El sobreajuste puede agravarse por el 'data snooping' o la fuga de datos. Si el modelo se expone inadvertidamente a información del conjunto de pruebas durante el entrenamiento, puede aprender patrones que no se generalicen bien a datos realmente no vistos.
  6. Sensibilidad a los hiperparámetros: Los modelos sobreajustados pueden ser demasiado sensibles a los hiperparámetros, lo que dificulta su ajuste para obtener un rendimiento sólido en diferentes condiciones de mercado.

Para mitigar estos peligros, los profesionales del aprendizaje profundo para el trading suelen emplear estrategias como la validación cruzada, las técnicas de regularización y la incorporación de características que representan una comprensión más amplia de la dinámica del mercado. Además, es necesario actuar con cautela a la hora de interpretar el rendimiento del modelo en datos históricos y validar su eficacia en conjuntos de datos fuera de muestra. El monitoreo regular y el reentrenamiento de modelos también son esenciales para adaptarse a las condiciones cambiantes del mercado.

Validación cruzada en aprendizaje profundo:

La validación cruzada es una técnica estadística utilizada para evaluar el rendimiento de un modelo de aprendizaje automático. En el contexto del aprendizaje profundo, la validación cruzada implica dividir el conjunto de datos en múltiples subconjuntos o pliegues. El modelo se entrena en algunos de estos pliegues y se prueba en el pliegue restante. Este proceso se repite varias veces, utilizando diferentes pliegues para el entrenamiento y la prueba en cada iteración. Las métricas de rendimiento se promedian en todas las iteraciones para proporcionar una evaluación más sólida del rendimiento del modelo.

Entre los tipos habituales de validación cruzada se incluyen la validación cruzada de 'k' pliegues, en la que el conjunto de datos se divide en 'k' pliegues, y cada pliegue se utiliza como conjunto de prueba exactamente una vez, y la validación cruzada 'leave-one-out', en la que cada punto de datos se trata como un único pliegue.

La validación cruzada ayuda a evaluar el grado de generalización de un modelo a datos desconocidos y reduce el riesgo de ajuste excesivo o insuficiente.

Regularizador de núcleo (kernel_regularizer=l2):

En el contexto del aprendizaje profundo y las redes neuronales, el término regularizador de núcleo se refiere a una técnica de regularización aplicada a los pesos (o núcleos) de las capas de la red neuronal. El parámetro `kernel_regularizer=l2` indica específicamente el uso de la regularización L2 en los pesos.

La regularización L2 añade un término de penalización a la función de pérdida que es proporcional a la magnitud al cuadrado de los pesos. El objetivo es evitar que un solo peso sea demasiado grande y domine el proceso de aprendizaje. De este modo se evita que el modelo se ajuste demasiado a los datos de entrenamiento.

En resumen, `kernel_regularizer=l2` es una técnica de regularización utilizada para controlar la complejidad de una red neuronal penalizando los pesos grandes, y es una de las herramientas para abordar los problemas de sobreajuste en los modelos de aprendizaje profundo.


Gráfico

Este gráfico se guarda cuando se ejecuta el script.

El número que aparece en el título es el tiempo en minutos desde la primera línea naranja hasta el final del gráfico.

Puedes cambiar lo que necesites en el gráfico (por ejemplo, mostrar solo el rango entre las líneas naranjas) con este código de línea:

plt.plot(dff5.iloc[punto_entrada, valor_25], linestyle='-', label='Predicted')

simplemente lee el código e intenta entenderlo.

Gráfico

Este es el gráfico que genera. Las líneas rojas indican dónde deben colocarse las órdenes de compra/venta y de cierre. Las líneas naranjas representan el intervalo en el que se supone que el modelo es más fiable y preciso, concretamente en el intervalo del primer 20%. En este caso, he utilizado un marco temporal de 4 horas, por lo que el intervalo óptimo es la primera hora, mostrando los puntos máximo y mínimo para entrar y salir. Una vez que el script llega al final, hace un bucle de vuelta, y si añadimos las órdenes, seguirá ejecutándose continuamente. El resto de las líneas marcadas ayudan a situarse en el gráfico a la hora de colocar órdenes manuales.

Los precios dados en las predicciones son sólo orientativos, lo importante es saber dónde están el mínimo y el máximo en el intervalo


Cómo utilizar todo esto

Lo que hago es:

En primer lugar, experimento con un símbolo utilizando la GUI, probándolo con R2, MAE y MSE. Itero a través de diferentes valores de épocas y días de retraso. En segundo lugar, una vez que identifique valores prometedores para la predicción, asegurándome de evitar cuidadosamente la sobreestimación, paso al script. Automatizo el script para ejecutar órdenes de forma autónoma, alquilando un VPS para la ejecución continua de órdenes durante toda la semana. Cabe destacar que si se producen errores elevados, también hay un parámetro que se puede ajustar. Por ejemplo, en el caso de las criptomonedas, se podría optar por un L2 de 0,01 en lugar del 0,001 utilizado para las divisas. Mediante ensayo y error, pueden determinarse los valores óptimos para la cantidad de datos (días de retraso) y las épocas.


Es importante tener en cuenta que calcular el MSE, R2 y MAE lleva aproximadamente una época en el tiempo. Por lo tanto, es aconsejable realizar experimentos inicialmente. Once a good model approximation is achieved, the model can be employed without these parameters. En Python, esto se consigue comentando el código relevante o utilizando el símbolo #.


Lo que hago con este programa Python es utilizar un bucle. Por si alguna vez hay un fallo al cerrar las órdenes he implementado un mecanismo para cancelar las órdenes desde el símbolo. También utilizo el timer.mql5 ya que he establecido un intervalo para las órdenes, concretamente una hora. Así se garantiza que ningún pedido permanezca abierto más de una hora.


Bucle

Para el bucle de DeepLearningForecast, en lugar de doint un while = True, podemos hacer esto (Loop.py):

import time
import subprocess

def execute_program():
    
    subprocess.run(['python', 'DeepLearningForecast.py'])

# Stablish and interval in seconds (for example, 60 seconds)
seconds_interval = 5


while True:
    execute_program()
    print(f"Program executed. Waiting {seconds_interval} seconds")

    # waits the interval before executing the program
    time.sleep(seconds_interval)


Bot de Telegram

En MT5 ya tenemos varias formas de ver la información, pero para este bot a veces me interesa saber si está prediciendo con precisión y ejecutando las órdenes correctamente. Para hacer un seguimiento de estas acciones y comparar posteriormente las predicciones con el gráfico real, envío el gráfico y la información relevante a un bot de Telegram. A continuación explicaré cómo crear el bot de Telegram y cómo enviar los datos a través de Telegram.

Guía paso a paso para crear un bot en Telegram y obtener su ID de chat y token para enviar mensajes a través de solicitudes:

Crea un bot en Telegram:

  1. Abre Telegram y busca BotFather:

    • Abre Telegram y busca "BotFather" en la barra de búsqueda.
    • Empieza a chatear con BotFather.
  2. Crear un nuevo bot:

    • Utiliza el comando /newbot para crear un nuevo bot.
    • Sigue las instrucciones de BotFather para asignar un nombre y un nombre de usuario a tu bot.
    • Una vez completado, BotFather le proporcionará un token. Este token es necesario para autenticar tu bot.

Obtener ID de chat:

  1. Inicia un chat con tu bot:

    • Después de crear tu bot inicia un chat con él en Telegram.
  2. Visite la URL de la API del bot:

    • Abra un navegador web y visite la siguiente URL, sustituyendo BOT_TOKEN por el token de su bot:
    https://api.telegram.org/botBOT_TOKEN/getUpdates
  1. Envía un mensaje al bot:

    • Vuelve a Telegram y envía un mensaje al bot con el que iniciaste el chat.
  2. Actualice la página del navegador:

    • Vuelva a la página del navegador en la que introdujo la URL de la API del bot.
    • Actualiza la página.
  3. Busca el ID del chat:

    • En la respuesta JSON, busque la sección que contiene el historial de mensajes.
    • Encuentre el objeto que representa su mensaje enviado recientemente.
    • Dentro de ese objeto, localiza el campo chat, y dentro de él, el campo id será el ID del Chat.


El resultado de esto, será que puedes recibir un mensaje como este (para seguir la pista en el bot)

Mensaje de Telegram



Otros ajustes

Como no me gustaba como se cerraban las órdenes, he modificado el script para aprovechar las tendencias. He añadido una Media Móvil Simple (SMA) y le he ordenado que cierre las órdenes cuando el precio cruce la SMA.

Así que para arreglar esto:

SMA


He añadido esto:

def obtain_sma_pandas(symbol, periodo):
    prices = mt5.copy_rates_from_pos(symbol, mt5.TIMEFRAME_M1, 0, periodo)
    df_sma = pd.DataFrame(prices)
    sma = df_sma['close'].rolling(window=periodo).mean().iloc[-1]
    return sma

y esto

    action="buy"
    price = mt5.symbol_info_tick(symbol).ask
    period_sma=14
    sma = obtain_sma_pandas(symbol, period_sma)
    while True:
        # Obtener el precio actual y la SMA
        actual_price = price
        sma = obtain_sma_pandas(symbol, period_sma)

        # Si el precio está por debajo de la SMA, cerrar la orden
        if actual_price > sma:
            close_all_position(symbol)
            continue

        # Esperar antes de verificar nuevamente
        time.sleep(10)

También puede agregar el ADX (indicador) a la secuencia de comandos, para buscar operaciones cuando está en una tendencia con esto:

def calculate_adx(high, low, close, period):

    tr_pos = []
    tr_neg = []

    for i in range(1, len(close)):
        trh = max(high[i] - high[i - 1], 0)
        trl = max(low[i - 1] - low[i], 0)

        if trh > trl:
            tr_pos.append(trh)
            tr_neg.append(0)
        elif trl > trh:
            tr_pos.append(0)
            tr_neg.append(trl)
        else:
            tr_pos.append(0)
            tr_neg.append(0)

    atr = pd.Series(tr_pos).ewm(span=period, adjust=False).mean() + pd.Series(tr_neg).ewm(span=period, adjust=False).mean()
    dx = (pd.Series(tr_pos).ewm(span=period, adjust=False).mean() / atr) * 100
    adx = dx.ewm(span=period, adjust=False).mean()

    return adx.iloc[-1]


ONNX

Ahora, aprovechando los conocimientos del artículo 'Uso de modelos ONNX en MQL5' de MetaQuotes, estoy en proceso de convertir el modelo a formato ONNX. Siguiendo las pautas proporcionadas en el mismo artículo, integraré el modelo ONNX resultante en el Asesor Experto (EA) base para iniciar las operaciones de trading. Este enfoque permite la integración perfecta de modelos de aprendizaje automático en el entorno MQL5, mejorando las capacidades del algoritmo de negociación.

Antes de formatear en ONNX, es necesario descargar los datos. Para ello, utilizaremos el script que he subido (ticks_to_csv). Simplemente guárdelo en la carpeta MQL5 EA, ábralo en el IDE y compílelo. Una vez hecho esto, añada el script a un gráfico y deje que se ejecute durante algún tiempo (como descarga todos los ticks de un símbolo, puede tardar un rato). En el diario, verá un mensaje de finalización cuando el proceso haya terminado. Como referencia, lo he utilizado para el EURUSD y ha ocupado varios gigabytes.

#property script_show_inputs
#property strict
//--- Requesting 100 million ticks to be sure we receive the entire tick history
input long      getticks=100000000000; // The number of required ticks
string fileName = "ticks_data.csv";
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
   int     attempts=0;     // Count of attempts
   bool    success=false;  // The flag of a successful copying of ticks
   MqlTick tick_array[];   // Tick receiving array
   MqlTick lasttick;       // To receive last tick data

   SymbolInfoTick(_Symbol,lasttick);
//--- Make 3 attempts to receive ticks
   while(attempts<3)
     {

      //--- Measuring start time before receiving the ticks
      uint start=GetTickCount();
      //--- Requesting the tick history since 1970.01.01 00:00.001 (parameter from=1 ms)
      long received=CopyTicks(_Symbol,tick_array,COPY_TICKS_ALL,1,getticks);

      // Check if ticks were successfully copied
      if(received > 0)
        {
         // Open the CSV file for writing
         int fileHandle = FileOpen(fileName, FILE_WRITE | FILE_CSV);

         // Check if the file was opened successfully
         if(fileHandle != INVALID_HANDLE)
           {
            // Write the CSV header
            FileWrite(fileHandle, "Time,Bid,Ask");

            // Write tick data to the CSV file
            for(long i = 0; i < received; i++)
              {
               string csvLine = StringFormat("%s,%.5f,%.5f", TimeToString(tick_array[i].time), tick_array[i].bid, tick_array[i].ask);
               FileWrite(fileHandle, csvLine);
              }


            // Close the CSV file
            FileClose(fileHandle);

            // Print success message
            Print("Downloaded ", received, " ticks for symbol ", _Symbol, " and period ", Period());
            Print("Ticks data saved to ", fileName);
           }
         else
           {
            // Print an error message if the file could not be opened
            Print("Failed to open the file for writing. Error code: ", GetLastError());
           }
        }
      else
        {
         // Print an error message if no ticks were downloaded
         Print("Failed to download ticks. Error code: ", GetLastError());
        }

      if(received!=-1)
        {
         //--- Showing information about the number of ticks and spent time
         PrintFormat("%s: received %d ticks in %d ms",_Symbol,received,GetTickCount()-start);
         //--- If the tick history is synchronized, the error code is equal to zero
         if(GetLastError()==0)
           {
            success=true;
            break;
           }
         else
            PrintFormat("%s: Ticks are not synchronized yet, %d ticks received for %d ms. Error=%d",
                        _Symbol,received,GetTickCount()-start,_LastError);
        }
      //--- Counting attempts
      attempts++;
      //--- A one-second pause to wait for the end of synchronization of the tick database
      Sleep(1000);
     }
  }

Y a partir de estos datos (CSV), leeremos y utilizaremos el segmento que necesitemos, convirtiéndolo en un DataFrame (el DeepLearning_ONNX.py se ha definido para los últimos 1000 días hasta hoy). Puede utilizar todo el conjunto de datos, pero necesitará memoria RAM suficiente.

Una vez que hemos descargado los datos, podemos empezar a obtener el modelo ONNX de entrenamiento con el DeepLearningForecast_ONNX_training.py. (por favor, guarde el archivo en una carpeta en la carpeta de archivos de MQL5.

Importa los datos con esto:

rates = pd.read_csv(file_path, encoding='utf-16le')

crea un modelo con esto:

onnx_model = tf2onnx.convert.from_keras(model, output_path=output_path)


Conclusión

En conclusión, este artículo ha esbozado un enfoque integral para desarrollar un script de Python para el trading automatizado utilizando el aprendizaje profundo. Exploramos la integración de MetaTrader 5, el preprocesamiento de datos, la formación de modelos y la ejecución de órdenes de compra/venta. La utilización de Tkinter y auto-py-to-exe para crear un ejecutable con una interfaz fácil de usar añade practicidad al script.

Además, se ofrecieron consideraciones sobre la elección de los datos de entrada adecuados, la evaluación del rendimiento del modelo y la aplicación de estrategias eficaces de orden de cierre. El resultado visual del script, que muestra predicciones, rangos fiables y colocación de órdenes, proporciona una visión clara y procesable tanto para la negociación automatizada como para la manual.

Por último, aprenderemos a importar todos los ticks de un par de divisas. Usaremos Python para leer estos datos, crear un modelo ONNX, y (si el próximo artículo es interesante) ejecutar el modelo en MT5 con un Asesor Experto (EA).

Sin embargo, es esencial hacer hincapié en la naturaleza dinámica de los mercados financieros, que justifica una supervisión, adaptación y posibles mejoras continuas del modelo. El marco esbozado sirve de base sólida, y se anima a los usuarios a adaptarlo y mejorarlo en función de la evolución de las condiciones del mercado y de sus objetivos específicos de negociación.


Descargo de responsabilidad

Descargo de responsabilidad: El rendimiento pasado no indica resultados futuros. Operar con criptomonedas y otros instrumentos financieros conlleva riesgos; ninguna estrategia puede garantizar beneficios en todos los escenarios. Investigue siempre a fondo y pida consejo a profesionales financieros antes de tomar decisiones de inversión.


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

Archivos adjuntos |
Timer.mq5 (4.57 KB)
Timer_modified.mq5 (9.73 KB)
Loop.py (0.4 KB)
gui_console.py (3.85 KB)
program_object.py (23.96 KB)
ticks_to_csv.mq5 (3.27 KB)
Usamos algoritmos de optimización para ajustar los parámetros del asesor sobre la marcha Usamos algoritmos de optimización para ajustar los parámetros del asesor sobre la marcha
El artículo analizará diversos aspectos prácticos relacionados con el uso de algoritmos de optimización para encontrar los mejores parámetros de un asesor sobre la marcha, y también virtualizar las operaciones comerciales y la lógica del asesor. El lector puede usar este artículo a modo de instrucciones para implementar algoritmos de optimización en un asesor comercial.
Desarrollamos de un asesor multidivisa (Parte 2): Transición a posiciones virtuales de estrategias comerciales Desarrollamos de un asesor multidivisa (Parte 2): Transición a posiciones virtuales de estrategias comerciales
Hoy continuaremos con el desarrollo de un asesor multidivisa con varias estrategias funcionando en paralelo. Intentaremos transferir todo el trabajo relacionado con la apertura de posiciones de mercado desde el nivel de las estrategias al nivel de un experto que gestiona estas. Las propias estrategias solo negociarán virtualmente, sin abrir posiciones de mercado.
Equilibrio de riesgos en la negociación simultánea de varios instrumentos comerciales Equilibrio de riesgos en la negociación simultánea de varios instrumentos comerciales
Este artículo permitirá a los principiantes escribir desde cero la implementación de un script para el equilibrio de riesgos en la negociación simultánea de varios instrumentos comerciales, mientras que los usuarios experimentados podrán obtener nuevas ideas para la implementación de sus soluciones en cuanto a las opciones propuestas en este artículo.
Desarrollo de un sistema de repetición (Parte 52): Esto complica las cosas (IV) Desarrollo de un sistema de repetición (Parte 52): Esto complica las cosas (IV)
En este artículo vamos a cambiar el indicador de mouse para poder interactuar con el indicador de control, ya que esta se está realizando de forma errática.