preview
Компьютерное зрение для трейдинга (Часть 1): Создаем базовый простой функционал

Компьютерное зрение для трейдинга (Часть 1): Создаем базовый простой функционал

MetaTrader 5Торговые системы |
836 0
Yevgeniy Koshtenko
Yevgeniy Koshtenko

Введение

В тихом мерцании мониторов, где свечные графики рисуют извилистые пути финансовых потоков, рождается новая эра трейдинга. Вы когда-нибудь задумывались, что чувствует нейронная сеть, глядя на рынок EURUSD? Как она воспринимает каждый всплеск волатильности, каждый разворот тренда, каждую неуловимую паттерн-формацию?

Представьте себе: компьютер, который не просто бездумно применяет заранее запрограммированные правила, а по-настоящему видит рынок — улавливает тончайшие нюансы ценовых движений, недоступные человеческому глазу. Искусственный интеллект, который смотрит на график EURUSD так, как опытный капитан смотрит на океанский горизонт, предчувствуя приближение шторма задолго до первых признаков непогоды.

Сегодня я приглашаю вас в путешествие на передовую финансовых технологий, туда, где компьютерное зрение встречается с биржевой аналитикой. Мы создадим систему, которая не просто анализирует рынок — она понимает его визуально, распознавая сложные образы движения цен так же естественно, как вы распознаёте лицо друга в толпе.

В мире, где миллисекунды решают судьбу миллионов, наша модель на базе сверточных нейронных сетей открывает дверь в новое измерение технического анализа. Она не использует стандартные индикаторы — она сама учится находить и интерпретировать сигналы прямо из сырых данных OHLC. И самое удивительное — мы можем заглянуть внутрь её "сознания", увидеть, какие именно фрагменты графика привлекают её внимание перед принятием решения.


История и применение моделей компьютерного зрения

Компьютерное зрение родилось в 1960-х годах в стенах МТИ, когда исследователи впервые попытались научить машины интерпретировать визуальную информацию. Изначально развитие было медленным: первые системы могли распознавать лишь простейшие формы и контуры.

Настоящий прорыв произошел в 2012 году с появлением глубоких сверточных нейронных сетей (CNN), революционизировавших отрасль. Архитектура AlexNet на конкурсе ImageNet продемонстрировала беспрецедентную точность распознавания изображений, открыв эру глубокого обучения.

Сегодня компьютерное зрение трансформирует множество отраслей. В медицине алгоритмы анализируют рентгеновские снимки и МРТ с точностью, сравнимой с опытными радиологами. В автомобильной индустрии системы помощи водителю и автопилоты используют CV для распознавания дорожных объектов. Смартфоны применяют технологию для улучшения фотографий и разблокировки по лицу. Системы безопасности используют распознавание лиц для контроля доступа.

Применение компьютерного зрения в финансовом анализе — новая и перспективная область. Алгоритмы CV способны распознавать сложные паттерны и формации на графиках, недоступные традиционным техническим индикаторам, открывая новые горизонты для алгоритмической торговли.


Технологический фундамент: подключение к рыночным данным

Наше путешествие начинается с установления живой связи с рынком. Подобно нервным окончаниям, тянущимся к пульсу финансовых потоков, наш код подключается к терминалу MetaTrader 5 — классическому инструменту трейдера, ставшему теперь порталом для искусственного интеллекта:

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

Первые строки кода — это рукопожатие между миром алгоритмов и миром финансов. Казалось бы, простой вызов функции, но за ним скрывается создание канала, по которому потекут гигабайты рыночных данных, котировки, формировавшиеся на пересечении миллионов решений трейдеров со всего мира.

Наша система будет использовать бэкенд Agg для визуализации без графического интерфейса — небольшая, но важная деталь, позволяющая ей работать в фоновом режиме на удалённых серверах, не прерывая своего бдительного наблюдения за рынком даже на секунду.


Погружение в историю: сбор и подготовка данных

Любой искусственный интеллект начинается с данных. Для нашей системы это тысячи часовых свечей EURUSD — молчаливые свидетели прошлых ценовых баталий, хранящие в себе закономерности, которые мы стремимся раскрыть:

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

