Visión por computadora para el trading (Parte 1): Creamos una funcionalidad básica sencilla
Introducción
En el silencioso parpadeo de los monitores, donde los gráficos de velas trazan las sinuosas trayectorias de los flujos financieros, está por nacer una nueva era del trading. ¿Se ha preguntado alguna vez qué siente una red neuronal al observar el mercado EURUSD? ¿Cómo percibe cada pico de volatilidad, cada cambio de tendencia, cada escurridiza formación de patrones?
Imagínese: una computadora que no se limita a aplicar sin pensar reglas preprogramadas, sino que realmente ve el mercado y capta los sutiles matices de los movimientos de los precios que son inaccesibles al ojo humano. Inteligencia artificial que mira el gráfico del EURUSD como un capitán experimentado mira el horizonte del mar, anticipando la llegada de una tormenta mucho antes de los primeros signos de mal tiempo.
Hoy les propongo un viaje a la vanguardia de la tecnología financiera, donde la visión por computadora se une al análisis bursátil. Así, crearemos un sistema que no se limite a analizar el mercado, sino que lo entienda visualmente, reconociendo patrones complejos de movimiento de precios con la misma naturalidad con la que se reconoce la cara de un amigo entre la multitud.

En un mundo en el que los milisegundos deciden el destino de millones de personas, nuestro modelo basado en redes neuronales convolucionales abre la puerta a una nueva dimensión del análisis técnico. No usa indicadores estándar, sino que aprende por sí mismo a encontrar e interpretar señales directamente a partir de los datos OHLC sin procesar. Y lo sorprendente es que podemos mirar dentro de su "mente" y ver exactamente qué fragmentos del gráfico le llaman la atención antes de tomar su decisión.
Historia y aplicaciones de los modelos de visión por computadora
La visión por computadora nació en los años 60 en el MIT, cuando los investigadores intentaron por primera vez enseñar a las máquinas a interpretar la información visual. Al principio, el desarrollo fue lento: los primeros sistemas solo podían reconocer las formas y contornos más simples.
El verdadero avance se produjo en 2012 con la llegada de las redes neuronales convolucionales profundas (CNN), que revolucionaron el sector. La arquitectura AlexNet demostró en la competición ImageNet una precisión sin precedentes en el reconocimiento de imágenes, iniciando la era del aprendizaje profundo.
Hoy en día, la visión por computadora ha transformado multitud de industrias. En medicina, los algoritmos analizan radiografías y resonancias magnéticas con una precisión comparable a la de radiólogos experimentados. En la industria del automóvil, los sistemas de asistencia al conductor y los pilotos automáticos usan CV para reconocer objetos de la carretera. Los smartphones utilizan esta tecnología para la mejora de fotos y el desbloqueo mediante reconocimiento facial, usado por los sistemas de seguridad para controlar el acceso.
La aplicación de la visión por computadora al análisis financiero es un campo nuevo y prometedor. Los algoritmos de CV son capaces de reconocer patrones y formaciones complejas en los gráficos que no están al alcance de los indicadores técnicos tradicionales, lo que abre nuevos horizontes al trading algorítmico.
Base tecnológica: conexión con los datos del mercado
Nuestro viaje comienza estableciendo una conexión en vivo con el mercado. Como terminaciones nerviosas que buscan el pulso de los flujos financieros, nuestro código se conecta al terminal MetaTrader 5, una herramienta clásica de los tráders que ahora se ha transformado en un portal para la inteligencia artificial:
import MetaTrader5 as mt5 import matplotlib matplotlib.use('Agg') # Использование бэкенда Agg для работы без GUI import matplotlib.pyplot as plt from tensorflow.keras.models import Sequential, Model from tensorflow.keras.layers import Dense, Conv1D, MaxPooling1D, Flatten, Dropout, BatchNormalization, Input # Подключение к терминалу MetaTrader5 def connect_to_mt5(): if not mt5.initialize(): print("Error initializing MetaTrader5") mt5.shutdown() return False return True
Las primeras líneas de código suponen el apretón de manos entre el mundo de los algoritmos y el de las finanzas. Parece una simple llamada a una función, pero detrás se esconde la creación de un canal por el que fluirán gigabytes de datos de mercado, cotizaciones formadas en la intersección de las decisiones de millones de tráders de todo el mundo.
Nuestro sistema usará el backend de Agg para la visualización sin interfaz gráfica, un detalle pequeño pero importante que le permite funcionar en segundo plano en servidores remotos sin interrumpir ni un segundo su vigilancia del mercado.
Inmersión en la historia: recogida y preparación de datos
Cualquier inteligencia artificial parte de los datos. Para nuestro sistema, hablamos de miles de velas horarias de EURUSD, testigos silenciosos de las batallas de precios pasadas, que contienen patrones que tratamos de descubrir:
def get_historical_data(symbol="EURUSD", timeframe=mt5.TIMEFRAME_H1, num_bars=1000): now = datetime.now() from_date = now - timedelta(days=num_bars/24) # Approximate for hourly bars rates = mt5.copy_rates_range(symbol, timeframe, from_date, now) if rates is None or len(rates) == 0: print("Error loading historical quotes") return None # Convert to pandas DataFrame rates_frame = pd.DataFrame(rates) rates_frame['time'] = pd.to_datetime(rates_frame['time'], unit='s') rates_frame.set_index('time', inplace=True) return rates_frame
En esta función comienza la magia: los bytes en bruto se convierten en un flujo ordenado de datos. Cada vela, cada fluctuación de precios se convierte en un punto de un espacio multidimensional que nuestra red neuronal debe explorar. Nosotros vamos a cargar 2.000 barras de la historia, suficientes para que el modelo vea una cierta variedad de condiciones de mercado, desde tendencias tranquilas hasta periodos caóticos de alta volatilidad.
Pero la visión por computadora no solo necesita números, sino también imágenes. El siguiente paso consiste en transformar las series temporales en "imágenes" que nuestra red convolucional pueda analizar:
def create_images(data, window_size=48, prediction_window=24): images = [] targets = [] # Using OHLC data to create images for i in range(len(data) - window_size - prediction_window): window_data = data.iloc[i:i+window_size] target_data = data.iloc[i+window_size:i+window_size+prediction_window] # Normalize data in the window scaler = MinMaxScaler(feature_range=(0, 1)) window_scaled = scaler.fit_transform(window_data[['open', 'high', 'low', 'close']]) # Predict price direction (up/down) for the forecast period price_direction = 1 if target_data['close'].iloc[-1] > window_data['close'].iloc[-1] else 0 images.append(window_scaled) targets.append(price_direction) return np.array(images), np.array(targets)
Esta es la alquimia de datos en estado puro. Así, tomamos una ventana de 48 barras de precios consecutivas, normalizamos sus valores entre 0 y 1 y las convertimos en una imagen multicanal en la que cada canal se corresponde con uno de los componentes OHLC. Para cada uno de estos "fotogramas" de la historia del mercado definimos un valor objetivo: la dirección del movimiento del precio en 24 barras en el futuro.
Una ventana deslizante se desplaza secuencialmente por todo el conjunto de datos, creando miles de ejemplos para el entrenamiento. Es como si un tráder experimentado hojeara los gráficos históricos, se empapara de las pautas del mercado y aprendiera a reconocer las situaciones que preceden a movimientos significativos.
Construyendo un "ojo" neuronal: la arquitectura del modelo
Vamos a pasar ahora a construir la red neuronal propiamente dicha: un ojo artificial que se adentrará en el caos de los datos del mercado en busca de un orden oculto. Nuestra arquitectura se inspira en los recientes avances de la visión por computadora, pero adaptada a la especificidad de las series temporales financieras:
def train_cv_model(images, targets): # Split data into training and validation sets X_train, X_val, y_train, y_val = train_test_split(images, targets, test_size=0.2, shuffle=True, random_state=42) # Create model with improved architecture inputs = Input(shape=X_train.shape[1:]) # First convolutional block x = Conv1D(filters=64, kernel_size=3, padding='same', activation='relu')(inputs) x = BatchNormalization()(x) x = Conv1D(filters=64, kernel_size=3, padding='same', activation='relu')(x) x = BatchNormalization()(x) x = MaxPooling1D(pool_size=2)(x) x = Dropout(0.2)(x) # Second convolutional block x = Conv1D(filters=128, kernel_size=3, padding='same', activation='relu')(x) x = BatchNormalization()(x) x = Conv1D(filters=128, kernel_size=3, padding='same', activation='relu')(x) x = BatchNormalization()(x) x = MaxPooling1D(pool_size=2)(x) feature_maps = x # Store feature maps for visualization x = Dropout(0.2)(x) # Output block x = Flatten()(x) x = Dense(128, activation='relu')(x) x = BatchNormalization()(x) x = Dropout(0.3)(x) x = Dense(64, activation='relu')(x) x = BatchNormalization()(x) x = Dropout(0.3)(x) outputs = Dense(1, activation='sigmoid')(x) # Create the full model model = Model(inputs=inputs, outputs=outputs) # Create a feature extraction model for visualization feature_model = Model(inputs=model.input, outputs=feature_maps)
En este caso, vamos a usar la API funcional de Keras en lugar de un modelo secuencial, esto nos da la flexibilidad de crear un modelo adicional que extrae vistas intermedias para la visualización. Este es un elemento clave de nuestro planteamiento: no solo estamos construyendo un sistema de predicción, sino también una herramienta para mirar dentro de la "conciencia" de la inteligencia artificial.
La arquitectura consta de dos bloques convolucionales, cada uno de los cuales contiene dos capas convolucionales con normalización por lotes. El primer bloque funciona con 64 filtros, y el segundo con 128, revelando gradualmente patrones cada vez más complejos. Tras la extracción de características, los datos pasan por varias capas completamente conectadas que integran la información obtenida para la predicción final.
Entrenar un modelo no consiste únicamente en minimizar la función de pérdida, sino que es un auténtico viaje a través del paisaje de parámetros en el que cada iteración nos acerca más al objetivo:
# Early stopping to prevent overfitting early_stopping = EarlyStopping( monitor='val_loss', patience=10, restore_best_weights=True, verbose=1 ) # Train model history = model.fit( X_train, y_train, epochs=50, batch_size=32, validation_data=(X_val, y_val), callbacks=[early_stopping], verbose=1 )
Usamos Early Stopping para evitar el sobreentrenamiento: la red neuronal dejará de entrenarse cuando deje de mejorar en el conjunto de validación. Esto nos permite encontrar la media de oro entre el infraentrenamiento y el sobreentrenamiento, el punto de máxima generalizabilidad.

