
Aprendizaje automático y Data Science (Parte 27): Redes neuronales convolucionales (CNN) en los robots comerciales de MetaTrader 5: ¿Merecen la pena?
La operación de agrupamiento utilizada en las redes neuronales convolucionales es un gran error, y el hecho de que funcione tan bien es un desastre.
Geoffrey Hinton
Contenido
- ¿Qué son las redes neuronales convolucionales (CNN)?
- Capas convolucionales
- Funciones de activación
- Capas de agrupación
- Capas completamente conectadas
- Capas de abandono - ¿Por qué utilizar redes neuronales convolucionales (CNN) para aplicaciones de análisis financiero y trading?
- Creación de una red neuronal convolucional (CNN) en Python
- Creación de un robot comercial basado en una red neuronal convolucional (CNN)
- El resultado final
Se requiere un conocimiento básico de lenguaje de programación Python, Redes Neuronales Artificiales, Aprendizaje Automático y ONNX en MQL5 para entender completamente el contenido de este artículo.
¿Qué son las redes neuronales convolucionales (CNNS)?
Las redes neuronales convolucionales (CNN) son una clase de algoritmos de aprendizaje profundo diseñados específicamente para procesar datos estructurados en forma de cuadrícula, como imágenes, espectrogramas de audio y datos de series temporales. Son especialmente adecuados para tareas de datos visuales porque pueden aprender de forma automática y adaptativa jerarquías espaciales de características a partir de los datos de entrada.
Las CNN son la versión extendida de las redes neuronales artificiales (ANN). Se utilizan predominantemente para extraer características del conjunto de datos de matriz tipo cuadrícula. Por ejemplo, conjuntos de datos visuales como imágenes o vídeos donde los patrones de datos juegan un papel importante.
Las redes neuronales convolucionales tienen varios componentes clave como: capas convolucionales, funciones de activación, capas de agrupación, capas completamente conectadas y capas de abandono. Para entender las CNN en profundidad, analicemos cada componente y veamos de qué se trata.
Capas convolucionales
Estos son los componentes básicos de las CNN; es donde se produce la mayor parte de los cálculos. Las capas convolucionales son responsables de detectar patrones locales en los datos de entrada, como los bordes en las imágenes. Esto se puede lograr mediante el uso de filtros (o núcleos) que se deslizan sobre los datos de entrada para producir mapas de características.
Una capa convolucional es una capa oculta que contiene varias unidades de convolución en una red neuronal convolucional, que se utiliza para la extracción de características.
from tensorflow.keras.layers import Conv1D
model = Sequential()
model.add(Conv1D(filters=64, kernel_size=3, activation='relu', input_shape=(window_size, X_train.shape[2])))
Filtros/Kernels
Los filtros (o kernels) son pequeñas matrices cuadradas que se pueden aprender (generalmente de tamaño 3x3, 5x5, etc.) y que se deslizan sobre los datos de entrada para detectar patrones locales.
¿Cómo funcionan?
Funcionan moviéndose a través de los datos de entrada y luego realizan una multiplicación elemento por elemento entre los valores del filtro y los valores de entrada dentro del campo receptivo actual del filtro, seguido de la suma de los resultados. Esta operación es lo que se llama convolución.
Durante el entrenamiento, la red aprende los valores óptimos de los filtros. En las primeras capas, los filtros generalmente aprenden a detectar características simples, como bordes y texturas, mientras que en capas más profundas, los filtros pueden detectar patrones más complejos, como formas y objetos.
Considere un filtro simple de 3x3 y una imagen de entrada de 5x5. El filtro se desliza sobre la imagen y calcula la operación de convolución para producir un mapa de características.
Zancada
Esta es otra característica que se encuentra en la capa de convolución. La zancada es el tamaño del paso en el que el filtro se mueve a través de los datos de entrada. Determina cuánto se desplaza el filtro en cada paso durante el proceso de convolución.
¿Cómo funcionan?
Zancada 1: el filtro se mueve una unidad a la vez, lo que da como resultado un mapa de características altamente superpuesto y detallado. Esto produce un mapa de características de salida más grande.
Zancada 2 o más: el filtro omite unidades, lo que da como resultado un mapa de características de salida menos detallado pero más pequeño. De este modo, se reducen las dimensiones espaciales de la salida, con lo que se reduce el muestreo de la entrada.
Por ejemplo, si tiene un filtro de 3x3 y una imagen de entrada de 5x5 con un paso de 1, el filtro se moverá un píxel a la vez, produciendo un mapa de características de salida de 3x3. Con un paso de 2, el filtro se moverá dos píxeles a la vez, produciendo un mapa de características de salida de 2x2.
Relleno
El relleno implica agregar píxeles adicionales (generalmente ceros) alrededor del borde de los datos de entrada. Esto garantiza que el filtro se ajuste correctamente y controle las dimensiones espaciales del mapa de características de salida.
Tipos de relleno
Según Keras, existen tres tipos de relleno. (Con distinción entre mayúsculas y minúsculas)
- válido - no se aplicará ningún relleno,
- igual - rellena la entrada para que el tamaño de salida coincida con el tamaño de entrada cuando la zancadas es igual a 1.
- causal - usado para datos temporales para asegurar que la salida en el paso de tiempo 𝑡 no depende de entradas futuras.
El relleno ayuda a preservar las dimensiones espaciales de los datos de entrada. Sin relleno, el mapa de características de salida se contrae con cada capa convolucional, lo que podría provocar la pérdida de información importante sobre los bordes.
Al agregar relleno, la red puede aprender características de los bordes de manera efectiva y mantener la resolución espacial de la entrada.
Considere un filtro de 3x3 y una imagen de entrada de 5x5. Con un relleno válido (sin relleno), el mapa de características de salida será 3x3. Con el mismo relleno, puedes agregar un borde de ceros alrededor de la entrada, haciéndolo 7x7. El mapa de características de salida será entonces de 5x5, conservando las dimensiones de entrada.
A continuación se muestra el código para una capa de convolución en Python.
from tensorflow.keras.models import Sequential from tensorflow.keras.layers import Conv1D model = Sequential() model.add(Conv1D(filters=64, kernel_size=3, activation='relu', strides=2, padding='causal', input_shape=(window_size, X_train.shape[2]) ) )
Funciones de activación
Como se explica en el artículo Desmitificación de las redes neuronales, una función de activación es una función matemática que toma una entrada y procesa una salida.
La función de activación se aplica por elementos para introducir no linealidad en el modelo. Entre las funciones de activación utilizadas habitualmente en las CNN se encuentran ReLU (Unidad Lineal Rectificada), Sigmoide y TanH.
Agrupación de capas
También conocidas como capas de desmuestreo, estas capas son una parte esencial de las CNN, ya que se encargan de reducir la dimensión espacial de los datos de entrada en términos de anchura y altura, conservando al mismo tiempo la información más importante.
¿Cómo funcionan?
En primer lugar, dividen los datos de entrada en regiones o ventanas superpuestas y, a continuación, aplican una función de agregación como Max pooling o Average pooling en cada ventana para obtener un valor único.
Max pooling toma el valor máximo de un conjunto de valores dentro de una región de filtrado. Reduce las dimensiones espaciales de los datos, lo que ayuda a reducir la carga computacional y el número de parámetros.
Python
from tensorflow.keras.layers import Conv1D, MaxPooling1D model = Sequential() model.add(Conv1D(filters=64, kernel_size=3, activation='relu', input_shape=(window_size, X_train.shape[2]))) model.add(MaxPooling1D(pool_size=2))
MaxPooling1D(pool_size=2)
Esta capa toma el valor máximo de cada ventana de 2 elementos.
Average pooling toma el valor medio de un conjunto de valores dentro de una región de filtrado. Se utiliza con menos frecuencia que el agrupamiento máximo.
Python
from tensorflow.keras.layers import Conv1D, AveragePooling1D model = Sequential() model.add(Conv1D(filters=64, kernel_size=3, activation='relu', input_shape=(window_size, X_train.shape[2]))) model.add(AveragePooling1D(pool_size=2))
AveragePooling1D(pool_size=2)
Esta capa toma el valor promedio de cada ventana de 2 elementos.
¿Por qué utilizar la capa convolucional 1D?
Existen capas Conv1D, Conv2D y Conv3D para las CNN. La capa de convolución 1D es una adecuada para este tipo de problemas ya que está diseñada para datos unidimensionales, lo que la hace adecuada para datos secuenciales o series temporales. Otras capas convolucionales como la Conv2D y la Conv3D son demasiado complejas para este tipo de problema.
Capas totalmente conectadas
Las neuronas de una capa totalmente conectada tienen conexiones con todas las activaciones de la capa anterior. Estas capas suelen utilizarse hacia el final de la red para realizar una clasificación o regresión basada en las características extraídas por las capas convolucionales y de agrupación.
from tensorflow.keras.layers import Conv1D, MaxPooling1D, Flatten, Dense, Dropout
model = Sequential()
model.add(Conv1D(filters=64, kernel_size=3, activation='relu', input_shape=(window_size, X_train.shape[2])))
model.add(MaxPooling1D(pool_size=2))
model.add(Flatten())
model.add(Dense(100, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(units=len(np.unique(y)), activation='sigmoid')) # For binary classification (e.g., buy/sell signal)
model.summary()
La capa aplanada (Flatten) convierte el mapa de características 1D agrupado en un vector 1D, de modo que pueda introducirse en las capas totalmente conectadas (densas).
Las capas densas (Dense) son capas totalmente conectadas que se utilizan para tomar decisiones finales basadas en las características extraídas por las capas de convolución y agrupación. Las capas densas son esencialmente el componente central de las redes neuronales artificiales (RNA) tradicionales.
Capas de abandono
La capa de abandono (Dropout) actúa como una máscara, eliminando las contribuciones de algunas neuronas a la capa siguiente, pero manteniendo la funcionalidad de todas las demás neuronas. Si aplicamos una capa Dropout al vector de entrada, se eliminan algunas de sus características; sin embargo, si la aplicamos a una capa oculta, se eliminan algunas neuronas ocultas.
Dado que evitan el sobreajuste de los datos de entrenamiento, las capas de abandono son cruciales en el entrenamiento de las CNN. Si están ausentes, el primer conjunto de muestras de entrenamiento tiene un impacto excesivamente grande en el aprendizaje. En consecuencia, no se aprenderían rasgos que sólo aparecen en muestras o lotes posteriores.
from tensorflow.keras.layers import Conv1D, MaxPooling1D, Flatten, Dense, Dropout
model = Sequential()
model.add(Conv1D(filters=64, kernel_size=3, activation='relu', input_shape=(window_size, X_train.shape[2])))
model.add(MaxPooling1D(pool_size=2))
model.add(Flatten())
model.add(Dense(100, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(units=len(np.unique(y)), activation='sigmoid')) # For binary classification (e.g., buy/sell signal)
model.summary()
¿Por qué utilizar redes neuronales convolucionales (CNN) para aplicaciones de análisis financiero y trading?
Las CNN se utilizan ampliamente en aplicaciones de procesamiento de imágenes y vídeo, ya que para eso están diseñadas. Si echas un vistazo a las explicaciones anteriores, podrás darte cuenta de que me refiero al uso de CNNs cuando trabajo con clasificaciones de imágenes y esas cosas.
El uso de redes neuronales convolucionales (CNN) para datos tabulares, como el análisis financiero, puede parecer poco convencional en comparación con el uso de otros tipos de redes neuronales, como las redes neuronales de alimentación directa (FFNN), las redes neuronales recurrentes (RNNN) , la memoria a corto plazo de larga duración (LSTM) y las unidades recurrentes controladas (GRU) . Sin embargo, existen varias razones y ventajas potenciales que se exponen a continuación para emplear las CNN en este contexto.
01. Las CNN son excelentes para extraer automáticamente patrones locales de los datos.
03. Pueden ser resistentes al ruido y a las características redundantes.
04: Las CNN pueden manejar bien series temporales multivariadas.
Ahora que tenemos razones válidas para usar CNN en aplicaciones comerciales, creemos una y entrenémosla, luego veremos cómo podemos usar una CNN en un Asesor Experto (EA) de Meta Trader 5.
Creación de una red neuronal convolucional (CNN) en Python
Esto implica varios pasos que son:
- Recopilación de datos
- Preparación de datos para un modelo CNN
- Entrenamiento de un modelo CNN
- Guardar un modelo CNN en formato ONNX
01: Recopilación de datos
Utilizando los datos realizados para la previsión de series temporales que utilizamos en los artículos anteriores.
Ahora que sabemos que las redes neuronales convolucionales (CNN) son buenas detectando patrones dentro de datos de alta dimensión, sin complicar el modelo podemos elegir algunas de las características que creo que pueden tener muchos patrones que el modelo CNN puede detectar.
Código Python
open_price = df['TARGET_OPEN'] close_price = df['TARGET_CLOSE'] # making the target variable target_var = [] for i in range(len(open_price)): if close_price[i] > open_price[i]: # if the price closed above where it opened target_var.append(1) # bullish signal else: target_var.append(0) # bearish signal new_df = pd.DataFrame({ 'OPEN': df['OPEN'], 'HIGH': df['HIGH'], 'LOW': df['LOW'], 'CLOSE': df['CLOSE'], 'TARGET_VAR': target_var }) print(new_df.shape)
Poco después de preparar la variable objetivo basada en TARGET_OPEN y TARGET_CLOSE, que son los valores de apertura y cierre respectivamente, recogidos una barra hacia adelante. Creamos una versión del minijuego de datos llamada nuevo_df que sólo tenía 4 variables independientes valores ABIERTO, ALTO y BAJO, y una variable dependiente llamada TARGET_VAR.
02: Preparación de datos para un modelo CNN
En primer lugar, tenemos que preprocesar los datos de entrada reformulándolos y alineándolos en ventanas. Esto es muy crucial cuando se trabaja con datos tabulares en CNN, aquí explicamos por qué.
Dado que los datos comerciales son secuenciales, los patrones a menudo surgen a lo largo de una serie de pasos de tiempo en lugar de en un único punto en el tiempo. Al crear ventanas superpuestas de datos podemos, captar dependencias temporales y proporcionar contexto al modelo CNN..
Además, las CNN esperan que los datos de entrada tengan una forma específica. Para las capas convolucionales 1D, la forma de entrada normalmente debe ser (número de ventanas, tamaño de ventana, número de características). Esta forma se asemeja a la que utilizamos en el análisis de series temporales mediante Redes Neuronales Recurrentes (RNNs) en el artículo anterior. El procedimiento de preprocesamiento que vamos a realizar garantiza que los datos tengan este formato, lo que los hace adecuados para la entrada de un modelo CNN.
# Example data preprocessing function def preprocess_data(df, window_size): X, y = [], [] for i in range(len(df) - window_size): X.append(df.iloc[i:i+window_size, :-1].values) y.append(df.iloc[i+window_size, -1]) return np.array(X), np.array(y) window_size = 10 X, y = preprocess_data(new_df, window_size) print(f"x_shape = {X.shape}\ny_shape = {y.shape}")
Salidas
x_shape = (990, 10, 4) y_shape = (990,)
Dado que nuestros datos se recopilaron en un período de tiempo diario, el tamaño de ventana de 10 indica que entrenaremos el modelo CNN para comprender patrones dentro de 10 días.
Luego tenemos que dividir los datos en muestras de entrenamiento y de prueba.
# Split data into training and testing sets X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, shuffle=False) # Standardize the data scaler = StandardScaler() X_train = scaler.fit_transform(X_train.reshape(-1, X_train.shape[-1])).reshape(X_train.shape) X_test = scaler.transform(X_test.reshape(-1, X_test.shape[-1])).reshape(X_test.shape) print(f"x_train\n{X_train.shape}\nx_test\n{X_test.shape}\n\ny_train {y_train.shape} y_test {y_test.shape}")
Salidas
x_train (792, 10, 4) x_test (198, 10, 4) y_train (792,) y_test (198,)
Por último tenemos que codificar en caliente la variable objetivo para esta tarea del problema de clasificación.
from tensorflow.keras.utils import to_categorical
y_train_encoded = to_categorical(y_train)
y_test_encoded = to_categorical(y_test)
print(f"One hot encoded\n\ny_train {y_train_encoded.shape}\ny_test {y_test_encoded.shape}")
Salidas
One hot encoded y_train (792, 2) y_test (198, 2)
03: Entrenamiento de un modelo CNN
Aquí es donde se hace la mayor parte del trabajo.
# Defining the CNN model model = Sequential() model.add(Conv1D(filters=64, kernel_size=3, activation='relu', strides=2, padding='causal', input_shape=(window_size, X_train.shape[2]) ) ) model.add(MaxPooling1D(pool_size=2)) model.add(Flatten()) model.add(Dense(100, activation='relu')) model.add(Dropout(0.5)) model.add(Dense(units=len(np.unique(y)), activation='softmax')) # For binary classification (buy/sell signal) model.summary() # Compiling the model optimizer = Adam(learning_rate=0.001) model.compile(optimizer=optimizer, loss='categorical_crossentropy', metrics=['accuracy']) # Training the model early_stopping = EarlyStopping(monitor='val_loss', patience=10, restore_best_weights=True) history = model.fit(X_train, y_train_encoded, epochs=100, batch_size=16, validation_split=0.2, callbacks=[early_stopping]) plt.figure(figsize=(7.5, 6)) plt.plot(history.history['loss'], label='Training Loss') plt.plot(history.history['val_loss'], label='Validation Loss') plt.xlabel('Epochs') plt.ylabel('Loss') plt.title('Training Loss Curve') plt.legend() plt.savefig("training loss cuver-cnn-clf.png") plt.show()
Salidas
Model: "sequential_2" ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓ ┃ Layer (type) ┃ Output Shape ┃ Param # ┃ ┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩ │ conv1d_2 (Conv1D) │ (None, 5, 64) │ 832 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ max_pooling1d_2 (MaxPooling1D) │ (None, 2, 64) │ 0 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ flatten_2 (Flatten) │ (None, 128) │ 0 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ dense_4 (Dense) │ (None, 100) │ 12,900 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ dropout_2 (Dropout) │ (None, 100) │ 0 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ dense_5 (Dense) │ (None, 2) │ 202 │ └─────────────────────────────────┴────────────────────────┴───────────────┘
El entrenamiento se detuvo en la 34ª época.
40/40 ━━━━━━━━━━━━━━━━━━━━ 0s 3ms/step - accuracy: 0.5105 - loss: 0.6875 - val_accuracy: 0.4843 - val_loss: 0.6955 Epoch 32/100 40/40 ━━━━━━━━━━━━━━━━━━━━ 0s 3ms/step - accuracy: 0.5099 - loss: 0.6888 - val_accuracy: 0.5283 - val_loss: 0.6933 Epoch 33/100 40/40 ━━━━━━━━━━━━━━━━━━━━ 0s 3ms/step - accuracy: 0.4636 - loss: 0.6933 - val_accuracy: 0.5283 - val_loss: 0.6926 Epoch 34/100 40/40 ━━━━━━━━━━━━━━━━━━━━ 0s 3ms/step - accuracy: 0.5070 - loss: 0.6876 - val_accuracy: 0.5346 - val_loss: 0.6963
El modelo tuvo una precisión de aproximadamente el 57% del tiempo en las predicciones fuera de la muestra.
y_pred = model.predict(X_test) classes_in_y = np.unique(y) y_pred_binary = classes_in_y[np.argmax(y_pred, axis=1)] # Confusion Matrix cm = confusion_matrix(y_test, y_pred_binary) sns.heatmap(cm, annot=True, fmt='d', cmap='Blues') plt.xlabel("Predicted Label") plt.ylabel("True Label") plt.title("Confusion Matrix") plt.savefig("confusion-matrix CNN") # Display the heatmap print("Classification Report\n", classification_report(y_test, y_pred_binary))
Salidas
7/7 ━━━━━━━━━━━━━━━━━━━━ 0s 11ms/step Classification Report precision recall f1-score support 0 0.53 0.24 0.33 88 1 0.58 0.83 0.68 110 accuracy 0.57 198 macro avg 0.55 0.53 0.50 198 weighted avg 0.55 0.57 0.52 198
Nuestro modelo CNN es lo suficientemente bueno para un Asesor Experto. Pero, antes de que podamos comenzar a codificar un EA, guardemos el modelo CNN que hemos entrenado en formato ONNX.
04: Guardar un modelo CNN en formato ONNX.
El proceso es bastante sencillo, tenemos que guardar el modelo CNN en formato .onnx, y los parámetros de la técnica de escalado en archivos binarios.
import tf2onnx onnx_file_name = "cnn.EURUSD.D1.onnx" spec = (tf.TensorSpec((None, window_size, X_train.shape[2]), tf.float16, name="input"),) model.output_names = ['outputs'] onnx_model, _ = tf2onnx.convert.from_keras(model, input_signature=spec, opset=13) # Save the ONNX model to a file with open(onnx_file_name, "wb") as f: f.write(onnx_model.SerializeToString()) # Save the mean and scale parameters to binary files scaler.mean_.tofile(f"{onnx_file_name.replace('.onnx','')}.standard_scaler_mean.bin") scaler.scale_.tofile(f"{onnx_file_name.replace('.onnx','')}.standard_scaler_scale.bin")
Creación de un robot comercial basado en una red neuronal convolucional (CNN)
Dentro de un Asesor Experto, lo primero que tenemos que hacer es incluir como recursos el modelo con formato ONNX y los ficheros binarios Standard Scaler.
MQL5 | ConvNet EA.mq5
#resource "\\Files\\cnn.EURUSD.D1.onnx" as uchar onnx_model[] #resource "\\Files\\cnn.EURUSD.D1.standard_scaler_scale.bin" as double scaler_stddev[] #resource "\\Files\\cnn.EURUSD.D1.standard_scaler_mean.bin" as double scaler_mean[]
Tenemos que inicializar ambos, el escalador y el modelo ONNX.
#include <MALE5\Convolutioal Neural Networks(CNNs)\Convnet.mqh> #include <MALE5\preprocessing.mqh> CConvNet cnn; StandardizationScaler scaler; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ input group "cnn"; input uint cnn_data_window = 10; //this value must be the same as the one used during training in a python script vector classes_in_y = {0,1}; //we have to assign the classes manually | it is essential that their order is preserved as they can be seen in python code, HINT: They are usually in ascending order //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- if (!cnn.Init(onnx_model)) //Initialize the ONNX model return INIT_FAILED; //--- Initializing the scaler with values loaded from binary files scaler = new StandardizationScaler(scaler_mean, scaler_stddev); //load the scaler return(INIT_SUCCEEDED); }
Eso es suficiente para poner en marcha el modelo. Hagamos que la función extraiga los datos de forma similar a como se utilizaron las variables independientes durante el entrenamiento. Utilizamos cuatro variables valores OHLC desde la barra cerrada anterior hasta 10 barras anteriores que era el tamaño de ventana que debe conservar el timeframe (Un marco temporal diario).
input group "cnn"; input uint cnn_data_window = 10; //this value must be the same as the one used during training in a python script input ENUM_TIMEFRAMES timeframe = PERIOD_D1; input int magic_number = 1945; input int slippage = 50;
matrix GetXVars(int bars, int start_bar=1) { vector open(bars), high(bars), low(bars), close(bars); //--- Getting OHLC values open.CopyRates(Symbol(), timeframe, COPY_RATES_OPEN, start_bar, bars); high.CopyRates(Symbol(), timeframe, COPY_RATES_HIGH, start_bar, bars); low.CopyRates(Symbol(), timeframe, COPY_RATES_LOW, start_bar, bars); close.CopyRates(Symbol(), timeframe, COPY_RATES_CLOSE, start_bar, bars); //--- matrix data(bars, 4); //we have 10 inputs from cnn | this value is fixed //--- adding the features into a data matrix data.Col(open, 0); data.Col(high, 1); data.Col(low, 2); data.Col(close, 3); return data; }
Ahora que tenemos una función para recoger las variables independientes, podemos finalizar nuestra estrategia de negociación.
void OnTick() { //--- if (NewBar()) //Trade at the opening of a new candle { matrix input_data_matrix = GetXVars(cnn_data_window); //get data for the past 10 days(default) input_data_matrix = scaler.transform(input_data_matrix); //applying StandardSCaler to the input data int signal = cnn.predict_bin(input_data_matrix, classes_in_y); //getting trade signal from the RNN model Comment("Signal==",signal); //--- MqlTick ticks; SymbolInfoTick(Symbol(), ticks); if (signal==1) //if the signal is bullish { if (!PosExists(POSITION_TYPE_BUY)) //There are no buy positions { if (!m_trade.Buy(lotsize, Symbol(), ticks.ask, 0, 0)) //Open a buy trade printf("Failed to open a buy position err=%d",GetLastError()); ClosePosition(POSITION_TYPE_SELL); //close opposite trade } } else if (signal==0) //Bearish signal { if (!PosExists(POSITION_TYPE_SELL)) //There are no Sell positions if (!m_trade.Sell(lotsize, Symbol(), ticks.bid, 0, 0)) //open a sell trade printf("Failed to open a sell position err=%d",GetLastError()); ClosePosition(POSITION_TYPE_BUY); } else //There was an error return; } }
La estrategia es sencilla. Al recibir una señal en particular, digamos una señal de compra, abrimos una operación de compra sin valores de stop loss y take profit, luego cerramos la señal opuesta y viceversa para una señal de venta.
Finalmente, probé esta estrategia en un símbolo en el que fue entrenada que es EURUSD, durante diez años. Desde 2014.01.01 hasta 2024.05.27 en un gráfico de 4 Horas sobre precios de apertura de cada barra.
Los resultados del probador de estrategia fueron sobresalientes.
El EA realizó predicciones precisas el 58% de las veces y, como resultado, el EA basado en CNN obtuvo una ganancia neta de $503.
El resultado final
A pesar de estar hecho específicamente para el procesamiento de imágenes y vídeos, cuando se adopta para manejar datos tabulares como los datos de forex que le proporcionamos. Las redes neuronales convolucionales (CNN) pueden hacer un buen trabajo detectando patrones y usarlos para hacer predicciones en el mercado de divisas.
Como se puede ver en el informe del probador de estrategia. El EA basado en CNN ha realizado predicciones decentes; apuesto a que muchos modelos tradicionales diseñados para datos tabulares como regresión lineal, máquina de vectores de soporte, Bayes naive, etc. no pueden lograr esta precisión predictiva considerando que al modelo CNN se le dieron solo 4 variables independientes (OHLC). En mi experiencia, no muchos modelos pueden llegar a ser tan buenos dadas unas pocas variables.
¡Saludos!
Siga el desarrollo de modelos de aprendizaje automático y mucho más discutido en esta serie de artículos en este repositorio de GitHub.
Tabla de archivos adjuntos
Nombre del archivo | Tipo de archivo | Descripción y uso |
---|---|---|
ConvNet EA.mq5 | Asesor experto | Robot comercial para cargar el modelo CNN en formato ONNX y probar la estrategia comercial final en MetaTrader 5. |
cnn.EURUSD.D1.onnx | ONNX | Modelo CNN en formato ONNX. |
cnn.EURUSD.D1.standard_scaler_mean.bin cnn.EURUSD.D1.standard_scaler_scale.bin | Archivos binarios | Archivos binarios para el escalador de estandarización |
preprocessing.mqh | Archivo de inclusión | Una librería que consta del escalador de estandarización |
ConvNet.mqh | Archivo de inclusión | Una librería para cargar e implementar modelos CNN en formato ONNX |
cnn-for-trading-applications-tutorial.ipynb | Python Script/Jupyter Notebook | Contiene todo el código Python analizado en este artículo. |
Fuentes y referencias
- Una nueva estrategia de seguimiento profundo de tendencias basada en redes neuronales convolucionales para operar en bolsa (https://ceur-ws.org/Vol-3052/paper2.pdf)
- ¿Qué son las redes neuronales convolucionales (CNN)? (https://youtu.be/QzY57FaENXg)
- Conversión de datos tabulares en imágenes para el aprendizaje profundo con redes neuronales convolucionales (https://www.nature.com/articles/s41598-021-90923-y)
- Image kernels (https://setosa.io/ev/image-kernels/)
- Revisión de los métodos de agrupación en redes neuronales profundas (https://arxiv.org/pdf/2009.07485)
Traducción del inglés realizada por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/en/articles/15259





- Aplicaciones de trading gratuitas
- 8 000+ señales para copiar
- Noticias económicas para analizar los mercados financieros
Usted acepta la política del sitio web y las condiciones de uso