MetaTrader5 と Python インテグレーション: データの受信と送信

7 5月 2019, 10:35
Maxim Dmitrievsky
0
359

MQL5 と Python を統合する理由

包括的なデータ処理には広範なツールが必要であり、多くの場合、1つのアプリケーションのサンドボックスの範疇を超えています。 専門のプログラミング言語は、データ、統計、機械学習の処理と分析に使用されます。 データ処理の主要なプログラミング言語の1つは Python です。 効果的な解決策は、言語の力を使用し、トレードシステムの開発のライブラリがあります。

2つ以上のプログラムの相互作用を実装するためのさまざまなソリューションがあります。 ソケットは、最速かつ最も柔軟なソリューションの1つです。

ネットワークソケットは、コンピュータネットワークを介したプロセス間通信のエンドポイントです。 MQL5 標準ライブラリには、インターネットで機能するための低レベルのインターフェイスを提供する Socket 関数のグループがあります。 オペレーティングシステムレベルでシステムコールを使用するため、さまざまなプログラミング言語で共通のインターフェイスです。

価格間のデータ交換は、TCP/IP (伝送制御プロトコル/インターネットプロトコル) 上で実装されています。 したがって、プロセスは、単一のコンピューター内で、ローカルネットワークまたはインターネット経由で通信できます。

接続を確立するには、クライアントプロセスが接続する TCP サーバーを作成して初期化する必要があります。 プロセスの相互作用が完了したら、接続を強制的にクローズする必要があります。 TCP 交換のデータは、バイトのストリームです。

サーバーを作成するときは、ソケットを1つ以上のホスト (IP アドレス) と未使用のポートに関連付ける必要があります。 ホストのリストが設定されていないか、 "0.0.0.0 " と指定されている場合、ソケットはすべてのホストをリッスンします。 "127.0.0.1 " または "localhost" を指定すると、接続は "内部ループ " (つまり、1台のコンピュータ内でのみ) 内でのみ可能になります。

MQL5 ではクライアントのみが利用可能なので、Python でサーバーを作成します。


Python でのソケットサーバーの作成

この記事の目的は Python プログラミングの基本を教えることではありません。 したがって、読者がこの言語に精通していることを前提とします。 

バージョン3.7.2 とビルトイン socket パッケージを使用します。 詳細については、関連ドキュメントを参照してください。

ソケットサーバーを作成し、クライアント (MQL5 プログラム) から必要な情報を受け取り、処理し、結果を返送する簡単なプログラムを作成します。 これは最も効率的なインタラクションメソッドです。 たとえば、scikit learn のような機械学習ライブラリを使用して、MetaTrader5 ターミナルで線を描画できる価格とリターン座標を使用して線形回帰を計算する必要があるとします。 これはあくまで基本的な例です。 しかし、このような相互作用は、ニューラルネットワークのトレーニング、ターミナルからの it データへの送信 (クオート)、結果の学習とターミナルへの復帰などにも利用できます。

socketserver.py プログラムを作成し、上記のライブラリをインポートしてみましょう:

import socket, numpy as np
from sklearn.linear_model import LinearRegression

これで、ソケット操作を担当するクラスの作成に進むことができます。

class socketserver:
    def __init__(self, address = '', port = 9090):
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.address = address
        self.port = port
        self.sock.bind((self.address, self.port))
        self.cummdata = ''
        
    def recvmsg(self):
        self.sock.listen(1)
        self.conn, self.addr = self.sock.accept()
        print('connected to', self.addr)
        self.cummdata = ''

        while True:
            data = self.conn.recv(10000)
            self.cummdata+=data.decode("utf-8")
            if not data:
                break    
            self.conn.send(bytes(calcregr(self.cummdata), "utf-8"))
            return self.cummdata
            
    def __del__(self):
        self.sock.close()

クラスオブジェクトを作成すると、コンストラクタはホスト名 (IP アドレス) とポート番号を取得します。 次に、sockオブジェクトが作成され、アドレスとポートsock.bind()に関連付けられます。

Recvmsgメソッドは、受信接続sock.listen(1)をリッスンします。 受信クライアント接続が到着すると、サーバーは self.sock.accept().を受け入れます。

その後、サーバーは、受信クライアントメッセージに対して無限ループで待機し、ストリームとして到着します。 メッセージの長さは事前にわかっていないため、サーバーは、メッセージ全体がself.conn.recv(10000)で読み取られるまで、このメッセージを部分的に、一度に1キロバイトとして受け取ります。 受信したデータは文字列データ data.decode("utf-8")に変換されます。また、文字列summdataの残りの部分に追加されます。