La mente de la inteligencia artificial
La singularidad de nuestro enfoque reside en la capacidad de visualizar exactamente cómo el modelo "ve" el mercado. Hemos desarrollado dos funciones especiales que permiten escrutar los misterios de la computación neuronal:
def visualize_model_perception(feature_model, last_window_scaled, window_size=48): # Get feature maps for the last window feature_maps = feature_model.predict(np.array([last_window_scaled]))[0] # Plot feature maps plt.figure(figsize=(7, 10)) # Plot original data plt.subplot(5, 1, 1) plt.title("Original Price Data (Normalized)") plt.plot(np.arange(window_size), last_window_scaled[:, 0], label='Open', alpha=0.7) plt.plot(np.arange(window_size), last_window_scaled[:, 1], label='High', alpha=0.7) plt.plot(np.arange(window_size), last_window_scaled[:, 2], label='Low', alpha=0.7) plt.plot(np.arange(window_size), last_window_scaled[:, 3], label='Close', color='black', linewidth=2) # Plot candlestick representation plt.subplot(5, 1, 2) plt.title("Candlestick Representation") # Width of the candles width = 0.6 for i in range(len(last_window_scaled)): # Candle color if last_window_scaled[i, 3] >= last_window_scaled[i, 0]: # close >= open color = 'green' body_bottom = last_window_scaled[i, 0] # open body_height = last_window_scaled[i, 3] - last_window_scaled[i, 0] # close - open else: color = 'red' body_bottom = last_window_scaled[i, 3] # close body_height = last_window_scaled[i, 0] - last_window_scaled[i, 3] # open - close # Candle body plt.bar(i, body_height, bottom=body_bottom, color=color, width=width, alpha=0.5) # Candle wicks plt.plot([i, i], [last_window_scaled[i, 2], last_window_scaled[i, 1]], color='black', linewidth=1) # Plot feature maps visualization (first 3 channels) plt.subplot(5, 1, 3) plt.title("Feature Map Channel 1 - Pattern Recognition") plt.plot(time_indices, feature_maps[:, 0], color='blue') plt.subplot(5, 1, 4) plt.title("Feature Map Channel 2 - Trend Detection") plt.plot(time_indices, feature_maps[:, 1], color='orange') plt.subplot(5, 1, 5) plt.title("Feature Map Channel 3 - Volatility Detection") plt.plot(time_indices, feature_maps[:, 2], color='green')
Esta función crea una visualización multipanel que muestra los datos de origen, la representación en velas y las activaciones de los tres primeros canales del filtro convolucional. Cada canal se especializa en un aspecto concreto de la dinámica del mercado: uno capta las pautas que se repiten, otro se centra en las tendencias y otro reacciona ante la volatilidad. Es como descubrir la especialización de las distintas áreas del cerebro de un tráder experimentado.

