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

 

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

Система прогнозирования EURUSD с применением компьютерного зрения и глубокого обучения. Узнайте, как сверточные нейронные сети могут распознавать сложные ценовые паттерны на валютном рынке и предсказывать движение курса с точностью до 54%. Статья раскрывает методологию создания алгоритма, использующего технологии искусственного интеллекта для визуального анализа графиков вместо традиционных технических индикаторов. Автор демонстрирует процесс трансформации ценовых данных в «изображения», их обработку нейронной сетью и уникальную возможность заглянуть в «сознание» ИИ через карты активации и тепловые карты внимания. Практический код на Python с использованием библиотеки MetaTrader 5 позволяет читателям воспроизвести систему и применить ее в собственной торговле.

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

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

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

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

Автор: Yevgeniy Koshtenko

 
Привет, как дела?
Я очень ценю эту статью, которую вы нам предоставили. Но я все еще хочу кое-что сказать для тех, кто, как и я, создавал торговые системы (советники) на языке MQL5, но имеет очень мало идей, когда дело доходит до машинного обучения или даже до python в целом.
Я хочу интегрировать ML в свою торговую систему, чтобы превратить ее из обычной программы, которая, как вы сказали, "бездумна", в программу, принимающую лучшие решения.
В вашей статье, насколько я знаю, не хватает нескольких шагов для начинающих. Ваш первый код не говорит нам, какую IDE мы будем использовать (это meta quotes IDE?) Я хотел бы знать это и шаги, чтобы настроить его для всей работы, которую мы будем делать позже.
За исключением того, что, возможно, ваша статья не совсем обучает новичков с нуля (не ознакомительная).
 
import MetaTrader5 as mt5
import numpy as np
import pandas as pd
import matplotlib
matplotlib.use('Agg') 
import matplotlib.pyplot as plt
from sklearn.preprocessing import MinMaxScaler
from sklearn.model_selection import train_test_split
from tensorflow.keras.models import Model
from tensorflow.keras.layers import Dense, Conv1D, MaxPooling1D, Flatten, Dropout, BatchNormalization, Input
from tensorflow.keras.callbacks import EarlyStopping
from datetime import datetime

# --- КОНФИГУРАЦИЯ ---
SYMBOL = "EURUSD"
TIMEFRAME = mt5.TIMEFRAME_H1
DATA_LOAD = 6200      # Увеличение до ~1 года данных H1
WINDOW_SIZE = 48      # Окно ввода (48 часов)
PRED_WINDOW = 24      # Горизонт прогнозирования (24 часа)
BACKTEST_ROWS = 20    # Количество последних баров для проверки вручную

def connect_to_mt5():
    if not mt5.initialize():
        print("Error initializing MetaTrader5")
        return False
    return True

def get_historical_data(num_bars):
    # Извлечение определенного графа из текущей позиции
    rates = mt5.copy_rates_from_pos(SYMBOL, TIMEFRAME, 0, num_bars)
    if rates is None or len(rates) == 0:
        return None
    df = pd.DataFrame(rates)
    df['time'] = pd.to_datetime(df['time'], unit='s')
    df.set_index('time', inplace=True)
    return df[['open', 'high', 'low', 'close']]

def create_images(data, window_size=48, prediction_window=24):
    images, targets = [], []
    for i in range(len(data) - window_size - prediction_window):
        window = data.iloc[i:i+window_size]
        # Наклейка основана на цене после 24 часов
        target_val = 1 if data.iloc[i+window_size+prediction_window-1]['close'] > window['close'].iloc[-1] else 0
        
        scaler = MinMaxScaler()
        window_scaled = scaler.fit_transform(window)
        
        images.append(window_scaled)
        targets.append(target_val)
    return np.array(images), np.array(targets)