すべてのデータを受信したら (data:) でない場合、サーバーは計算された回帰直線の右端と左端の座標を含む文字列をクライアントに送信します。 文字列は、conn.send(bytes(calcregr(self.cummdata), "utf-8"))にバイト配列に変換されます。

最後に、メソッドはクライアントから受信した文字列を返します。 とりわけ、受信したクオートの可視化に使用することができます。

デストラクタは、Python プログラムの実行が完了するとソケットを閉じます。

クラスの唯一の可能な実装ではないことに注意してください。 また、メッセージを送受信するためのメソッドを分離して、異なる時点でさまざまな方法で使用することもできます。 接続を作成するための基本的な技術を説明しました。 これで、独自のソリューションを実装できます。

現在の実装における線形回帰学習法について、さらに詳しく考えてみましょう。

def calcregr(msg = ''):
    chartdata = np.fromstring(msg, dtype=float, sep= ' ') 
    Y = np.array(chartdata).reshape(-1,1)
    X = np.array(np.arange(len(chartdata))).reshape(-1,1)
        
    lr = LinearRegression()
    lr.fit(X, Y)
    Y_pred = lr.predict(X)
    type(Y_pred)
    P = Y_pred.astype(str).item(-1) + ' ' + Y_pred.astype(str).item(0)
    print(P)
    return str(P)