Los resultados del mapa de calor de la atención resultan aún más interesantes:
def visualize_attention_heatmap(feature_model, last_window_scaled, window_size=48): # Get feature maps for the last window feature_maps = feature_model.predict(np.array([last_window_scaled]))[0] # Average activation across all channels to get a measure of "attention" avg_activation = np.mean(np.abs(feature_maps), axis=1) # Normalize to [0, 1] for visualization attention = (avg_activation - np.min(avg_activation)) / (np.max(avg_activation) - np.min(avg_activation)) # Upsample attention to match original window size upsampled_attention = np.zeros(window_size) ratio = window_size / len(attention) for i in range(len(attention)): start_idx = int(i * ratio) end_idx = int((i+1) * ratio) upsampled_attention[start_idx:end_idx] = attention[i] # Plot the heatmap plt.figure(figsize=(7, 6)) # Price plot with attention heatmap plt.subplot(2, 1, 1) plt.title("Model Attention Heatmap") # Plot close prices time_indices = np.arange(window_size) plt.plot(time_indices, last_window_scaled[:, 3], color='black', linewidth=2, label='Close Price') # Add shading based on attention plt.fill_between(time_indices, last_window_scaled[:, 3].min(), last_window_scaled[:, 3].max(), alpha=upsampled_attention * 0.5, color='red') # Highlight points with high attention high_attention_threshold = 0.7 high_attention_indices = np.where(upsampled_attention > high_attention_threshold)[0] plt.scatter(high_attention_indices, last_window_scaled[high_attention_indices, 3], color='red', s=50, zorder=5, label='High Attention Points')
Esta función crea un verdadero mapa de la mente del modelo, mostrando a qué partes del gráfico le presta más atención a la hora de tomar una decisión. Las zonas rojas de mayor atención suelen coincidir con niveles clave y puntos pivote, lo cual confirma que nuestro modelo sí ha aprendido a destacar formaciones de precios significativas.