def train_cv_model(images, targets):
    X_train, X_val, y_train, y_val = train_test_split(images, targets, test_size=0.15, shuffle=True)
    inputs = Input(shape=(X_train.shape[1], X_train.shape[2]))
    
    # Архитектура CNN в соответствии с логикой CV_Model.py
    x = Conv1D(64, 3, padding='same', activation='relu')(inputs)
    x = BatchNormalization()(x)
    x = MaxPooling1D(2)(x)
    x = Conv1D(128, 3, padding='same', activation='relu')(x)
    x = BatchNormalization()(x)
    x = MaxPooling1D(2)(x)
    
    x = Flatten()(x)
    x = Dense(64, activation='relu')(x)
    x = Dropout(0.3)(x)
    outputs = Dense(1, activation='sigmoid')(x)
    
    model = Model(inputs, outputs)
    model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])
    model.fit(X_train, y_train, epochs=40, batch_size=64, validation_data=(X_val, y_val), 
              callbacks=[EarlyStopping(patience=10, restore_best_weights=True)], verbose=0)
    return model

def run_author_backtest(model, full_data, num_checks=20):
    """
    Backtests the last 20 hours to see if a 24-hour prediction 
    made at that time would have been correct.
    """
    print(f"\n--- BACKTEST TABLE (Last {num_checks} Prediction Points) ---")
    print(f"{'Time (UTC)':<20} | {'Pred (24h)':<10} | {'Actual (24h)':<12} | {'Result'}")
    print("-" * 75)
    
    wins = 0
    # Мы делаем шаг назад, чтобы убедиться, что 24-часовое окно действительно завершилось для бэктеста
    for i in range(num_checks + PRED_WINDOW, PRED_WINDOW, -1):
        idx = len(full_data) - i
        
        # 1. Получите 48-часовое окно, доступное В ТО ВРЕМЯ
        window = full_data.iloc[idx - WINDOW_SIZE : idx]
        timestamp = full_data.index[idx-1]
        
        # 2. Получите АКТУАЛЬНЫЙ результат ровно через 24 часа
        actual_price_then = window['close'].iloc[-1]
        actual_price_future = full_data.iloc[idx + PRED_WINDOW - 1]['close']
        actual_dir = "UP ▲" if actual_price_future > actual_price_then else "DOWN ▼"
        
        # 3. Прогнозирование модели на основе окна
        scaler = MinMaxScaler()
        window_scaled = scaler.fit_transform(window)
        pred_val = model.predict(np.array([window_scaled]), verbose=0)[0][0]
        pred_dir = "UP ▲" if pred_val > 0.5 else "DOWN ▼"
        
        # 4. Результат
        res = "✅ WIN" if pred_dir == actual_dir else "❌ ПОТЕРИ"
        if res == "✅ WIN": wins += 1
        
        print(f"{str(timestamp):<20} | {pred_dir:<10} | {actual_dir:<12} | {res}")

    print("-" * 75)
    print(f"TOTAL BACKTEST ACCURACY: {(wins/num_checks)*100:.2 f}% ({wins}/{num_checks})")

def main():
    if not connect_to_mt5(): return
    
    print(f"Loading {DATA_LOAD} bars for EURUSD...")
    data = get_historical_data(DATA_LOAD)
    if data is None: 
        mt5.shutdown()
        return

    # Обучение только на данных, которые не входят в наше окно бэктеста
    train_data = data.iloc[:-(BACKTEST_ROWS + PRED_WINDOW)]
    images, targets = create_images(train_data, WINDOW_SIZE, PRED_WINDOW)
    
    print("Training model on ~1 year of data...")
    model = train_cv_model(images, targets)
    
    # Запустите бэктест в точности, как указано
    run_author_backtest(model, data, BACKTEST_ROWS)
    
    # Живой прогноз на ПРЯМО СЕЙЧАС (ближайшие 24 часа)
    last_window = data.iloc[-WINDOW_SIZE:]
    scaler = MinMaxScaler()
    live_pred = model.predict(np.array([scaler.fit_transform(last_window)]), verbose=0)[0][0]
    live_dir = "UP ▲" if live_pred > 0.5 else "DOWN ▼"
    
    print(f"\nLIVE FORECAST FOR NEXT 24 HOURS: {live_dir}")
    print(f"Confidence: {live_pred*100 if live_pred > 0.5 else (1-live_pred)*100:.2 f}%")
    input("Process complete. Press Enter to close this window...")
    
    mt5.shutdown()

if __name__ == "__main__":
    main()
Внесены небольшие изменения в прогнозы бэктестов.