English Русский 中文 Español Deutsch 日本語 Português Français Italiano
preview
Python과 MQL5로 로봇 개발하기(1부): 데이터 전처리

Python과 MQL5로 로봇 개발하기(1부): 데이터 전처리

MetaTrader 5트레이딩 시스템 |
110 71
Yevgeniy Koshtenko
Yevgeniy Koshtenko

소개

시장은 점점 더 복잡해지고 있습니다. 오늘날은 알고리즘의 전쟁으로 변하고 있으며 거래의 95% 이상이 로봇에 의해 발생합니다. 

다음 단계는 머신 러닝입니다. 이들은 강력한 AI는 아니지만 단순한 선형 알고리즘도 아닙니다. 머신 러닝 모델은 어려운 조건에서도 수익을 창출할 수 있습니다. 트레이딩 시스템을 만드는 데 머신 러닝을 적용하는 것은 흥미로운 일입니다. 트레이딩 로봇은 신경망 덕분에 빅 데이터를 분석하고 패턴을 찾아 가격 변동을 예측할 것입니다.


우리는 데이터 수집, 처리, 샘플 확장, 피처 엔지니어링, 모델 선택 및 트레이닝, 파이썬을 통한 트레이딩 시스템 생성, 거래 모니터링 등 트레이딩 로봇의 개발 주기를 살펴볼 것입니다.

파이썬으로 작업하면 머신 러닝에서의 속도와 피처를 선택하고 생성할 수 있다는 장점이 있습니다. 모델을 ONNX로 내보내려면 파이썬에서와 완전히 동일한 피처 생성 로직이 필요한데 이는 쉽지 않습니다. 그래서 저는 파이썬을 통한 온라인 트레이딩을 선택했습니다.

작업 설정 및 도구 선택

이 프로젝트의 목표는 파이썬 트레이딩을 위한 수익성 있고 지속 가능한 머신 러닝 모델을 만드는 것입니다. 작업 단계:

  • MetaTrader 5에서 데이터를 수집하고 주요 기능을 로드 합니다.
  • 데이터 보강을 통해 샘플을 확장합니다.  
  • 레이블로 데이터 마크업 하기.
  • 기능 엔지니어링: 생성, 클러스터링, 선택.
  • ML 모델 선택 및 학습. 아마도 앙상블일 것입니다.
  • 메트릭별 모델 평가.
  • 수익성 평가를 위한 테스터 개발.  
  • 새로운 데이터를 기반으로 긍정적인 결과를 달성.
  • 파이썬 MQL5를 통한 트레이딩 알고리즘 구현.
  • MetaTrader 5와 통합.
  • 모델 개선.

도구: 속도와 기능을 위한 Python MQL5, Python의 ML 라이브러리.

이제 우리는 목표와 목적을 정의했습니다. 우리는 이 기사의 프레임워크 내에서 다음과 같은 작업을 수행할 것입니다:

  • MetaTrader 5에서 데이터를 수집하고 주요 기능을 로드 합니다.
  • 데이터 보강을 통해 샘플을 확장합니다.  
  • 레이블로 데이터 마크업 하기.
  • 기능 엔지니어링: 생성, 클러스터링, 선택.

환경 및 가져오기 설정하기 데이터 수집

먼저 MetaTrader 5를 통해 과거 데이터를 가져와야 합니다. 이 코드는 터미널 파일의 경로를 초기화 메서드에 전달하여 트레이딩 플랫폼에 대한 연결을 설정합니다.

루프에서 상품, 기간, 시작일 및 종료일 매개변수와 함께 mt5.copy_rates_range() 메서드를 사용하여 데이터를 가져옵니다. 실패한 시도 횟수와 안정적인 연결을 위한 지연 시간이 카운터로 표시됩니다.

이 함수는 mt5.shutdown() 메서드를 사용하여 플랫폼으로부터 연결을 끊음으로써 종료됩니다.

이 함수는 프로그램에서 추가로 호출할 수 있는 별도의 함수입니다. 

스크립트를 실행하려면 다음의 라이브러리를 설치해야 합니다:

  1. NumPy: 다차원 배열 및 수학 함수 작업을 위한 라이브러리입니다.

  2. Pandas: 표와 시계열 작업에 편리한 데이터 구조를 제공하는 데이터 분석 도구입니다.

  3. Random: 난수를 생성하고 시퀀스에서 임의의 요소를 선택하기 위한 모듈입니다.

  4. Datetime: 날짜와 시간 작업을 위한 클래스와 함수를 제공합니다.

  5. MetaTrader5: MetaTrader 5 트레이딩 터미널과의 상호 작용을 위한 라이브러리입니다.

  6. Time: 시간 및 프로그램 실행을 지연하기 위한 모듈입니다.

  7. Concurrent.futures: 병렬 및 비동기 작업을 실행하기 위한 도구입니다. 향후에는 다중 통화 병행 작업을 위해 이 기능이 필요할 것입니다.

  8. Tqdm: 반복 작업을 수행할 때 진행률 표시기를 표시하는 라이브러리입니다. 향후에는 다중 통화 병행 작업을 위해 이 기능이 필요할 것입니다.

  9. Train_test_split: 머신 러닝 모델을 학습할 때 데이터 집합을 학습 및 테스트 집합으로 분할하는 기능입니다.