受け取ったバイトストリームは utf-8 文字列に変換され、 calcregr (msg = ')メソッドによって受け入れられます。 文字列には、(クライアントで実装されているように) スペースで区切られた価格のシーケンスが含まれるため、float 型のNumPy配列に変換します。 その後、価格配列は列に変換されます (データ受信形式は sclearn) Y = np.array(chartdata).reshape(-1,1). モデルの予測変数は線形時間 (値のシーケンスであり、そのサイズはトレーニングサンプルの長さに等しい) X = np.array(np.arange(len(chartdata))).reshape(-1,1)

続いてトレーニングとモデルの予測が実行され、行の最初と直近の値 (セグメントの端) が "P" 変数に書き込まれ、文字列に変換してクライアントにバイト形式で渡されるようになります。

次に、クラスオブジェクトを作成し、ループで recvmsg() メソッドを呼び出すだけです。

serv = socketserver('127.0.0.1', 9090)

while True:  
    msg = serv.recvmsg()


MQL5 でのソケットクライアントの作成

サーバーに接続し、最近の終値の指定された数を渡し、回帰直線の座標を取得し、チャート上に描画することができる、シンプルなEAを作成してみましょう。 

Socksend() 関数は、データをサーバーに渡します。

bool socksend(int sock,string request) 
  {
   char req[];
   int  len=StringToCharArray(request,req)-1;
   if(len<0) return(false);
   return(SocketSend(sock,req,len)==len); 
  }

文字列を受け取り、バイト配列に変換してサーバーに送信します。

Socketreceive() 関数は、ポートをリッスンします。 サーバー応答を受信すると、関数はを文字列として返します。

string socketreceive(int sock,int timeout)
  {
   char rsp[];
   string result="";
   uint len;
   uint timeout_check=GetTickCount()+timeout;
   do
     {
      len=SocketIsReadable(sock);
      if(len)
        {
         int rsp_len;
         rsp_len=SocketRead(sock,rsp,len,timeout);
         if(rsp_len>0) 
           {
            result+=CharArrayToString(rsp,0,rsp_len); 
           }
        }
     }
   while((GetTickCount()<timeout_check) && !IsStopped());
   return result;
  }

直近の関数 drawlr() は、左と右の行座標が書き込まれた文字列を受け取り、文字列を文字列配列に解析し、線形回帰直線をチャートに描画します。

void drawlr(string points) 
  {
   string res[];
   StringSplit(points,' ',res);

   if(ArraySize(res)==2) 
     {
      Print(StringToDouble(res[0]));
      Print(StringToDouble(res[1]));
      datetime temp[];
      CopyTime(Symbol(),Period(),TimeCurrent(),lrlenght,temp);
      ObjectCreate(0,"regrline",OBJ_TREND,0,TimeCurrent(),NormalizeDouble(StringToDouble(res[0]),_Digits),temp[0],NormalizeDouble(StringToDouble(res[1]),_Digits)); 
     }
  

この関数は、OnTick() ハンドラで実装されます。

void OnTick() {
 socket=SocketCreate();
 if(socket!=INVALID_HANDLE) {
  if(SocketConnect(socket,"localhost",9090,1000)) {
   Print("Connected to "," localhost",":",9090);
         
   double clpr[];
   int copyed = CopyClose(_Symbol,PERIOD_CURRENT,0,lrlenght,clpr);
         
   string tosend;
   for(int i=0;i<ArraySize(clpr);i++) tosend+=(string)clpr[i]+" ";       
   string received = socksend(socket, tosend) ? socketreceive(socket, 10) : ""; 
   drawlr(recieved); }
   
  else Print("Connection ","localhost",":",9090," error ",GetLastError());
  SocketClose(socket); }
 else Print("Socket creation error ",GetLastError()); }

MQL5 Python クライアントサーバーアプリケーションのテスト

このアプリケーションを実行するには、Python インタプリタがインストールされている必要があります。 公式サイトからダウンロードできます。

次に、サーバーアプリケーション socketserver.py を実行します。 ソケットを作成し、MQL5 プログラム socketclientEA.mq5からの新しい接続をリッスンします。

接続が成功すると、接続プロセスと回帰ラインの価格がプログラムウィンドウに表示されます。 価格はクライアントに返送されます:



接続アクティビティと回帰ラインの価格も MetaTrader5 ターミナルに表示されます。 また、回帰直線はチャート上に描画され、新しいティックごとにさらに更新されます。

ソケット接続を介して2つのプログラムの直接相互作用の実装を検討しました。 同時に、MetaQuotes は、ターミナルから直接データを受信できる Python パッケージを開発しました。 詳細については、 MetaTrader での Python の使用に関連するフォーラムの考察を参照してください (ロシア語なので、自動翻訳オプションを使用してください)。

ターミナルからクオートを受け取る方法を示すスクリプトを作成しましょう。

MetaTrader5 Python API を使用したクオートの取得と分析

まず、MetaTrader5 Python モジュールをインストールする必要があります (Python の考察の概要は ここ で利用可能です)。 

pip インストール MetaTrader5

プログラムにインポートし、ターミナルへの接続を初期化します。

from MetaTrader5 import *
from datetime import date
import pandas as pd 
import matplotlib.pyplot as plt 

# Initializing MT5 connection 
MetaTrader5Initialize()
MetaTrader5WaitForTerminal()

print(MetaTrader5TerminalInfo())
print(MetaTrader5Version())

その後、必要な銘柄のリストを作成し、ターミナルからパンダのデータフレームにそれぞれの通貨ペアの終値をリクエストします。

# 相関行列をプロットする通貨ウォッチリストを作成する
sym = ['EURUSD','GBPUSD','USDJPY','USDCHF','AUDUSD','GBPJPY']

# Copying data to dataframe
d = pd.DataFrame()
for i in sym:
     rates = MT5CopyRatesFromPos(i, MT5_TIMEFRAME_M1, 0, 1000)
     d[i] = [y.close for y in rates]

ターミナルからブレイクし、相関行列を計算し、画面上に表示することにより、パーセントの変化として通貨ペアの価格を表すことができます:

# Deinitializing MT5 connection
MetaTrader5Shutdown()

# Compute Percentage Change
rets = d.pct_change()

# Compute Correlation
corr = rets.corr()

# Plot correlation matrix
plt.figure(figsize=(10, 10))
plt.imshow(corr, cmap='RdYlGn', interpolation='none', aspect='auto')
plt.colorbar()
plt.xticks(range(len(corr)), corr.columns, rotation='vertical')
plt.yticks(range(len(corr)), corr.columns);
plt.suptitle('FOREX Correlations Heat Map', fontsize=15, fontweight='bold')
plt.show()

上記のヒートマップで GBPUSD と GBPJPY の間の良好な相関関係を見ることができます。 次に、statmodels ライブラリをインポートして、共同統合をテストします。

# Importing statmodels for cointegration test
import statsmodels
from statsmodels.tsa.stattools import coint

x = d['GBPUSD']
y = d['GBPJPY']
x = (x-min(x))/(max(x)-min(x))
y = (y-min(y))/(max(y)-min(y))

score = coint(x, y)
print('t-statistic: ', score[0], ' p-value: ', score[1])

2つの通貨ペア間の関係は、Z スコアとして表示できます。

# Plotting z-score transformation
diff_series = (x - y)
zscore = (diff_series - diff_series.mean()) / diff_series.std()

plt.plot(zscore)
plt.axhline(2.0, color='red', linestyle='--')
plt.axhline(-2.0, color='green', linestyle='--')

plt.show()



Plotly ライブラリを使用した相場データの視覚化

多くの場合、便利な形式でクオートを視覚化する必要があります。 Plotly ライブラリを使用して実装することができ、インタラクティブ html 形式でのチャートの保存も可能になります。

EURUSD のクオートをダウンロードして、ローソク足チャートに表示してみましょう:

# -*- coding: utf-8 -*-
"""
Created on Thu Mar 14 16:13:03 2019

@author: dmitrievsky
"""
from MetaTrader5 import *
from datetime import datetime
import pandas as pd
# Initializing MT5 connection 
MetaTrader5Initialize()
MetaTrader5WaitForTerminal()

print(MetaTrader5TerminalInfo())
print(MetaTrader5Version())

# Copying data to pandas data frame
stockdata = pd.DataFrame()
rates = MT5CopyRatesFromPos("EURUSD", MT5_TIMEFRAME_M1, 0, 5000)
# Deinitializing MT5 connection
MetaTrader5Shutdown()

stockdata['Open'] = [y.open for y in rates]
stockdata['Close'] = [y.close for y in rates]
stockdata['High'] = [y.high for y in rates]
stockdata['Low'] = [y.low for y in rates]
stockdata['Date'] = [y.time for y in rates]

import plotly.graph_objs as go
from plotly.offline import download_plotlyjs, init_notebook_mode, plot, iplot

trace = go.Ohlc(x=stockdata['Date'],
                open=stockdata['Open'],
                high=stockdata['High'],
                low=stockdata['Low'],
                close=stockdata['Close'])

data = [trace]
plot(data)

また、Bid/Askをダウンロードして表示することも可能です:

# -*- coding: utf-8 -*-
"""
Created on Thu Mar 14 16:13:03 2019

@author: dmitrievsky
"""
from MetaTrader5 import *
from datetime import datetime

# Initializing MT5 connection 
MetaTrader5Initialize()
MetaTrader5WaitForTerminal()

print(MetaTrader5TerminalInfo())
print(MetaTrader5Version())

# Copying data to list
rates = MetaTrader5CopyTicksFrom("EURUSD", datetime(2019,3,14,13), 1000, MetaTrader5_COPY_TICKS_ALL)
bid = [x.bid for x in rates]
ask = [x.ask for x in rates]
time = [x.time for x in rates]

# Deinitializing MT5 connection
MetaTrader5Shutdown()

import plotly.graph_objs as go
from plotly.offline import download_plotlyjs, init_notebook_mode, plot, iplot
data = [go.Scatter(x=time, y=bid), go.Scatter(x=time, y=ask)]

plot(data)


結論

本稿では、ターミナルと Python で書かれたプログラムとの間でソケットを介して直接メタクオーツの専門ライブラリを使用して通信を実装するためのオプションを検討しました。 残念ながら、MetaTrader5 のソケットクライアントの現在の実装はストラテジーテスターでの実行には適していないので、完全なテストとソリューションのパフォーマンスの測定は実行されませんでした。 ソケット関数のさらなる更新を待ちましょう。

MetaQuotes Software Corp.によりロシア語から翻訳された
元の記事: https://www.mql5.com/ru/articles/5691

添付されたファイル |
MetaTraderプログラムを簡単かつ迅速に開発するためのライブラリ(第1部)概念、データ管理および最初の結果 MetaTraderプログラムを簡単かつ迅速に開発するためのライブラリ(第1部)概念、データ管理および最初の結果

膨大な数の取引戦略やMetaTrader 5およびMetaTrader 4ターミナル用アプリケーションの開発の注文、さまざまなMetaTrader Webサイトを分析しているうちに、私は、このすべての多様性のほとんどが、異なるプログラムで定期的に現れる同じ基本的な機能、行動、および価値観に基づいているという結論に達しました。これにより、МetaТrader5およびМetaТrader4アプリケーションを簡単かつ迅速に開発するためのDoEasyクロスプラットフォームライブラリが完成しました。

アルゴリズムトレードにおける Kohonen ニューラルネットワークの活用 パート II. 最適化と予測 アルゴリズムトレードにおける Kohonen ニューラルネットワークの活用 パート II. 最適化と予測

Kohonen ネットワークを扱うために設計されたユニバーサルツールに基づいて、最適なEAパラメータを分析して選択するシステムを構築し、時系列の予測を検討します。 第 I 部では、必要なアルゴリズムを追加して、一般に公開されているニューラルネットワーククラスを修正し、改善しました。 今回はこれを実践に応用しましょう。

トレード戦略の色の最適化 トレード戦略の色の最適化

この記事では、ある実験をします。つまり、色の最適化の結果を行います。 色は、赤、緑、青 (RGB) のレベルの3つのパラメータによって決まります。 他にも3つのパラメータを使用した色分け方法があります。 したがって、3つのテストパラメータを1つの色に変換して、値を視覚的に表すことができます。 この記事を読んで、このような表現が役立つかどうかを確認してください。

取引における相関の実用化 取引における相関の実用化

この記事では、数値の相関の概念について説明し、また相関係数の計算方法と取引における実用的な応用について説明します。相関関係とは、2つ以上の確率変数(またはある程度許容できる程度の精度でそのように考えることができる数量)間の統計的関係です。この時、これらの値の1つまたはいくつかの値の変化は、別または他の値の系統的な変化を伴います。