
Pythonを使ったEAとバックテストのための感情分析とディープラーニング
はじめに
ディープラーニングと感情分析をMetaTrader 5 (MQL5)の取引戦略に統合することは、アルゴリズム取引の高度な進展を意味します。ディープラーニングは機械学習のサブセットであり、複数の層を持つニューラルネットワークを通じて、膨大で複雑なデータセットから学習し予測をおこないます。一方、感情分析は自然言語処理(NLP)の技術を利用して、テキストの背後にある感情や感情的なトーンを解析します。これらの技術を活用することで、トレーダーは意思決定プロセスを強化し、取引結果を向上させることができます。
この記事では、Windowsで必要なものを実行するDLL shell32.dllを使用してPythonをMQL5に統合します。Pythonをインストールし、shell32.dllを介して実行することで、MQL5エキスパートアドバイザー(EA)からPythonスクリプトを起動できるようになります。1つはTensorFlowから学習したONNXモデルを実行するスクリプトで、もう1つはライブラリを使用してインターネットからニュースを取得し、ヘッドラインを読み、AIを使用してメディアの感情を数値化するスクリプトです。これは一つの可能な解決策ですが、銘柄や銘柄の感情を得るには多くの方法やさまざまな情報源があります。モデルと感情が取得されると、両方の値が一致する場合、注文はEAによって実行されます。
感情分析とディープラーニングを組み合わせた結果を理解するために、Pythonでテストをおこなうことはできるでしょうか。できます。ここではコードを見ていきます。
Pythonを使ったディープラーニングによる感情分析のバックテスト
この戦略のバックテストをおこなうために、以下のライブラリを使用します。私の別の記事を出発点として使用します。ここでは必要な説明もします。
以下のライブラリを使用します。import ccxt import pandas as pd import numpy as np import onnx import onnxruntime as ort import matplotlib.pyplot as plt from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score, mean_absolute_percentage_error from sklearn.model_selection import TimeSeriesSplit from sklearn.preprocessing import MinMaxScaler import requests from datetime import datetime, timedelta import nltk from nltk.sentiment import SentimentIntensityAnalyzer from newsapi import NewsApiClient
まず、nltkがアップデートされていることを確認します。
nltk.download('vader_lexicon')
nltk (Natural Language Toolkit)は、人間の言語データ(テキスト)を扱うためのライブラリです。分類、トークン化、ステミング、タグ付け、構文解析、セマンティック推論などのテキスト処理ライブラリ一式に加え、WordNetなどの50以上のコーパスや語彙リソースへの使いやすいインターフェイスを提供します。
読者は、データ、ニュースフィード、ONNXモデル用データの入手先を指定するために、Pythonのバックテストスクリプトを修正しなければなりません。
感情分析を得るために以下を使用します。
def get_news_sentiment(symbol, api_key, date): try: newsapi = NewsApiClient(api_key=api_key) # Obtener noticias relacionadas con el símbolo para la fecha específica end_date = date + timedelta(days=1) articles = newsapi.get_everything(q=symbol, from_param=date.strftime('%Y-%m-%d'), to=end_date.strftime('%Y-%m-%d'), language='en', sort_by='relevancy', page_size=10) sia = SentimentIntensityAnalyzer() sentiments = [] for article in articles['articles']: text = article.get('title', '') if article.get('description'): text += ' ' + article['description'] if text: sentiment = sia.polarity_scores(text) sentiments.append(sentiment['compound']) avg_sentiment = np.mean(sentiments) if sentiments else 0 return avg_sentiment except Exception as e: print(f"Error al obtener el sentimiento para {symbol} en la fecha {date}: {e}") return 0
バックテストでは、フィードとしてnews-apiを使用します。news-apiの無料APIを使用すれば、ニュースの1ヶ月先までの情報を取得できるからです。それ以上必要な場合は、定期購読を購入することができます。
残りのコードでは、ONNXモデルから予測を取得し、次の終値を予測します。感情とディープラーニングによる予測を比較し、両者が同じ結果になれば、注文が作成されます。次のようになります。
investment_df = comparison_df.copy() investment_df['price_direction'] = np.where(investment_df['prediction'].shift(-1) > investment_df['prediction'], 1, -1) investment_df['sentiment_direction'] = np.where(investment_df['sentiment'] > 0, 1, -1) investment_df['position'] = np.where(investment_df['price_direction'] == investment_df['sentiment_direction'], investment_df['price_direction'], 0) investment_df['strategy_returns'] = investment_df['position'] * (investment_df['actual'].shift(-1) - investment_df['actual']) / investment_df['actual'] investment_df['buy_and_hold_returns'] = (investment_df['actual'].shift(-1) - investment_df['actual']) / investment_df['actual']
このコードでは、まずcomparison_dfのコピーを作成し、investment_dfと名付けます。次に、price_directionという新しい列を追加します。この列は、次の予測が現在の予測より高ければ「1」、そうでなければ「-1」という値をとります。次にsentiment_directionという列が追加され、感情が肯定的な場合は「1」、否定的な場合は「-1」となります。そして、positionという列を追加します。この列は、sentiment_directionにマッチすればprice_directionの値になり、そうでなければ0になります。次に、このコードは、positionに、ある行から次の行への実際の値の相対的な変化を乗じて、strategy_returnsを計算します。最後に、ポジションを考慮せずに、ある行から次の行への実際の値の相対的な変化としてbuy_and_hold_returnsを計算します。
このバックテストの結果は次のようになります。
Datos normalizados guardados en 'binance_data_normalized.csv' Sentimientos diarios guardados en 'daily_sentiments.csv' Predicciones y sentimiento guardados en 'predicted_data_with_sentiment.csv' Mean Absolute Error (MAE): 30.66908467315391 Root Mean Squared Error (RMSE): 36.99641752814565 R-squared (R2): 0.9257591918098058 Mean Absolute Percentage Error (MAPE): 0.00870572230484879 Gráfica guardada como 'ETH_USDT_price_prediction.png' Gráfica de residuales guardada como 'ETH_USDT_residuals.png' Correlation between actual and predicted prices: 0.9752007459642241 Gráfica de estrategia de inversión guardada como 'ETH_USDT_investment_strategy.png' Gráfica de drawdown guardada como 'ETH_USDT_drawdown.png' Sharpe Ratio: 9.41431958149606 Sortino Ratio: 11800588386323879936.0000 Número de rendimientos totales: 28 Número de rendimientos en exceso: 28 Número de rendimientos negativos: 19 Media de rendimientos en exceso: 0.005037 Desviación estándar de rendimientos negativos: 0.000000 Sortino Ratio: nan Beta: 0.33875104783408166 Alpha: 0.006981197358213854 Cross-Validation MAE: 1270.7809910146143 ± 527.5746657573876 SMA Mean Absolute Error (MAE): 344.3737716856061 SMA Mean Absolute Error (MAE): 344.3737716856061 SMA Root Mean Squared Error (RMSE): 483.0396130996611 SMA R-squared (R2): 0.5813550203375846 Gráfica de predicción SMA guardada como 'ETH_USDT_sma_price_prediction.png' Gráfica de precio, predicción y sentimiento guardada como 'ETH_USDT_price_prediction_sentiment.png' Gráfica de drawdown guardada como 'ETH_USDT_drawdown.png' Maximum Drawdown: 0.00%
その結果、予測価格と実際の価格との相関関係は非常に良好でした。R2(モデルの予測精度を測る指標)も良好です。シャープレシオは5を上回っており、ソルティノと同様に優れています。また、その他の結果もグラフで示されています。
戦略とホールドを比較したグラフは次のようになります。
以下は、価格予測と実際の価格のような他のグラフです。
以下は、実際の価格、価格予測、感情です。
その結果、この戦略は非常に収益性が高いと結論づけました。
このEAには、感情分析とディープラーニングモデルを作成する2つのPythonスクリプトがあり、EAで機能するようにすべてマージされている必要があります。
ONNXモデル
データ取得、訓練、ONNXモデルのコードは、以前の記事で使用したものと同じです。そこで、感情分析のためのPythonコードについて説明します。
Pythonによる感情分析
FXのニュースを取得し、感情分析をおこなうために、requestsとTextBlobライブラリを使用し、データの読み書きのためにcsvライブラリを使用します。さらに、datetimeライブラリとtimeライブラリが利用されます。
import requests from textblob import TextBlob import csv from datetime import datetime import time from time import sleep
このスクリプトのアイデアは、まず開始時に数秒間遅延させる(スクリプトの次の部分が適切に機能するようにするため)ことです。スクリプトの後半では、使用したいAPIキーを読み込みます。この場合、一連の無料ニュースと無料通話を提供するMarketaux APIを使用します。News API、Alpha Vantage、Finhubなど、有料ではあるが、過去のニュースを含むより多くのニュースを提供し、MT5でストラテジーのバックテストを可能にするオプションもあります。前述したように、日々のニュースを取得するためのAPIが無料で提供されているため、当面はMarketauxを使用します。他のソースを使いたい場合は、コードを変更する必要があります。
スクリプトの下書きはこんな感じです。
以下は、EAの入力からapiキーを読み取る関数です。
api_file_path = 'C:/Users/jsgas/AppData/Roaming/MetaQuotes/Terminal/24F345EB9F291441AFE537834F9D8A19/MQL5/Files/Files/api.txt' print(api_file_path) def read_api_from_file(): try: with open(api_file_path, 'r', encoding='utf-16') as file: raw_data = file.read() print(f"Raw data from file: {repr(raw_data)}") # Print raw data api = raw_data.strip() # Lee el contenido y elimina espacios en blanco adicionales api = api.replace('\ufeff', '') # Remove BOM character if present print(f"API after stripping whitespace: {api}") time.sleep(5) return api except FileNotFoundError: print(f"El archivo {api_file_path} no existe.") time.sleep(5) return None # Configuración de la API de Marketaux api=read_api_from_file() MARKETAUX_API_KEY = api
ニュースを読む前に、何を読むべきかを知る必要があります。そのために、EAが作成したテキストファイルからPythonスクリプトを読み込ませます。Pythonスクリプトは、何を読むべきか、どの銘柄を研究してニュースを取得すべきかを知っています。
また、感情の結果をEAの入力として使用できるように、txtまたはcsvを書き出すことができなければなりません。
def read_symbol_from_file(): try: with open(symbol_file_path, 'r', encoding='utf-16') as file: raw_data = file.read() print(f"Raw data from file: {repr(raw_data)}") # Print raw data symbol = raw_data.strip() # Lee el contenido y elimina espacios en blanco adicionales symbol = symbol.replace('\ufeff', '') # Remove BOM character if present print(f"Symbol after stripping whitespace: {symbol}") return symbol except FileNotFoundError: print(f"El archivo {symbol_file_path} no existe.") return None
def save_sentiment_to_txt(average_sentiment, file_path='C:/Users/jsgas/AppData/Roaming/MetaQuotes/Terminal/24F345EB9F291441AFE537834F9D8A19/MQL5/Files/Files/'+str(symbol)+'sentiment.txt'): with open(file_path, 'w') as f: f.write(f"{average_sentiment:.2f}")
if symbol: news, current_rate = get_forex_news(symbol) if news: print(f"Noticias para {symbol}:") for i, (title, description) in enumerate(news, 1): print(f"{i}. {title}") print(f" {description[:100]}...") # Primeros 100 caracteres de la descripción print(f"\nTipo de cambio actual: {current_rate if current_rate else 'No disponible'}") # Calcular el sentimiento promedio sentiment_scores = [TextBlob(title + " " + description).sentiment.polarity for title, description in news] average_sentiment = sum(sentiment_scores) / len(sentiment_scores) if sentiment_scores else 0 print(f"Sentimiento promedio: {average_sentiment:.2f}") # Guardar resultados en CSV #save_to_csv(symbol, current_rate, average_sentiment) # Guardar sentimiento promedio en un archivo de texto save_sentiment_to_txt(average_sentiment) print("Sentimiento promedio guardado en 'sentiment.txt'") else: print("No se pudieron obtener noticias de Forex.") else: print("No se pudo obtener el símbolo del archivo.")
読者は、外国為替、株式、暗号など、研究内容に応じて脚本全体を適応させなければなりません。
EA
pythonスクリプトを実行するには、shell32.dllをインクルードします。
#include <WinUser32.mqh> #import "shell32.dll" int ShellExecuteW(int hwnd, string lpOperation, string lpFile, string lpParameters, string lpDirectory, int nShowCmd); #import
Fileフォルダにpythonスクリプトを追加します。
string script1 = "C:\\Users\\jsgas\\AppData\\Roaming\\MetaQuotes\\Terminal\\24F345EB9F291441AFE537834F9D8A19\\MQL5\\Files\\Files\\dl model for mql5 v6 Final EURUSD_bien.py"; string script2 = "C:\\Users\\jsgas\\AppData\\Roaming\\MetaQuotes\\Terminal\\24F345EB9F291441AFE537834F9D8A19\\MQL5\\Files\\Files\\sentiment analysis marketaux v6 Final EURUSD_bien.py";
pythonスクリプトの入力と出力へのすべてのパスも追加します。
// Ruta del archivo donde se escribirá el símbolo string filePathSymbol = "//Files//symbol.txt"; // Ruta del archivo donde se escribirá el timeframe string filePathTimeframe = "//Files//timeframe.txt"; string filePathTime = "//Files//time.txt"; string filePathApi = "//Files//api.txt"; string fileToSentiment = "//Files//"+Symbol()+"sentiment.txt"; string file_add = "C://Users//jsgas//AppData//Roaming//MetaQuotes//Terminal//24F345EB9F291441AFE537834F9D8A19//MQL5//Files"; string file_str = "//Files//model_"; string file_str_final = ".onnx"; string file_str_nexo = "_"; string file_add2 = "C:\\Users\\jsgas\\AppData\\Roaming\\MetaQuotes\\Terminal\\24F345EB9F291441AFE537834F9D8A19\\MQL5\\Files"; string file_str2 = "\\Files\\model_"; string file_str_final2 = ".onnx"; string file_str_nexo2 = "_";
MarketauxのAPIキーを入力する必要があります。
input string api_key = "mWpORHgs3GdjqNZkxZwnXmrFLYmG5jhAbVrF"; // MARKETAUX_API_KEY www.marketaux.com
これは、こちらから取得できて次のようになります。
私はmarketauxのために働いているわけではないので、他のニュースフィードや、ご自分が望む/必要とする購読をお使いください。
注文が混ざらないようにマジックナンバーを設定します。
int OnInit() { ExtTrade.SetExpertMagicNumber(Magic_Number);
ここに追加することもできます。
void OpenBuyOrder(double lotSize, double slippage, double stopLoss, double takeProfit) { // Definir la estructura MqlTradeRequest MqlTradeRequest request; MqlTradeResult result; // Inicializar la estructura de la solicitud ZeroMemory(request); // Establecer los parámetros de la orden request.action = TRADE_ACTION_DEAL; request.symbol = _Symbol; request.volume = lotSize; request.type = ORDER_TYPE_BUY; request.price = SymbolInfoDouble(_Symbol, SYMBOL_ASK); request.deviation= slippage; request.sl = stopLoss; request.tp = takeProfit; request.magic = Magic_Number; request.comment = "Buy Order"; // Enviar la solicitud de comercio if(!OrderSend(request,result)) { Print("Error al abrir orden de compra: ", result.retcode);
この最後のコードスニペットは、注文がどのようにおこなわれるかを示しています。
(.pyスクリプトの入力として使用する)ファイルを書き込みます。
void WriteToFile(string filePath, string data) { Print("Intentando abrir el archivo: ", filePath); // Abre el archivo en modo de escritura, crea el archivo si no existe int fileHandle = FileOpen(filePath, FILE_WRITE | FILE_TXT); if(fileHandle != INVALID_HANDLE) { // Escribe los datos en el archivo FileWriteString(fileHandle, data); FileClose(fileHandle); // Cierra el archivo Print("Archivo escrito exitosamente: ", filePath); } else { Print("Error al abrir el archivo ", filePath, ". Código de error: ", GetLastError()); } }
これにより、銘柄、時間枠、現在の日付がファイルに書き込まれます。
void WriteSymbolAndTimeframe() { // Obtén el símbolo actual currentSymbol = Symbol(); // Obtén el período de tiempo del gráfico actual string currentTimeframe = GetTimeframeString(Period()); currentTime = TimeToString(TimeCurrent(), TIME_DATE); // Escribe cada dato en su respectivo archivo WriteToFile(filePathSymbol, currentSymbol); WriteToFile(filePathTimeframe, currentTimeframe); WriteToFile(filePathTime, currentTime); WriteToFile(filePathApi,api_key); Sleep(10000); // Puedes ajustar o eliminar esto según sea necesario }
関数WriteSymbolAndTimeframeは、以下のタスクを実行します。
- まず、現在の取引銘柄を取得してcurrentSymbolに格納します。
- 次に、GetTimeframeString(Period())を使用して、現在のチャートの時間枠を文字列として取得し、currentTimeframeに格納します。
- また、TimeToString(TimeCurrent(), TIME_DATE)を使用して特定のフォーマットで現在時刻を取得し、currentTimeに格納します。
- 次に、これらの値をそれぞれのファイルに書き込みます。
- currentSymbolがfilePathSymbolに書き込まれます。
- currentTimeframeがfilePathTimeframeに書き込まれます。
- currentTimeがfilePathTimeに書き込まれます。
- api_keyがfilePathApiに書き込まれます。
- 最後に、この関数はSleep(10000)を使用して10秒間休止します。
これでスクリプトを起動できます。
void OnTimer() { datetime currentTime2 = TimeCurrent(); // Verifica si ha pasado el intervalo para el primer script if(currentTime2 - lastExecutionTime1 >= interval1) { // Escribe los datos necesarios antes de ejecutar el script WriteSymbolAndTimeframe(); // Ejecuta el primer script de Python int result = ShellExecuteW(0, "open", "cmd.exe", "/c python \"" + script1 + "\"", "", 1); if(result > 32) Print("Script 1 iniciado exitosamente"); else Print("Error al iniciar Script 1. Código de error: ", result); lastExecutionTime1 = currentTime2; }
関数OnTimerは定期的に実行され、以下のタスクをおこないます。
- まず、現在時刻を取得してcurrentTime2に格納します。
- そして、最初のスクリプトの最後の実行からの経過時間(lastExecutionTime1)が、あらかじめ定義された間隔(interval1)以上であるかどうかを確認します。
- 条件が満たされれば、WriteSymbolAndTimeframeを呼び出して必要なデータを書き込みます。
- 次に、cmd.exeを開いてscript1で指定されたPythonスクリプトを実行すShellExecuteWコマンドを実行して、最初のPythonスクリプトを実行します。
- スクリプトの実行が成功すれば(結果が32より大きければ)、成功メッセージが表示され、そうでなければ、対応するエラーコードとともにエラーメッセージが表示されます。
- 最後に、lastExecutionTime1を現在の時刻(currentTime2)に更新します。
この関数でファイルを読むことができます。
string ReadFile(string file_name) { string result = ""; int handle = FileOpen(file_name, FILE_READ|FILE_TXT|FILE_ANSI); // Use FILE_ANSI for plain text if(handle != INVALID_HANDLE) { int file_size = FileSize(handle); // Get the size of the file result = FileReadString(handle, file_size); // Read the whole file content FileClose(handle); } else { Print("Error opening file: ", file_name); } return result; }
このコードでは、引数としてファイル名を取り、ファイルの内容を文字列として返すReadFileという名前の関数を定義しています。まず、空の文字列の結果を初期化し、ファイルハンドルが有効であれば、FileOpenを使用してファイルを読み取り権限付きでプレーンテキストモードで開こうとします。ファイルハンドルが無効であれば、FileSizeを使用してファイルサイズを取得し、FileReadStringを使用してファイルの内容全体を結果に読み取り、FileCloseを使用してファイルを閉じます。
この条件を変更することで、感情をもうひとつ加えることができます。
if(ExtPredictedClass==PRICE_DOWN && Sentiment_number<0) signal=ORDER_TYPE_SELL; // sell condition else { if(ExtPredictedClass==PRICE_UP && Sentiment_number>0) signal=ORDER_TYPE_BUY; // buy condition else Print("No order possible"); }
この場合の感情は10から-10で、0は中立シグナルです。この戦略は好きなように変更できます。
残りのコードは、「MQL5でONNXモデルを使用する方法」稿で使用したシンプルなEAを少し修正したものです。
これは完成したEAではなく、pythonとmql5を使用して感情とディープラーニングのEAを作成する方法の簡単な例です。EAに投資する時間が長くなればなるほど、エラーや問題は少なくなっていきます。これは最先端のケーススタディであり、バックテストは有望な結果を示しています。この記事がお役に立つことを願っています。もしどなたかがニュースの良いサンプルを手に入れたり、しばらくの間うまく機能させることができたら、ぜひ結果を共有してください。戦略をテストするには、デモ口座を使用する必要があります。
結論
結論として、ディープラーニングと感情分析をMetaTrader 5 (MQL5)の取引戦略に統合することは、現代のアルゴリズム取引における高度な能力を示すものです。DLL shell32.dlインターフェイスを通じてPythonスクリプトを活用することで、複雑なモデルをシームレスに実行し、貴重な感情データを取得できます。このプロセスには、Pythonを使用してニュースの感情を分析し、ONNXモデルで価格を予測し、両指標が一致した際に取引を実行することが含まれます。
バックテストの結果、強い相関指標、高いR二乗値、優れたシャープレシオとソルティノレシオが示すように、この戦略の潜在的な収益性が確認されました。これらの結果は、感情分析とディープラーニングの組み合わせが、取引シグナルの精度と戦略全体のパフォーマンスを大幅に向上させる可能性を示唆しています。
今後、完全に機能するEAの開発には、感情分析のためのPythonスクリプトや価格予測のためのONNXモデルなど、さまざまなコンポーネントの綿密な統合が必要です。これらの要素を継続的に改良し、異なる市場やデータソースに戦略を適応させることで、トレーダーは強固で効果的な取引ツールを構築することができます。
本研究は、機械学習、感情分析、アルゴリズム取引の融合に興味を持つ人々にとって重要な基盤となり、より情報に基づいた、潜在的に利益をもたらす取引の意思決定への道を切り開くものです。
MetaQuotes Ltdにより英語から翻訳されました。
元の記事: https://www.mql5.com/en/articles/15225





- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索