De la previsión al beneficio: la aplicación práctica
El colofón final de nuestro sistema es la visualización de la previsión y su presentación de forma comprensible para los tráders:
def plot_prediction(data, window_size=48, prediction_window=24, direction="UP ▲"): plt.figure(figsize=(7, 4.2)) # Get the last window of data for visualization last_window = data.iloc[-window_size:] # Create time index for prediction last_date = last_window.index[-1] future_dates = pd.date_range(start=last_date, periods=prediction_window+1, freq=data.index.to_series().diff().mode()[0])[1:] # Plot closing prices plt.plot(last_window.index, last_window['close'], label='Historical Data') # Add marker for current price current_price = last_window['close'].iloc[-1] plt.scatter(last_window.index[-1], current_price, color='blue', s=100, zorder=5) plt.annotate(f'Current price: {current_price:.5f}', xy=(last_window.index[-1], current_price), xytext=(10, -30), textcoords='offset points', fontsize=10, arrowprops=dict(arrowstyle='->', color='black')) # Visualize the predicted direction arrow_start = (last_window.index[-1], current_price) # Calculate range for the arrow (approximately 10% of price range) price_range = last_window['high'].max() - last_window['low'].min() arrow_length = price_range * 0.1 # Up or down prediction if direction == "UP ▲": arrow_end = (future_dates[-1], current_price + arrow_length) arrow_color = 'green' else: arrow_end = (future_dates[-1], current_price - arrow_length) arrow_color = 'red' # Direction arrow plt.annotate('', xy=arrow_end, xytext=arrow_start, arrowprops=dict(arrowstyle='->', lw=2, color=arrow_color)) plt.title(f'EURUSD - Forecast for {prediction_window} periods: {direction}')
Esta visualización convierte una predicción abstracta en una señal comercial clara. Las flechas verdes indican una subida prevista, mientras que las flechas rojas indican una caída. Los tráders puede evaluar instantáneamente la situación actual y tomar una decisión respaldada por un análisis de inteligencia artificial.
Pero nuestro sistema va más allá de la simple predicción de la dirección. Cuantifica la confianza en la previsión:
# Predict on the last available window def make_prediction(model, data, window_size=48): # Get the last window of data last_window = data.iloc[-window_size:][['open', 'high', 'low', 'close']] # Normalize data scaler = MinMaxScaler(feature_range=(0, 1)) last_window_scaled = scaler.fit_transform(last_window) # Prepare data for the model last_window_reshaped = np.array([last_window_scaled]) # Get prediction prediction = model.predict(last_window_reshaped)[0][0] # Interpret result direction = "UP ▲" if prediction > 0.5 else "DOWN ▼" confidence = prediction if prediction > 0.5 else 1 - prediction return direction, confidence * 100, last_window_scaled
El valor de salida de la red neuronal se interpreta no solo como una respuesta binaria, sino como una probabilidad de movimiento alcista. Esto permite al tráder tomar decisiones informadas considerando no solo la dirección, sino también la confianza del sistema en su previsión. Una previsión con un 95% de confianza puede merecer una postura más agresiva que una previsión con un 55%.
Orquestación de procesos: la función principal
Todos los elementos del sistema confluyen en una función principal que coordina todo el proceso, desde la conexión a los datos hasta la visualización de los resultados:
def main(): print("Starting EURUSD prediction system with computer vision") # Connect to MT5 if not connect_to_mt5(): return print("Successfully connected to MetaTrader5") # Load historical data bars_to_load = 2000 # Load more than needed for training data = get_historical_data(num_bars=bars_to_load) if data is None: mt5.shutdown() return print(f"Loaded {len(data)} bars of EURUSD history") # Convert data to image format print("Converting data for computer vision processing...") images, targets = create_images(data) print(f"Created {len(images)} images for training") # Train model print("Training computer vision model...") model, history, feature_model = train_cv_model(images, targets) # Visualize training process plot_learning_history(history) # Prediction direction, confidence, last_window_scaled = make_prediction(model, data) print(f"Forecast for the next 24 periods: {direction} (confidence: {confidence:.2f}%)") # Visualize prediction plot_prediction(data, direction=direction) # Visualize how the model "sees" the market visualize_model_perception(feature_model, last_window_scaled) # Visualize attention heatmap visualize_attention_heatmap(feature_model, last_window_scaled) # Disconnect from MT5 mt5.shutdown() print("Work completed")
Esta función es como un director de orquesta que gestiona una compleja sinfonía de datos y algoritmos. Nos lleva secuencialmente a través de todo el proceso, desde la primera conexión al terminal hasta las visualizaciones finales que revelan el mundo interior de la inteligencia artificial.
Conclusión: una nueva era de negociación algorítmica
Hoy hemos creado algo más que otro indicador técnico o un sistema comercial más. Nuestro modelo de visión por computadora supone una nueva forma de percibir el mercado, una herramienta que nos permite mirar más allá de la visión humana y descubrir patrones ocultos en el ruido de las fluctuaciones de precio.
No es solo una caja negra que emite señales de origen desconocido. Gracias a las visualizaciones, podemos ver cómo percibe el mercado el modelo, a qué características de los movimientos de precios presta atención y cómo se forman sus previsiones. Y esto crea un nuevo nivel de confianza y entendimiento entre el tráder y el algoritmo.
En una era en la que los algoritmos de alta frecuencia ejecutan millones de transacciones por segundo, nuestro sistema representa un enfoque diferente y más profundo del trading algorítmico, un enfoque basado no en la velocidad de ejecución, sino en una comprensión profunda de la dinámica del mercado a través de la lente de la visión por computadora.
El código es abierto, la tecnología está disponible y los resultados son impresionantes. Su viaje al mundo de la visión por computadora para el trading no ha hecho más que empezar. Y quién sabe, quizá esta misma visión (a través del prisma algorítmico de las redes neuronales) le permita ver lo que antes permanecía invisible y encontrar la clave para entender los movimientos siempre cambiantes de las cotizaciones de las divisas.
Imagine una sesión comercial del futuro: en su pantalla no solo aparecerán los tradicionales gráficos de velas y líneas indicadoras, sino también una visualización en directo de cómo la inteligencia artificial percibe la situación actual del mercado, qué patrones destaca y a qué niveles de precios presta especial atención. No es ciencia ficción: es tecnología disponible hoy en día. Solo le queda dar un paso hacia la nueva era del trading algorítmico.
Traducción del ruso hecha por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/ru/articles/17981
Advertencia: todos los derechos de estos materiales pertenecen a MetaQuotes Ltd. Queda totalmente prohibido el copiado total o parcial.
Este artículo ha sido escrito por un usuario del sitio web y refleja su punto de vista personal. MetaQuotes Ltd. no se responsabiliza de la exactitud de la información ofrecida, ni de las posibles consecuencias del uso de las soluciones, estrategias o recomendaciones descritas.
Utilizando redes neuronales en MetaTrader
Del básico al intermedio: Indicador (V)
Particularidades del trabajo con números del tipo double en MQL4
Creación de interfaces gráficas dinámicas MQL5 mediante el escalado de imágenes basado en recursos con interpolación bicúbica en gráficos de trading
- 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