В этой функции происходит первая магия — сырые байты превращаются в упорядоченный поток данных. Каждая свеча, каждое колебание цены становится точкой в многомерном пространстве, которое предстоит исследовать нашей нейронной сети. Мы загружаем 2000 баров истории — достаточно, чтобы модель смогла увидеть разнообразные рыночные условия, от спокойных трендов до хаотичных периодов высокой волатильности.

Но для компьютерного зрения нужны не просто цифры, а образы. Следующий шаг — трансформация временных рядов в "изображения", которые сможет проанализировать наша сверточная сеть:

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)

Это алхимия данных в чистом виде. Мы берем окно из 48 последовательных ценовых баров, нормализуем их значения в диапазоне от 0 до 1, и превращаем в многоканальное изображение, где каждый канал соответствует одному из компонентов OHLC. Для каждого такого "кадра" рыночной истории мы определяем целевое значение — направление движения цены через 24 бара в будущем.

Скользящее окно последовательно перемещается по всему набору данных, создавая тысячи примеров для обучения. Это похоже на опытного трейдера, который пролистывает исторические графики, впитывая закономерности рынка и учась распознавать ситуации, предшествующие значимым движениям.


Конструирование нейронного "глаза": архитектура модели

Теперь приступаем к созданию самой нейронной сети — искусственного глаза, который будет вглядываться в хаос рыночных данных в поисках скрытого порядка. Наша архитектура вдохновлена последними достижениями в области компьютерного зрения, но адаптирована для специфики финансовых временных рядов:

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)

Мы используем функциональный API Keras вместо последовательной модели — это дает нам гибкость для создания дополнительной модели, извлекающей промежуточные представления для визуализации. Это ключевой элемент нашего подхода: мы не только создаем систему прогнозирования, но и инструмент для заглядывания внутрь "сознания" искусственного интеллекта.

Архитектура состоит из двух сверточных блоков, каждый из которых содержит по два сверточных слоя с пакетной нормализацией. Первый блок работает с 64 фильтрами, второй — со 128, постепенно выявляя всё более сложные закономерности. После извлечения признаков, данные проходят через несколько полносвязных слоев, которые интегрируют полученную информацию для итогового прогноза.

Обучение модели — это не просто минимизация функции потерь, это настоящее путешествие по ландшафту параметров, где каждая итерация приближает нас к цели:

# 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
)

Мы используем Early Stopping для предотвращения переобучения — нейронная сеть прекратит обучение, когда перестанет улучшаться на валидационном наборе. Это позволяет найти золотую середину между недообучением и переобучением, точку максимальной обобщающей способности.


Заглядывая в сознание искусственного интеллекта

Уникальность нашего подхода — возможность визуализировать, как именно модель "видит" рынок. Мы разработали две специальные функции, позволяющие заглянуть в тайны нейронных вычислений:

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')

Эта функция создает многопанельную визуализацию, показывающую исходные данные, свечную репрезентацию и активации первых трех каналов сверточных фильтров. Каждый канал специализируется на определенном аспекте рыночной динамики: один улавливает повторяющиеся паттерны, другой фокусируется на трендах, третий реагирует на волатильность. Это подобно раскрытию специализации разных областей мозга опытного трейдера.

Еще более захватывающие результаты дает тепловая карта внимания:

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')

Эта функция создает настоящую карту сознания модели, показывая, на какие участки графика она обращает наибольшее внимание при принятии решения. Красные зоны повышенного внимания часто совпадают с ключевыми уровнями и точками разворота, что подтверждает: наша модель действительно научилась выделять значимые ценовые формации.


От прогноза к прибыли: практическое применение

Финальный аккорд нашей системы — визуализация прогноза и его представление в понятной для трейдера форме:

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}')

Эта визуализация превращает абстрактный прогноз в четкий торговый сигнал. Зеленая стрелка указывает на ожидаемый рост, красная — на падение. Трейдер может мгновенно оценить текущую ситуацию и принять решение, подкрепленное анализом искусственного интеллекта.

Но наша система идет дальше простого предсказания направления. Она дает количественную оценку уверенности в прогнозе:

# 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

Выходное значение нейронной сети интерпретируется не просто как бинарный ответ, но как вероятность движения вверх. Это позволяет трейдеру принимать взвешенные решения, учитывая не только направление, но и уверенность системы в своем прогнозе. Прогноз с уверенностью 95% может заслуживать более агрессивной позиции, чем прогноз с уверенностью 55%.


