MQL5とデータ処理パッケージの統合(第1回):高度なデータ分析と統計処理
はじめに
金融市場は膨大な量のデータを生成しており、テクニカル分析だけに基づいてデータを分析するのは困難です。手作業でのテクニカル分析では、トレーダーはデータ内のパターン、トレンド、アノマリーを効果的に分析し、解釈することができません。一方、Jupyter Labのような高度なデータ分析パッケージを使用することで、トレーダーは複雑な統計分析、機械学習、データの可視化をおこなうことが可能になります。これにより、有益な取引機会を特定し、市場行動や季節的傾向を理解し、将来の値動きを予測する助けとなります。
履歴データの収集
始めるには、MetaTrader 5から.csv形式で保存された履歴データが必要です。MetaTraderプラットフォームを起動し、MetaTrader 5のパネルの上部にある[ツール]>[オプション]に移動し、[チャート]オプションに移動します。次に、ダウンロードするチャートのバー数を選択します。バーの数は無制限にするのが一番です。日付を扱うことになるし、ある期間にいくつのバーがあるかわからないからです。
その後、実際のデータをダウンロードする必要があります。そのためには、 [表示] に移動し、次に[銘柄] に移動して、[仕様] タブに移動し、ダウンロードするデータの種類に応じて[バー] または [ティック] に移動するだけです。ダウンロードする履歴データの開始日と終了日を入力し、リクエストボタンをクリックすると、データがダウンロードされ、.csv形式で保存されます。
以上の手順で、MetaTrader取引プラットフォームから履歴データをダウンロードすることができました。次に、分析用のJupyter Lab環境をダウンロードして設定する必要があります。Jupyter Labをダウンロードして設定するには、公式の webサイトにアクセスし、簡単な手順に従ってダウンロードできます。使用しているOSの種類に応じてpip、conda、brewなど、さまざまなインストール方法が用意されています。
Jupyter LabでMetaTrader 5の履歴データをロードする
MetaTrader 5の履歴データをJupyter Labに正常にロードするには、データをダウンロードしたフォルダを把握しておく必要があります。その後、Jupyter Labでそのフォルダに移動するだけです。まず、データをロードして列名を確認する必要があります。列名を正しく処理し、誤った列名を使用した場合に発生する可能性のあるエラーを回避するために、列名をしっかりと検査することが重要です。
前処理
データ分析に入る前に、データを前処理する必要があります。
1. 日時の解析:日付列を日付-時刻形式に変換します。
2. 欠測値の処理:欠損値を処理します。
3. 特徴量エンジニアリング:必要であれば、新しい特徴量を作成します。
pythonコード
import pandas as pd # Load historical data file_path = '/home/int_junkie/Documents/ML/XAUUSD.m_H1_historical.csv' data = pd.read_csv(file_path) # Display the first few rows and column names print(data.head()) print(data.columns)
出力
出力から、列の中にいくつかの特殊文字<>があり、ファイルがタブ区切りであることを示す\tが存在することがわかります。これで、正しい列名で履歴データをロードする手順に進むことができます。
以下のコードでは次のようにします。
1. ライブラリをインポートする
- PandasはPythonの強力なデータ操作ライブラリです。
- テクニカル分析ライブラリ(TA lib)は、金融市場データのテクニカル分析に使用されます。
2. 履歴データを読み込む
- File-pathは、履歴データを含むCSVファイルの場所を指定するために使用されます。
- Pd.readはCSVファイルをpandasのData-Frameに読み込みます。区切り文字の「\t」は、ファイルがタブ区切りであることを示します。
3. データを表示する
- Data.headはData-frameの最初の数行を表示し、内容を確認します。
- Data.columnsはデータフレームの構造を確認するために列名を表示します。
4. データを日付順に並べ替える
- Date.sortは、<DATE>列に基づいてデータフレームを並び替えます。これにより、データが時系列順になります。
5. RSIを計算する
- TA.RSIは、<CLOSE>価格列を使用して相対力指数(RSI)を計算します。
- Time-periodは14期間のRSIを指定します。
- 計算された値は、データフレームの「RSI」という新しい列に格納されます。
6. 更新されたデータを表示する
- Data.headは、RSI計算を検証するために、更新されたデータフレームの最初の数行を表示します。
import pandas as pd import talib as ta # Load historical data file_path = '/home/int_junkie/Documents/ML/XAUUSD.m_H1_historical.csv' data = pd.read_csv(file_path, delimiter='\t') # Display the first few rows and column names to verify print(data.head()) print(data.columns) # Ensure data is sorted by the correct date column data.sort_values('<DATE>', inplace=True) # Calculate RSI using the '<CLOSE>' price column data['RSI'] = ta.RSI(data['<CLOSE>'], timeperiod=14) # Display the first few rows to verify print(data.head())
出力
出力から、RSI列の下にNAN値があることがわかります。NAN値を正しく処理する必要があります。RSI関数は、指標を計算するために最小限のデータポイントを必要とします。初期にはNAN値を返すかもしれません。NAN値を正しく扱うには、列<CLOSE>のデータ型を知る必要があります。Data-Frameと列へのアクセスが正しいことを確認します。以下のPythonコードは、NAN値をどのように扱うかを示しています。
import pandas as pd import talib as ta # Load the historical data file_path = '/home/int_junkie/Documents/ML/XAUUSD.m_H1_historical.csv' data = pd.read_csv(file_path, delimiter='\t')data['<CLOSE>'] = data['<CLOSE>'].astype(float) # Verify the column names print(data.columns) # Convert the column to the correct data type if necessary data['<CLOSE>'] = data['<CLOSE>'].astype(float) # Calculate the RSI data['RSI'] = ta.RSI(data['<CLOSE>'], timeperiod=14) # Display the RSI values print(data[['<CLOSE>', 'RSI']].tail(20))
出力
NAN値が正しく処理されていることがわかります。(ロックバック期間により予想される)初期期間にNAN値が表示された場合は、以下のように処理を進めることができます。
data['RSI'] = ta.RSI(data['<CLOSE>'], timeperiod=14) data['RSI'] = data['RSI'].fillna(0) # or use any other method to handle NaN values
探索的データ分析
探索的データ分析(EDA)の主な目的は、データの主要な特徴を要約することで、その根本的な構造を理解することです。EDAを実施する際には、パターンを発見し、データ内の傾向や関係を特定します。また、異常や外れ値、さらなる調査が必要とされる異常な観察結果を検出します。さらに、後の分析に影響を与える可能性のあるデータに関する仮定をチェックします。そして、データの欠損値、エラー、不整合など、対処が必要な問題を探し出し、データのクリーニングをおこないます。
次のpythonスクリプトを使用してEDAをおこないます。
import seaborn as sns import matplotlib.pyplot as plt import warnings warnings.filterwarnings("ignore") for i in data.select_dtypes(include="number").columns: sns.histplot(data=data, x=i) plt.show()
上記のコードから、必要なライブラリをすべてインポートした後、クリーンな出力を得るために警告を無視することから始めます。「data.select_dtypes(include="number")」は数値列のみを含むデータフレームを返し、columnsはこれらの列の名前を返します。そして、データからヒストグラムをプロットします。上のコードからプロットされたヒストグラムを以下に示します。
統計処理の操作の後、収集したデータに対してモデルの学習を進めることができます。目標は、集めた履歴データから予測を立てられるようにすることです。ここでは、RSI指標だけを使って予測します。その前に、データ間にどのような関係があるのかを知る必要があります。これは相関行列を実行することによっておこないます。その関係が、正の相関があるのか、負の相関があるのか、あるいは相関がないのかを解釈できるようにしなければなりません。
- 正の相関:相関係数が1に近い値を示す場合、2つの変数の間に強い正の相関が存在することを意味します。例えば、「始値」と「終値」の相関が1に近い場合、これらの値は同じ方向に動く傾向があります。
- 負の相関:相関係数が-1に近い値を示す場合、強い負の相関が存在します。例えば、「出来高」と「価格」の相関が-1に近い場合、出来高が増加すると価格が下がる傾向があることを示しています。
- 相関関係なし:相関係数が0に近い値を示す場合、2つの変数間に相関がないことを意味します。
import pandas as pd import numpy as np import matplotlib.pyplot as plt import seaborn as sns from sklearn.model_selection import train_test_split from sklearn.ensemble import RandomForestRegressor from sklearn.metrics import r2_score, mean_squared_error import talib as ta # Technical Analysis library # Load the data file_path = '/home/int_junkie/Documents/ML/XAUUSD.m_H1_historical.csv' data = pd.read_csv(file_path, delimiter='\t') # Exploratory Data Analysis (EDA) print(data.info()) print(data.describe()) # Visualize the closing price plt.figure(figsize=(12, 6)) plt.plot(data['<CLOSE>']) plt.title('XAUUSD Closing Price') plt.xlabel('<DATE>') plt.ylabel('Price') plt.show() # Feature Engineering data['RSI'] = ta.RSI(data['<CLOSE>'], timeperiod=14) # Drop rows with missing values data.dropna(inplace=True) # Define target variable data['Target'] = data['<CLOSE>'].shift(-1) data.dropna(inplace=True) # Split the data X = data[['RSI']] # Only use RSI as the feature y = data['Target'] X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, shuffle=False) # Model Development model = RandomForestRegressor(n_estimators=100, random_state=42) model.fit(X_train, y_train) # Predictions y_pred = model.predict(X_test) # Evaluate the model mse = mean_squared_error(y_test, y_pred) print(f'Mean Squared Error: {mse}') # Visualize the predictions plt.figure(figsize=(12, 6)) plt.plot(y_test.index, y_test, label='Actual Values') plt.plot(y_test.index, y_pred, label='Predicted Values') plt.xlabel('Samples') plt.ylabel('TARGET_CLOSE') plt.title('Actual vs Predicted Values') plt.legend() plt.show()
これがモデルを訓練したときの出力です。
データ分析の結果、予測値が実際の値と一致していないことが確認されました。これは、モデルが根底にあるパターンを効果的に捉えていないことを示唆しています。この問題にはいくつかの原因が考えられます。
1. 訓練データの不足:データセットが小さい場合、モデルは十分な情報を得られず、パターンを正確に学習できない可能性があります。
2. 過剰適合:モデルが学習データを過度に記憶し、汎化できていない可能性があります。これは、モデルが過度に複雑であるか、データに適切に一般化されていないことが原因でよく発生します。
3. 過少適合:モデルが単純すぎて、データに存在するパターンを捉えられない場合があります。これは、モデルの複雑さが不十分であったり、重要な特徴量が欠けている場合に起こります。
4. 特徴量エンジニアリング:選択した特徴量やエンジニアリングが不十分だと、モデルが予測をおこなうための必要な関連情報を十分に持たない可能性があります。
問題を診断し、解決するためのステップ
1. データをチェックする:データがクリーンで一貫性があり、適切に前処理されていることを確認します。
2. モデルの性能を評価する:平均二乗誤差(MSE)や平均絶対誤差(MAB)などの行列を使用します。
3. 特徴量エンジニアリングの改善:テクニカル指標、ラグ値、その他の関連する金融指標など、さまざまな機能を試します。
4. ハイパーパラメータを調整する:グリッドサーチやランダムサーチのようなテクニックを使って、モデルに最適なハイパーパラメータを見つけます。
MQL5ですべてをまとめる
モデルを保存した後、予測用のpythonスクリプトを作成する必要があります。このスクリプトはモデルを読み込み、予測をおこないます。
import joblib import sys import os
- Joblib:シリアライズされた機械学習モデルをロードするために使用されます。
- Sys:「システム」の略で、コマンドライン引数へのアクセスを提供します。
- OS:「オペレーティングシステム」の略で、ファイルの存在を確認し、ファイル操作を実行するために使用されます。
model_path = sys.argv[/home/int_junkie/Documents/ML/random_forest_model.pkl] features_path = sys.argv[/home/int_junkie/Documents/ML/features.txt]
- Sys.argv[1]:最初のコマンドライン引数は、モデルファイルへのパスです。
- Sys.argv[2]:2番目のコマンドライン引数は、特徴量ファイルへのパスです。
print(f"Model path: {model_path}") print(f"Features path: {features_path}")
デバッグ情報を出力します。デバッグ用にモデルファイルと特徴量ファイルのパスを表示します。
if not os.path.exists(model_path): print(f"Error: Model file not found at {model_path}") sys.exit(1) if not os.path.exists(features_path): print(f"Error: Features file not found at {features_path}") sys.exit(1)
- モデルファイルと特徴量ファイルが存在するかどうかをチェックします。
- どちらかが存在しない場合、エラーメッセージを表示し、ステータスコード1でスクリプトを終了します。
model = joblib.load(model_path)
- 指定された'model-path'から学習済みの機械学習モデルをロードします。
with open(features_path, 'r') as f: features = [float(line.strip()) for line in f]
- 読み込むために機能ファイルを開きます。
- 各行を読み込み、先頭や末尾の空白を取り除き、ファイルをfloatに変換して特徴量リストに格納します。
prediction = model.predict([features])[0]
- ロードされたモデルを使用して、ロードされた特徴量に基づいて予測をおこないます。
- モデル.予測予測値のリスト(この場合は単一の予測値)を返し、[0]は最初の予測値を抽出します。
print(prediction)
- 予測をストランド出力にプリントします。この出力は、MQL5などの別のスクリプトやプログラムによって取り込まれ、取引の意思決定をおこなうことができます。
MQL5
OnInit()でモデルをロードします。
int OnInit(){ // Load the model and feature names string modelPath = "/home/int_junkie/Documents/ML/random_forest_model.pkl"; string featurePath = "/home/int_junkie/Documents/ML/features.txt"; // Your code to load the model (use appropriate library for pkl files) // Initialize the features double features[]; int fileHandle = FileOpen(featurePath, FILE_READ | FILE_TXT); if (fileHandle != INVALID_HANDLE) { string line; while(!FileIsEnding(fileHandle)) { line = FileReadString(fileHandle); ArrayResize(features, ArraySize(features) + 1); features[ArraySize(features) - 1] = StringToDouble(line); } FileClose(fileHandle); } return(INIT_SUCCEEDED); }
OnTick()でpythonファイルから予測を読み込みます。
void OnTick(){ // Declare static variables to retain values across function calls static bool isNewBar = false; static int prevBars = 0; // Get the current number of bars int newbar = iBars(_Symbol, _Period); // Check if the number of bars has changed if (prevBars == newbar) { // No new bar isNewBar = false; } else { // New bar detected isNewBar = true; // Update previous bars count to current prevBars = newbar; } // Update the features based on current data double features[]; ArrayResize(features, 1); features[0] = iClose(Symbol(), 0, 0); // Write the features to a file int fileHandle = FileOpen("/home/int_junkie/Documents/ML/features.txt", FILE_WRITE | FILE_TXT); if (fileHandle != INVALID_HANDLE) { for (int i = 0; i < ArraySize(features); i++) { FileWrite(fileHandle, DoubleToString(features[i])); } FileClose(fileHandle); } else { Print("Error: Cannot open features file for writing"); return; } // Call the Python script to get the prediction string command = "python /home/int_junkie/Documents/ML/predict.py /home/int_junkie/Documents/ML/random_forest_model.pkl /home/int_junkie/Documents/ML/features.txt"; int result = ShellExecuteA(command); if(result != 0) { Print("Error: ShellExecuteA failed with code ", result); return; } // Read the prediction from a file Sleep(1000); // Wait for the Python script to complete fileHandle = FileOpen("/home/int_junkie/Documents/ML/prediction.txt", FILE_READ | FILE_TXT); if (fileHandle != INVALID_HANDLE) { string prediction = FileReadString(fileHandle); FileClose(fileHandle); double pred_value = StringToDouble(prediction); // Generate trading signals based on predictions double some_threshold = 0.0; // Define your threshold if (pred_value > some_threshold) { // Buy signal double Ask = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_ASK),Digits()); double sl = Ask - stopLoss * _Point; double tp = Ask + takeProfit * _Point; trade.PositionOpen(_Symbol, ORDER_TYPE_BUY, lotsize, Ask, sl, tp, "ML"); } else if (pred_value < some_threshold) { // Sell signal double Bid = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_BID),Digits()); double sl = Bid + stopLoss * _Point; double tp = Bid - takeProfit * _Point; trade.PositionOpen(_Symbol, ORDER_TYPE_SELL, lotsize, Bid, sl, tp, "ML"); } } else { Print("Error: Cannot open prediction file for reading"); } }
OnTickで、変数commandは、特徴量ファイルとモデルファイルを引数としてpythonスクリプトを実行する文字列コマンドを準備します。「ShellExecuteA (command)」は、ShellExecuteAを使ってpythonスクリプトを実行します。「Sleep (1000)」は、pythonスクリプトの実行が完了するまで1秒間待ちます。その後、予測ファイルを開いて読みます。次に、予測ファイルが正常に開いたかどうかをチェックします。正常に開いている場合、予想を読みます。もしそうでなければ、エラーを表示します。閾値変数は、取引の意思決定に使用されます。予測値より大きければ買いシグナル、予測値より小さければ、売りシグナルが発生します。
結論
要約すると、MetaTrader 5取引プラットフォームからデータを収集し、そのデータをJupyter Labで分析・統計処理に利用しました。Jupyter Labでの分析結果を基に、MQL5で取引判断を下すプロセスを統合しました。この統合により、MQL5の限られた分析や可視化機能を補完し、戦略開発やデータの処理効率を向上させます。また、取引における高度なデータ分析と統計処理が可能な柔軟かつ強力な環境を提供します。
結論として、MQL5とJupyter Labを連携させることで、従来の取引プラットフォームでは難しかった高度なデータ分析や統計処理が可能となり、取引戦略の開発・最適化に大きく貢献します。これにより、データ主導のダイナミックな金融取引の分野において、競争力を高めることができます。
MetaQuotes Ltdにより英語から翻訳されました。
元の記事: https://www.mql5.com/en/articles/15155
- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索