다음 명령어를 실행하여 'pip'를 사용하여 설치할 수 있습니다:

pip install numpy pandas MetaTrader5 concurrent-futures tqdm sklearn matplotlib imblearn
import numpy as np
import pandas as pd
import random
from datetime import datetime
import MetaTrader5 as mt5
import time
import concurrent.futures
from tqdm import tqdm
from sklearn.model_selection import train_test_split
import matplotlib.pyplot as plt
from sklearn.utils import class_weight
from imblearn.under_sampling import RandomUnderSampler

# GLOBALS
MARKUP = 0.00001
BACKWARD = datetime(2000, 1, 1)
FORWARD = datetime(2010, 1, 1)
EXAMWARD = datetime(2024, 1, 1)
MAX_OPEN_TRADES = 3
symbol = "EURUSD"

def retrieve_data(symbol, retries_limit=300):
    terminal_path = "C:/Program Files/MetaTrader 5/Arima/terminal64.exe"

    attempt = 0
    raw_data = None

    while attempt < retries_limit:
        if not mt5.initialize(path=terminal_path):
            print("MetaTrader initialization failed")
            return None

        instrument_count = mt5.symbols_total()
        if instrument_count > 0:
            print(f"Number of instruments in the terminal: {instrument_count}")
        else:
            print("No instruments in the terminal")

        rates = mt5.copy_rates_range(symbol, mt5.TIMEFRAME_H1, BACKWARD, EXAMWARD)
        mt5.shutdown()

        if rates is None or len(rates) == 0:
            print(f"Data for {symbol} not available (attempt {attempt+1})")
            attempt += 1
            time.sleep(1)
        else:
            raw_data = pd.DataFrame(rates[:-1], columns=['time', 'open', 'high', 'low', 'close', 'tick_volume'])
            raw_data['time'] = pd.to_datetime(raw_data['time'], unit='s')
            raw_data.set_index('time', inplace=True)
            break

    if raw_data is None:
        print(f"Data retrieval failed after {retries_limit} attempts")
        return None

    # Add simple features
    raw_data['raw_SMA_10'] = raw_data['close'].rolling(window=10).mean()
    raw_data['raw_SMA_20'] = raw_data['close'].rolling(window=20).mean()
    raw_data['Price_Change'] = raw_data['close'].pct_change() * 100

    # Additional features
    raw_data['raw_Std_Dev_Close'] = raw_data['close'].rolling(window=20).std()
    raw_data['raw_Volume_Change'] = raw_data['tick_volume'].pct_change() * 100

    raw_data['raw_Prev_Day_Price_Change'] = raw_data['close'] - raw_data['close'].shift(1)
    raw_data['raw_Prev_Week_Price_Change'] = raw_data['close'] - raw_data['close'].shift(7)
    raw_data['raw_Prev_Month_Price_Change'] = raw_data['close'] - raw_data['close'].shift(30)

    raw_data['Consecutive_Positive_Changes'] = (raw_data['Price_Change'] > 0).astype(int).groupby((raw_data['Price_Change'] > 0).astype(int).diff().ne(0).cumsum()).cumsum()
    raw_data['Consecutive_Negative_Changes'] = (raw_data['Price_Change'] < 0).astype(int).groupby((raw_data['Price_Change'] < 0).astype(int).diff().ne(0).cumsum()).cumsum()
    raw_data['Price_Density'] = raw_data['close'].rolling(window=10).apply(lambda x: len(set(x)))
    raw_data['Fractal_Analysis'] = raw_data['close'].rolling(window=10).apply(lambda x: 1 if x.idxmax() else (-1 if x.idxmin() else 0))
    raw_data['Price_Volume_Ratio'] = raw_data['close'] / raw_data['tick_volume']
    raw_data['Median_Close_7'] = raw_data['close'].rolling(window=7).median()
    raw_data['Median_Close_30'] = raw_data['close'].rolling(window=30).median()
    raw_data['Price_Volatility'] = raw_data['close'].rolling(window=20).std() / raw_data['close'].rolling(window=20).mean()

    print("\nOriginal columns:")
    print(raw_data[['close', 'high', 'low', 'open', 'tick_volume']].tail(100))

    print("\nList of features:")
    print(raw_data.columns.tolist())

    print("\nLast 100 features:")
    print(raw_data.tail(100))

    # Replace NaN values with the mean
    raw_data.fillna(raw_data.mean(), inplace=True)

    return raw_data