Оркестровка процесса: главная функция

Все элементы системы объединяются в главной функции, которая координирует весь процесс — от подключения к данным до визуализации результатов:

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")

Эта функция словно дирижер, управляющий сложной симфонией данных и алгоритмов. Она последовательно проводит нас через весь процесс, от первого подключения к терминалу, до финальных визуализаций, раскрывающих внутренний мир искусственного интеллекта.


Заключение: новая эра алгоритмического трейдинга

Мы создали нечто большее, чем просто очередной технический индикатор или торговую систему. Наша модель компьютерного зрения — это новый способ восприятия рынка, инструмент, позволяющий заглянуть за пределы человеческого видения и обнаружить закономерности, скрытые в шуме ценовых колебаний.

Это не просто черный ящик, выдающий сигналы неизвестного происхождения. Благодаря визуализациям, мы можем видеть, как модель воспринимает рынок, на какие особенности ценового движения она обращает внимание, как формируются ее прогнозы. Это создает новый уровень доверия и понимания между трейдером и алгоритмом.

В эпоху, когда высокочастотные алгоритмы совершают миллионы сделок в секунду, наша система представляет другой, более глубокий подход к алгоритмической торговле — подход, основанный не на скорости исполнения, а на глубоком понимании рыночной динамики через призму компьютерного зрения.

Код открыт, технология доступна, результаты впечатляют. Ваше путешествие в мир компьютерного зрения для трейдинга только начинается. И кто знает, может быть, именно этот взгляд — через алгоритмическую призму нейронных сетей — позволит вам увидеть то, что раньше оставалось невидимым, и найти ключ к пониманию вечно меняющегося танца валютных котировок.

Представьте себе торговую сессию будущего: на вашем экране не только традиционные свечные графики и линии индикаторов, но и живая визуализация того, как искусственный интеллект воспринимает текущую рыночную ситуацию, какие паттерны он выделяет, на какие ценовые уровни обращает особое внимание. Это не фантастика — это технология, доступная уже сегодня. Осталось только сделать шаг навстречу новой эре алгоритмического трейдинга.

Прикрепленные файлы |
CV_Model.py (15.71 KB)
Нейросети в трейдинге: Прогнозирование временных рядов при помощи адаптивного модального разложения (ACEFormer) Нейросети в трейдинге: Прогнозирование временных рядов при помощи адаптивного модального разложения (ACEFormer)
Предлагаем познакомиться с архитектурой ACEFormer — современным решением, сочетающим эффективность вероятностного внимания и адаптивное разложение временных рядов. Материал будет полезен тем, кто ищет баланс между вычислительной производительностью и точностью прогноза на финансовых рынках.
MQL5-советник, интегрированный в Telegram (Часть 7): Анализ команд для автоматизации индикаторов на графиках MQL5-советник, интегрированный в Telegram (Часть 7): Анализ команд для автоматизации индикаторов на графиках
В этой статье мы узнаем, как интегрировать команды Telegram с MQL5 для автоматизации добавления индикаторов на торговые графики. Мы рассмотрим процесс анализа пользовательских команд, их выполнение на языке MQL5 и тестирование системы для обеспечения бесперебойной торговли на основе индикаторов.
Арбитражный трейдинг Forex: Матричная торговая система на возврат к справедливой стоимости с ограничением риска Арбитражный трейдинг Forex: Матричная торговая система на возврат к справедливой стоимости с ограничением риска
Статья содержит детальное описание алгоритма расчета кросс-курсов, визуализацию матрицы дисбалансов и рекомендации по оптимальной настройке параметров MinDiscrepancy и MaxRisk для эффективной торговли. Система автоматически рассчитывает "справедливую стоимость" каждой валютной пары через кросс-курсы, генерируя сигналы на покупку при отрицательных отклонениях, и на продажу — при положительных.
Алгоритм хаотической оптимизации — Chaos optimization algorithm (COA): Продолжение Алгоритм хаотической оптимизации — Chaos optimization algorithm (COA): Продолжение
Продолжение исследования алгоритма хаотической оптимизации. Вторая часть статьи посвящена практическим аспектам реализации алгоритма, его тестированию и выводам.