retrieve_data(symbol)

스프레드 비용 및 브로커 수수료, 학습 및 테스트 샘플 날짜, 최대 거래 수, 심볼 등 글로벌 변수를 정의합니다.

MetaTrader 5에서 호가를 반복해서 로드합니다. 데이터는 DataFrame으로 변환되고 기능이 강화됩니다:

  • 10 및 20 기간 SMA 이동 평균
  • 가격 변경 
  • 표준 가격 편차
  • 볼륨 변경
  • 일별/월별 가격 변동
  • 가격 중앙값

이러한 기능들은 가격에 영향을 미치는 요소를 고려하는 데 도움이 됩니다.

DataFrame 열 및 최신 항목에 대한 정보가 표시됩니다.

첫 번째 함수가 어떻게 실행되었는지 살펴보겠습니다:

첫 번째 함수

모든 것이 작동합니다. 코드가 성공적으로 호가를 로드하고 기능을 준비하고 로드했습니다. 코드의 다음 부분으로 넘어가겠습니다.


샘플 확장을 위한 데이터 보강

데이터 보강은 샘플 크기를 늘리고 모델의 품질을 개선하기 위해 기존의 예제를 기반으로 새로운 학습 예제를 생성하며 제한된 데이터로 시계열을 예측하는 데 적합합니다. 또한 모델 오류를 줄이고 더 견고하게 해줍니다.

재무 데이터 보강 방법:

  • 노이즈에 대해서 더욱 견고하게 하기 위해 노이즈(무작위 편차)를 추가합니다.
  • 다양한 개발 시나리오 모델링을 위한 시간 이동
  • 가격 급등/급락을 모델링하기 위한 스케일링
  • 소스 데이터 반전

저는 DataFrame과 각 메서드에 대한 새로운 예제 수를 받아들이는 입력 증강 함수를 구현했습니다. 다양한 접근 방식을 사용하여 새 데이터를 생성하고 원본 DataFrame과 연결합니다.

def augment_data(raw_data, noise_level=0.01, time_shift=1, scale_range=(0.9, 1.1)):
    print(f"Number of rows before augmentation: {len(raw_data)}")

    # Copy raw_data into augmented_data
    augmented_data = raw_data.copy()

    # Add noise
    noisy_data = raw_data.copy()
    noisy_data += np.random.normal(0, noise_level, noisy_data.shape)

    # Replace NaN values with the mean
    noisy_data.fillna(noisy_data.mean(), inplace=True)

    augmented_data = pd.concat([augmented_data, noisy_data])
    print(f"Added {len(noisy_data)} rows after adding noise")

    # Time shift
    shifted_data = raw_data.copy()
    shifted_data.index += pd.DateOffset(hours=time_shift)

    # Replace NaN values with the mean
    shifted_data.fillna(shifted_data.mean(), inplace=True)

    augmented_data = pd.concat([augmented_data, shifted_data])
    print(f"Added {len(shifted_data)} rows after time shift")

    # Scaling
    scale = np.random.uniform(scale_range[0], scale_range[1])
    scaled_data = raw_data.copy()
    scaled_data *= scale

    # Replace NaN values with the mean
    scaled_data.fillna(scaled_data.mean(), inplace=True)

    augmented_data = pd.concat([augmented_data, scaled_data])
    print(f"Added {len(scaled_data)} rows after scaling")

    # Inversion
    inverted_data = raw_data.copy()
    inverted_data *= -1

    # Replace NaN values with the mean
    inverted_data.fillna(inverted_data.mean(), inplace=True)

    augmented_data = pd.concat([augmented_data, inverted_data])
    print(f"Added {len(inverted_data)} rows after inversion")

    print(f"Number of rows after augmentation: {len(augmented_data)}")

    # Print dates by years
    print("Print dates by years:")
    for year, group in augmented_data.groupby(augmented_data.index.year):
        print(f"Year {year}: {group.index}")

    return augmented_data

코드를 호출하면 다음과 같은 결과를 얻을 수 있습니다:

2

데이터 증강 메서드를 적용한 후 원래 150,000개의 H1 가격 바 세트는 무려 747,000개의 문자열로 확장되었습니다. 머신 러닝 분야의 많은 권위 있는 연구에 따르면 합성 예제 생성으로 인해 학습 데이터의 양이 크게 증가하면 학습된 모델의 품질 지표에 긍정적인 영향을 미친다고 합니다. 우리의 경우에도 이 기술을 통해 원하는 효과를 얻을 수 있을 것으로 기대합니다.


레이블 데이터

데이터 레이블링은 지도 학습 알고리즘이 성공하기 위해 매우 중요합니다. 이를 통해 소스 데이터에 레이블이 제공되면 이후 모델이 학습할 수 있습니다. 레이블이 지정된 데이터는 정확도를 높이고, 일반화를 개선하며, 학습 속도를 높이고, 모델을 더 쉽게 평가할 수 있게 해줍니다. EURUSD 예측 문제에서 우리는 가격 변동이 스프레드 및 수수료보다 큰지 여부를 나타내는 "레이블" 이진 열을 추가했습니다. 이를 통해 모델은 확산 재생 및 비롤백 추세의 패턴을 학습할 수 있습니다.

    레이블링은 머신 러닝 알고리즘이 원시 형태로는 보이지 않는 데이터의 복잡한 패턴을 찾을 수 있도록 하는 핵심적인 역할을 합니다. 코드 리뷰로 넘어가겠습니다.

    def markup_data(data, target_column, label_column, markup_ratio=0.00002):
        data.loc[:, label_column] = np.where(data.loc[:, target_column].shift(-1) > data.loc[:, target_column] + markup_ratio, 1, 0)
    
        data.loc[data[label_column].isna(), label_column] = 0
    
        print(f"Number of markups on price change greater than markup: {data[label_column].sum()}")
    
        return data

    이 코드를 실행하고 데이터의 레이블 수를 가져옵니다. 이 함수는 프레임을 반환합니다. 모든 것이 작동합니다. 그런데 70만 개가 넘는 데이터 포인트 중 스프레드보다 가격이 더 많이 변동한 경우는 7만 건에 불과했습니다.

    3

    이제 우리는 또 다른 데이터 마크업 기능을 가지게 되었습니다. 이번에는 실제 수익에 더 가깝습니다.


    대상 레이블 함수

    def label_data(data, symbol, min=2, max=48):
        terminal_path = "C:/Program Files/MetaTrader 5/Arima/terminal64.exe"
    
        if not mt5.initialize(path=terminal_path):
            print("Error connecting to MetaTrader 5 terminal")
            return
    
        symbol_info = mt5.symbol_info(symbol)
        stop_level = 100 * symbol_info.point
        take_level = 800 * symbol_info.point
    
        labels = []
    
        for i in range(data.shape[0] - max):
            rand = random.randint(min, max)
            curr_pr = data['close'].iloc[i]
            future_pr = data['close'].iloc[i + rand]
            min_pr = data['low'].iloc[i:i + rand].min()
            max_pr = data['high'].iloc[i:i + rand].max()
    
            price_change = abs(future_pr - curr_pr)
    
            if price_change > take_level and future_pr > curr_pr and min_pr > curr_pr - stop_level:
                labels.append(1)  # Growth
            elif price_change > take_level and future_pr < curr_pr and max_pr < curr_pr + stop_level:
                labels.append(0)  # Fall
            else:
                labels.append(None)
    
        data = data.iloc[:len(labels)].copy()
        data['labels'] = labels
    
        data.dropna(inplace=True)
    
        X = data.drop('labels', axis=1)
        y = data['labels']
    
        rus = RandomUnderSampler(random_state=2)
        X_balanced, y_balanced = rus.fit_resample(X, y)
    
        data_balanced = pd.concat([X_balanced, y_balanced], axis=1)
    
        return data

    이 함수는 트레이딩 수익에 대한 머신 러닝 모델 학습을 위한 목표 레이블을 얻습니다. 이 함수는 MetaTrader 5에 연결하여 심볼 정보를 검색하고 스톱/테이크 레벨을 계산합니다. 그런 다음 각 진입점에 대해 무작위 기간이 지난 후의 미래 가격이 결정됩니다. 가격 변동이 익절을 초과하고 스톱에 닿지 않을 뿐만 아니라 상승/하락 조건을 만족하면 그에 따라 1.0/0.0의 표시가 추가됩니다. 그렇지 않으면 - 없음. 레이블 된 데이터만 포함된 새 데이터프레임이 생성됩니다. 없음은 평균으로 대체됩니다.

    성장/하락 레이블의 수가 표시됩니다.

    모든 것이 의도한 대로 작동합니다. 데이터와 그 파생물을 받았습니다. 데이터는 보강되고 크게 보완되었으며 두 가지 다른 함수로 표시되었습니다. 다음 단계인 클래스 밸런싱으로 넘어가겠습니다.

    그런데 머신 러닝에 경험이 있는 독자라면 우리가 궁극적으로 회귀 모델이 아닌 분류 모델을 개발할 것이라는 점을 이미 아셨을 것입니다. 저는 회귀 모델을 더 좋아하는데 그 이유는 분류 모델보다 예측 논리가 좀 더 잘 드러나기 때문입니다. 

    그래서 다음 단계는 클래스 밸런싱입니다.


    클래스 밸런싱. 분류

    분류(Classification)는 공통된 특징에 따라 정보를 구조화 하는 인간의 타고난 능력에 기반한 기본적인 분석 방법입니다. 분류의 첫 번째 응용 분야 중 하나는 지질학적 특징을 기반으로 유망한 지역을 식별하는 탐사 분야였습니다.

    컴퓨터의 등장으로 분류는 새로운 차원에 도달했지만 본질은 여전히 남아 있습니다 - 겉으로 보이는 세부 사항의 혼돈 속에서 패턴을 발견하는 것 금융 시장의 경우 가격의 움직임을 상승/하락으로 분류하는 것이 중요합니다. 그러나 클래스는 불균형 할 수 있습니다. 트렌드는 적고 횡보는 많기 때문입니다.

    따라서 지배적인 예제를 제거하거나 희귀한 예제를 생성하는 클래스 밸런싱 메서드가 사용됩니다. 이를 통해 모델은 중요하지만 드물게 발생하는 가격 움직임의 패턴을 안정적으로 인식할 수 있습니다.

    pip install imblearn

        data = data.iloc[:len(labels)].copy()
        data['labels'] = labels
    
        data.dropna(inplace=True)
    
        X = data.drop('labels', axis=1)
        y = data['labels']
    
        rus = RandomUnderSampler(random_state=2)
        X_balanced, y_balanced = rus.fit_resample(X, y)
    
        data_balanced = pd.concat([X_balanced, y_balanced], axis=1)

    이제 클래스의 균형이 잡혔습니다. 각 클래스(가격 하락 및 상승)에 대해 동일한 수의 레이블이 있습니다.

    데이터 예측에서 가장 중요한 것에 대해 살펴보겠습니다 - 피처.


    머신 러닝에서 피처란 무엇인가요?

    속성과 특성은 어린 시절부터 모든 사람에게 친숙한 기본 개념입니다. 우리는 객체를 설명할 때 해당 객체의 속성을 나열하는데 이것이 바로 속성(attribute)입니다. 이러한 특성의 집합을 통해 객체를 완전히 특성화 할 수 있습니다.

    데이터 분석에서도 마찬가지입니다. 각 관찰은 일련의 수치 및 범주형 피처로 설명됩니다. 성공하려면 유익한 피처를 선택하는 것이 중요합니다.

    더 높은 수준에서는 연구 대상을 더 잘 설명하기 위해 초기 매개변수에서 새로운 파생 특성(characteristcis)을 구성하는 피처 엔지니어링이 있습니다.

    따라서 사물의 특성에 따른 설명을 통해 세상을 인지하는 인간의 경험은 형식화 및 자동화 수준에서 과학으로 이전됩니다.


    자동 피처 추출

    피처 엔지니어링은 소스 데이터를 머신 러닝 모델 학습을 위한 피처 집합으로 변환하는 작업으로 가장 유익한 피처를 찾는 것이 목표입니다. 수동 접근 방식(사람이 기능을 선택하는 방식)과 자동 접근 방식(알고리즘을 사용하는 방식)이 있습니다.

    우리는 자동 접근 방식을 사용할 것입니다. 데이터에서 최적의 피처를 자동으로 추출하는 피처 생성 메서드를 적용해 보겠습니다. 그런 다음 결과 세트에서 가장 유익한 것을 선택합니다.

    새로운 피처를 생성하는 방법: 

    def generate_new_features(data, num_features=200, random_seed=1):
        random.seed(random_seed)
        new_features = {}
    
        for _ in range(num_features):
            feature_name = f'feature_{len(new_features)}'
    
            col1_idx, col2_idx = random.sample(range(len(data.columns)), 2)
            col1, col2 = data.columns[col1_idx], data.columns[col2_idx]
    
            operation = random.choice(['add', 'subtract', 'multiply', 'divide', 'shift', 'rolling_mean', 'rolling_std', 'rolling_max', 'rolling_min', 'rolling_sum'])
    
            if operation == 'add':
                new_features[feature_name] = data[col1] + data[col2]
            elif operation == 'subtract':
                new_features[feature_name] = data[col1] - data[col2]
            elif operation == 'multiply':
                new_features[feature_name] = data[col1] * data[col2]
            elif operation == 'divide':
                new_features[feature_name] = data[col1] / data[col2]
            elif operation == 'shift':
                shift = random.randint(1, 10)
                new_features[feature_name] = data[col1].shift(shift)
            elif operation == 'rolling_mean':
                window = random.randint(2, 20)
                new_features[feature_name] = data[col1].rolling(window).mean()
            elif operation == 'rolling_std':
                window = random.randint(2, 20)
                new_features[feature_name] = data[col1].rolling(window).std()
            elif operation == 'rolling_max':
                window = random.randint(2, 20)
                new_features[feature_name] = data[col1].rolling(window).max()
            elif operation == 'rolling_min':
                window = random.randint(2, 20)
                new_features[feature_name] = data[col1].rolling(window).min()
            elif operation == 'rolling_sum':
                window = random.randint(2, 20)
                new_features[feature_name] = data[col1].rolling(window).sum()
    
        new_data = pd.concat([data, pd.DataFrame(new_features)], axis=1)
    
        print("\nGenerated features:")
        print(new_data[list(new_features.keys())].tail(100))
    
        return data

    다음 매개변수에 주의하세요:

    random_seed=42

    random_seed 매개변수는 새로운 피처를 생성한 결과의 재현성을 위해 필요합니다. generate_new_features 함수는 소스 데이터에서 새로운 피처를 생성합니다. Input: 데이터, 피처 수, 시드.

    Random은 주어진 시드로 초기화됩니다. In the loop: 이름이 생성되고 기존 피처 2개와 연산(덧셈, 뺄셈 등)이 무작위로 선택됩니다. 선택한 작업에 대한 새로운 피처가 계산됩니다.

    생성 후에는 원본 데이터에 새로운 피처가 추가됩니다. 자동으로 생성된 피처로 업데이트된 데이터가 반환됩니다.

    이 코드를 사용하면 머신 러닝의 품질을 개선하기 위해 새로운 피처를 자동으로 생성할 수 있습니다.

    코드를 실행하고 결과를 살펴봅시다:

    5

    100개의 새로운 피처가 생성되었습니다. 다음 단계인 피처 클러스터링으로 넘어가겠습니다.


    피처 클러스터링

    피처 클러스터링은 유사한 피처를 그룹으로 묶어 그 수를 줄여줍니다. 이를 통해 중복 데이터를 제거하고 상관관계를 줄이며 과적합 없이 모델을 단순화할 수 있습니다.

    널리 사용되는 알고리즘: k-평균(클러스터 수가 지정되고 피처가 중심을 중심으로 그룹화됨) 및 계층적 클러스터링(다단계 트리 구조).

    피처를 클러스터링 하면 쓸모없는 피처를 정리하고 모델의 효율성을 개선할 수 있습니다.

    피처 클러스터링 코드를 살펴보겠습니다:

    from sklearn.mixture import GaussianMixture
    
    def cluster_features_by_gmm(data, n_components=4):
        X = data.drop(['label', 'labels'], axis=1)
    
        X = X.replace([np.inf, -np.inf], np.nan)
        X = X.fillna(X.median())
    
        gmm = GaussianMixture(n_components=n_components, random_state=1)
    
        gmm.fit(X)
    
        data['cluster'] = gmm.predict(X)
    
        print("\nFeature clusters:")
        print(data[['cluster']].tail(100))
    
        return data

    우리는 피처 클러스터링에 GMM(가우스 혼합 모델) 알고리즘을 사용합니다. 기본 개념은 데이터가 정규 분포의 혼합으로 생성되며 각 분포는 하나의 클러스터라는 것입니다.

    먼저 클러스터 수를 설정합니다. 그런 다음 모델의 초기 매개 변수인 평균, 공분산 행렬 및 군집 확률을 설정합니다. 알고리즘은 이러한 매개변수가 변경되지 않을 때까지 최대 가능성 메서드를 사용하여 주기적으로 다시 계산합니다.

    결과적으로 우리는 각 클러스터에 대한 최종 매개변수를 얻게 되며 이를 통해 새로운 기능이 어느 클러스터에 속하는지 결정할 수 있게 됩니다.

    GMM은 멋진 기능입니다. 다양한 작업에서 사용되며 특히 클러스터의 모양이 복잡하고 경계가 흐릿한 데이터에 적합합니다.

    이 코드는 GMM을 사용하여 피처를 클러스터로 분할합니다. 원본 데이터를 가져오고 클래스 레이블이 제거됩니다. GMM은 주어진 수의 클러스터로 파티셔닝하는 데 사용됩니다. 클러스터 번호가 새 열로 추가됩니다. 마지막에 획득한 클러스터의 표가 인쇄됩니다.

    이제 클러스터링 코드를 실행하고 결과를 확인해 보겠습니다:

    6

    이제 최고의 피처를 선택하는 함수로 넘어가 보겠습니다.


    최고의 피처 선택

    from sklearn.feature_selection import RFECV
    from sklearn.ensemble import RandomForestClassifier
    import pandas as pd
    
    def feature_engineering(data, n_features_to_select=10):
        # Remove the 'label' column as it is not a feature
        X = data.drop(['label', 'labels'], axis=1)
        y = data['labels']
    
        # Create a RandomForestClassifier model
        clf = RandomForestClassifier(n_estimators=100, random_state=1)
    
        # Use RFECV to select n_features_to_select best features
        rfecv = RFECV(estimator=clf, step=1, cv=5, scoring='accuracy', n_jobs=-1, verbose=1,
                      min_features_to_select=n_features_to_select)
        rfecv.fit(X, y)
    
        # Return a DataFrame with the best features, 'label' column, and 'labels' column
        selected_features = X.columns[rfecv.get_support(indices=True)]
        selected_data = data[selected_features.tolist() + ['label', 'labels']]  # Convert selected_features to a list
    
        # Print the table of best features
        print("\nBest features:")
        print(pd.DataFrame({'Feature': selected_features}))
    
        return selected_data
    
    labeled_data_engineered = feature_engineering(labeled_data_clustered, n_features_to_select=10)

    이 함수는 데이터에서 가장 멋지고 유용한 피처를 추출합니다. 입력은 클래스 기능 및 레이블이 포함된 원본 데이터와 필요한 수의 선택된 피처입니다.

    첫째, 클래스 레이블은 피처 선택에 도움이 되지 않으므로 재설정됩니다. 그런 다음 무작위 피처 집합에 대해 여러 개의 의사 결정 트리를 구축하는 모델인 랜덤 포레스트 알고리즘이 시작됩니다.

    모든 트리를 학습한 후 랜덤 포레스트는 각 피처가 얼마나 중요한지, 분류에 얼마나 영향을 미치는지를 평가합니다. 이 함수는 이러한 중요도 점수를 기반으로 상위 기능을 선택합니다.

    마지막으로 선택한 피처가 데이터에 추가되고 클래스 레이블이 반환됩니다. 이 함수는 선택한 피처가 포함된 테이블을 인쇄하고 업데이트된 데이터를 반환합니다.

    왜 이렇게 호들갑을 떨까요? 이를 통해 우리는 프로세스의 속도를 저하시키는 정크 피처들을 제거하고 가장 멋진 피처는 남겨두어 모델이 이러한 데이터를 학습하여 더 나은 결과를 보여줄 수 있도록 합니다.

    함수를 실행하고 결과를 확인해 보겠습니다:

    8

    가격 예측을 위한 가장 좋은 지표는 시초가로 밝혀졌습니다. 상위에 위치한 것은 이동 평균, 가격 증분, 표준 편차, 일간 및 월간 가격 변동에 기반한 피처입니다. 자동으로 생성된 피처는 유용하지 않은 것으로 밝혀졌습니다.

    이 코드를 사용하면 중요한 피처를 자동으로 선택할 수 있어 모델의 성능과 일반화의 능력을 향상시킬 수 있습니다.


    결론

    우리는 향후의 머신 러닝 모델의 개발을 대비하여 데이터 조작 코드를 만들었습니다. 수행한 단계를 간략히 살펴보겠습니다:

    • EURUSD의 초기 데이터는 MetaTrader 5 플랫폼에서 추출했습니다. 그런 다음 샘플 크기를 크게 늘리기 위해 무작위 연산을 사용하여 변환을 수행했습니다 - 노이즈 부과, 이동 및 스케일링 등
    • 다음 단계는 손절매와 이익 실현 수준을 고려하여 상승과 하락이라는 특별한 추세 마커로 가격 값을 표시하는 것이었습니다. 클래스의 균형을 맞추기 위해 중복되는 예제를 제거했습니다.
    • 다음으로 피처 엔지니어링 절차가 수행되었습니다. 먼저, 원본 시계열에서 수백 개의 새로운 파생 피처가 자동으로 생성되었습니다. 그런 다음 가우시안 혼합 클러스터링을 수행하여 중복성을 감지했습니다. 마지막으로 랜덤 포레스트 알고리즘을 사용하여 가장 유익한 변수 하위 집합의 순위를 매기고 선택했습니다.
    • 그 결과 최적의 피처를 갖춘 고품질의 풍부한 데이터 세트가 생성되었습니다. 이 데이터 세트는 MetaTrader 5에 통합되어 머신 러닝 모델 추가 학습 및 파이썬 트레이딩 전략 개발의 기반이 될 것입니다.


    다음 글에서는 최적의 분류 모델을 선택하고 개선하고 교차 검증을 구현하고 Python/MQL5 번들에 대한 테스터 함수를 작성하는 것에 대해 알아보겠습니다.

    MetaQuotes 소프트웨어 사를 통해 러시아어가 번역됨.
    원본 기고글: https://www.mql5.com/ru/articles/14350

    파일 첨부됨 |
    synergy_ml_bot.py (11.74 KB)
    최근 코멘트 | 토론으로 가기 (71)
    Andreas Kress
    Andreas Kress | 10 10월 2024 에서 07:58
    raw_Prev_Day_Price_Change
    raw_Prev_Week_Price_Change
    raw_Prev_Week_Price_Change
    어떻게 작동해야 하는지 이해가 되지 않는데, 이를 계산하기 전에 일일 단위의 시간 프레임이 필요한 것 같나요?
    Andreas Kress
    Andreas Kress | 10 10월 2024 에서 08:03
    stenli21 #:

    작성자님께.

    사용된 파이썬 버전과 모듈을 알려주세요.


    스크립트를 실행할 때 오류가 발생합니다.




    경로에 ANSI가 없습니다. Степан.
    모든 사용자에 대해 파이썬을 설치해 보세요. 그러면 c:\프로그램 파일\python에 파이썬이 설치됩니다.
    또는 이와 비슷한 위치에 설치합니다.

    또는 C:\python에 파이썬을 설치합니다.
    필요한 경우 시스템 경로 변수를 변경하는 것을 잊지 마세요.
    stenli21
    stenli21 | 16 10월 2024 에서 19:16
    Andreas Kress #:
    경로에 ansi가 없습니다. Stepan.
    모든 사용자에 대해 파이썬을 설치해 보세요. 그러면 파이썬이 c:\Program Files\python에 설치됩니다.
    또는 다음과 같이 설치합니다.

    또는 C:\python에 파이썬을 설치합니다.
    필요한 경우 시스템 경로 변수를 변경하는 것을 잊지 마세요.

    답변 주셔서 감사합니다.

    예, 문제는 실제로 러시아어 문자가있는 경로로 인한 것이 었습니다. 수정하고 모든 것이 작동했습니다.....

    Andreas Kress
    Andreas Kress | 30 10월 2024 에서 08:43
    파트 3은 언제 나오나요!
    Roberto Liguoro
    Roberto Liguoro | 22 7월 2025 에서 08:48
    MetaQuotes:

    새 문서 파이썬과 MQL5로 로봇 개발하기(1부) 가 게시되었습니다: 데이터 전처리 문서가 게시되었습니다:

    저자: 예브게니 코시텐코

    멋진 기사
    Python과 MQL5로 로봇 개발하기(2부): 모델 선택, 생성 및 훈련, Python 사용자 지정 테스터 Python과 MQL5로 로봇 개발하기(2부): 모델 선택, 생성 및 훈련, Python 사용자 지정 테스터
    파이썬과 MQL5로 트레이딩 로봇을 개발하는 방법에 대한 시리즈 기사를 계속 이어갑니다. 오늘 우리는 모델 선택 및 훈련, 테스트, 교차 검증, 그리드 검색 구현, 모델 앙상블 문제를 해결해 보겠습니다.
    패턴 검색에서 무자비 대입 방식(6부): 주기적 최적화 패턴 검색에서 무자비 대입 방식(6부): 주기적 최적화
    이 기사에서는 MetaTrader 4 및 5 거래에서 자동화 체인 전체를 닫을 수 있을 뿐만 아니라 훨씬 더 흥미로운 작업을 할 수 있게 해준 개선 사항의 첫 번째 부분을 보여드리겠습니다. 이제부터는 이 솔루션을 사용하면 EA를 생성하고 최적화하는 것을 완전히 자동화할 수 있을 뿐만 아니라 효과적인 트레이딩 구성을 찾는 데 드는 인건비를 최소화할 수 있습니다.
    파이썬으로 트레이딩 로봇 개발하기(3부): 모델 기반 트레이딩 알고리즘 구현하기 파이썬으로 트레이딩 로봇 개발하기(3부): 모델 기반 트레이딩 알고리즘 구현하기
    파이썬과 MQL5로 트레이딩 로봇을 개발하는 방법에 대한 시리즈 기사를 계속 이어갑니다. 이 글에서 우리는 파이썬으로 트레이딩 알고리즘을 만들어 볼 것입니다.
    측정 지표 정보 측정 지표 정보
    머신러닝은 전략 개발을 위한 인기 있는 방법이 되었습니다. 수익성과 예측 정확도를 극대화하는 데는 더 많은 관심이 집중되었지만 예측 모델을 구축하는 데 사용되는 데이터 처리의 중요성은 그다지 주목을 받지 못했습니다. 이 글에서는 티모시 마스터스의 책 '시장 트레이딩 시스템 테스트 및 조정'에 설명된 대로 엔트로피 개념을 사용해 예측 모델 구축에 사용할 지표의 적절성을 평가하는 방법을 살펴봅니다.